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)
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
typescript
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
typescript
// 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, notqueryordo - •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
typescript
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).
typescript
console.error("[MCP] Tool called:", toolName);
console.error("[MCP] Result:", JSON.stringify(result));
Claude Configuration
json
{
"mcpServers": {
"server-name": {
"command": "node",
"args": ["path/to/build/index.js"],
"env": {
"DB_HOST": "localhost",
"DB_NAME": "mydb"
}
}
}
}
Testing
bash
# Use MCP Inspector for interactive testing npx @modelcontextprotocol/inspector