model-context-protocol

Model Context Protocol (MCP) - Open standard for connecting AI applications to external data sources, tools, and systems. Use for building MCP servers (tools, resources, prompts), clients, understanding protocol architecture, and implementing AI integrations.

11 stars

Best use case

model-context-protocol is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Model Context Protocol (MCP) - Open standard for connecting AI applications to external data sources, tools, and systems. Use for building MCP servers (tools, resources, prompts), clients, understanding protocol architecture, and implementing AI integrations.

Teams using model-context-protocol should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/model-context-protocol/SKILL.md --create-dirs "https://raw.githubusercontent.com/enuno/claude-command-and-control/main/skills-templates/model-context-protocol/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/model-context-protocol/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How model-context-protocol Compares

Feature / Agentmodel-context-protocolStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Model Context Protocol (MCP) - Open standard for connecting AI applications to external data sources, tools, and systems. Use for building MCP servers (tools, resources, prompts), clients, understanding protocol architecture, and implementing AI integrations.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Model Context Protocol Skill

The Model Context Protocol (MCP) is an open-source standard that provides a universal way to connect AI-powered applications to external data sources, tools, and systems. Think of MCP as a **USB-C port for AI applications** - a standardized interface that enables seamless integration regardless of the underlying implementation.

**Core Value Proposition**: Build once, connect anywhere. MCP servers work with any MCP-compatible AI application, eliminating the need for custom integrations per application.

## When to Use This Skill

This skill should be triggered when:
- Building MCP servers to expose tools, resources, or prompts
- Implementing MCP clients in AI applications
- Understanding MCP protocol architecture and message flow
- Creating tool handlers for AI agent operations
- Implementing resource providers for data access
- Building prompt templates for AI interactions
- Integrating external services with AI applications
- Debugging MCP server/client communication

## Protocol Overview

### The AI Integration Paradox

MCP addresses a fundamental challenge: **AI systems need dynamic, context-aware access to resources, but traditional APIs were built for predictable workflows.**

Traditional APIs assume:
- Known endpoints at design time
- Predictable request patterns
- Static data schemas

AI systems require:
- **Dynamic Discovery** - Identify needed resources at runtime
- **Rich Context Exchange** - Metadata and relationships flow with data
- **Secure Sandboxing** - Controlled access without direct AI permissions
- **Bidirectional Communication** - Systems ask questions, not just consume

### The Problem MCP Solves

Before MCP:
- Each AI application builds custom integrations for each data source
- Every data source implements provider-specific APIs
- N applications × M data sources = N×M integrations

After MCP:
- One protocol specification
- N + M implementations needed
- Any server works with any client

### The USB-C Analogy

Just as USB-C provides a universal connector for devices:
- **MCP Host** = Device (AI application like Claude Desktop)
- **MCP Client** = Port (connection manager within the host)
- **MCP Server** = Peripheral (service providing context)

### Mediated Access Pattern (Security Broker Model)

> "The Host mediates ALL AI-resource interactions"

```
┌────────────────────────────────────────────────────────┐
│                     HOST APPLICATION                    │
│            (Claude Desktop, IDE, Custom App)            │
│                                                        │
│   ┌──────────┐   ┌──────────┐   ┌──────────┐         │
│   │ Client 1 │   │ Client 2 │   │ Client 3 │         │
│   │   ↕      │   │   ↕      │   │   ↕      │         │
│   │Server A  │   │Server B  │   │Server C  │   1:1   │
│   └──────────┘   └──────────┘   └──────────┘  mapping │
└────────────────────────────────────────────────────────┘
```

Key security principles:
- Each Client-Server pair is isolated
- Host acts as central authority
- No direct AI-to-resource access
- Prevents resource interference

---

## Architecture

### Core Components

```
┌─────────────────────────────────────────────────────────────┐
│                    MCP ARCHITECTURE                          │
└─────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────┐
│                        HOST (AI App)                          │
│  ┌────────────────────────────────────────────────────────┐  │
│  │                    MCP CLIENT                           │  │
│  │  • Maintains 1:1 connections with servers              │  │
│  │  • Handles protocol negotiation                         │  │
│  │  • Routes messages to/from servers                      │  │
│  └───────────┬────────────────────────┬───────────────────┘  │
│              │                        │                       │
└──────────────┼────────────────────────┼───────────────────────┘
               │ stdio                  │ HTTP
               ▼                        ▼
┌──────────────────────┐    ┌──────────────────────┐
│    LOCAL SERVER      │    │   REMOTE SERVER      │
│  (subprocess)        │    │   (network)          │
│                      │    │                      │
│  • Tools             │    │  • Tools             │
│  • Resources         │    │  • Resources         │
│  • Prompts           │    │  • Prompts           │
└──────────────────────┘    └──────────────────────┘
```

### Communication Protocol

MCP uses **JSON-RPC 2.0** over various transports (Specification: 2024-11-05):

**JSON-RPC Requirements:**
- `id` MUST NOT be null for requests (use string or integer)
- `id` MUST be unique within a session
- Requests expect responses; notifications do not
- Unknown methods return `-32601` (Method not found)

```typescript
// Request (id required, must be unique per session)
{
  "jsonrpc": "2.0",
  "id": "req-1",  // String or integer, never null
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": { "city": "San Francisco" }
  }
}

// Response (id matches request)
{
  "jsonrpc": "2.0",
  "id": "req-1",
  "result": {
    "content": [{
      "type": "text",
      "text": "Weather in San Francisco: 65°F, partly cloudy"
    }]
  }
}

// Notification (no id, no response expected)
{
  "jsonrpc": "2.0",
  "method": "notifications/resources/updated",
  "params": { "uri": "file:///data/config.json" }
}
```

### Connection Lifecycle

```
┌─────────────────────────────────────────────────────────────┐
│                  CONNECTION LIFECYCLE                        │
└─────────────────────────────────────────────────────────────┘

1. INITIALIZATION (Version Negotiation)
   Client ──initialize──────► Server
     └─ protocolVersion: "2024-11-05"
     └─ capabilities: { sampling: {}, roots: {} }
     └─ clientInfo: { name, version }

   Client ◄──result────────── Server
     └─ protocolVersion: "2024-11-05"  (server's supported version)
     └─ capabilities: { tools: {}, resources: {} }
     └─ serverInfo: { name, version }

   Client ──initialized──────► Server (notification, no response)

2. OPERATION PHASE
   Client ◄──► Server (bidirectional messages)
   • Client calls server methods (tools/call, resources/read)
   • Server sends notifications (resource updates, progress)
   • Server may call client methods (sampling/createMessage)

3. TERMINATION
   For stdio:  Close input stream, wait for server exit, terminate
   For HTTP:   Send HTTP DELETE with Mcp-Session-Id header
```

**Version Negotiation:**
- Client sends supported `protocolVersion` in `initialize`
- Server responds with its version (SHOULD match or be compatible)
- If incompatible, client MAY disconnect or proceed with limitations

---

## Server Primitives

MCP servers expose three primary primitives:

### 1. Tools (Model-Controlled)

Tools are **executable functions** that AI models can invoke to perform actions:

```json
{
  "name": "send_email",
  "description": "Send an email to a recipient",
  "inputSchema": {
    "type": "object",
    "properties": {
      "to": {
        "type": "string",
        "description": "Recipient email address"
      },
      "subject": {
        "type": "string",
        "description": "Email subject line"
      },
      "body": {
        "type": "string",
        "description": "Email body content"
      }
    },
    "required": ["to", "subject", "body"]
  }
}
```

**Tool Call Flow:**
```
1. Client requests: tools/list
2. Server returns: Available tools with schemas
3. Model decides to call tool
4. Client sends: tools/call with arguments
5. Server executes and returns: result content
```

**Tool Result Content Types:**
- `text` - Plain text response
- `image` - Base64-encoded image data
- `audio` - Base64-encoded audio data
- `resource` - Embedded resource content

**Error Handling with `isError`:**
```json
// Normal result
{
  "content": [{ "type": "text", "text": "Success!" }],
  "isError": false  // Optional, defaults to false
}

// Execution error (not a JSON-RPC error)
{
  "content": [{ "type": "text", "text": "File not found: /data/missing.txt" }],
  "isError": true  // Tool ran but encountered an error
}
```

Use `isError: true` when the tool executed but encountered an expected error (file not found, validation failed, etc.). Use JSON-RPC errors for protocol-level failures.

### 2. Resources (Application-Controlled)

Resources are **data sources** that provide context to AI applications:

```json
{
  "uri": "file:///projects/myapp/README.md",
  "name": "README.md",
  "description": "Project readme file",
  "mimeType": "text/markdown"
}
```

**Resource URIs:**
- Standard schemes: `file://`, `https://`
- Custom schemes: `postgres://`, `git://`
- Resource templates: `file:///{path}` (parameterized)

**Resource Templates:**
```json
{
  "uriTemplate": "file:///{path}",
  "name": "Project Files",
  "description": "Access files in the project directory",
  "mimeType": "text/plain"
}
```
Templates use URI Template syntax (RFC 6570) for parameterized resource access. Servers that support templates should also expose `completion/complete` for auto-completion.

**Content Types:**
```json
// Text content
{
  "uri": "file:///README.md",
  "mimeType": "text/markdown",
  "text": "# Project Title\n..."
}

// Binary content (blob)
{
  "uri": "file:///image.png",
  "mimeType": "image/png",
  "blob": "iVBORw0KGgoAAAANSUhEUgAA..."  // base64-encoded
}
```

**Resource Operations:**
```json
// List resources
{ "method": "resources/list" }

// Read resource
{
  "method": "resources/read",
  "params": { "uri": "file:///data/config.json" }
}

// Subscribe to changes
{
  "method": "resources/subscribe",
  "params": { "uri": "file:///data/config.json" }
}
```

### 3. Prompts (User-Controlled)

Prompts are **reusable templates** for AI interactions:

```json
{
  "name": "code_review",
  "title": "Request Code Review",
  "description": "Analyze code quality and suggest improvements",
  "arguments": [
    {
      "name": "code",
      "description": "The code to review",
      "required": true
    },
    {
      "name": "language",
      "description": "Programming language",
      "required": false
    }
  ]
}
```

**Prompt Messages:**
```json
{
  "method": "prompts/get",
  "params": {
    "name": "code_review",
    "arguments": {
      "code": "def hello(): print('world')",
      "language": "python"
    }
  }
}

// Response
{
  "result": {
    "messages": [
      {
        "role": "user",
        "content": {
          "type": "text",
          "text": "Please review this Python code:\ndef hello(): print('world')"
        }
      }
    ]
  }
}
```

---

## Client Features

### Sampling (Server → LLM)

Servers can request LLM completions through the client:

```json
{
  "method": "sampling/createMessage",
  "params": {
    "messages": [
      {
        "role": "user",
        "content": {
          "type": "text",
          "text": "Summarize this document..."
        }
      }
    ],
    "modelPreferences": {
      "hints": [{ "name": "claude-3-sonnet" }],
      "intelligencePriority": 0.8,
      "speedPriority": 0.5
    },
    "systemPrompt": "You are a helpful assistant.",
    "maxTokens": 500
  }
}
```

**Model Preferences (0-1 scale):**
- `costPriority` - Prefer cheaper models
- `speedPriority` - Prefer faster models
- `intelligencePriority` - Prefer more capable models

**Human-in-the-Loop:** Sampling requests SHOULD be reviewed by users before execution.

### Roots (Context Boundaries)

Clients can expose filesystem roots to servers:

```json
{
  "capabilities": {
    "roots": {
      "listChanged": true
    }
  }
}
```

Roots define boundaries for server access, allowing servers to understand which directories or resources they can interact with.

---

## Utilities

MCP includes base utilities and server utilities for protocol-level operations.

### Base Utilities

**Ping (Connection Health):**
```json
// Request
{ "jsonrpc": "2.0", "id": 1, "method": "ping" }

// Response
{ "jsonrpc": "2.0", "id": 1, "result": {} }
```
Used to check connection health. Either party can send ping; receiver MUST respond promptly.

**Cancellation:**
```json
{
  "jsonrpc": "2.0",
  "method": "notifications/cancelled",
  "params": {
    "requestId": "req-123",
    "reason": "User cancelled operation"
  }
}
```
Notification to cancel a pending request. The receiver SHOULD stop processing and MAY return a partial result or error.

**Progress Notifications:**
```json
{
  "jsonrpc": "2.0",
  "method": "notifications/progress",
  "params": {
    "progressToken": "token-456",
    "progress": 50,
    "total": 100,
    "message": "Processing files..."
  }
}
```
For long-running operations. The `progressToken` is provided in the original request's `_meta.progressToken`.

### Server Utilities

**Completion (Auto-complete):**
```json
// Request
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "completion/complete",
  "params": {
    "ref": {
      "type": "ref/resource",
      "uri": "file:///{path}"
    },
    "argument": {
      "name": "path",
      "value": "src/"
    }
  }
}

// Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "completion": {
      "values": ["src/index.ts", "src/utils/", "src/types/"],
      "hasMore": false
    }
  }
}
```
Provides auto-completion suggestions for resource template arguments or prompt arguments.

**Logging:**
```json
{
  "jsonrpc": "2.0",
  "method": "notifications/message",
  "params": {
    "level": "info",  // debug, info, notice, warning, error, critical, alert, emergency
    "logger": "database",
    "data": "Connected to PostgreSQL at localhost:5432"
  }
}
```
Servers can send log messages to clients. The client MAY filter based on level threshold set via `logging/setLevel`.

**Pagination:**
For large result sets, use cursor-based pagination:
```json
// Request with cursor
{
  "method": "tools/list",
  "params": { "cursor": "eyJvZmZzZXQiOjEwMH0=" }
}

// Response with next cursor
{
  "result": {
    "tools": [...],
    "nextCursor": "eyJvZmZzZXQiOjIwMH0="  // null if no more results
  }
}
```
Cursors are opaque strings. Clients SHOULD NOT assume any structure.

---

## Transports

### stdio Transport (Local)

For subprocess-based communication:

```bash
# Server launched by client as subprocess
$ my-mcp-server

# Communication via stdin/stdout
Server reads: stdin (JSON-RPC messages)
Server writes: stdout (JSON-RPC responses)
Server logs: stderr (debugging only)
```

**Requirements:**
- Messages delimited by newlines
- Must NOT contain embedded newlines
- Client SHOULD support stdio whenever possible

### Streamable HTTP Transport (Remote)

For network-based communication:

```
POST /mcp HTTP/1.1
Content-Type: application/json
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2025-06-18

{"jsonrpc":"2.0","id":1,"method":"tools/list"}
```

**Response Types:**
- `application/json` - Single JSON response
- `text/event-stream` - SSE stream for multiple messages

**Session Management:**
```
1. Server returns: Mcp-Session-Id header
2. Client includes: Mcp-Session-Id in subsequent requests
3. Server MAY: Return 404 to terminate session
4. Client MAY: DELETE with session ID to close
```

**Security Requirements:**
- Validate `Origin` header (prevent DNS rebinding)
- Local servers bind to localhost only
- Implement authentication for remote access

---

## SDK Installation

### TypeScript

```bash
npm install @modelcontextprotocol/sdk
```

```typescript
import { McpServer, StdioServerTransport } from "@modelcontextprotocol/sdk/server";

const server = new McpServer({
  name: "my-server",
  version: "1.0.0"
});

// Add a tool
server.tool("get_weather", {
  description: "Get weather for a city",
  inputSchema: {
    type: "object",
    properties: {
      city: { type: "string", description: "City name" }
    },
    required: ["city"]
  }
}, async (args) => {
  const weather = await fetchWeather(args.city);
  return {
    content: [{ type: "text", text: `Weather: ${weather}` }]
  };
});

// Start server
const transport = new StdioServerTransport();
await server.connect(transport);
```

**GitHub**: https://github.com/modelcontextprotocol/typescript-sdk

### Python

```bash
pip install mcp
# or with uv
uv add mcp
```

```python
from mcp.server import Server
from mcp.server.stdio import stdio_server

server = Server("my-server")

@server.tool()
async def get_weather(city: str) -> str:
    """Get weather for a city."""
    weather = await fetch_weather(city)
    return f"Weather: {weather}"

@server.resource("config://app")
async def get_config() -> str:
    """Get application configuration."""
    return json.dumps(config)

async def main():
    async with stdio_server() as (read, write):
        await server.run(read, write)

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())
```

**GitHub**: https://github.com/modelcontextprotocol/python-sdk

### Other SDKs

| Language | Installation | Repository |
|----------|--------------|------------|
| **Go** | `go get github.com/modelcontextprotocol/go-sdk` | [go-sdk](https://github.com/modelcontextprotocol/go-sdk) |
| **Kotlin** | Maven/Gradle | [kotlin-sdk](https://github.com/modelcontextprotocol/kotlin-sdk) |
| **Swift** | Swift Package Manager | [swift-sdk](https://github.com/modelcontextprotocol/swift-sdk) |
| **Java** | Maven | [java-sdk](https://github.com/modelcontextprotocol/java-sdk) |
| **C#** | NuGet | [csharp-sdk](https://github.com/modelcontextprotocol/csharp-sdk) |
| **Ruby** | `gem install mcp` | [ruby-sdk](https://github.com/modelcontextprotocol/ruby-sdk) |
| **Rust** | `cargo add mcp` | [rust-sdk](https://github.com/modelcontextprotocol/rust-sdk) |
| **PHP** | Composer | [php-sdk](https://github.com/modelcontextprotocol/php-sdk) |

---

## Building an MCP Server

### Minimal TypeScript Server

```typescript
import { McpServer, StdioServerTransport } from "@modelcontextprotocol/sdk/server";

const server = new McpServer({
  name: "example-server",
  version: "1.0.0",
  capabilities: {
    tools: {},
    resources: {},
    prompts: {}
  }
});

// Tool: Calculate
server.tool("calculate", {
  description: "Perform basic calculations",
  inputSchema: {
    type: "object",
    properties: {
      operation: { type: "string", enum: ["add", "subtract", "multiply", "divide"] },
      a: { type: "number" },
      b: { type: "number" }
    },
    required: ["operation", "a", "b"]
  }
}, async ({ operation, a, b }) => {
  let result: number;
  switch (operation) {
    case "add": result = a + b; break;
    case "subtract": result = a - b; break;
    case "multiply": result = a * b; break;
    case "divide": result = a / b; break;
  }
  return {
    content: [{ type: "text", text: `Result: ${result}` }]
  };
});

// Resource: Static config
server.resource("config://app", {
  name: "App Configuration",
  description: "Application settings",
  mimeType: "application/json"
}, async () => {
  return {
    contents: [{
      uri: "config://app",
      mimeType: "application/json",
      text: JSON.stringify({ version: "1.0", debug: false })
    }]
  };
});

// Prompt: Greeting
server.prompt("greeting", {
  name: "greeting",
  description: "Generate a personalized greeting",
  arguments: [
    { name: "name", description: "Person's name", required: true }
  ]
}, async ({ name }) => {
  return {
    messages: [{
      role: "user",
      content: { type: "text", text: `Please greet ${name} warmly.` }
    }]
  };
});

// Connect transport
const transport = new StdioServerTransport();
await server.connect(transport);
```

### Minimal Python Server

```python
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent, Resource, Prompt, PromptMessage

server = Server("example-server")

# Tool: Calculate
@server.tool()
async def calculate(operation: str, a: float, b: float) -> list[TextContent]:
    """Perform basic calculations (add, subtract, multiply, divide)."""
    ops = {
        "add": a + b,
        "subtract": a - b,
        "multiply": a * b,
        "divide": a / b if b != 0 else float('inf')
    }
    result = ops.get(operation, 0)
    return [TextContent(type="text", text=f"Result: {result}")]

# Resource: Config
@server.resource("config://app")
async def get_config() -> str:
    """Application configuration."""
    return '{"version": "1.0", "debug": false}'

# Prompt: Greeting
@server.prompt()
async def greeting(name: str) -> list[PromptMessage]:
    """Generate a personalized greeting."""
    return [
        PromptMessage(
            role="user",
            content=TextContent(type="text", text=f"Please greet {name} warmly.")
        )
    ]

async def main():
    async with stdio_server() as (read, write):
        await server.run(read, write)

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())
```

---

## Building an MCP Client

### TypeScript Client

```typescript
import { McpClient, StdioClientTransport } from "@modelcontextprotocol/sdk/client";
import { spawn } from "child_process";

// Spawn server as subprocess
const serverProcess = spawn("node", ["path/to/server.js"]);

// Create client
const client = new McpClient({
  name: "my-client",
  version: "1.0.0"
});

// Connect via stdio
const transport = new StdioClientTransport({
  reader: serverProcess.stdout,
  writer: serverProcess.stdin
});

await client.connect(transport);

// Initialize and get capabilities
const capabilities = await client.initialize();
console.log("Server capabilities:", capabilities);

// List available tools
const tools = await client.listTools();
console.log("Available tools:", tools);

// Call a tool
const result = await client.callTool("calculate", {
  operation: "add",
  a: 5,
  b: 3
});
console.log("Tool result:", result);

// List and read resources
const resources = await client.listResources();
const config = await client.readResource("config://app");
console.log("Config:", config);

// Get a prompt
const prompt = await client.getPrompt("greeting", { name: "Alice" });
console.log("Prompt messages:", prompt.messages);

// Cleanup
await client.close();
serverProcess.kill();
```

### Python Client

```python
from mcp.client import ClientSession
from mcp.client.stdio import stdio_client
import subprocess
import asyncio

async def main():
    # Spawn server subprocess
    server = subprocess.Popen(
        ["python", "path/to/server.py"],
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE
    )

    # Connect client
    async with stdio_client(server.stdin, server.stdout) as (read, write):
        async with ClientSession(read, write) as session:
            # Initialize
            await session.initialize()

            # List tools
            tools = await session.list_tools()
            print("Tools:", tools)

            # Call tool
            result = await session.call_tool("calculate", {
                "operation": "multiply",
                "a": 7,
                "b": 6
            })
            print("Result:", result)

            # Read resource
            config = await session.read_resource("config://app")
            print("Config:", config)

if __name__ == "__main__":
    asyncio.run(main())
```

---

## Capabilities Negotiation

Servers and clients exchange capabilities during initialization:

### Server Capabilities

```json
{
  "capabilities": {
    "tools": {
      "listChanged": true
    },
    "resources": {
      "subscribe": true,
      "listChanged": true
    },
    "prompts": {
      "listChanged": true
    },
    "logging": {}
  }
}
```

### Client Capabilities

```json
{
  "capabilities": {
    "sampling": {},
    "roots": {
      "listChanged": true
    }
  }
}
```

### Capability Flags

| Capability | Flag | Description |
|------------|------|-------------|
| `tools.listChanged` | boolean | Server sends notifications when tools change |
| `resources.subscribe` | boolean | Client can subscribe to resource updates |
| `resources.listChanged` | boolean | Server sends notifications when resources change |
| `prompts.listChanged` | boolean | Server sends notifications when prompts change |
| `sampling` | object | Client supports LLM sampling requests |
| `roots.listChanged` | boolean | Client sends notifications when roots change |

---

## Error Handling

### JSON-RPC Error Codes

| Code | Name | Description |
|------|------|-------------|
| -32700 | Parse error | Invalid JSON |
| -32600 | Invalid Request | Not a valid JSON-RPC request |
| -32601 | Method not found | Unknown method name |
| -32602 | Invalid params | Invalid method parameters |
| -32603 | Internal error | Server-side error |

### Error Response Format

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params",
    "data": {
      "details": "Missing required parameter: city"
    }
  }
}
```

### Best Practices

1. **Validate inputs** before processing
2. **Return descriptive errors** with actionable messages
3. **Use appropriate error codes** for different failure types
4. **Include error data** for debugging when helpful
5. **Log errors** for server-side troubleshooting

---

## Security Considerations

### Transport Security

- **stdio**: Inherently secure (same machine)
- **HTTP**: Use HTTPS in production
- **Origin validation**: Prevent DNS rebinding attacks
- **Session tokens**: Cryptographically secure (UUID, JWT)

### Input Validation

```typescript
// Always validate tool inputs
server.tool("query_database", schema, async (args) => {
  // Validate SQL to prevent injection
  if (!isValidQuery(args.query)) {
    throw new Error("Invalid query format");
  }
  // Sanitize parameters
  const sanitizedParams = sanitize(args.params);
  // Execute with prepared statements
  return await db.query(args.query, sanitizedParams);
});
```

### Resource Access

```typescript
// Validate resource URIs
server.resource("file://{path}", async (uri, params) => {
  const path = params.path;
  // Prevent directory traversal
  if (path.includes("..") || path.startsWith("/")) {
    throw new Error("Invalid path");
  }
  // Check allowed directories
  if (!isInAllowedDirectory(path)) {
    throw new Error("Access denied");
  }
  return await readFile(path);
});
```

### Sampling Security

- **Human-in-the-loop**: Always allow user review
- **Rate limiting**: Prevent abuse
- **Content filtering**: Validate request/response content
- **Cost controls**: Set token limits

---

## Best Practices

### For Server Developers

1. **Implement clear tool descriptions** - Models rely on these to decide when to use tools
2. **Use JSON Schema properly** - Define required fields, types, and constraints
3. **Return structured content** - Use appropriate content types (text, image, resource)
4. **Handle errors gracefully** - Provide actionable error messages
5. **Support notifications** - Emit `listChanged` when capabilities update
6. **Implement pagination** - For large resource/tool lists
7. **Document your server** - Describe capabilities and usage patterns

### For Client Developers

1. **Handle all message types** - Requests, responses, notifications
2. **Implement timeout handling** - Don't block indefinitely
3. **Support reconnection** - Handle transport failures gracefully
4. **Respect capabilities** - Only use features the server supports
5. **Implement human-in-the-loop** - For sampling requests
6. **Cache appropriately** - Tools/resources/prompts lists

### Security Best Practices

1. **Validate all inputs** - Never trust user or model input
2. **Use least privilege** - Request only necessary permissions
3. **Sanitize outputs** - Prevent injection attacks
4. **Implement rate limiting** - Protect against abuse
5. **Log audit trails** - Track all operations
6. **Use secure transports** - HTTPS for remote, validate origins

---

## Production Operations

### Performance Targets

Production MCP servers should target:

| Metric | Target | Notes |
|--------|--------|-------|
| **Throughput** | >1,000 req/sec | Per instance |
| **Latency (P95)** | <100ms | Simple operations |
| **Error Rate** | <0.1% | Under normal conditions |
| **Availability** | >99.9% | Uptime target |

### Architectural Principles

**Single Responsibility**: Each server should have one clear, well-defined purpose:
```
✅ weather-server     → Only weather data
✅ database-server    → Only database operations
❌ everything-server  → Too broad, hard to maintain
```

**Defense in Depth**: Layer security controls:
```
Network → Authentication → Authorization → Input Validation → Output Sanitization
```

**Fail-Safe Design**: Graceful degradation:
- Circuit breakers for external APIs
- Caching fallbacks when services are down
- Safe defaults when configuration missing

### Health Checks

Expose comprehensive health endpoints:
```json
{
  "status": "healthy",
  "checks": {
    "database": "connected",
    "cache": "available",
    "external_api": "reachable",
    "disk_space": "sufficient",
    "memory": "normal"
  },
  "uptime": 86400,
  "version": "1.0.0"
}
```

### Monitoring & Observability

**Key Metrics to Collect:**
- Request count, latency (P50, P95, P99)
- Active connections
- Error count by type
- Resource usage (CPU, memory)

**Structured Logging:**
```json
{
  "timestamp": "2024-01-15T10:30:00Z",
  "level": "info",
  "client_id": "client-123",
  "method": "tools/call",
  "tool": "get_weather",
  "duration_ms": 45,
  "status": "success"
}
```

---

## Testing and Debugging

### MCP Inspector

The MCP Inspector is an interactive developer tool for testing and debugging MCP servers. It provides a web-based interface without requiring installation.

**Basic Usage:**
```bash
# Run directly via npx (no installation needed)
npx @modelcontextprotocol/inspector <command>

# With arguments
npx @modelcontextprotocol/inspector <command> <arg1> <arg2>
```

**Inspecting Different Server Types:**
```bash
# NPM packages
npx -y @modelcontextprotocol/inspector npx @modelcontextprotocol/server-filesystem /path/to/dir

# PyPI packages
npx @modelcontextprotocol/inspector uvx mcp-server-git --repository ~/code/repo.git

# Local TypeScript server
npx @modelcontextprotocol/inspector node path/to/server/index.js args...

# Local Python server
npx @modelcontextprotocol/inspector uv --directory path/to/server run package-name args...
```

**Inspector UI Panels:**

| Panel | Purpose |
|-------|---------|
| **Server Connection** | Configure transport, command-line args, environment variables |
| **Resources Tab** | List resources, view metadata, inspect content, test subscriptions |
| **Prompts Tab** | View templates, test with custom arguments, preview generated messages |
| **Tools Tab** | Browse tool schemas, test with custom inputs, view execution results |
| **Notifications** | Monitor server logs and notifications in real-time |

**Development Workflow:**

```
┌─────────────────────────────────────────────────────────────┐
│                INSPECTOR DEVELOPMENT WORKFLOW                │
└─────────────────────────────────────────────────────────────┘

1. VERIFICATION
   • Launch Inspector with your server
   • Verify basic connectivity
   • Check capability negotiation

2. ITERATION
   • Make server code changes
   • Rebuild server
   • Reconnect Inspector
   • Test affected features
   • Monitor JSON-RPC messages

3. EDGE CASES
   • Test invalid inputs
   • Missing prompt arguments
   • Concurrent operations
   • Verify error handling
```

**Repository:** https://github.com/modelcontextprotocol/inspector

### Debugging Tips

1. **Enable verbose logging** - Set `DEBUG=mcp:*` environment variable
2. **Inspect JSON-RPC messages** - Log raw request/response pairs
3. **Test tools individually** - Before integrating with clients
4. **Validate schemas** - Ensure input/output schemas are correct
5. **Check capabilities** - Verify both sides support required features

### Common Debugging Scenarios

**Server won't connect:**
```bash
# Check if server starts independently
node path/to/server.js

# Check for port conflicts
lsof -i :3000

# Verify environment variables are set
env | grep API_KEY
```

**Tool calls failing:**
```typescript
// Add debug logging to tool handler
server.tool("my_tool", schema, async (args) => {
  console.error("Tool called with:", JSON.stringify(args));
  try {
    const result = await processArgs(args);
    console.error("Tool result:", JSON.stringify(result));
    return result;
  } catch (error) {
    console.error("Tool error:", error);
    throw error;
  }
});
```

**Capability mismatch:**
```bash
# In Inspector, check the initialization exchange:
# 1. Client capabilities sent
# 2. Server capabilities returned
# 3. Verify both sides support required features
```

### Claude Desktop Debugging

**Log locations:**
```bash
# macOS
~/Library/Logs/Claude/mcp*.log

# Windows
%APPDATA%\Claude\logs\mcp*.log

# Linux
~/.config/Claude/logs/mcp*.log

# Real-time log monitoring (macOS)
tail -n 20 -F ~/Library/Logs/Claude/mcp*.log
```

**Enable Chrome DevTools:**
```bash
# Create developer settings file
echo '{"allowDevTools": true}' > ~/Library/Application\ Support/Claude/developer_settings.json

# Access DevTools: Command-Option-Shift-i (macOS)
# Use Console panel for client-side errors
# Use Network panel for message payloads and timing
```

**Checking Server Status in Claude Desktop:**
- Click the **plug icon** to view connected servers, available prompts, and resources
- Click the **"Search and tools" slider icon** to view tools available to the model

**Common issues:**
- Malformed JSON in config file
- Relative paths instead of absolute (servers often start with `/` as working directory)
- Missing environment variables (servers only inherit `USER`, `HOME`, `PATH` by default)
- Rate limiting from external APIs

**Environment Variable Gotcha:**
```json
{
  "myserver": {
    "command": "mcp-server-myapp",
    "env": {
      "MYAPP_API_KEY": "your-key-here",
      "DATABASE_URL": "postgres://localhost/mydb"
    }
  }
}
```

**Reloading Changes:**
- **Configuration changes**: Restart Claude Desktop completely
- **Server code changes**: Use `Command-R` to reload servers

### Server-Side Logging

**Important**: Log to stderr, NOT stdout (stdout interferes with JSON-RPC protocol).

**Python:**
```python
import sys

# Direct stderr logging
print("Debug: Processing request", file=sys.stderr)

# Using MCP logging API
server.request_context.session.send_log_message(
    level="info",
    data="Server started successfully"
)
```

**TypeScript:**
```typescript
// Direct stderr logging
console.error("Debug: Processing request");

// Using MCP logging API
server.sendLoggingMessage({
  level: "info",
  data: "Server started successfully"
});
```

**What to Log:**
- Initialization steps and configuration loaded
- Resource access (URI, user, timestamp)
- Tool execution (name, arguments, duration, result type)
- Error conditions with stack traces
- Performance metrics (operation timing, message sizes)

### Debugging Workflow

```
┌─────────────────────────────────────────────────────────────┐
│                    DEBUGGING WORKFLOW                        │
└─────────────────────────────────────────────────────────────┘

1. INITIAL DEVELOPMENT
   └─ Use MCP Inspector for basic testing
   └─ Implement core functionality
   └─ Add logging at key points

2. INTEGRATION TESTING
   └─ Test in Claude Desktop
   └─ Monitor logs in real-time
   └─ Check error handling paths

3. TROUBLESHOOTING
   └─ Check server logs first
   └─ Verify configuration syntax
   └─ Test standalone with Inspector
   └─ Review environment variables
```

### Getting Help

**First steps:**
1. Check server logs for errors
2. Test with MCP Inspector standalone
3. Review `claude_desktop_config.json` syntax
4. Verify environment variables are set

**When reporting issues, provide:**
- Relevant log excerpts
- Configuration files (sanitized)
- Steps to reproduce
- Environment details (OS, Node/Python version)

---

## Integration Patterns

### Claude Desktop Configuration

Add MCP servers to Claude Desktop's configuration:

```json
{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["/path/to/server.js"],
      "env": {
        "API_KEY": "your-key"
      }
    },
    "remote-server": {
      "url": "https://mcp.example.com/",
      "headers": {
        "Authorization": "Bearer token"
      }
    }
  }
}
```

### AI SDK Integration

MCP works with various AI frameworks:

```typescript
// With Vercel AI SDK
import { experimental_createMCPClient } from "ai";

const mcpClient = await experimental_createMCPClient({
  transport: { type: "stdio", command: "node", args: ["server.js"] }
});

const tools = await mcpClient.tools();
// Use tools with AI model...
```

---

## Resources

### Official Documentation
- [MCP Website](https://modelcontextprotocol.io/)
- [Specification](https://modelcontextprotocol.io/specification)
- [Getting Started](https://modelcontextprotocol.io/docs/getting-started/intro)

### SDKs
- [TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
- [Python SDK](https://github.com/modelcontextprotocol/python-sdk)
- [Go SDK](https://github.com/modelcontextprotocol/go-sdk)
- [All SDKs](https://github.com/modelcontextprotocol)

### Tools
- [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector)
- [MCP Servers Directory](https://github.com/modelcontextprotocol/servers)

### Community
- [GitHub Discussions](https://github.com/modelcontextprotocol/specification/discussions)
- [Discord](https://discord.gg/anthropic)

---

## Version History

- **1.4.0** (2026-01-10): Enhanced with comprehensive debugging documentation
  - Enhanced Claude Desktop Debugging:
    - Real-time log monitoring commands
    - Chrome DevTools integration (enable, access, panels)
    - Server status checking via UI icons
    - Environment variable inheritance gotcha (`USER`, `HOME`, `PATH` only)
    - Reloading changes (config vs code)
  - Added Server-Side Logging section:
    - stderr vs stdout importance
    - Python and TypeScript logging examples
    - MCP logging API usage
    - What to log checklist
  - Added Debugging Workflow diagram
  - Added Getting Help section with issue reporting guidance

- **1.3.0** (2026-01-10): Enhanced Testing and Debugging with MCP Inspector
  - Comprehensive MCP Inspector documentation:
    - Installation-free usage via npx
    - Commands for NPM, PyPI, and local servers
    - UI panels table (Server Connection, Resources, Prompts, Tools, Notifications)
    - Development workflow diagram (Verification → Iteration → Edge Cases)
  - Added Common Debugging Scenarios section:
    - Server connection troubleshooting
    - Tool call debugging with logging examples
    - Capability mismatch diagnosis
  - Added Claude Desktop Debugging:
    - Log file locations (macOS, Windows, Linux)
    - Common configuration issues

- **1.2.0** (2026-01-10): Enhanced with official documentation content
  - Added AI Integration Paradox design philosophy
  - Added Mediated Access Pattern (security broker model)
  - Added Production Operations section:
    - Performance targets (throughput, latency, error rate)
    - Architectural principles (single responsibility, defense in depth)
    - Health checks and monitoring patterns
    - Structured logging examples
  - Enhanced protocol overview with dynamic discovery concepts

- **1.1.0** (2026-01-10): Enhanced with official specification details
  - Added specification version reference (2024-11-05)
  - Enhanced JSON-RPC requirements (id uniqueness, null prohibition)
  - Added detailed lifecycle with version negotiation
  - Added shutdown procedures (stdio vs HTTP)
  - Added tool `isError` handling for execution errors
  - Added resource templates with URI Template syntax (RFC 6570)
  - Added blob content type for binary resources
  - Added Utilities section:
    - Ping (connection health)
    - Cancellation (notifications/cancelled)
    - Progress notifications
    - Completion (auto-complete)
    - Logging (notifications/message)
    - Pagination (cursor-based)

- **1.0.0** (2026-01-10): Initial skill release
  - Complete protocol overview (architecture, primitives, transports)
  - Server development guide (tools, resources, prompts)
  - Client development guide (connecting, calling, sampling)
  - 10 SDKs documented (TypeScript, Python, Go, Kotlin, Swift, Java, C#, Ruby, Rust, PHP)
  - Security best practices
  - Testing and debugging guidance
  - Integration patterns (Claude Desktop, AI SDKs)

Related Skills

We are still matching the closest adjacent skills for this page. In the meantime, continue through the full directory.