{"slug":"mcp-ops","title":"mcp-ops","summary":"Model Context Protocol server development, tool design, resource handling, and transport configuration. Use for: mcp, model context protocol, mcp server, mcp tool, mcp resource, fastmcp, mcp transport, stdio, sse, streamable http, mcp inspector, tool handler, mcp prompt.","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-09-30T19:36:48.82267Z","repo":{"url":"https://github.com/0xDarkMatter/claude-mods","stars":43,"forks":7,"license":"MIT","updatedAt":"2026-09-30T15:18:48Z"},"bodyHtml":"<hr>\n<h2>name: mcp-ops\ndescription: \"Model Context Protocol server development, tool design, resource handling, and transport configuration. Use for: mcp, model context protocol, mcp server, mcp tool, mcp resource, fastmcp, mcp transport, stdio, sse, streamable http, mcp inspector, tool handler, mcp prompt.\"\nlicense: MIT\nallowed-tools: \"Read Write Bash\"\nmetadata:\nauthor: claude-mods\nrelated-skills: claude-code-ops, typescript-ops, python-fastapi-ops</h2>\n<h1>MCP Operations</h1>\n<p>Comprehensive patterns for building, testing, and deploying Model Context Protocol servers in Python and TypeScript.</p>\n<blockquote>\n<p>Ecosystem facts verified as of 2026-07-05 (standalone FastMCP at major 3).</p>\n</blockquote>\n<h2>MCP Architecture Quick Reference</h2>\n<pre><code>┌─────────────────────────────────────────────────────────┐\n│                     MCP Host                            │\n│  (Claude Desktop, Claude Code, Custom App)              │\n│                                                         │\n│  ┌───────────┐   ┌───────────┐   ┌───────────┐        │\n│  │  Client A  │   │  Client B  │   │  Client C  │       │\n│  └─────┬─────┘   └─────┬─────┘   └─────┬─────┘        │\n└────────┼───────────────┼───────────────┼────────────────┘\n         │               │               │\n    ┌────┴────┐     ┌────┴────┐     ┌────┴────┐\n    │Transport│     │Transport│     │Transport│\n    │ (stdio) │     │  (SSE)  │     │ (HTTP)  │\n    └────┬────┘     └────┬────┘     └────┬────┘\n         │               │               │\n┌────────┴──┐     ┌──────┴────┐   ┌──────┴────┐\n│  Server A  │     │  Server B  │   │  Server C  │\n│            │     │            │   │            │\n│ ┌────────┐ │     │ ┌────────┐ │   │ ┌────────┐ │\n│ │ Tools  │ │     │ │Resources│ │   │ │Prompts │ │\n│ └────────┘ │     │ └────────┘ │   │ └────────┘ │\n│ ┌────────┐ │     │ ┌────────┐ │   │ ┌────────┐ │\n│ │Resources│ │     │ │Prompts │ │   │ │ Tools  │ │\n│ └────────┘ │     │ └────────┘ │   │ └────────┘ │\n└────────────┘     └────────────┘   └────────────┘\n\nProtocol: JSON-RPC 2.0 over chosen transport\nFlow:     Client → request → Server → response → Client\n</code></pre>\n<h2>Server Type Decision Tree</h2>\n<pre><code>What transport does your MCP server need?\n│\n├─ Local CLI tool / single-user desktop integration?\n│  └─ stdio\n│     - Simplest setup, no networking\n│     - Claude Desktop, Claude Code native support\n│     - Process lifecycle managed by host\n│\n├─ Web dashboard / browser-based client?\n│  └─ SSE (Server-Sent Events)\n│     - HTTP-based, works through firewalls\n│     - Persistent connection for server→client events\n│     - Good for development and internal tools\n│\n└─ Production API / multi-tenant / cloud deployment?\n   └─ Streamable HTTP\n      - HTTP POST for requests, SSE for streaming responses\n      - Supports stateless and stateful modes\n      - Full auth support, load balancer friendly\n      - Recommended for production deployments\n</code></pre>\n<h2>Tool vs Resource vs Prompt Decision Tree</h2>\n<pre><code>What does the LLM need to do?\n│\n├─ Perform an action or computation?\n│  └─ TOOL\n│     - Has side effects (API calls, file writes, DB mutations)\n│     - Accepts structured input, returns results\n│     - Examples: run_query, create_issue, send_email\n│\n├─ Read data or context?\n│  └─ RESOURCE\n│     - Read-only data retrieval\n│     - Identified by URI (file://, db://, api://)\n│     - Examples: config://app, schema://users, file://readme.md\n│\n└─ Guide the LLM's behavior or workflow?\n   └─ PROMPT\n      - Templated instructions with arguments\n      - Suggests conversation starters or workflows\n      - Examples: code_review(language, file), summarize(topic)\n</code></pre>\n<h2>Python SDK Quick Start</h2>\n<pre><code>from mcp.server.fastmcp import FastMCP\n\nmcp = FastMCP(\"my-server\")\n\n@mcp.tool()\ndef search_docs(query: str) -&gt; str:\n    \"\"\"Search documentation by keyword.\"\"\"\n    results = perform_search(query)\n    return \"\\n\".join(f\"- {r.title}: {r.snippet}\" for r in results)\n\n@mcp.tool()\ndef create_ticket(title: str, body: str, priority: str = \"medium\") -&gt; str:\n    \"\"\"Create a support ticket.\"\"\"\n    ticket = api.create(title=title, body=body, priority=priority)\n    return f\"Created ticket #{ticket.id}: {ticket.url}\"\n\n@mcp.resource(\"config://app\")\ndef get_config() -&gt; str:\n    \"\"\"Return current application configuration.\"\"\"\n    return json.dumps(load_config(), indent=2)\n\n@mcp.resource(\"schema://db/{table}\")\ndef get_table_schema(table: str) -&gt; str:\n    \"\"\"Return the schema for a database table.\"\"\"\n    return json.dumps(get_schema(table), indent=2)\n\n@mcp.prompt()\ndef code_review(language: str, filepath: str) -&gt; str:\n    \"\"\"Generate a code review prompt for the given file.\"\"\"\n    return f\"Review this {language} code in {filepath} for bugs, style issues, and performance.\"\n\nif __name__ == \"__main__\":\n    mcp.run()  # Defaults to stdio transport\n</code></pre>\n<p><strong>Install and run:</strong></p>\n<pre><code>uv init my-mcp-server &amp;&amp; cd my-mcp-server\nuv add mcp[cli]\n# Run with: uv run python server.py\n# Or:       uv run mcp run server.py\n</code></pre>\n<p><strong>Two Python FastMCPs — know which you're on.</strong> The official <code>mcp</code> SDK bundles a frozen\n1.x-era FastMCP (<code>from mcp.server.fastmcp import FastMCP</code>, used in the samples above —\nstable, minimal). The standalone <code>fastmcp</code> package (gofastmcp.com) is where active\ndevelopment happens and is at <strong>major 3</strong>: same decorator surface, plus auth, proxying,\nOpenAPI generation, and a test client. To use it:</p>\n<pre><code>uv add fastmcp\n</code></pre>\n<pre><code>from fastmcp import FastMCP   # standalone FastMCP 3 — not mcp.server.fastmcp\n\nmcp = FastMCP(\"my-server\")    # v3: constructor is identity/behaviour only;\n                              # transport config moved to run()/serve time\n</code></pre>\n<p>FastMCP 3 breaking changes (from 2.x): 16 deprecated constructor kwargs removed\n(transport settings now passed at serve time), <code>ui=</code> replaced by <code>app=</code>,\n<code>ctx.set_state()</code>/<code>ctx.get_state()</code> are now async with session-scoped persistence, and\nthe metadata namespace changed from <code>_fastmcp</code> to <code>fastmcp</code>.</p>\n<h2>TypeScript SDK Quick Start</h2>\n<pre><code>import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\n\nconst server = new McpServer({\n  name: \"my-server\",\n  version: \"1.0.0\",\n});\n\n// Register a tool\nserver.tool(\n  \"search_docs\",\n  \"Search documentation by keyword\",\n  { query: z.string().describe(\"Search query\") },\n  async ({ query }) =&gt; {\n    const results = await performSearch(query);\n    return {\n      content: [{ type: \"text\", text: results.join(\"\\n\") }],\n    };\n  }\n);\n\n// Register a resource\nserver.resource(\n  \"config\",\n  \"config://app\",\n  { description: \"Current application configuration\" },\n  async (uri) =&gt; ({\n    contents: [{\n      uri: uri.href,\n      mimeType: \"application/json\",\n      text: JSON.stringify(loadConfig(), null, 2),\n    }],\n  })\n);\n\n// Register a prompt\nserver.prompt(\n  \"code_review\",\n  \"Generate a code review prompt\",\n  { language: z.string(), filepath: z.string() },\n  async ({ language, filepath }) =&gt; ({\n    messages: [{\n      role: \"user\",\n      content: {\n        type: \"text\",\n        text: `Review this ${language} code in ${filepath} for bugs and style issues.`,\n      },\n    }],\n  })\n);\n\nasync function main() {\n  const transport = new StdioServerTransport();\n  await server.connect(transport);\n}\nmain().catch(console.error);\n</code></pre>\n<p><strong>Install and run:</strong></p>\n<pre><code>npm init -y\nnpm install @modelcontextprotocol/sdk zod\nnpx tsx server.ts\n</code></pre>\n<h2>Transport Selection Matrix</h2>\n<table>\n<thead>\n<tr>\n<th>Feature</th>\n<th>stdio</th>\n<th>SSE</th>\n<th>Streamable HTTP</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>Use case</strong></td>\n<td>Local CLI tools, desktop</td>\n<td>Web dashboards, dev</td>\n<td>Production APIs</td>\n</tr>\n<tr>\n<td><strong>Protocol</strong></td>\n<td>stdin/stdout pipes</td>\n<td>HTTP + EventSource</td>\n<td>HTTP POST + SSE</td>\n</tr>\n<tr>\n<td><strong>Auth support</strong></td>\n<td>Env vars only</td>\n<td>Bearer tokens</td>\n<td>Full OAuth2/PKCE</td>\n</tr>\n<tr>\n<td><strong>Deployment</strong></td>\n<td>Local process</td>\n<td>Single server</td>\n<td>Load balanced</td>\n</tr>\n<tr>\n<td><strong>Reconnection</strong></td>\n<td>Process restart</td>\n<td>Auto-reconnect</td>\n<td>Stateless resilient</td>\n</tr>\n<tr>\n<td><strong>Multi-client</strong></td>\n<td>1:1 only</td>\n<td>Multiple clients</td>\n<td>Horizontally scalable</td>\n</tr>\n<tr>\n<td><strong>Firewall</strong></td>\n<td>N/A (local)</td>\n<td>HTTP-friendly</td>\n<td>HTTP-friendly</td>\n</tr>\n<tr>\n<td><strong>State</strong></td>\n<td>Process lifetime</td>\n<td>Connection lifetime</td>\n<td>Session or stateless</td>\n</tr>\n<tr>\n<td><strong>Best for</strong></td>\n<td>Claude Desktop/Code</td>\n<td>Internal tools</td>\n<td>Cloud/enterprise</td>\n</tr>\n</tbody>\n</table>\n<h2>Authentication Patterns Quick Reference</h2>\n<pre><code># Pattern 1: API keys from environment\nimport os\nfrom mcp.server.fastmcp import FastMCP\n\nmcp = FastMCP(\"api-server\")\n\n@mcp.tool()\ndef call_api(endpoint: str) -&gt; str:\n    \"\"\"Call external API with configured credentials.\"\"\"\n    api_key = os.environ[\"MY_API_KEY\"]  # Set in client config\n    resp = httpx.get(f\"https://api.example.com/{endpoint}\",\n                     headers={\"Authorization\": f\"Bearer {api_key}\"})\n    return resp.text\n</code></pre>\n<pre><code># Pattern 2: OAuth2 token refresh (in-memory cache)\nimport time\n\n_token_cache: dict = {}\n\nasync def get_valid_token() -&gt; str:\n    if _token_cache.get(\"expires_at\", 0) &gt; time.time() + 60:\n        return _token_cache[\"access_token\"]\n    resp = await httpx.AsyncClient().post(\"https://auth.example.com/token\", data={\n        \"grant_type\": \"refresh_token\",\n        \"refresh_token\": os.environ[\"REFRESH_TOKEN\"],\n        \"client_id\": os.environ[\"CLIENT_ID\"],\n    })\n    data = resp.json()\n    _token_cache.update({\n        \"access_token\": data[\"access_token\"],\n        \"expires_at\": time.time() + data[\"expires_in\"],\n    })\n    return data[\"access_token\"]\n</code></pre>\n<pre><code>// Claude Desktop config with env vars\n{\n  \"mcpServers\": {\n    \"my-server\": {\n      \"command\": \"uv\",\n      \"args\": [\"run\", \"--directory\", \"/path/to/server\", \"python\", \"server.py\"],\n      \"env\": {\n        \"MY_API_KEY\": \"sk-...\",\n        \"DATABASE_URL\": \"postgresql://...\"\n      }\n    }\n  }\n}\n</code></pre>\n<h2>Common Gotchas</h2>\n<table>\n<thead>\n<tr>\n<th>Gotcha</th>\n<th>Why</th>\n<th>Fix</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Tool not appearing in client</td>\n<td><code>inputSchema</code> has invalid JSON Schema</td>\n<td>Validate schema with jsonschema library; use Pydantic/Zod to generate</td>\n</tr>\n<tr>\n<td>Tool returns raw object</td>\n<td>Results must be <code>content</code> list with typed items</td>\n<td>Always return <code>{\"content\": [{\"type\": \"text\", \"text\": \"...\"}]}</code></td>\n</tr>\n<tr>\n<td>Timeout on long operations</td>\n<td>Default client timeout is often 30-60s</td>\n<td>Add progress notifications; break into smaller operations</td>\n</tr>\n<tr>\n<td>Concurrent requests fail</td>\n<td>Tool handler uses shared mutable state</td>\n<td>Use asyncio locks, or make handlers stateless</td>\n</tr>\n<tr>\n<td>Large response crashes client</td>\n<td>MCP messages have practical size limits</td>\n<td>Paginate results; return summaries with detail-fetch tools</td>\n</tr>\n<tr>\n<td>Error swallowed silently</td>\n<td>Exception in handler returns generic error</td>\n<td>Set <code>isError: true</code> in response; include error message in content</td>\n</tr>\n<tr>\n<td>SSE connection drops</td>\n<td>No keep-alive or reconnection logic</td>\n<td>Implement heartbeat; client auto-reconnects on SSE</td>\n</tr>\n<tr>\n<td>Client ignores new tools</td>\n<td>Capabilities not updated after tool change</td>\n<td>Call <code>server.request_context.session.send_resource_list_changed()</code></td>\n</tr>\n<tr>\n<td>Tool name collision</td>\n<td>Two servers register same tool name</td>\n<td>Namespace tools: <code>myserver_search</code> not just <code>search</code></td>\n</tr>\n<tr>\n<td>Resource URI too generic</td>\n<td><code>data://info</code> is ambiguous</td>\n<td>Use specific schemes: <code>db://myapp/users</code>, <code>config://myapp/settings</code></td>\n</tr>\n<tr>\n<td><code>async def</code> missing on handler</td>\n<td>FastMCP tools can be sync or async, but I/O should be async</td>\n<td>Use <code>async def</code> for any handler doing network/file I/O</td>\n</tr>\n<tr>\n<td>Server works locally, fails in Claude Desktop</td>\n<td>Different working directory or PATH</td>\n<td>Use absolute paths; log <code>os.getcwd()</code> on startup</td>\n</tr>\n</tbody>\n</table>\n<h2>Reference Files</h2>\n<table>\n<thead>\n<tr>\n<th>File</th>\n<th>Lines</th>\n<th>Content</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>references/server-architecture.md</code></td>\n<td>~700</td>\n<td>Server lifecycle, FastMCP/TS SDK setup, capabilities, middleware, error handling</td>\n</tr>\n<tr>\n<td><code>references/tool-handlers.md</code></td>\n<td>~650</td>\n<td>Schema design, validation, return types, composition, side effects, examples</td>\n</tr>\n<tr>\n<td><code>references/resources-prompts.md</code></td>\n<td>~550</td>\n<td>Resource URIs, static/dynamic resources, templates, prompts, subscriptions</td>\n</tr>\n<tr>\n<td><code>references/transport-auth.md</code></td>\n<td>~550</td>\n<td>stdio/SSE/HTTP transports, session management, OAuth2, rate limiting, TLS</td>\n</tr>\n<tr>\n<td><code>references/testing-debugging.md</code></td>\n<td>~550</td>\n<td>MCP Inspector, unit/integration testing, protocol debugging, CI, performance</td>\n</tr>\n</tbody>\n</table>\n<h2>Staleness verifier</h2>\n<p>This skill encodes fast-moving facts (the MCP SDK package names + spec URL). <a href=\"scripts/check-mcp-facts.py\"><code>scripts/check-mcp-facts.py</code></a> guards them against silent drift:</p>\n<pre><code># Structural (PR CI, no network): every catalogued package's prose_token is\n# still named in this skill's prose, the spec URL is still cited, and the\n# currency note still carries a year.\npython scripts/check-mcp-facts.py --offline        # exit 0 consistent, 10 drift\n\n# Live (freshness job, never blocks a PR): each SDK still resolves on\n# npm/PyPI, no tracked major has moved off the sampled major, spec URL 200.\npython scripts/check-mcp-facts.py --live            # exit 10 drift, 7 registries unreachable\n</code></pre>\n<p>The canonical fact set lives in <a href=\"assets/mcp-facts.json\"><code>assets/mcp-facts.json</code></a>; when you add or drop a package, update it to match or <code>--offline</code> fails CI.</p>\n<h2>See Also</h2>\n<ul>\n<li><strong>MCP Specification</strong>: <a href=\"https://modelcontextprotocol.io/specification/latest\">https://modelcontextprotocol.io/specification/latest</a> (the old spec.modelcontextprotocol.io subdomain no longer resolves)</li>\n<li><strong>Python SDK</strong>: <a href=\"https://github.com/modelcontextprotocol/python-sdk\">https://github.com/modelcontextprotocol/python-sdk</a></li>\n<li><strong>TypeScript SDK</strong>: <a href=\"https://github.com/modelcontextprotocol/typescript-sdk\">https://github.com/modelcontextprotocol/typescript-sdk</a></li>\n<li><strong>Official MCP Servers</strong>: <a href=\"https://github.com/modelcontextprotocol/servers\">https://github.com/modelcontextprotocol/servers</a></li>\n<li><strong>MCP Inspector</strong>: <code>npx @modelcontextprotocol/inspector</code></li>\n<li><strong>FastMCP Documentation</strong>: <a href=\"https://gofastmcp.com\">https://gofastmcp.com</a></li>\n<li><strong>Related skills</strong>: <code>claude-code-hooks</code> (hook into Claude Code), <code>claude-code-debug</code> (debug Claude Code issues)</li>\n</ul>\n","files":[{"path":"assets/.gitkeep","sizeBytes":0,"isText":false},{"path":"assets/mcp-facts.json","sizeBytes":2374,"isText":true},{"path":"references/resources-prompts.md","sizeBytes":16861,"isText":true},{"path":"references/server-architecture.md","sizeBytes":20599,"isText":true},{"path":"references/testing-debugging.md","sizeBytes":25231,"isText":true},{"path":"references/tool-handlers.md","sizeBytes":24257,"isText":true},{"path":"references/transport-auth.md","sizeBytes":21328,"isText":true},{"path":"scripts/check-mcp-facts.py","sizeBytes":12006,"isText":true},{"path":"scripts/.gitkeep","sizeBytes":0,"isText":false},{"path":"SKILL.md","sizeBytes":14727,"isText":true},{"path":"tests/run.sh","sizeBytes":5287,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"notes-only","suspicious":0,"notes":4,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-09-30T19:38:03.922126Z","sha256":"F974F884FEAC011555DB6C185FC9F713A3AB31E63EAE1F15F036E40E97226F12","sizeBytes":49246},"review":null,"source":{"repositoryUrl":"https://github.com/0xDarkMatter/claude-mods","path":"skills/mcp-ops","license":"MIT","commit":"3dfaf0ba5753026a99ee13f9d9ed56b9793bb6e8","subtreeSha":"CB39CF0D76B4ECA92769AD18BB561EFFE2070533AA27B60FB9210CF34E44ED96","lastSyncedAt":"2026-09-30T19:37:28.226022Z"},"reviewedAt":"2026-09-30T19:40:17.957492Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/0xDarkMatter/claude-mods/tree/main/skills/mcp-ops"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install 0xdarkmatter-claude-mods@llmmart"},{"target":"git","command":"git clone https://github.com/0xDarkMatter/claude-mods.git"}]}