MCP Protocol Specification for Tools and Resources: A Complete Implementation Guide

The Model Context Protocol (MCP) specification defines a JSON-RPC based contract that allows LLM-powered clients to discover, invoke, and stream data from server-exposed tools and resources through standardized registration methods and capability negotiation.

The MCP protocol specification for tools and resources is implemented in the modelcontextprotocol/servers repository, which serves as the official reference implementation. This protocol enables secure, discoverable interactions between AI clients and external data sources or computational capabilities.

Core Concepts of the MCP Protocol Specification

The specification establishes distinct abstractions for capabilities exposed by an MCP server:

Concept Specification Definition Implementation in Repository
Tool A callable operation returning a CallToolResult containing messages, resources, or errors. Discovered via the tools/list endpoint and invoked through tools/call. TypeScript modules under src/everything/tools/ (e.g., get-sum.ts, get-tiny-image.ts) register via server.registerTool() in src/everything/tools/index.ts.
Resource Addressable content items (static files or dynamically generated blobs) accessible via URI. Advertised through resources/list and fetched via resources/read, with optional subscription support. Modules under src/everything/resources/ (e.g., templates.ts, session.ts) use server.registerResource() exported from src/everything/resources/index.ts.
ToolAnnotations Optional metadata indicating tool behavior: idempotentHint, destructiveHint, and readOnlyHint. Used by clients to determine auto-invocation safety. Referenced in src/filesystem/README.md (line 180) and implemented in tool config objects passed to registerTool.
Capability Negotiation Handshake protocol where client and server agree on supported features (tools, resources, logging, experimental tasks). src/everything/server/index.ts constructs McpServer with capabilities derived from configuration flags.

How Tools Are Registered in MCP

Tool Registration Flow

The specification requires tools to be registered through a centralized server instance. In src/everything/server/index.ts, the server factory creates an McpServer instance and triggers registration:

  1. Server instantiation with capability flags
  2. Tool module loading via src/everything/tools/index.ts
  3. Individual registration using server.registerTool(name, config, handler)

Tool Configuration Schema

According to the MCP specification (2025-03-26), the configuration object passed to registerTool must conform to:

{
  description: string;
  input_schema: JSONSchema7;      // Required argument validation
  output_schema?: JSONSchema7;    // Optional result validation
  annotations?: {
    idempotentHint?: boolean;     // Safe to retry
    destructiveHint?: boolean;    // Modifies state destructively
    readOnlyHint?: boolean;       // No side effects
  };
}

Example: Registering a Simple Tool

The following implementation from src/everything/tools/get-sum.ts demonstrates a pure, idempotent tool with proper annotations:

import { CallToolResult } from "modelcontextprotocol/types";

export const registerTool = (server: McpServer) => {
  const name = "get-sum";
  const config = {
    description: "Returns the sum of two numbers",
    input_schema: {
      type: "object",
      properties: {
        a: { type: "number" },
        b: { type: "number" },
      },
      required: ["a", "b"],
    },
    // MCP ToolAnnotations – this tool is pure (no side‑effects)
    annotations: { idempotentHint: true, readOnlyHint: true },
  };

  server.registerTool(name, config, async (args): Promise<CallToolResult> => {
    const { a, b } = args as { a: number; b: number };
    return { messages: [{ role: "assistant", content: `${a} + ${b} = ${a + b}` }] };
  });
};

How Resources Are Registered in MCP

Static and Dynamic Resources

The MCP specification distinguishes between static resources (fixed files) and dynamic resources (generated content). Both are registered via server.registerResource(name, uri, config, handler) in src/everything/resources/index.ts.

Dynamic resources, such as the session blob example from src/everything/resources/session.ts, generate content on demand:

export const registerSessionResource = (server: McpServer) => {
  const name = "session-blob";
  const uri = "demo://resource/session/blob";
  const config = {
    description: "Per‑session gzipped data blob",
    mimeType: "application/gzip",
    // MCP ResourceAnnotations (optional)
    annotations: { readOnlyHint: true },
  };

  server.registerResource(name, uri, config, async () => {
    // Generate a gzipped Buffer on demand
    const payload = Buffer.from("session‑specific‑data");
    const gzipped = await gzipAsync(payload);
    return { data: gzipped };
  });
};

Resources are advertised through the resources/list endpoint and accessed via resources/read or real-time subscriptions if the server supports them.

Advanced MCP Features: Task-Based Tools and Annotations

ToolAnnotations for Safety

The MCP specification (2025-03-26) defines ToolAnnotations as critical metadata for client-side safety decisions. As noted in src/filesystem/README.md (line 180), these annotations inform the client whether a tool can be automatically invoked or requires user confirmation:

  • readOnlyHint: Indicates the tool does not modify server state (safe for automatic invocation)
  • idempotentHint: Indicates repeated invocations with the same arguments produce the same result (safe to retry)
  • destructiveHint: Warns that the tool performs destructive operations (requires explicit confirmation)

Long-Running Task Tools

For operations that exceed typical request timeouts, the MCP specification supports task-based tools via server.experimental.tasks.registerToolTask. This pattern, implemented in src/everything/tools/simulate-research-query.ts, allows servers to:

  1. Accept a tool call and return a taskId immediately
  2. Stream progress updates through the progress callback
  3. Complete asynchronously while the client polls or listens for completion
// src/everything/tools/simulate-research-query.ts
export const registerSimulatedTask = (server: McpServer) => {
  const name = "simulate-research-query";
  const config = {
    description: "Runs a multi‑stage simulated research task",
    input_schema: {
      type: "object",
      properties: {
        topic: { type: "string" },
        ambiguous: { type: "boolean" },
      },
      required: ["topic"],
    },
  };

  server.experimental.tasks.registerToolTask(name, config, async (args, progress) => {
    // Emit staged progress updates
    await progress({ status: "searching", detail: "Gathering sources…" });
    await sleep(1000);
    await progress({ status: "reading", detail: "Reading abstracts…" });
    await sleep(1000);
    // Final result
    return { messages: [{ role: "assistant", content: `Research on ${args.topic} completed.` }] };
  });
};

Key Implementation Files in the Reference Server

The modelcontextprotocol/servers repository implements the MCP protocol specification through the following critical paths:

Summary

  • The MCP protocol specification for tools and resources defines a JSON-RPC interface for LLM clients to discover and invoke server capabilities.

  • Tools are registered via server.registerTool() with JSON Schema validation and optional ToolAnnotations (idempotentHint, destructiveHint, readOnlyHint) that govern client-side safety decisions.

  • Resources are registered via server.registerResource() and can be static files or dynamically generated content streams, identified by unique URIs.

  • Task-based tools support long-running operations through server.experimental.tasks.registerToolTask, enabling asynchronous execution with progress streaming.

  • The reference implementation in modelcontextprotocol/servers enforces the specification through TypeScript types in src/everything/server/index.ts, runtime validation, and comprehensive test coverage in src/everything/__tests__/registrations.test.ts.

Frequently Asked Questions

What is the difference between tools and resources in the MCP protocol specification?

Tools are executable functions that perform operations and return structured results (text, images, or errors) to the LLM client. They are invoked on-demand via the tools/call endpoint and can accept parameters validated against JSON Schema. Resources are addressable content items (files, blobs, or generated data) accessed via URI through the resources/read endpoint. Unlike tools, resources are typically read-only streams of data that clients can subscribe to for updates, rather than executable logic. In the reference server, tools live in src/everything/tools/ while resources are defined in src/everything/resources/.

How does MCP handle tool safety and permissions?

The MCP protocol specification defines ToolAnnotations that servers attach to tool registrations to communicate safety characteristics to clients. These boolean hints include readOnlyHint (indicating no state modification), idempotentHint (safe to retry), and destructiveHint (irreversible changes). According to the implementation in src/filesystem/README.md (line 180), clients like VS Code use these annotations to decide whether to auto-invoke a tool or require explicit user confirmation. The TypeScript SDK enforces these types at compile time, while runtime validation ensures tools behave according to their declared annotations.

What is the registration flow for adding new tools to an MCP server?

Adding a tool requires implementing the three-phase registration pattern used in src/everything/server/index.ts. First, create a TypeScript module in src/everything/tools/ that exports a registerTool function accepting an McpServer instance. Second, define the tool's configuration object containing description, input_schema (JSON Schema 7), and optional annotations. Third, invoke server.registerTool(name, config, handler) where the handler implements the business logic and returns a CallToolResult. Finally, export the module from src/everything/tools/index.ts to include it in the server's capability advertisement during client handshake.

How do task-based tools work in the MCP protocol?

Task-based tools extend the standard tool interface to support long-running operations that exceed typical HTTP timeouts. Implemented via server.experimental.tasks.registerToolTask as shown in src/everything/tools/simulate-research-query.ts, these tools accept a progress callback alongside arguments. When invoked, the server immediately returns a taskId while continuing execution asynchronously. The handler emits progress updates through the callback (e.g., {status: "searching", detail: "Gathering sources…"}), which the client receives via polling or server-sent events. This pattern is essential for operations like research queries, file indexing, or data processing that require minutes rather than seconds to complete.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →