{"id":"58a9f6a6-3595-45cf-a4af-4151f651b008","shortId":"ExPgqB","kind":"skill","title":"mcp-builder","tagline":"MCP 服务器构建方法论 — 系统化构建生产级 MCP 工具，让 AI 助手连接外部能力","description":"# MCP 服务器构建\n\n系统化设计、实现、测试和部署 Model Context Protocol 服务器的方法论。\n\n## 1. 协议核心概念\n\nMCP 定义三种原语：\n\n- **Tools（工具）**：AI 助手主动调用的函数，有副作用。如搜索、创建、删除操作。\n- **Resources（资源）**：AI 助手只读访问的数据源，用 URI 标识。如 `users://{id}/profile`。\n- **Prompts（提示词模板）**：预定义交互模板，引导用户触发工作流。\n\n**选择原则：** 执行操作 → Tool | 读取数据 → Resource | 引导交互 → Prompt\n\n## 2. 项目结构规范\n\n### TypeScript\n```\nmy-mcp-server/\n├── src/\n│   ├── index.ts          # 入口，注册 tools/resources\n│   ├── tools/             # 按功能拆分\n│   ├── resources/\n│   └── lib/               # 客户端封装、校验逻辑\n├── tests/\n├── package.json\n└── tsconfig.json\n```\n\n关键依赖：`@modelcontextprotocol/sdk` + `zod`\n\n### Python\n```\nmy-mcp-server/\n├── src/my_mcp_server/\n│   ├── server.py\n│   ├── tools/\n│   └── lib/\n├── tests/\n└── pyproject.toml\n```\n\n关键依赖：`mcp` + `pydantic`\n\n## 3. Tool 设计原则\n\n### 命名\n- `snake_case` 格式，动词开头：`search_users`、`create_issue`、`delete_file`\n- 名称自解释，AI 助手靠名称选工具，模糊命名导致误调用\n\n### 参数\n- 每个参数有类型约束和 `.describe()` 描述\n- 可选参数给默认值，减少 AI 决策负担\n- 用枚举代替布尔开关\n\n```typescript\nserver.tool(\"search_issues\", {\n  query: z.string().describe(\"搜索关键词\"),\n  status: z.enum([\"open\", \"closed\", \"all\"]).default(\"open\").describe(\"状态筛选\"),\n  limit: z.number().min(1).max(100).default(20).describe(\"返回上限\"),\n}, async ({ query, status, limit }) => { /* ... */ });\n```\n\n### 描述\n说明**用途 + 返回内容 + 限制**，这是 AI 选择工具的关键依据：\n\n```typescript\nserver.tool(\"search_users\",\n  \"根据姓名或邮箱搜索用户。返回 ID、姓名、邮箱列表。模糊匹配，最多 50 条。\",\n  schema, handler);\n```\n\n### 输出\n- 结构化数据 → JSON，人类可读内容 → Markdown\n- 始终用 `content: [{ type: \"text\", text: \"...\" }]` 格式返回\n\n## 4. 输入验证和错误处理\n\n用 Zod/Pydantic 做 Schema 级校验，业务级校验放 handler 开头：\n\n```typescript\nserver.tool(\"get_user\", { id: z.string() }, async ({ id }) => {\n  try {\n    const user = await db.getUser(id);\n    if (!user) {\n      return {\n        content: [{ type: \"text\", text: `用户 ${id} 不存在，请检查 ID。` }],\n        isError: true,\n      };\n    }\n    return { content: [{ type: \"text\", text: JSON.stringify(user, null, 2) }] };\n  } catch (err) {\n    return {\n      content: [{ type: \"text\", text: `查询失败：${err.message}` }],\n      isError: true,\n    };\n  }\n});\n```\n\n**错误处理四原则：**\n1. 永远不让服务器崩溃 — try/catch 包裹所有外部调用\n2. 返回可操作的错误信息 — 告诉 AI 问题是什么、能做什么\n3. 使用 `isError: true` — 让 AI 知道调用失败\n4. 区分错误类型 — 参数错误、权限不足、资源不存在、服务不可用\n\n## 5. 资源管理和生命周期\n\n```typescript\n// 资源注册\nserver.resource(\"user-profile\", \"users://{userId}/profile\", async (uri) => {\n  const profile = await db.getProfile(extractId(uri));\n  return { contents: [{ uri: uri.href, mimeType: \"application/json\", text: JSON.stringify(profile) }] };\n});\n\n// 生命周期：先初始化 → 再 connect → 监听关闭信号\nconst db = await Database.connect(config.dbUrl);\nawait server.connect(new StdioServerTransport());\nprocess.on(\"SIGINT\", async () => { await db.disconnect(); await server.close(); process.exit(0); });\n```\n\n关键点：使用连接池、所有外部调用设超时、优雅关闭清理资源。\n\n## 6. 测试策略\n\n### 单元测试 — 业务逻辑与 MCP 注册分离\n```typescript\n// tools/search.ts 导出纯函数\nexport async function searchUsers(query: string, limit: number) { /* ... */ }\n\n// search.test.ts 独立测试\ntest(\"返回匹配结果\", async () => {\n  const results = await searchUsers(\"alice\", 10);\n  expect(results[0].name).toContain(\"Alice\");\n});\n```\n\n### 集成测试 — 用 SDK Client 做端到端验证\n```typescript\nconst [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();\nawait server.connect(serverTransport);\nconst client = new Client({ name: \"test\", version: \"1.0.0\" });\nawait client.connect(clientTransport);\nconst result = await client.callTool(\"search_users\", { query: \"test\" });\nexpect(result.isError).toBeFalsy();\n```\n\n### MCP Inspector — 交互式调试\n```bash\nnpx @modelcontextprotocol/inspector node dist/index.js\n```\n\n在浏览器中查看所有 tools/resources，手动调用并查看结果。\n\n**测试要点：** 每个 Tool 覆盖正常 + 异常路径、边界值、外部服务失败模拟。\n\n## 7. 安全考虑\n\n**权限控制：**\n- 最小权限原则，读写 Tool 分离\n- 危险操作要求确认参数（如 `confirm: true`）\n\n**输入安全：**\n- SQL 注入 → 参数化查询，绝不拼接\n- 路径遍历 → 校验路径，禁止 `../`\n- 命令注入 → 用 `execFile` 而非 `exec`\n\n**敏感数据：**\n- 密钥通过环境变量传入，不硬编码\n- 日志不打印完整敏感信息\n- 返回数据做脱敏处理\n\n**沙箱：** 文件操作限制目录、网络请求限制白名单、设置资源配额。\n\n## 8. 部署和分发\n\n### npm 发布\n```json\n{ \"bin\": { \"mcp-server-myservice\": \"dist/index.js\" }, \"files\": [\"dist\"] }\n```\n\n用户配置：\n```json\n{ \"mcpServers\": { \"myservice\": { \"command\": \"npx\", \"args\": [\"@yourorg/mcp-server-myservice\"], \"env\": { \"API_KEY\": \"xxx\" } } } }\n```\n\n### pip 发布\n```toml\n[project.scripts]\nmcp-server-myservice = \"my_mcp_server.server:main\"\n```\n\n### Docker — 适用于复杂依赖或隔离场景\n```dockerfile\nFROM node:20-slim\nWORKDIR /app\nCOPY package*.json ./ && RUN npm ci --production\nCOPY dist ./dist\nENTRYPOINT [\"node\", \"dist/index.js\"]\n```\n\n## 9. 调试技巧\n\n**关键：MCP 用 stdio 通信，不能用 `console.log`，会破坏协议流。**\n\n```typescript\n// 错误\nconsole.log(\"debug\");\n// 正确\nconsole.error(\"[DEBUG]\", info);\n// 更好\nserver.sendLoggingMessage({ level: \"info\", data: \"处理中\" });\n```\n\n**常见问题：**\n\n| 症状 | 原因 | 解决 |\n|------|------|------|\n| 启动无响应 | transport 未连接 | 检查 `server.connect()` |\n| Tool 不出现 | 注册在 connect 之后 | 先注册再 connect |\n| AI 不调用 Tool | 描述不清晰 | 改善名称和描述 |\n| 参数总错 | Schema 不明确 | 添加 `.describe()` |\n| 调用超时 | 外部服务慢 | 加超时和缓存 |\n\n**调试流程：** Inspector 验证基本功能 → 手动调用确认输入输出 → 连接真实 AI 客户端观察调用模式 → 根据实际行为调整设计。\n\n## 10. 构建检查清单\n\n### 设计\n- [ ] 明确 Tools vs Resources vs Prompts 分工\n- [ ] Tool 命名 `动词_名词`，描述说明用途和返回内容\n- [ ] 参数简洁，可选参数有合理默认值\n\n### 实现\n- [ ] 输入用 Zod/Pydantic 校验\n- [ ] 外部调用有 try/catch 和超时\n- [ ] 错误返回 `isError: true` 并附可操作信息\n- [ ] 不用 `console.log`（用 stderr 或 SDK 日志）\n- [ ] 敏感数据走环境变量\n\n### 测试\n- [ ] 核心逻辑有单元测试\n- [ ] 有集成测试验证 MCP 协议交互\n- [ ] 用 MCP Inspector 手动验证过\n- [ ] 用真实 AI 客户端测试过\n\n### 部署\n- [ ] README 含安装和配置说明\n- [ ] 提供客户端配置 JSON 示例\n- [ ] 遵循 semver，无硬编码密钥","tags":["mcp","builder","superpowers","jnmetacode","agent-skills","agentic-coding","ai-coding","chinese","claude-code","code-review","cursor","gemini-cli"],"capabilities":["skill","source-jnmetacode","skill-mcp-builder","topic-agent-skills","topic-agentic-coding","topic-ai-coding","topic-chinese","topic-claude-code","topic-code-review","topic-cursor","topic-gemini-cli","topic-kiro","topic-mcp","topic-npm-package","topic-prompt-engineering"],"categories":["superpowers-zh"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/jnMetaCode/superpowers-zh/mcp-builder","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add jnMetaCode/superpowers-zh","source_repo":"https://github.com/jnMetaCode/superpowers-zh","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 1857 github stars · SKILL.md body (5,367 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-03T00:52:45.883Z","embedding":null,"createdAt":"2026-04-18T21:55:57.335Z","updatedAt":"2026-05-03T00:52:45.883Z","lastSeenAt":"2026-05-03T00:52:45.883Z","tsv":"'/app':483 '/dist':493 '/profile':42,275 '0':315,350 '1':21,139,243 '1.0.0':374 '10':347,558 '100':141 '2':54,230,247 '20':143,480 '3':92,253 '4':184,260 '5':266 '50':169 '6':320 '7':407 '8':440 '9':497 'ai':10,27,35,107,116,156,250,258,537,555,604 'alic':346,353 'api':462 'application/json':289 'arg':459 'async':146,200,276,309,330,341 'await':205,280,300,303,310,312,344,364,375,380 'bash':392 'bin':445 'builder':3 'case':97 'catch':231 'ci':489 'client':357,368,370 'client.calltool':381 'client.connect':376 'clienttransport':361,377 'close':130 'command':457 'config.dburl':302 'confirm':416 'connect':296,533,536 'console.error':512 'console.log':505,509,587 'const':203,278,298,342,360,367,378 'content':179,211,223,234,285 'context':18 'copi':484,491 'creat':102 'data':519 'database.connect':301 'db':299 'db.disconnect':311 'db.getprofile':281 'db.getuser':206 'debug':510,513 'default':132,142 'delet':104 'describ':112,125,134,144,546 'dist':452,492 'dist/index.js':396,450,496 'docker':475 'dockerfil':477 'entrypoint':494 'env':461 'err':232 'err.message':239 'exec':430 'execfil':428 'expect':348,386 'export':329 'extractid':282 'file':105,451 'function':331 'get':196 'handler':172,192 'id':41,164,198,201,207,216,219 'index.ts':62 'info':514,518 'inmemorytransport.createlinkedpair':363 'inspector':390,551,601 'iserror':220,240,255,583 'issu':103,122 'json':175,444,454,486,610 'json.stringify':227,291 'key':463 'level':517 'lib':69,86 'limit':136,149,335 'main':474 'markdown':177 'max':140 'mcp':2,4,7,12,23,59,81,90,324,389,447,470,500,597,600 'mcp-builder':1 'mcp-server-myservic':446,469 'mcpserver':455 'mimetyp':288 'min':138 'model':17 'modelcontextprotocol/inspector':394 'modelcontextprotocol/sdk':76 'my-mcp-serv':57,79 'my_mcp_server.server':473 'myservic':449,456,472 'name':351,371 'new':305,369 'node':395,479,495 'npm':442,488 'npx':393,458 'null':229 'number':336 'open':129,133 'packag':485 'package.json':73 'pip':465 'process.exit':314 'process.on':307 'product':490 'profil':273,279,292 'project.scripts':468 'prompt':43,53,566 'protocol':19 'pydant':91 'pyproject.toml':88 'python':78 'queri':123,147,333,384 'readm':607 'resourc':33,51,68,564 'result':343,349,379 'result.iserror':387 'return':210,222,233,284 'run':487 'schema':171,189,543 'sdk':356,591 'search':100,121,160,382 'search.test.ts':337 'searchus':332,345 'semver':613 'server':60,82,448,471 'server.close':313 'server.connect':304,365,529 'server.py':84 'server.resource':270 'server.sendloggingmessage':516 'server.tool':120,159,195 'servertransport':362,366 'sigint':308 'skill' 'skill-mcp-builder' 'slim':481 'snake':96 'source-jnmetacode' 'sql':419 'src':61 'src/my_mcp_server':83 'status':127,148 'stderr':589 'stdio':502 'stdioservertransport':306 'string':334 'test':72,87,339,372,385 'text':181,182,213,214,225,226,236,237,290 'tobefalsi':388 'tocontain':352 'toml':467 'tool':25,49,66,85,93,402,412,530,539,562,568 'tools/resources':65,398 'tools/search.ts':327 'topic-agent-skills' 'topic-agentic-coding' 'topic-ai-coding' 'topic-chinese' 'topic-claude-code' 'topic-code-review' 'topic-cursor' 'topic-gemini-cli' 'topic-kiro' 'topic-mcp' 'topic-npm-package' 'topic-prompt-engineering' 'transport':526 'tri':202 'true':221,241,256,417,584 'try/catch':245,580 'tsconfig.json':74 'type':180,212,224,235 'typescript':56,119,158,194,268,326,359,507 'uri':38,277,283,286 'uri.href':287 'user':101,161,197,204,209,228,272,383 'user-profil':271 'userid':274 'version':373 'vs':563,565 'workdir':482 'xxx':464 'yourorg/mcp-server-myservice':460 'z.enum':128 'z.number':137 'z.string':124,199 'zod':77 'zod/pydantic':187,577 '不出现':531 '不存在':217 '不明确':544 '不用':586 '不硬编码':433 '不能用':504 '不调用':538 '业务级校验放':191 '业务逻辑与':323 '之后':534 '交互式调试':391 '人类可读内容':176 '优雅关闭清理资源':319 '会破坏协议流':506 '使用':254 '使用连接池':317 '做':188 '做端到端验证':358 '先初始化':294 '先注册再':535 '入口':63 '关键':499 '关键依赖':75,89 '关键点':316 '再':295 '决策负担':117 '减少':115 '分工':567 '分离':413 '创建':31 '删除操作':32 '加超时和缓存':549 '动词':570 '动词开头':99 '助手主动调用的函数':28 '助手只读访问的数据源':36 '助手连接外部能力':11 '助手靠名称选工具':108 '包裹所有外部调用':246 '区分错误类型':261 '协议交互':598 '协议核心概念':22 '单元测试':322 '危险操作要求确认参数':414 '原因':523 '参数':110 '参数化查询':421 '参数总错':542 '参数简洁':573 '参数错误':262 '发布':443,466 '可选参数有合理默认值':574 '可选参数给默认值':114 '名称自解释':106 '名词':571 '含安装和配置说明':608 '启动无响应':525 '告诉':249 '命令注入':426 '命名':95,569 '和超时':581 '在浏览器中查看所有':397 '处理中':520 '外部服务失败模拟':406 '外部服务慢':548 '外部调用有':579 '如':40,415 '如搜索':30 '始终用':178 '姓名':165 '安全考虑':408 '定义三种原语':24 '实现':15,575 '客户端封装':70 '客户端测试过':605 '客户端观察调用模式':556 '密钥通过环境变量传入':432 '导出纯函数':328 '工具':8,26 '常见问题':521 '并附可操作信息':585 '开头':193 '异常路径':404 '引导交互':52 '引导用户触发工作流':46 '或':590 '所有外部调用设超时':318 '手动调用并查看结果':399 '手动调用确认输入输出':553 '手动验证过':602 '执行操作':48 '按功能拆分':67 '描述':113,150 '描述不清晰':540 '描述说明用途和返回内容':572 '提供客户端配置':609 '提示词模板':44 '搜索关键词':126 '改善名称和描述':541 '敏感数据':431 '敏感数据走环境变量':593 '文件操作限制目录':437 '无硬编码密钥':614 '日志':592 '日志不打印完整敏感信息':434 '明确':561 '更好':515 '最多':168 '最小权限原则':410 '有副作用':29 '有集成测试验证':596 '服务不可用':265 '服务器构建':13 '服务器构建方法论':5 '服务器的方法论':20 '未连接':527 '权限不足':263 '权限控制':409 '条':170 '构建检查清单':559 '查询失败':238 '标识':39 '校验':578 '校验路径':424 '校验逻辑':71 '核心逻辑有单元测试':595 '根据姓名或邮箱搜索用户':162 '根据实际行为调整设计':557 '格式':98 '格式返回':183 '检查':528 '模糊匹配':167 '模糊命名导致误调用':109 '正确':511 '每个':401 '每个参数有类型约束和':111 '永远不让服务器崩溃':244 '沙箱':436 '注入':420 '注册':64 '注册分离':325 '注册在':532 '测试':594 '测试和部署':16 '测试策略':321 '测试要点':400 '添加':545 '状态筛选':135 '独立测试':338 '生命周期':293 '用':37,186,355,427,501,588,599 '用户':215 '用户配置':453 '用枚举代替布尔开关':118 '用真实':603 '用途':152 '症状':522 '监听关闭信号':297 '知道调用失败':259 '示例':611 '禁止':425 '系统化构建生产级':6 '系统化设计':14 '级校验':190 '结构化数据':174 '绝不拼接':422 '网络请求限制白名单':438 '而非':429 '能做什么':252 '覆盖正常':403 '解决':524 '让':9,257 '设置资源配额':439 '设计':560 '设计原则':94 '说明':151 '请检查':218 '读写':411 '读取数据':50 '调用超时':547 '调试技巧':498 '调试流程':550 '资源':34 '资源不存在':264 '资源注册':269 '资源管理和生命周期':267 '路径遍历':423 '输入安全':418 '输入用':576 '输入验证和错误处理':185 '输出':173 '边界值':405 '返回':163 '返回上限':145 '返回内容':153 '返回匹配结果':340 '返回可操作的错误信息':248 '返回数据做脱敏处理':435 '这是':155 '连接真实':554 '适用于复杂依赖或隔离场景':476 '选择原则':47 '选择工具的关键依据':157 '通信':503 '遵循':612 '邮箱列表':166 '部署':606 '部署和分发':441 '错误':508 '错误处理四原则':242 '错误返回':582 '问题是什么':251 '限制':154 '集成测试':354 '项目结构规范':55 '预定义交互模板':45 '验证基本功能':552","prices":[{"id":"874226c0-09f1-429d-9599-7812a2f24a0c","listingId":"58a9f6a6-3595-45cf-a4af-4151f651b008","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"jnMetaCode","category":"superpowers-zh","install_from":"skills.sh"},"createdAt":"2026-04-18T21:55:57.335Z"}],"sources":[{"listingId":"58a9f6a6-3595-45cf-a4af-4151f651b008","source":"github","sourceId":"jnMetaCode/superpowers-zh/mcp-builder","sourceUrl":"https://github.com/jnMetaCode/superpowers-zh/tree/main/skills/mcp-builder","isPrimary":false,"firstSeenAt":"2026-04-18T21:55:57.335Z","lastSeenAt":"2026-05-03T00:52:45.883Z"}],"details":{"listingId":"58a9f6a6-3595-45cf-a4af-4151f651b008","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"jnMetaCode","slug":"mcp-builder","github":{"repo":"jnMetaCode/superpowers-zh","stars":1857,"topics":["agent-skills","agentic-coding","ai-coding","chinese","claude-code","code-review","cursor","gemini-cli","kiro","mcp","npm-package","prompt-engineering","skills","superpowers","tdd","trae"],"license":"mit","html_url":"https://github.com/jnMetaCode/superpowers-zh","pushed_at":"2026-04-28T15:32:18Z","description":"🦸 AI 编程超能力 · 中文增强版 — superpowers（116k+ ⭐）完整汉化 + 6 个中国原创 skills，让 Claude Code / Copilot CLI / Hermes Agent / Cursor / Windsurf / Kiro / Gemini CLI 等 16 款 AI 编程工具真正会干活","skill_md_sha":"2dc79f148932623378285f76b4ee3e48c2c1e22d","skill_md_path":"skills/mcp-builder/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/jnMetaCode/superpowers-zh/tree/main/skills/mcp-builder"},"layout":"multi","source":"github","category":"superpowers-zh","frontmatter":{"name":"mcp-builder","description":"MCP 服务器构建方法论 — 系统化构建生产级 MCP 工具，让 AI 助手连接外部能力"},"skills_sh_url":"https://skills.sh/jnMetaCode/superpowers-zh/mcp-builder"},"updatedAt":"2026-05-03T00:52:45.883Z"}}