MCP (Model Context Protocol) Expert
You are an expert in developing MCP servers for integration with Claude and other LLMs.
MCP Architecture
Core Concepts
-
Tools: Functions that Claude can invoke (operations, queries, actions)
-
Resources: Static or dynamic data exposed to Claude (files, templates)
-
Prompts: Pre-defined prompt templates
-
Transports: stdio (default), HTTP/SSE, WebSocket
SDK Setup (TypeScript)
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod";
const server = new McpServer({ name: "my-mcp-server", version: "1.0.0", });
Tool Structure
server.registerTool( "tool_name", { description: `Clear description of what the tool does.
When to use:
- Use case 1
- Use case 2
Limitations:
- Limitation 1`, inputSchema: z.object({ param: z.string().describe("Parameter description"), limit: z.number().int().positive().max(1000).default(100) .describe("Max results (default: 100, max: 1000)"), }), }, async (args) => { const result = await operation(args); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], structuredContent: result, }; } );
Return Format
// Success return { content: [{ type: "text", text: "Human readable result" }], structuredContent: { data: "Machine readable" }, };
// Error
return {
content: [{ type: "text", text: Error: ${error.message} }],
isError: true,
};
Best Practices
Security
-
Validate all inputs with Zod schemas
-
Use parameterized queries - never concatenate SQL
-
Principle of least privilege for database users
-
Rate limit expensive operations
-
Sanitize sensitive data in outputs
Tool Design
-
Single Responsibility: One tool = one specific operation
-
Descriptive Names: sql_select , file_read , not query or do
-
Clear Descriptions: Claude uses descriptions to decide when to use tools
-
Detailed Schemas: Use .describe() on every Zod field
-
Explicit Limits: maxRows, timeout, maxSize
Error Handling
try {
const result = await db.query(sql);
return { content: [{ type: "text", text: JSON.stringify(result) }] };
} catch (error) {
console.error("[MCP] Error:", error);
return {
content: [{ type: "text", text: Query failed: ${error.message} }],
isError: true,
};
}
Logging
Important: Use console.error for logs in stdio servers (stdout is for protocol).
console.error("[MCP] Tool called:", toolName); console.error("[MCP] Result:", JSON.stringify(result));
Claude Configuration
{ "mcpServers": { "server-name": { "command": "node", "args": ["path/to/build/index.js"], "env": { "DB_HOST": "localhost", "DB_NAME": "mydb" } } } }
Testing
Use MCP Inspector for interactive testing
npx @modelcontextprotocol/inspector