第四节:MCP 服务器开发
服务端实现与调试

作者:小学子 📚 | 日期:2026年4月2日 | 第七阶段 · 模块七


# 第七阶段 · 模块七 · 第四节:MCP 服务器开发

核心问题

如何开发一个 MCP 服务器?MCP 服务器需要实现哪些端点?如何注册和发布 MCP 服务器?


◇ 本节位置


        Claude Code 全局架构
        
        ┌─────────────────────────────────────────────────────────────────────┐
        │  MCP 系统                                                            │
        │                                                                      │
        │  MCP 服务器开发 ← 本节                                              │
        │  ├── 创建服务器 ──> Server 实现                                     │
        │  ├── 实现端点 ──> tools/list、tools/call                           │
        │  └── 注册发布 ──> Claude Code 配置                                  │
        └─────────────────────────────────────────────────────────────────────┘
        


一、MCP 服务器结构

1.1 服务器骨架


        // 使用 @modelcontextprotocol/sdk 创建服务器
        import { Server } from '@modelcontextprotocol/sdk/server/index.js';
        import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
        
        const server = new Server(
          {
            name: 'my-mcp-server',
            version: '1.0.0',
          },
          {
            capabilities: {
              tools: {},  // 工具能力
              resources: {},  // 资源能力
            },
          }
        );
        

1.2 传输层选择


        // 1. STDIO(本地进程)
        import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
        
        const transport = new StdioServerTransport();
        await server.connect(transport);
        
        // 2. SSE(远程服务器)
        import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
        
        const transport = new SSEServerTransport('/sse');
        await server.connect(transport);
        


二、实现工具端点

2.1 工具列表


        // 实现 tools/list 端点
        server.setRequestHandler(ListToolsRequestSchema, async () => {
          return {
            tools: [
              {
                name: 'get_weather',
                description: 'Get weather for a location',
                inputSchema: {
                  type: 'object',
                  properties: {
                    location: {
                      type: 'string',
                      description: 'City name',
                    },
                  },
                  required: ['location'],
                },
              },
              {
                name: 'send_email',
                description: 'Send an email',
                inputSchema: {
                  type: 'object',
                  properties: {
                    to: { type: 'string' },
                    subject: { type: 'string' },
                    body: { type: 'string' },
                  },
                  required: ['to', 'subject', 'body'],
                },
              },
            ],
          };
        });
        

2.2 工具调用


        // 实现 tools/call 端点
        server.setRequestHandler(CallToolRequestSchema, async (request) => {
          const { name, arguments: args } = request.params;
        
          try {
            switch (name) {
              case 'get_weather':
                return await getWeather(args.location);
        
              case 'send_email':
                return await sendEmail(args.to, args.subject, args.body);
        
              default:
                throw new Error(`Unknown tool: ${name}`);
            }
          } catch (error) {
            return {
              content: [
                {
                  type: 'text',
                  text: `Error: ${error.message}`,
                },
              ],
              isError: true,
            };
          }
        });
        
        async function getWeather(location: string) {
          const weather = await fetchWeather(location);
        
          return {
            content: [
              {
                type: 'text',
                text: `Weather in ${location}: ${weather.description}, ${weather.temperature}°C`,
              },
            ],
          };
        }
        


三、实现资源端点

3.1 资源列表


        // 实现 resources/list 端点
        server.setRequestHandler(ListResourcesRequestSchema, async () => {
          return {
            resources: [
              {
                uri: 'weather://cities',
                name: 'Available Cities',
                description: 'List of available cities for weather queries',
                mimeType: 'application/json',
              },
            ],
          };
        });
        

3.2 资源读取


        // 实现 resources/read 端点
        server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
          const { uri } = request.params;
        
          switch (uri) {
            case 'weather://cities':
              return {
                contents: [
                  {
                    uri,
                    mimeType: 'application/json',
                    text: JSON.stringify(['Beijing', 'Shanghai', 'Guangzhou']),
                  },
                ],
              };
        
            default:
              throw new Error(`Unknown resource: ${uri}`);
          }
        });
        


四、完整示例

4.1 天气 MCP 服务器


        // weather-server.ts
        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: 'weather-server', version: '1.0.0' },
          { capabilities: { tools: {} } }
        );
        
        // 工具列表
        server.setRequestHandler(ListToolsRequestSchema, async () => {
          return {
            tools: [
              {
                name: 'get_weather',
                description: 'Get weather for a location',
                inputSchema: {
                  type: 'object',
                  properties: {
                    location: { type: 'string' },
                  },
                  required: ['location'],
                },
              },
            ],
          };
        });
        
        // 工具调用
        server.setRequestHandler(CallToolRequestSchema, async (request) => {
          const { name, arguments: args } = request.params;
        
          if (name === 'get_weather') {
            const weather = await fetch(`https://api.weather.com?q=${args.location}`)
              .then(r => r.json());
        
            return {
              content: [
                {
                  type: 'text',
                  text: `${args.location}: ${weather.temp}°C, ${weather.description}`,
                },
              ],
            };
          }
        
          throw new Error(`Unknown tool: ${name}`);
        });
        
        // 启动
        const transport = new StdioServerTransport();
        server.connect(transport);
        

4.2 package.json


        {
          "name": "mcp-weather-server",
          "version": "1.0.0",
          "type": "module",
          "main": "weather-server.ts",
          "scripts": {
            "start": "tsx weather-server.ts"
          },
          "dependencies": {
            "@modelcontextprotocol/sdk": "^0.5.0"
          }
        }
        


五、配置和发布

5.1 Claude Code 配置


        {
          "mcpServers": {
            "weather": {
              "type": "stdio",
              "command": "npx",
              "args": ["mcp-weather-server"]
            }
          }
        }
        

5.2 发布到 NPM


        # 1. 登录 NPM
        npm login
        
        # 2. 发布
        npm publish
        
        # 3. 用户安装
        npm install -g mcp-weather-server
        
        # 4. 配置使用
        claude mcp add weather npx mcp-weather-server
        


六、测试 MCP 服务器

6.1 本地测试


        # 1. 运行服务器
        npx mcp-weather-server
        
        # 2. 测试工具调用
        echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_weather","arguments":{"location":"Beijing"}}}' | npx mcp-weather-server
        

6.2 调试技巧


        // 添加日志
        server.setRequestHandler(CallToolRequestSchema, async (request) => {
          console.error('[DEBUG] Tool call:', request.params);
        
          try {
            const result = await handleTool(request.params);
            console.error('[DEBUG] Result:', result);
            return result;
          } catch (error) {
            console.error('[ERROR]', error);
            throw error;
          }
        });
        


七、思考题

思考题 1:MCP 服务器需要处理认证吗?

答案


        // 可以,但需要实现自定义传输
        // 或使用 MCP 的 OAuth 支持
        
        // 简单场景:不需要认证
        // 内部工具、无敏感数据
        
        // 复杂场景:需要认证
        // 外部 API、用户数据
        


思考题 2:如何处理并发请求?

答案


        // MCP 服务器支持并发
        // 每个请求独立处理
        
        // 但如果共享资源(如数据库连接),需要加锁
        const db = await getDatabase();
        
        server.setRequestHandler(CallToolRequestSchema, async (request) => {
          // 数据库操作已经处理了并发
          return await db.query(request.params);
        });
        


思考题 3:MCP 服务器如何处理错误?

答案


        // 错误时返回 isError: true
        return {
          content: [
            {
              type: 'text',
              text: `Error: ${error.message}`,
            },
          ],
          isError: true,
        };
        


八、延伸阅读

资源说明
MCP SDK@modelcontextprotocol/sdk
MCP 协议规范https://modelcontextprotocol.io
MCP 服务器示例https://github.com/modelcontextprotocol/servers


九、下节预告

第八章:调试与日志

- 日志系统架构

- 调试模式

- 常见问题排查


*- 第一轮:□ 事实准确性*

*- 第二轮:□ 深度与洞见*

*- 第三轮:□ 可读性与价值*