mcp-server-building

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

MCP Server Building

构建MCP服务器

Build custom MCP servers to extend Claude with tools, resources, and prompts.
构建自定义MCP服务器,通过工具、资源和提示词扩展Claude的能力。

Architecture

架构

+-------------+     JSON-RPC      +-------------+
|   Claude    |<----------------->| MCP Server  |
|   (Host)    |   stdio/SSE/WS    |  (Tools)    |
+-------------+                   +-------------+
Three Primitives:
  • Tools: Functions Claude can call (with user approval)
  • Resources: Data Claude can read (files, API responses)
  • Prompts: Pre-defined prompt templates
+-------------+     JSON-RPC      +-------------+
|   Claude    |<----------------->| MCP Server  |
|   (Host)    |   stdio/SSE/WS    |  (Tools)    |
+-------------+                   +-------------+
三大核心组件:
  • Tools:Claude可调用的函数(需用户授权)
  • Resources:Claude可读取的数据(文件、API响应)
  • Prompts:预定义的提示词模板

Quick Start

快速开始

Minimal Python Server (stdio)

轻量Python服务器(stdio传输)

python
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent

server = Server("my-tools")

@server.list_tools()
async def list_tools() -> list[Tool]:
    return [
        Tool(
            name="greet",
            description="Greet a user by name",
            inputSchema={
                "type": "object",
                "properties": {
                    "name": {"type": "string", "description": "Name to greet"}
                },
                "required": ["name"]
            }
        )
    ]

@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
    if name == "greet":
        return [TextContent(type="text", text=f"Hello, {arguments['name']}!")]
    raise ValueError(f"Unknown tool: {name}")

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

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())
python
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent

server = Server("my-tools")

@server.list_tools()
async def list_tools() -> list[Tool]:
    return [
        Tool(
            name="greet",
            description="Greet a user by name",
            inputSchema={
                "type": "object",
                "properties": {
                    "name": {"type": "string", "description": "Name to greet"}
                },
                "required": ["name"]
            }
        )
    ]

@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
    if name == "greet":
        return [TextContent(type="text", text=f"Hello, {arguments['name']}!")]
    raise ValueError(f"Unknown tool: {name}")

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

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

TypeScript Server (production)

生产环境TypeScript服务器

typescript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

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

server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [{
    name: "fetch_url",
    description: "Fetch content from a URL",
    inputSchema: {
      type: "object",
      properties: { url: { type: "string" } },
      required: ["url"],
    },
  }],
}));

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === "fetch_url") {
    const { url } = request.params.arguments as { url: string };
    const response = await fetch(url);
    return { content: [{ type: "text", text: await response.text() }] };
  }
  throw new Error("Unknown tool");
});

await server.connect(new StdioServerTransport());
typescript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

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

server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [{
    name: "fetch_url",
    description: "Fetch content from a URL",
    inputSchema: {
      type: "object",
      properties: { url: { type: "string" } },
      required: ["url"],
    },
  }],
}));

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === "fetch_url") {
    const { url } = request.params.arguments as { url: string };
    const response = await fetch(url);
    return { content: [{ type: "text", text: await response.text() }] };
  }
  throw new Error("Unknown tool");
});

await server.connect(new StdioServerTransport());

Detailed Guides

详细指南

  • Transport patterns: See references/transport-patterns.md for stdio, SSE, WebSocket
  • Tool definitions: See references/tool-definitions.md for schemas, error handling, caching
  • Resource patterns: See references/resource-patterns.md for files and dynamic data
  • Testing: See references/testing-patterns.md for MCP Inspector and pytest
  • Auto-discovery: See references/auto-discovery.md for CC 2.1.7+ optimization
  • 传输模式:查看 references/transport-patterns.md 了解stdio、SSE、WebSocket的使用
  • 工具定义:查看 references/tool-definitions.md 了解 schema、错误处理、缓存机制
  • 资源模式:查看 references/resource-patterns.md 了解文件和动态数据的处理
  • 测试方法:查看 references/testing-patterns.md 了解MCP Inspector和pytest的使用
  • 自动发现:查看 references/auto-discovery.md 了解CC 2.1.7+版本的优化方案

Key Decisions

关键决策

DecisionChoiceRationale
Transportstdio for CLI, SSE for webstdio simplest, SSE for browsers
LanguageTypeScript for productionBetter SDK support, type safety
Error handlingReturn errors as textClaude can interpret and retry
决策项选择方案决策依据
传输方式CLI用stdio,Web用SSEstdio实现最简单,SSE适配浏览器场景
开发语言生产环境用TypeScript更完善的SDK支持,类型安全
错误处理以文本形式返回错误Claude可解析错误并重试

Anti-Patterns

反模式(需避免)

  1. Stateful tools without cleanup - Always clean up connections
  2. Blocking synchronous code - Use
    asyncio.to_thread()
  3. Missing input validation - Validate before processing
  4. Secrets in tool output - Never return credentials
  5. Unbounded responses - Limit response sizes
  1. 无清理机制的有状态工具 - 务必清理连接资源
  2. 阻塞式同步代码 - 使用
    asyncio.to_thread()
    处理
  3. 缺少输入验证 - 处理前必须验证输入
  4. 工具输出包含敏感信息 - 绝对不要返回凭证数据
  5. 无限制的响应内容 - 限制响应大小

Related Skills

相关技能

  • function-calling
    - LLM function calling patterns
  • agent-loops
    - Agentic patterns using MCP tools
  • input-validation
    - Input validation for arguments
  • function-calling
    - 大模型函数调用模式
  • agent-loops
    - 基于MCP工具的智能体循环模式
  • input-validation
    - 参数输入验证

Resources

资源链接