Model Context Protocol (MCP) Resources

repository·main·Indexed 43 days ago

https://github.com/cyanheads/model-context-protocol-resources

A collection of guides, utilities, and server implementations for the Model Context Protocol (MCP). Includes development guides for clients and servers, the mcp-ts-template for TypeScript, the mcp-reporter utility, and various example servers for GitHub, Obsidian, Perplexity, and more. Provides technical implementation details for the McpServer class, including resource, tool, and prompt registration using the TypeScript SDK v1.11.0 and Spec 2025-03-26.

Tokens
45.3K
Snippets
64
Records
97
Agent score
49%

What's inside MCP Resources

  1. Introduction to Model Context Protocol (MCP) Servers

    main

    The Model Context Protocol (MCP) is an open standard that standardizes how AI applications (clients/hosts) interact with external data sources and tools (servers). It acts as a universal interface (similar to USB-C for AI) to decouple LLM applications from specific data retrieval or execution logic.

    Core Roles

    • Hosts: Applications (e.g., Claude Desktop, VS Code extensions) that manage MCP clients and interact with the user/LLM.
    • Clients: Protocol handlers within a host that initiate and manage stateful 1:1 connections to servers.
    • Servers: Independent processes (local or remote) that expose capabilities like Resources, Tools, and Prompts.

    Key Capabilities Exposed by Servers

    • Resources: Providing access to data (databases, APIs, filesystems).
    • Tools: Exposing executable functions (API calls, code execution, file manipulation).
    • Prompts: Offering guided interactions via pre-defined prompt templates or workflows.
  2. Explore available MCP Server implementations

    main

    This repository provides a collection of example Model Context Protocol (MCP) server implementations. You can use these to see how different capabilities (file systems, APIs, workflows, etc.) are exposed to LLM agents via MCP.

    Key implementations include:

    • atlas-mcp-server: Neo4j-powered task management for LLM Agents.
    • clinicaltrialsgov-mcp-server: Search and analyze clinical study data.
    • filesystem-mcp-server: Platform-agnostic file and directory management.
    • git-mcp-server: Git operations (clone, branch, commit) via STDIO & Streamable HTTP.
    • github-mcp-server: GitHub API integration for managing repos, issues, and PRs.
    • mentor-mcp-server: AI-powered mentorship/code review via Deepseek API.
    • ntfy-mcp-server: Push notifications via ntfy.sh.
    • obsidian-mcp-server: Secure interaction with Obsidian vaults.
    • perplexity-mcp-server: Real-time web information via Perplexity.
    • pubmed-mcp-server: Biomedical literature retrieval via NCBI.
    • toolkit-mcp-server: System utilities (IP geolocation, network diagnostics, crypto, etc.).
    • workflows-mcp-server: Declarative workflow engine using YAML files.
  3. Introduction to Model Context Protocol (MCP)

    main

    The Model Context Protocol (MCP) is an open standard that standardizes how AI applications (clients/hosts) connect to and interact with external data sources and tools (servers). It acts as a universal interface (similar to USB-C) for plugging capabilities into LLM applications.

    Key Concepts:

    • Consistent Interface: Standardized methods for LLMs to access tools and resources.
    • Enhanced Capabilities: Allows LLMs to interact with databases, APIs, and local systems.
    • Security & Control: Provides structured access patterns with built-in validation.
    • Extensibility & Modularity: Enables adding new capabilities via isolated, reusable server components without modifying the core LLM application.
  4. Handle Timeouts and Request Cancellation

    main
    Implementations SHOULD establish timeouts for sent requests. If a timeout occurs, the sender SHOULD issue a $/cancelRequest notification for that specific request ID and stop waiting. While SDKs often abstract this, the underlying requirement is to enforce a maximum overall timeout, though implementations MAY reset timeouts upon receiving notifications/progress.
  5. Manage Multiple MCP Servers

    main

    You can build a manager to handle multiple MCP server connections simultaneously. This allows you to aggregate tools and resources from different sources.

    Key Capabilities of a Multi-Server Manager:

    • Dynamic Addition: Use addServer(id, config) to connect to new servers. Supports stdio (via command and args) and sse (via url and headers) transports.
    • Capability Discovery: Upon connection, fetch listTools(), listResources(), and listPrompts() to build a local registry of what each server provides.
    • Unified Tool Execution: Implement a findTool(toolName) method to locate which server owns a specific tool, then use that server's specific Client instance to call callTool(toolName, args).
    • Lifecycle Management: Ensure close() is called on all managed clients to prevent hanging processes.
    // Example of adding an SSE server to a manager
    await manager.addServer('my-sse-server', {
      type: 'sse',
      url: 'http://localhost:3000/sse',
      headers: { 'Authorization': 'Bearer token' }
    });
    
    // Example of executing a tool found across servers
    const result = await manager.executeTool('add', { a: 5, b: 3 });
  6. Implement Sampling (Client-Initiated LLM Requests)

    main

    Sampling allows an MCP server to request the LLM's assistance to complete a task (e.g., asking the LLM to write a commit message). This is a request sent by the server to the client.

    Requirements:

    • The client must support the sampling capability.
    • You must check exchange.clientCapabilities?.sampling before attempting a request.
    • The client controls the actual LLM call, including model choice (guided by modelPreferences) and user approval.

    Use exchange.createMessage(samplingRequest) to initiate the request.

    import { McpServerExchange } from "@modelcontextprotocol/sdk/server/index.js";
    import { McpSchema } from "@modelcontextprotocol/sdk/types.js";
    
    async function someToolHandler(input: any, exchange: McpServerExchange) {
      if (!exchange.clientCapabilities?.sampling) {
        return { content: [{ type: "text", text: "Client does not support sampling." }], isError: true };
      }
    
      const samplingRequest: McpSchema.CreateMessageRequest = {
        messages: [
          {
            role: "user",
            content: [{ type: "text", text: `Analyze this data: ${JSON.stringify(input)}` }],
          },
        ],
        modelPreferences: { intelligencePriority: 0.7 },
        maxTokens: 500,
      };
    
      const samplingResult = await exchange.createMessage(samplingRequest);
      const responseText = samplingResult.messages?.[0]?.content?.[0]?.text ?? "No response text found.";
    
      return { content: [{ type: "text", text: `Analysis complete: ${responseText}` }] };
    }
  7. The MCP Server Lifecycle: Connect, Exchange, Terminate

    main

    The MCP connection follows a strict stateful lifecycle:

    1. Initialization

    • The client sends an initialize request containing its protocolVersion, capabilities, and clientInfo.
    • The server responds with its protocolVersion, capabilities, serverInfo, and optional instructions.
    • The client sends an initialized notification to confirm readiness.
    • CRITICAL: Before initialization is complete, only ping requests and server logging notifications are permitted. All other requests are FORBIDDEN.

    2. Message Exchange

    Once initialized, the parties exchange messages based on negotiated capabilities:

    • Request-Response: Used for operations like tools/call, resources/read, prompts/get, and sampling/createMessage.
    • Notifications: One-way updates like listChanged, progress, cancelled, or logging.
    • Ping: Can be used as a keep-alive or health check.

    3. Termination

    Connections end when the transport is closed (e.g., stdin closes for stdio), an unrecoverable error occurs, or the transport layer is dropped.

  8. Understand MCP Server Architecture

    main

    An MCP server implementation is composed of four primary layers:

    1. Protocol Handling: Manages the connection lifecycle, capability negotiation, and JSON-RPC message processing (Requests, Responses, Notifications).
    2. Transport Layer: The physical mechanism for message exchange (e.g., stdio or Streamable HTTP).
    3. Capability Implementation: The actual business logic that provides specific Tools, Resources, or Prompts to the LLM.
    4. Schema Definitions: The data contracts (typically using JSON Schema or zod) that define the expected inputs and outputs for your capabilities.
  9. Manage the MCP Client Lifecycle

    main

    An MCP connection follows a specific lifecycle:

    1. Initialization:
      • Client sends an initialize request (including protocol version and capabilities).
      • Server responds with its own version and capabilities.
      • Client sends an initialized notification to confirm.
    2. Message Exchange: Once initialized, the client and server exchange:
      • Request-Response: A client sends a request and waits for a response.
      • Notifications: One-way messages where no response is expected.
    3. Termination: Connections are closed via the close() method, through transport disconnection, or due to error conditions.
  10. Core MCP Client Architecture and Lifecycle

    main

    An MCP Client is structured around a specific lifecycle and communication pattern to ensure robust integration with LLMs.

    Client Lifecycle:

    1. Connect: Establishing the initial connection to an MCP server.
    2. Exchange: The phase where messages, requests, and responses are communicated between the client and server.
    3. Terminate: Gracefully closing the connection.

    Key Capabilities Managed by Clients:

    • Tools: Executable functions (e.g., API calls, system operations).
    • Resources: Data sources (e.g., files, database records, live system data).
    • Prompts: Pre-defined templates for LLM interactions.
  11. Implement Human-in-the-Loop Security for Tool Calls

    main

    To prevent LLMs from performing unauthorized or harmful actions, implement a security layer that intercepts tool calls.

    Key strategies include:

    • Policy Mapping: Define a map of tool names to security policies (e.g., file-write requires approval, while read-data does not).
    • Rate Limiting: Track maxCallsPerMinute per tool to prevent runaway loops or resource exhaustion.
    • Explicit Approval: For sensitive tools, pause execution to prompt the user for consent via a UI or CLI.
    class SecurityManager {
      private toolPolicies = {
        'file-write': { requiresApproval: true, maxCallsPerMinute: 5 },
        'execute-command': { requiresApproval: true, maxCallsPerMinute: 2 },
        'read-data': { requiresApproval: false, maxCallsPerMinute: 20 }
      };
      
      private toolCallCounts: Record<string, { count: number, timestamp: number }> = {};
      
      async checkToolCall(toolName: string, args: any): Promise<boolean> {
        const policy = this.toolPolicies[toolName] || { requiresApproval: true, maxCallsPerMinute: 10 };
        
        if (!this.checkRateLimit(toolName, policy.maxCallsPerMinute)) {
          return false;
        }
        
        if (policy.requiresApproval) {
          return await this.getUserApproval(toolName, args);
        }
        
        return true;
      }
      
      // ... implementation of checkRateLimit and getUserApproval
    }
  12. Organize MCP Servers using Modular Capability Structure

    main

    For larger MCP servers, avoid registering all capabilities in a single file. Instead, use a modular structure to separate logic from registration.

    Recommended Pattern:

    1. Logic Module: Create a file (e.g., myToolLogic.ts) that exports the Zod inputSchema and the async handler function. This allows for independent testing of the core logic.
    2. Registration Module: Create a file (e.g., registration.ts) that imports the schema and handler, then defines a registration function (e.g., registerMyTool(server: McpServer)) that calls server.tool() or server.resource().
    3. Orchestration: In your main server.ts, import the registration functions and call them during the server initialization phase.
    // --- src/mcp-server/tools/myTool/myToolLogic.ts ---
    export const myToolInputSchema = z.object({ /* ... */ });
    export async function handleMyTool(args: z.infer<typeof myToolInputSchema>) { /* ... */ }
    
    // --- src/mcp-server/tools/myTool/registration.ts ---
    export function registerMyTool(server: McpServer): void {
      server.tool("my-tool", "desc", myToolInputSchema, undefined, handleMyTool);
    }
    
    // --- src/mcp-server/server.ts ---
    function createMcpServerInstance(): McpServer {
      const server = new McpServer({ name: '...', version: '...' });
      registerMyTool(server);
      return server;
    }