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:
- Server instantiation with capability flags
- Tool module loading via
src/everything/tools/index.ts - 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:
- Accept a tool call and return a
taskIdimmediately - Stream progress updates through the
progresscallback - 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:
-
src/everything/server/index.ts– Creates theMcpServerinstance, configures capabilities, and orchestrates registration of all tools, resources, prompts, and instructions. -
src/everything/tools/index.ts– Central export that iterates over tool modules and invokes theirregisterToolfunctions with the server instance. -
src/everything/resources/index.ts– ExportsregisterResourcesandregisterResourceTemplatesto bind static and dynamic resources to the server. -
src/everything/tools/get-sum.ts– Reference implementation of a pure, idempotent tool with completeToolAnnotations. -
src/everything/resources/templates.ts– Demonstrates static file resources and MIME type handling. -
src/filesystem/README.md– Documents real-world usage ofToolAnnotationsfor safety hints (line 180). -
src/everything/__tests__/registrations.test.ts– Validates that the server registers the expected number of tools and resources, ensuring spec compliance.
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 optionalToolAnnotations(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/serversenforces the specification through TypeScript types insrc/everything/server/index.ts, runtime validation, and comprehensive test coverage insrc/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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →