MCP Developer Senior MCP (Model Context Protocol) developer with deep expertise in building servers and clients that connect AI systems with external tools and data sources. Core Workflow 1. Analyze requirements — Identify data sources, tools needed, and client apps 2. Initialize project — (TypeScript) or + scaffold (Python) 3. Design protocol — Define resource URIs, tool schemas (Zod/Pydantic), and prompt templates 4. Implement — Register tools and resource handlers; configure transport (stdio/SSE/HTTP) 5. Test — Run to verify protocol compliance interactively; confirm tools appear, schemas…

, uri)\n if match:\n user_id = match.group(1)\n profile = await get_user_profile(user_id)\n return json.dumps(profile, indent=2)\n\n raise ValueError(f\"Unknown resource: {uri}\")\n```\n\n## Content Types\n\n### Text Content\n\n```typescript\n{\n \"uri\": \"file:///data.txt\",\n \"mimeType\": \"text/plain\",\n \"text\": \"The content of the file\"\n}\n```\n\n### JSON Content\n\n```typescript\n{\n \"uri\": \"api://status\",\n \"mimeType\": \"application/json\",\n \"text\": JSON.stringify({\n \"status\": \"ok\",\n \"uptime\": 12345\n }, null, 2)\n}\n```\n\n### Binary Content (Base64)\n\n```typescript\n{\n \"uri\": \"file:///image.png\",\n \"mimeType\": \"image/png\",\n \"blob\": \"base64-encoded-data-here\"\n}\n```\n\n### Markdown Content\n\n```typescript\n{\n \"uri\": \"docs://api-reference\",\n \"mimeType\": \"text/markdown\",\n \"text\": \"# API Reference\\n\\n## Endpoints\\n...\"\n}\n```\n\n## Implementation Patterns\n\n### File System Resources\n\n```typescript\nimport * as fs from \"fs/promises\";\nimport * as path from \"path\";\n\nconst ALLOWED_DIR = \"/path/to/allowed/directory\";\n\nserver.setRequestHandler(ListResourcesRequestSchema, async () => {\n const files = await fs.readdir(ALLOWED_DIR);\n\n return {\n resources: files.map((file) => ({\n uri: `file:///${file}`,\n name: file,\n description: `File: ${file}`,\n mimeType: getMimeType(file),\n })),\n };\n});\n\nserver.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n const uri = request.params.uri;\n\n if (uri.startsWith(\"file:///\")) {\n const filename = uri.slice(8); // Remove \"file:///\"\n const safePath = path.resolve(ALLOWED_DIR, filename);\n\n // Security: ensure path is within allowed directory\n if (!safePath.startsWith(ALLOWED_DIR)) {\n throw new McpError(ErrorCode.InvalidParams, \"Access denied\");\n }\n\n const content = await fs.readFile(safePath, \"utf-8\");\n\n return {\n contents: [\n {\n uri,\n mimeType: getMimeType(filename),\n text: content,\n },\n ],\n };\n }\n\n throw new Error(`Unknown resource: ${uri}`);\n});\n```\n\n### Database Resources\n\n```python\[email protected]_resources()\nasync def list_resources() -> list[Resource]:\n tables = await db.get_tables()\n\n return [\n Resource(\n uri=f\"db://{table}/schema\",\n name=f\"{table} Schema\",\n description=f\"Schema for {table} table\",\n mimeType=\"text/plain\",\n )\n for table in tables\n ]\n\[email protected]_resource()\nasync def read_resource(uri: str) -> str:\n if uri.startswith(\"db://\"):\n parts = uri[5:].split(\"/\")\n table = parts[0]\n resource_type = parts[1] if len(parts) > 1 else \"data\"\n\n if resource_type == \"schema\":\n schema = await db.get_schema(table)\n return schema\n\n if resource_type == \"data\":\n rows = await db.query(f\"SELECT * FROM {table} LIMIT 100\")\n return json.dumps(rows, indent=2)\n\n raise ValueError(f\"Unknown resource: {uri}\")\n```\n\n### API Resources\n\n```typescript\nserver.setRequestHandler(ListResourcesRequestSchema, async () => {\n return {\n resources: [\n {\n uri: \"api://v1/status\",\n name: \"API Status\",\n mimeType: \"application/json\",\n },\n {\n uri: \"api://v1/metrics\",\n name: \"API Metrics\",\n mimeType: \"application/json\",\n },\n ],\n };\n});\n\nserver.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n const uri = request.params.uri;\n\n if (uri === \"api://v1/status\") {\n const status = await checkApiStatus();\n return {\n contents: [\n {\n uri,\n mimeType: \"application/json\",\n text: JSON.stringify(status, null, 2),\n },\n ],\n };\n }\n\n if (uri === \"api://v1/metrics\") {\n const metrics = await collectMetrics();\n return {\n contents: [\n {\n uri,\n mimeType: \"application/json\",\n text: JSON.stringify(metrics, null, 2),\n },\n ],\n };\n }\n\n throw new Error(`Unknown resource: ${uri}`);\n});\n```\n\n### Git Repository Resources\n\n```python\nimport git\n\[email protected]_resources()\nasync def list_resources() -> list[Resource]:\n return [\n Resource(\n uri=\"git://log\",\n name=\"Git Log\",\n description=\"Recent commits\",\n mimeType=\"text/plain\",\n ),\n Resource(\n uri=\"git://status\",\n name=\"Git Status\",\n description=\"Working tree status\",\n mimeType=\"text/plain\",\n ),\n ]\n\[email protected]_resource()\nasync def read_resource(uri: str) -> str:\n repo = git.Repo(\".\")\n\n if uri == \"git://log\":\n log = repo.git.log(\"--oneline\", \"-n\", \"10\")\n return log\n\n if uri == \"git://status\":\n status = repo.git.status()\n return status\n\n raise ValueError(f\"Unknown resource: {uri}\")\n```\n\n## Resource Subscriptions\n\nAllow clients to subscribe to resource updates.\n\n```typescript\n// Declare subscription capability\nconst server = new Server(\n { name: \"example\", version: \"1.0.0\" },\n {\n capabilities: {\n resources: {\n subscribe: true,\n listChanged: true,\n },\n },\n }\n);\n\n// Track subscriptions\nconst subscriptions = new Set\u003cstring>();\n\nserver.setRequestHandler(SubscribeRequestSchema, async (request) => {\n subscriptions.add(request.params.uri);\n return {};\n});\n\nserver.setRequestHandler(UnsubscribeRequestSchema, async (request) => {\n subscriptions.delete(request.params.uri);\n return {};\n});\n\n// Notify subscribers when resource changes\nasync function notifyResourceUpdate(uri: string) {\n if (subscriptions.has(uri)) {\n await server.notification({\n method: \"notifications/resources/updated\",\n params: { uri },\n });\n }\n}\n\n// Example: file watcher\nconst watcher = fs.watch(WATCHED_DIR, async (event, filename) => {\n if (event === \"change\") {\n const uri = `file:///${filename}`;\n await notifyResourceUpdate(uri);\n }\n});\n```\n\n## Best Practices\n\n### 1. URI Design\n\n```typescript\n// Good: Hierarchical and descriptive\n\"db://users/schema\"\n\"db://users/data\"\n\"api://v1/endpoints/users\"\n\"file:///config/app.json\"\n\n// Bad: Flat and ambiguous\n\"db1\"\n\"data\"\n\"config\"\n```\n\n### 2. MIME Types\n\n```typescript\nfunction getMimeType(filename: string): string {\n const ext = filename.split(\".\").pop()?.toLowerCase();\n\n const mimeTypes: Record\u003cstring, string> = {\n json: \"application/json\",\n txt: \"text/plain\",\n md: \"text/markdown\",\n html: \"text/html\",\n xml: \"application/xml\",\n csv: \"text/csv\",\n png: \"image/png\",\n jpg: \"image/jpeg\",\n pdf: \"application/pdf\",\n };\n\n return mimeTypes[ext || \"\"] || \"application/octet-stream\";\n}\n```\n\n### 3. Security\n\n```python\ndef is_safe_path(base_dir: str, path: str) -> bool:\n \"\"\"Ensure path doesn't escape base directory\"\"\"\n base = os.path.abspath(base_dir)\n target = os.path.abspath(os.path.join(base_dir, path))\n return target.startswith(base)\n\[email protected]_resource()\nasync def read_resource(uri: str) -> str:\n if uri.startswith(\"file:///\"):\n path = uri[8:]\n if not is_safe_path(ALLOWED_DIR, path):\n raise ValueError(\"Access denied\")\n\n full_path = os.path.join(ALLOWED_DIR, path)\n with open(full_path) as f:\n return f.read()\n```\n\n### 4. Caching\n\n```typescript\nconst resourceCache = new Map\u003cstring, { content: string; timestamp: number }>();\nconst CACHE_TTL = 60000; // 1 minute\n\nserver.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n const uri = request.params.uri;\n const now = Date.now();\n\n // Check cache\n const cached = resourceCache.get(uri);\n if (cached && now - cached.timestamp \u003c CACHE_TTL) {\n return {\n contents: [{ uri, mimeType: \"application/json\", text: cached.content }],\n };\n }\n\n // Fetch and cache\n const content = await fetchResource(uri);\n resourceCache.set(uri, { content, timestamp: now });\n\n return {\n contents: [{ uri, mimeType: \"application/json\", text: content }],\n };\n});\n```\n\n### 5. Large Resources\n\n```python\[email protected]_resource()\nasync def read_resource(uri: str) -> str:\n if uri == \"db://logs/recent\":\n # For large datasets, limit size\n logs = await db.query(\n \"SELECT * FROM logs ORDER BY timestamp DESC LIMIT 1000\"\n )\n return json.dumps(logs, indent=2)\n\n if uri == \"file:///large.txt\":\n # Read first 100KB only\n with open(\"/path/to/large.txt\") as f:\n content = f.read(100 * 1024)\n if f.read(1): # Check if there's more\n content += \"\\n\\n[Content truncated...]\"\n return content\n```\n\n### 6. Error Handling\n\n```typescript\nserver.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n try {\n const content = await fetchResource(request.params.uri);\n return {\n contents: [\n {\n uri: request.params.uri,\n mimeType: \"application/json\",\n text: content,\n },\n ],\n };\n } catch (error) {\n if (error instanceof NotFoundError) {\n throw new McpError(ErrorCode.InvalidParams, `Resource not found: ${request.params.uri}`);\n }\n throw new McpError(ErrorCode.InternalError, `Failed to read resource: ${error.message}`);\n }\n});\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":12214,"content_sha256":"c32f64a706515ea0a782c574a71024c97b43342f077f06825573e551168dd7c8"},{"filename":"references/tools.md","content":"# MCP Tools Reference\n\n## Tool Definition\n\nTools are functions that AI assistants can invoke to perform actions or retrieve data.\n\n```typescript\n{\n \"name\": \"tool_name\",\n \"description\": \"Clear description of what the tool does\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"param1\": {\n \"type\": \"string\",\n \"description\": \"What this parameter is for\"\n }\n },\n \"required\": [\"param1\"]\n }\n}\n```\n\n## Input Schema Patterns\n\n### Simple String Parameter\n\n```typescript\n{\n \"name\": \"search_docs\",\n \"description\": \"Search documentation for a query\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"query\": {\n \"type\": \"string\",\n \"description\": \"Search query\",\n \"minLength\": 1\n }\n },\n \"required\": [\"query\"]\n }\n}\n```\n\n### Enum Values\n\n```typescript\n{\n \"name\": \"get_weather\",\n \"description\": \"Get weather information\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"location\": { \"type\": \"string\" },\n \"units\": {\n \"type\": \"string\",\n \"enum\": [\"celsius\", \"fahrenheit\"],\n \"default\": \"celsius\",\n \"description\": \"Temperature units\"\n }\n },\n \"required\": [\"location\"]\n }\n}\n```\n\n### Nested Objects\n\n```typescript\n{\n \"name\": \"create_task\",\n \"description\": \"Create a new task\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"title\": { \"type\": \"string\", \"minLength\": 1 },\n \"metadata\": {\n \"type\": \"object\",\n \"properties\": {\n \"priority\": { \"type\": \"string\", \"enum\": [\"low\", \"medium\", \"high\"] },\n \"tags\": { \"type\": \"array\", \"items\": { \"type\": \"string\" } }\n }\n }\n },\n \"required\": [\"title\"]\n }\n}\n```\n\n### Array Parameters\n\n```typescript\n{\n \"name\": \"batch_process\",\n \"description\": \"Process multiple items\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"items\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": { \"type\": \"string\" },\n \"action\": { \"type\": \"string\", \"enum\": [\"update\", \"delete\"] }\n },\n \"required\": [\"id\", \"action\"]\n },\n \"minItems\": 1,\n \"maxItems\": 100\n }\n },\n \"required\": [\"items\"]\n }\n}\n```\n\n### Union Types (anyOf)\n\n```typescript\n{\n \"name\": \"search\",\n \"description\": \"Search by ID or query\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"search\": {\n \"anyOf\": [\n { \"type\": \"string\", \"description\": \"Search query\" },\n { \"type\": \"number\", \"description\": \"Item ID\" }\n ]\n }\n },\n \"required\": [\"search\"]\n }\n}\n```\n\n## Tool Response Formats\n\n### Text Response\n\n```typescript\n{\n \"content\": [\n {\n \"type\": \"text\",\n \"text\": \"Operation completed successfully\"\n }\n ]\n}\n```\n\n### Multiple Content Blocks\n\n```typescript\n{\n \"content\": [\n {\n \"type\": \"text\",\n \"text\": \"Found 3 results:\"\n },\n {\n \"type\": \"text\",\n \"text\": \"1. First result\\n2. Second result\\n3. Third result\"\n }\n ]\n}\n```\n\n### Image Content\n\n```typescript\n{\n \"content\": [\n {\n \"type\": \"image\",\n \"data\": \"base64-encoded-image-data\",\n \"mimeType\": \"image/png\"\n }\n ]\n}\n```\n\n### Resource Reference\n\n```typescript\n{\n \"content\": [\n {\n \"type\": \"resource\",\n \"resource\": {\n \"uri\": \"file:///data/results.json\",\n \"mimeType\": \"application/json\",\n \"text\": \"{\\\"results\\\": [...]}\"\n }\n }\n ]\n}\n```\n\n## Tool Implementation Patterns\n\n### Database Query Tool\n\n```typescript\n// TypeScript\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n if (request.params.name === \"query_database\") {\n const { table, filter, limit } = request.params.arguments as {\n table: string;\n filter?: Record\u003cstring, any>;\n limit?: number;\n };\n\n // Validate table name (prevent SQL injection)\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(table)) {\n throw new McpError(ErrorCode.InvalidParams, \"Invalid table name\");\n }\n\n const results = await db.query(table, filter, limit || 10);\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(results, null, 2),\n },\n ],\n };\n }\n});\n```\n\n```python\n# Python\[email protected]_tool()\nasync def call_tool(name: str, arguments: dict) -> list[TextContent]:\n if name == \"query_database\":\n args = QueryArgs(**arguments) # Pydantic validation\n\n # Validate table name\n if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*

MCP Developer Senior MCP (Model Context Protocol) developer with deep expertise in building servers and clients that connect AI systems with external tools and data sources. Core Workflow 1. Analyze requirements — Identify data sources, tools needed, and client apps 2. Initialize project — (TypeScript) or + scaffold (Python) 3. Design protocol — Define resource URIs, tool schemas (Zod/Pydantic), and prompt templates 4. Implement — Register tools and resource handlers; configure transport (stdio/SSE/HTTP) 5. Test — Run to verify protocol compliance interactively; confirm tools appear, schemas…

, args.table):\n raise ValueError(\"Invalid table name\")\n\n results = await db.query(args.table, args.filter, args.limit)\n\n return [\n TextContent(type=\"text\", text=json.dumps(results, indent=2))\n ]\n```\n\n### File System Tool\n\n```typescript\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n if (request.params.name === \"read_file\") {\n const { path } = request.params.arguments as { path: string };\n\n // Security: validate path is within allowed directory\n const safePath = resolvePath(ALLOWED_DIR, path);\n if (!safePath.startsWith(ALLOWED_DIR)) {\n throw new McpError(ErrorCode.InvalidParams, \"Access denied\");\n }\n\n const content = await fs.readFile(safePath, \"utf-8\");\n\n return {\n content: [{ type: \"text\", text: content }],\n };\n }\n});\n```\n\n### HTTP API Tool\n\n```python\[email protected]_tool()\nasync def call_tool(name: str, arguments: dict) -> list[TextContent]:\n if name == \"fetch_api\":\n args = FetchArgs(**arguments)\n\n async with httpx.AsyncClient() as client:\n try:\n response = await client.get(\n args.url,\n timeout=30.0,\n headers={\"User-Agent\": \"MCP Server\"}\n )\n response.raise_for_status()\n\n return [\n TextContent(\n type=\"text\",\n text=response.text\n )\n ]\n except httpx.HTTPError as e:\n raise McpError(INTERNAL_ERROR, f\"HTTP request failed: {e}\")\n```\n\n### Async Background Task\n\n```typescript\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n if (request.params.name === \"start_job\") {\n const { jobType, params } = request.params.arguments as {\n jobType: string;\n params: Record\u003cstring, any>;\n };\n\n // Start job asynchronously\n const jobId = await jobQueue.enqueue(jobType, params);\n\n return {\n content: [\n {\n type: \"text\",\n text: `Job started with ID: ${jobId}`,\n },\n ],\n };\n }\n\n if (request.params.name === \"check_job\") {\n const { jobId } = request.params.arguments as { jobId: string };\n\n const status = await jobQueue.getStatus(jobId);\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(status, null, 2),\n },\n ],\n };\n }\n});\n```\n\n## Best Practices\n\n### 1. Descriptive Names and Descriptions\n\n```typescript\n// Good\n{\n \"name\": \"search_knowledge_base\",\n \"description\": \"Search the knowledge base using semantic search. Returns top 5 relevant documents with excerpts.\",\n \"inputSchema\": { ... }\n}\n\n// Bad\n{\n \"name\": \"search\",\n \"description\": \"Search\",\n \"inputSchema\": { ... }\n}\n```\n\n### 2. Input Validation\n\n```python\nclass SearchArgs(BaseModel):\n query: str = Field(..., min_length=1, max_length=500)\n max_results: int = Field(default=5, ge=1, le=50)\n filters: dict[str, str] = Field(default_factory=dict)\n\n @field_validator(\"query\")\n @classmethod\n def validate_query(cls, v: str) -> str:\n # Sanitize query\n return v.strip()\n```\n\n### 3. Error Handling\n\n```typescript\ntry {\n const result = await executeOperation(params);\n return { content: [{ type: \"text\", text: result }] };\n} catch (error) {\n if (error instanceof ValidationError) {\n throw new McpError(ErrorCode.InvalidParams, error.message);\n }\n if (error instanceof NotFoundError) {\n return {\n content: [{ type: \"text\", text: \"Resource not found\" }],\n isError: true,\n };\n }\n throw new McpError(ErrorCode.InternalError, `Operation failed: ${error.message}`);\n}\n```\n\n### 4. Rate Limiting\n\n```python\nfrom asyncio import Lock\nfrom datetime import datetime, timedelta\n\nrate_limiter = {}\nrate_limit_lock = Lock()\n\nasync def check_rate_limit(tool_name: str, limit: int = 10) -> None:\n async with rate_limit_lock:\n now = datetime.now()\n if tool_name not in rate_limiter:\n rate_limiter[tool_name] = []\n\n # Remove old entries\n rate_limiter[tool_name] = [\n t for t in rate_limiter[tool_name]\n if now - t \u003c timedelta(minutes=1)\n ]\n\n if len(rate_limiter[tool_name]) >= limit:\n raise McpError(-32004, \"Rate limit exceeded\")\n\n rate_limiter[tool_name].append(now)\n```\n\n### 5. Idempotency\n\n```typescript\n// For operations that should be idempotent, use unique IDs\n{\n \"name\": \"create_record\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"idempotency_key\": {\n \"type\": \"string\",\n \"description\": \"Unique key to prevent duplicate operations\"\n },\n \"data\": { \"type\": \"object\" }\n },\n \"required\": [\"idempotency_key\", \"data\"]\n }\n}\n```\n\n### 6. Timeouts\n\n```python\nimport asyncio\n\[email protected]_tool()\nasync def call_tool(name: str, arguments: dict) -> list[TextContent]:\n if name == \"long_operation\":\n try:\n result = await asyncio.wait_for(\n execute_operation(arguments),\n timeout=30.0 # 30 second timeout\n )\n return [TextContent(type=\"text\", text=str(result))]\n except asyncio.TimeoutError:\n raise McpError(INTERNAL_ERROR, \"Operation timed out\")\n```\n\n### 7. Logging\n\n```typescript\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n const startTime = Date.now();\n console.error(`[${new Date().toISOString()}] Tool call: ${request.params.name}`);\n\n try {\n const result = await executeTool(request.params.name, request.params.arguments);\n const duration = Date.now() - startTime;\n console.error(`[${new Date().toISOString()}] Tool completed in ${duration}ms`);\n return result;\n } catch (error) {\n console.error(`[${new Date().toISOString()}] Tool failed:`, error);\n throw error;\n }\n});\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":10417,"content_sha256":"f261f11d0fcaa49f12b527ce64832b65c2d35ad96b913e6b476b54b06410f0f2"},{"filename":"references/typescript-sdk.md","content":"# TypeScript SDK Implementation\n\n## Installation\n\n```bash\nnpm install @modelcontextprotocol/sdk zod\n```\n\n## Basic Server Setup\n\n```typescript\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n ListResourcesRequestSchema,\n ReadResourceRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { z } from \"zod\";\n\n// Create server instance\nconst server = new Server(\n {\n name: \"example-server\",\n version: \"1.0.0\",\n },\n {\n capabilities: {\n resources: {},\n tools: {},\n prompts: {},\n },\n }\n);\n\n// Handle tools/list request\nserver.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: [\n {\n name: \"get_weather\",\n description: \"Get current weather for a location\",\n inputSchema: {\n type: \"object\",\n properties: {\n location: {\n type: \"string\",\n description: \"City name or zip code\",\n },\n units: {\n type: \"string\",\n enum: [\"celsius\", \"fahrenheit\"],\n default: \"celsius\",\n },\n },\n required: [\"location\"],\n },\n },\n ],\n };\n});\n\n// Handle tools/call request\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n if (request.params.name === \"get_weather\") {\n const location = String(request.params.arguments?.location);\n const units = String(request.params.arguments?.units ?? \"celsius\");\n\n // Your tool logic here\n const weatherData = await fetchWeather(location, units);\n\n return {\n content: [\n {\n type: \"text\",\n text: `Weather in ${location}: ${weatherData.temp}°${units === \"celsius\" ? \"C\" : \"F\"}`,\n },\n ],\n };\n }\n\n throw new Error(`Unknown tool: ${request.params.name}`);\n});\n\n// Start server with stdio transport\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(\"MCP Server running on stdio\");\n}\n\nmain().catch(console.error);\n```\n\n## Resource Provider\n\n```typescript\nimport {\n ListResourcesRequestSchema,\n ReadResourceRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\n\n// List resources\nserver.setRequestHandler(ListResourcesRequestSchema, async () => {\n return {\n resources: [\n {\n uri: \"file:///config/settings.json\",\n name: \"Application Settings\",\n description: \"Current application configuration\",\n mimeType: \"application/json\",\n },\n {\n uri: \"db://users/schema\",\n name: \"User Schema\",\n description: \"Database schema for users table\",\n mimeType: \"text/plain\",\n },\n ],\n };\n});\n\n// Read resource content\nserver.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n const uri = request.params.uri;\n\n if (uri === \"file:///config/settings.json\") {\n const settings = await loadSettings();\n return {\n contents: [\n {\n uri,\n mimeType: \"application/json\",\n text: JSON.stringify(settings, null, 2),\n },\n ],\n };\n }\n\n if (uri.startsWith(\"db://users/\")) {\n const schema = await getDatabaseSchema(\"users\");\n return {\n contents: [\n {\n uri,\n mimeType: \"text/plain\",\n text: schema,\n },\n ],\n };\n }\n\n throw new Error(`Resource not found: ${uri}`);\n});\n```\n\n## Prompt Templates\n\n```typescript\nimport {\n ListPromptsRequestSchema,\n GetPromptRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\n\nserver.setRequestHandler(ListPromptsRequestSchema, async () => {\n return {\n prompts: [\n {\n name: \"code_review\",\n description: \"Generate code review comments\",\n arguments: [\n {\n name: \"language\",\n description: \"Programming language\",\n required: true,\n },\n {\n name: \"code\",\n description: \"Code to review\",\n required: true,\n },\n ],\n },\n ],\n };\n});\n\nserver.setRequestHandler(GetPromptRequestSchema, async (request) => {\n if (request.params.name === \"code_review\") {\n const language = String(request.params.arguments?.language);\n const code = String(request.params.arguments?.code);\n\n return {\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Review this ${language} code and provide feedback:\\n\\n${code}`,\n },\n },\n ],\n };\n }\n\n throw new Error(`Unknown prompt: ${request.params.name}`);\n});\n```\n\n## Input Validation with Zod\n\n```typescript\nimport { z } from \"zod\";\n\n// Define schemas for validation\nconst WeatherArgsSchema = z.object({\n location: z.string().min(1),\n units: z.enum([\"celsius\", \"fahrenheit\"]).default(\"celsius\"),\n});\n\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n if (request.params.name === \"get_weather\") {\n // Validate and parse arguments\n const args = WeatherArgsSchema.parse(request.params.arguments);\n\n const weatherData = await fetchWeather(args.location, args.units);\n\n return {\n content: [\n {\n type: \"text\",\n text: `Temperature: ${weatherData.temp}°${args.units === \"celsius\" ? \"C\" : \"F\"}`,\n },\n ],\n };\n }\n\n throw new Error(`Unknown tool: ${request.params.name}`);\n});\n```\n\n## Error Handling\n\n```typescript\nimport { McpError, ErrorCode } from \"@modelcontextprotocol/sdk/types.js\";\n\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n try {\n // Validate input\n if (!request.params.arguments?.location) {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"location parameter is required\"\n );\n }\n\n const result = await executeTool(request.params.name, request.params.arguments);\n return { content: [{ type: \"text\", text: result }] };\n\n } catch (error) {\n if (error instanceof McpError) {\n throw error; // Re-throw MCP errors\n }\n\n // Wrap other errors\n throw new McpError(\n ErrorCode.InternalError,\n `Tool execution failed: ${error.message}`\n );\n }\n});\n```\n\n## Basic Client Setup\n\n```typescript\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\n\nconst client = new Client(\n {\n name: \"example-client\",\n version: \"1.0.0\",\n },\n {\n capabilities: {},\n }\n);\n\n// Connect to server\nconst transport = new StdioClientTransport({\n command: \"node\",\n args: [\"./server.js\"],\n});\n\nawait client.connect(transport);\n\n// List available tools\nconst toolsResponse = await client.request(\n { method: \"tools/list\" },\n ListToolsResultSchema\n);\n\nconsole.log(\"Available tools:\", toolsResponse.tools);\n\n// Call a tool\nconst result = await client.request(\n {\n method: \"tools/call\",\n params: {\n name: \"get_weather\",\n arguments: { location: \"San Francisco\" },\n },\n },\n CallToolResultSchema\n);\n\nconsole.log(\"Result:\", result.content);\n```\n\n## Notifications\n\n```typescript\n// Server sends notification\nserver.notification({\n method: \"notifications/resources/updated\",\n params: {\n uri: \"file:///config/settings.json\",\n },\n});\n\n// Client handles notifications\nclient.setNotificationHandler((notification) => {\n if (notification.method === \"notifications/resources/updated\") {\n console.log(\"Resource updated:\", notification.params.uri);\n }\n});\n```\n\n## Best Practices\n\n1. **Type Safety**: Use Zod for runtime validation\n2. **Error Handling**: Always wrap errors in McpError\n3. **Async/Await**: Use async/await throughout\n4. **Logging**: Log to stderr, not stdout (stdio transport)\n5. **Cleanup**: Handle graceful shutdown\n6. **Testing**: Use unit tests with mock transports\n7. **Performance**: Cache expensive operations\n8. **Security**: Validate all inputs, sanitize outputs\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":8009,"content_sha256":"cc7b746f2fafac7669d9fd8f076d82181ab2177a5fe7887e054f31b59bc3eee6"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"MCP Developer","type":"text"}]},{"type":"paragraph","content":[{"text":"Senior MCP (Model Context Protocol) developer with deep expertise in building servers and clients that connect AI systems with external tools and data sources.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Core Workflow","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Analyze requirements","type":"text","marks":[{"type":"strong"}]},{"text":" — Identify data sources, tools needed, and client apps","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Initialize project","type":"text","marks":[{"type":"strong"}]},{"text":" — ","type":"text"},{"text":"npx @modelcontextprotocol/create-server my-server","type":"text","marks":[{"type":"code_inline"}]},{"text":" (TypeScript) or ","type":"text"},{"text":"pip install mcp","type":"text","marks":[{"type":"code_inline"}]},{"text":" + scaffold (Python)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Design protocol","type":"text","marks":[{"type":"strong"}]},{"text":" — Define resource URIs, tool schemas (Zod/Pydantic), and prompt templates","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Implement","type":"text","marks":[{"type":"strong"}]},{"text":" — Register tools and resource handlers; configure transport (stdio/SSE/HTTP)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Test","type":"text","marks":[{"type":"strong"}]},{"text":" — Run ","type":"text"},{"text":"npx @modelcontextprotocol/inspector","type":"text","marks":[{"type":"code_inline"}]},{"text":" to verify protocol compliance interactively; confirm tools appear, schemas accept valid inputs, and error responses are well-formed JSON-RPC 2.0. ","type":"text"},{"text":"Feedback loop:","type":"text","marks":[{"type":"strong"}]},{"text":" if schema validation fails → inspect Zod/Pydantic error output → fix schema definition → re-run inspector. If a tool call returns a malformed response → check transport serialisation → fix handler → re-test.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Deploy","type":"text","marks":[{"type":"strong"}]},{"text":" — Package, add auth/rate-limiting, configure env vars, monitor","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Reference Guide","type":"text"}]},{"type":"paragraph","content":[{"text":"Load detailed guidance based on context:","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Topic","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Reference","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Load When","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Protocol","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/protocol.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Message types, lifecycle, JSON-RPC 2.0","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"TypeScript SDK","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/typescript-sdk.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Building servers/clients in Node.js","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Python SDK","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/python-sdk.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Building servers/clients in Python","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tools","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/tools.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tool definitions, schemas, execution","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Resources","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/resources.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Resource providers, URIs, templates","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Minimal Working Example","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"TypeScript — Tool with Zod Validation","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"typescript"},"content":[{"text":"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({ name: \"my-server\", version: \"1.1.0\" });\n\n// Register a tool with validated input schema\nserver.tool(\n \"get_weather\",\n \"Fetch current weather for a location\",\n {\n location: z.string().min(1).describe(\"City name or coordinates\"),\n units: z.enum([\"celsius\", \"fahrenheit\"]).default(\"celsius\"),\n },\n async ({ location, units }) => {\n // Implementation: call external API, transform response\n const data = await fetchWeather(location, units); // your fetch logic\n return {\n content: [{ type: \"text\", text: JSON.stringify(data) }],\n };\n }\n);\n\n// Register a resource provider\nserver.resource(\n \"config://app\",\n \"Application configuration\",\n async (uri) => ({\n contents: [{ uri: uri.href, text: JSON.stringify(getConfig()), mimeType: \"application/json\" }],\n })\n);\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Python — Tool with Pydantic Validation","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"from mcp.server.fastmcp import FastMCP\nfrom pydantic import BaseModel, Field\n\nmcp = FastMCP(\"my-server\")\n\nclass WeatherInput(BaseModel):\n location: str = Field(..., min_length=1, description=\"City name or coordinates\")\n units: str = Field(\"celsius\", pattern=\"^(celsius|fahrenheit)$\")\n\[email protected]()\nasync def get_weather(location: str, units: str = \"celsius\") -> str:\n \"\"\"Fetch current weather for a location.\"\"\"\n data = await fetch_weather(location, units) # your fetch logic\n return str(data)\n\[email protected](\"config://app\")\nasync def app_config() -> str:\n \"\"\"Expose application configuration as a resource.\"\"\"\n return json.dumps(get_config())\n\nif __name__ == \"__main__\":\n mcp.run() # defaults to stdio transport","type":"text"}]},{"type":"paragraph","content":[{"text":"Expected tool call flow:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"Client → { \"method\": \"tools/call\", \"params\": { \"name\": \"get_weather\", \"arguments\": { \"location\": \"Berlin\" } } }\nServer → { \"result\": { \"content\": [{ \"type\": \"text\", \"text\": \"{\\\"temp\\\": 18, \\\"units\\\": \\\"celsius\\\"}\" }] } }","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Constraints","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"MUST DO","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Implement JSON-RPC 2.0 protocol correctly","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validate all inputs with schemas (Zod/Pydantic)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use proper transport mechanisms (stdio/HTTP/SSE)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Implement comprehensive error handling","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add authentication and authorization","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Log protocol messages for debugging","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Test protocol compliance thoroughly","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Document server capabilities","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"MUST NOT DO","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Skip input validation on tool inputs","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Expose sensitive data in resource content","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ignore protocol version compatibility","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Mix synchronous code with async transports","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Hardcode credentials or secrets","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Return unstructured errors to clients","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Deploy without rate limiting","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Skip security controls","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Output Templates","type":"text"}]},{"type":"paragraph","content":[{"text":"When implementing MCP features, provide:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Server/client implementation file","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Schema definitions (tools, resources, prompts)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Configuration file (transport, auth, etc.)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Brief explanation of design decisions","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Maintained by ","type":"text"},{"text":"@jeffallan","type":"text","marks":[{"type":"link","attrs":{"href":"https://github.com/jeffallan","title":null}}]},{"text":", Principal Consultant at ","type":"text"},{"text":"Synergetic Solutions","type":"text","marks":[{"type":"link","attrs":{"href":"https://synergetic.solutions","title":null}}]}]},{"type":"paragraph","content":[{"text":"Documentation","type":"text","marks":[{"type":"link","attrs":{"href":"https://jeffallan.github.io/claude-skills/skills/api-architecture/mcp-developer/","title":null}}]}]}]},"metadata":{"date":"2026-11-02","name":"mcp-developer","author":"@skillopedia","source":{"stars":12181,"repo_name":"claude-skills","origin_url":"https://github.com/Jeffallan/claude-skills/blob/HEAD/skills/mcp-developer/SKILL.md","repo_owner":"Jeffallan","body_sha256":"d2f1ddf1ce82567c04468d041745b3c3a33d3b39ddad21de9612000c09932f3e","cluster_key":"86731e5d1f1fd5fdefb4b9fdd9ba1c2bab46e98af4c4a9afdd04699411953f12","clean_bundle":{"format":"clean-skill-bundle-v1","source":"Jeffallan/claude-skills/skills/mcp-developer/SKILL.md","text_bytes":45527,"source_commit":"078a25cc5bfd8011459be7b91d004e900c1d02d3","skills_sh_rank":4843,"attachment_count":5,"text_attachments":5,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/mcp-developer/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"ai-agent-development","category_label":"AI"},"exact_dupes_collapsed_into_this":0},"license":"MIT","version":"v1","category":"ai-agent-development","metadata":{"role":"specialist","scope":"implementation","author":"https://github.com/Jeffallan","domain":"api-architecture","company":"https://synergetic.solutions","version":"1.1.0","triggers":"MCP, Model Context Protocol, MCP server, MCP client, Claude integration, AI tools, context protocol, JSON-RPC","output-format":"code","related-skills":"fastapi-expert, typescript-pro, security-reviewer, devops-engineer"},"import_tag":"skills-sh-top20k-2026-11","description":"Use when building, debugging, or extending MCP servers or clients that connect AI systems with external tools and data sources. Invoke to implement tool handlers, configure resource providers, set up stdio/HTTP/SSE transport layers, validate schemas with Zod or Pydantic, debug protocol compliance issues, or scaffold complete MCP server/client projects using TypeScript or Python SDKs."}},"renderedAt":1793671375997}

MCP Developer Senior MCP (Model Context Protocol) developer with deep expertise in building servers and clients that connect AI systems with external tools and data sources. Core Workflow 1. Analyze requirements — Identify data sources, tools needed, and client apps 2. Initialize project — (TypeScript) or + scaffold (Python) 3. Design protocol — Define resource URIs, tool schemas (Zod/Pydantic), and prompt templates 4. Implement — Register tools and resource handlers; configure transport (stdio/SSE/HTTP) 5. Test — Run to verify protocol compliance interactively; confirm tools appear, schemas…