《Claude Code 工程化实战》第 19 讲 MCP 协议与外部工具连接

📅 2026/7/15 4:22:23
《Claude Code 工程化实战》第 19 讲 MCP 协议与外部工具连接
本讲摘要Claude Code 原生只能读写本地文件Bash / Read / Edit / Write / Grep / Glob)、前 18 讲我们通过 Skills / SubAgent / Hooks 扩展了 Claude 的能力边界、但这些扩展都基于本地文件或本地命令。本讲进入第 4 种扩展——MCP(Model Context Protocol)让 Claude Code 连接 GitHub / Notion / 数据库 / 实时文档等外部世界。MCP 是 Anthropic 在 2024-11 推出的开放标准、3 种传输方式stdio / HTTP / SSE)、本讲讲清楚 MCP 是什么、3 种传输方式怎么选、5 个实战 MCP 服务器怎么用、以及如何自己写一个自定义 MCP 服务器。本讲的三条主线第一、MCP 是什么?为什么需要它?——Claude Code 原生能力边界只能本地文件/命令 MCP 解决如何连接外部世界(GitHub / Notion / 数据库 MCP 是 Anthropic 2024-11 推出的开放标准JSON-RPC 2.0 over stdio / HTTP / SSE) MCP 工具调用模式tool discovery / tool call / structured output。第二、3 种传输方式 stdio / HTTP / SSE 怎么选 5 个实战 MCP 服务器——stdio本地进程、最快/ HTTP远程 SaaS)/ SSE流式长连接;5 个实战GitHub / Notion / Filesystem / Database / Puppeteer。第三、如何自己写一个自定义 MCP 服务器 4 种扩展机制边界——用 Python / TypeScript MCP SDK 写MCP vs Skills vs Hooks vs SubAgent 的工程定位。学完本讲、你应该能配置 5 个常见 MCP server在 .mcp.json)、能用 stdio / HTTP / SSE 3 种传输方式、能自己用 Python SDK 写一个最小 MCP server、能区分 MCP / Skills / Hooks / SubAgent 4 种扩展机制的工程定位。 详细内容MCP 是什么?为什么需要它?前 18 讲我们用 3 种方式扩展 Claude CodeSubAgent角色层独立上下文/ Skills能力层软规范/ Hooks事件层硬约束。3 种扩展都基于本地文件 本地命令、但 Claude Code 想要连接外部世界(GitHub / Notion / 数据库 / 实时文档、就需要 MCP。Claude Code 原生能力边界Claude Code 默认带 6 类工具Bash本地命令/ Read / Edit / Write / Grep / Glob本地文件。这 6 类工具只能操作当前工作目录 子进程能访问的范围。如果 Claude 想• 创建 GitHub issue → 没有 GitHub API 工具。• 写 Notion 页面 → 没有 Notion API 工具。• 查 PostgreSQL 数据库 → 没有 SQL 工具。• 抓网页内容 → 没有浏览器工具。这 4 类需求都超出本地、需要外部连接。MCP 解决如何连接外部世界MCP(Model Context Protocol是 Anthropic 在 2024-11 推出的开放标准、目标是让 AI Agent 像 USB-C 一样、即插即用地连接任何外部工具。MCP 的工作方式开发者把外部工具打包成 MCP server一个进程,MCP client(Claude Code 内置通过 JSON-RPC 2.0 协议和 server 通信、把 server 暴露的工具注入到 Claude 的工具列表、Claude 就能像调 Bash 一样调这些外部工具。类比MCP 之于 AI Agent ≈ USB-C 之于硬件。一个 USB-C 接口、接显示器 / 硬盘 / 充电器、协议统一。一个 MCP 协议、接 GitHub / Notion / 数据库、API 统一。MCP 是开放标准MCP 不绑定 Claude Code。OpenAI Codex / Cursor / GitHub Copilot / Windsurf 等主流 AI Agent 工具都已支持 MCP 协议2025-02 之后。这意味着你写一个 MCP server、可以在 5 个 AI Agent 工具里通用。这是 MCP 与 Skills / SubAgent / Hooks 最大的不同Skills / SubAgent / Hooks 都是 Claude Code 专有机制、MCP 是行业标准协议。MCP 工具调用模式3 步调用流程tool discovery工具发现——Claude 启动时、mcp client 拉所有 MCP server 的工具清单、合并到 Claude 工具列表。Claude 看到mcp\_\_github\_\_create\_issue等工具、知道可以用。tool call工具调用——Claude 推理决定调mcp\_\_github\_\_create\_issue,mcp client 通过 JSON-RPC 2.0 协议调用对应的 MCP server。structured output结构化输出——MCP server 调 GitHub API、把结果JSON返回给 mcp client,mcp client 解析后返回给 Claude。3 步形成工具全生命周期——从发现到调用到结果、标准化。3 种传输方式 stdio / HTTP / SSE 怎么选MCP 协议层都是 JSON-RPC 2.0标准 RPC 协议、只是传输层有 3 种实现。方式 1stdio本地进程stdio standard input / output。MCP server 是一个本地进程、Claude Code 启动它、通过 stdin / stdout 收发 JSON-RPC 消息。配置command: npx -y modelcontextprotocol/server-github——直接启动本地命令。适用场景本地 MCP server如 filesystem MCP / GitHub MCP 通过 npx 启动的本地包。优势最快无网络开销/ 最简单无需 HTTP server)/ 最安全进程隔离。劣势只能本地、不能跨机器。方式 2HTTP远程 HTTP 调用HTTP 标准的 HTTP 请求-响应。MCP server 跑在远程或本地 HTTP server),Claude Code 用 HTTP POST 发 JSON-RPC 消息。配置url: https://mcp.example.com/apitype: http——指向远程 MCP server URL。适用场景远程 SaaS 服务如 Anthropic 官方托管的 MCP / 第三方托管的 Notion MCP。优势跨机器 / 集中部署 / 多 client 共享一个 server。劣势有网络延迟 / 需要 HTTPS / 需要鉴权。方式 3SSE(Server-Sent Events、流式长连接SSE 服务端推送。MCP server 主动推送消息给 client,client 保持长连接。配置url: https://mcp.example.com/ssetype: sse。适用场景长连接 / 实时推送如数据库变更通知 / 实时文档同步。优势实时服务端主动推送/ 适合长任务。劣势实现复杂 / 防火墙可能拦截 / 资源占用。3 种方式的选择原则• 本地 server、追求性能 → stdio。• 远程 SaaS、需要跨机器 → HTTP。• 需要服务端推送、实时场景 → SSE。具体配置见后面 3 种传输方式对比代码代码块。维度stdioHTTPSSE传输层stdin/stdoutHTTP POSTHTTP 长连接适用场景本地 MCP server远程 SaaS流式长连接性能~5-10ms最快~50-200ms~50-200ms 首字节配置command argsurl typehttpurl typesse调试echo 测试简单Postman / curl浏览器 DevTools安全性进程隔离最安全需要 HTTPS 鉴权需要 HTTPS 鉴权5 个实战 MCP 服务器配置5 个常见 MCP server 覆盖了连接外部世界的 4 类典型需求代码托管GitHub)/ 文档Notion)/ 文件扩展Filesystem)/ 数据Database)/ 浏览器Puppeteer。Server 1GitHub MCP管理 issue / PR / repo)用途让 Claude 直接操作 GitHub——创建 issue / 提 PR / 读 repo / 触发 workflow。配置github: {command: npx -y modelcontextprotocol/server-github, env: {GITHUB_TOKEN: ghp_...}}——stdio 模式启动、通过 env 传 GitHub token。Server 2Notion MCP读写 Notion 页面用途让 Claude 读写 Notion 数据库 / 页面——查询任务清单 / 写会议纪要 / 更新文档。配置notion: {command: npx -y modelcontextprotocol/server-notion, env: {NOTION_API_KEY: secret_...}}。Server 3Filesystem MCP扩展文件访问到任意路径用途让 Claude 访问工作目录外的文件如 ~/.claude/ 全局配置 / 共享盘 / 其他项目的文件。配置filesystem: {command: npx -y modelcontextprotocol/server-filesystem, args: [/path/to/allowed/dir]}——args 限定可访问路径安全。Server 4Database MCP(SQLite / PostgreSQL)用途让 Claude 查数据库——查用户数据 / 跑 SQL / 导出报表。配置以 SQLite 为例:sqlite: {command: uvx mcp-server-sqlite, args: [--db-path, /path/to/db.sqlite]}。Server 5Puppeteer MCP浏览器自动化用途让 Claude 操作浏览器——抓网页内容 / 填表单 / 点按钮 / 截图。配置puppeteer: {command: npx -y modelcontextprotocol/server-puppeteer}。5 个 server 一起配、就形成了 Claude Code 的瑞士军刀——任何外部世界都能连接。完整配置见后面 .mcp.json 完整配置代码块。.mcp.json 配置文件结构所有 MCP server 都配置在 .mcp.json项目根目录或 ~/.claude/.mcp.json全局。完整结构{ mcpServers: { github: {...}, notion: {...}, filesystem: {...}, sqlite: {...}, puppeteer: {...} } }每个 server 配置项的字段•name键名、如 github)——MCP server 名字、工具名前缀是mcp\_\_name\_\_tool。•command(stdio 模式——启动 server 的本地命令。•args(stdio 模式——传给 command 的参数。•url(HTTP / SSE 模式——远程 MCP server URL。•type——http或sse默认 stdio、不用写。•env——传给 server 的环境变量API token 等。加载机制Claude Code 启动时读 .mcp.json项目级。读 ~/.claude/.mcp.json全局级。合并两份配置项目级优先。启动所有 stdio 模式的 server子进程。连接所有 HTTP / SSE 模式的 server。拉所有 server 的工具清单、合并到 Claude 工具列表。Claude 看到mcp\_\_github\_\_create\_issue等工具、就能调用。如何自己写一个自定义 MCP 服务器MCP server 是个普通进程、可以用任何语言写。官方 SDK 支持 Python / TypeScript / Go / Rust、本节用 Python SDK 演示。step 1装 SDKpip install mcpstep 2写最小 MCP server(2 个 toolhello / echo)完整代码见后面 自定义 MCP 服务器完整实现代码块。step 3配置到 .mcp.json{ mcpServers: { my-server: { command: python, args: [/path/to/my_server.py] } } }step 4Claude Code 启动时、自动加载 my-serverClaude 看到工具mcp\_\_my\_server\_\_hello和mcp\_\_my\_server\_\_echo、能直接调。step 5调试用 mcp-inspector 调试 MCP servernpx -y modelcontextprotocol/inspector python /path/to/my_server.py打开浏览器 http://localhost:5173、看 server 暴露的工具列表 / 调工具 / 看 JSON-RPC 消息。mcp-inspector 是 MCP server 的 Postman——必备调试工具。MCP vs Skills vs Hooks vs SubAgent 边界前 14 讲我们学了 3 种扩展机制Skills能力/ SubAgent角色/ Hooks门卫。本讲加了第 4 种 MCP桥梁。4 者的工程定位不同、不能互相替代。4 者的工程定位•MCP桥梁——连接外部世界、标准化协议、跨 AI Agent 工具通用。负责调用外部 API。•Skills说明书——LLM 推理该用就用、渐进披露、Markdown 描述。负责描述本地能力。•Hooks门卫——事件驱动、硬约束、瞬间拦截。负责瞬间检查。•SubAgent角色——独立上下文、name 显式调。负责复杂任务隔离执行。4 者的工作层次不同MCP 在工具层连接外部 API),Skill 在能力层(LLM 推理,HW 在事件层瞬时检查,SubAgent 在角色层独立上下文。4 者的协同典型协同Claude 用 GitHub MCP(mcp\_\_github\_\_create\_issue) Stop Hook检查是否 commit) 文档 Skill自动写 changelog。3 者各司其职、形成完整工作流。典型反协同不要用 MCP 替代 Skill。MCP 是调外部 API、不能做复杂任务。比如代码审查用 code-reviewer SubAgent第 6 讲、不用 GitHub MCP只能调 API、不能推理。4 者的边界判断这件事是调外部 API吗?是 → MCP。这件事是LLM 推理该用就用吗?是 → Skill。这件事是瞬间检查吗?是 → HW。这件事需要独立上下文吗?是 → SubAgent。维度MCPSkillsHooksSubAgent扩展方式连接外部 API本地能力描述事件驱动拦截独立上下文触发LLM 推理LLM 推理description 匹配工具执行前后 / Stopname 显式调边界工具层能力层事件层角色层配置位置.mcp.json.claude/skills/*/SKILL.md.claude/settings.json hooks.claude/agents/*.md典型用途调 GitHub / Notion / DB API自动发现的本地能力危险拦截 / 自动格式化复杂任务隔离调试mcp-inspector看 SKILL.md description看 stderr 输出看 subagent 报告️ 实战代码 第 19 讲配套.mcp.json 完整配置5 个 MCP servergithub / notion / filesystem / database / puppeteer)// .mcp.json(项目根目录) { mcpServers: { github: { command: npx, args: [-y, modelcontextprotocol/server-github], env: { GITHUB_TOKEN: ghp_your_token_here } }, notion: { command: npx, args: [-y, modelcontextprotocol/server-notion], env: { NOTION_API_KEY: secret_your_key_here } }, filesystem: { command: npx, args: [-y, modelcontextprotocol/server-filesystem, /Users/me/projects] }, sqlite: { command: uvx, args: [mcp-server-sqlite, --db-path, /Users/me/data/app.sqlite] }, puppeteer: { command: npx, args: [-y, modelcontextprotocol/server-puppeteer] } } } // 配置说明: // - github / notion:stdio 模式 env 传 API token // - filesystem:stdio 模式 args 限定可访问路径(安全) // - sqlite:stdio 模式 args 传数据库路径 // - puppeteer:stdio 模式,无额外配置 // 加载后 Claude 看到的工具: // - mcp__github__create_issue / list_issues / create_pull_request / ... // - mcp__notion__create_page / query_database / ... // - mcp__filesystem__read_file / write_file / list_directory // - mcp__sqlite__query / list_tables / describe_table // - mcp__puppeteer__navigate / click / screenshot / ... 第 19 讲配套3 种传输方式对比代码stdio / HTTP / SSE 各自的配置 调用示例// .mcp.json(3 种传输方式对比) { mcpServers: { // 方式 1:stdio(本地进程) github-local: { command: npx, args: [-y, modelcontextprotocol/server-github], env: {GITHUB_TOKEN: ghp_...} }, // 方式 2:HTTP(远程 SaaS) github-remote: { url: https://mcp.example-github.com/api, type: http, headers: { Authorization: Bearer ghp_... } }, // 方式 3:SSE(流式长连接) github-sse: { url: https://mcp.example-github.com/sse, type: sse, headers: { Authorization: Bearer ghp_... } } } } // 3 种方式选择: // stdio: 本地 server, 最快, 适合本地进程 // HTTP: 远程 SaaS, 跨机器, 适合集中部署 // SSE: 流式推送, 实时场景, 适合长任务 // 性能对比(同网络条件下): // stdio: ~5-10ms(本地进程间通信) // HTTP: ~50-200ms(网络 RTT) // SSE: ~50-200ms 首字节,后续流式 第 19 讲配套自定义 MCP 服务器完整实现Python SDK 写最小 MCP server,2 个 tool)#!/usr/bin/env python3 # my_server.py # 最小 MCP server(2 个 tool:hello / echo) import asyncio from mcp.server import Server from mcp.types import Tool, TextContent from mcp.server.stdio import stdio_server # 创建 server 实例 app Server(my-server) # 注册工具列表 app.list_tools() async def list_tools() - list[Tool]: return [ Tool( namehello, descriptionSay hello to a name. Use this when the user wants a greeting., inputSchema{ type: object, properties: { name: {type: string, description: The name to greet} }, required: [name] } ), Tool( nameecho, descriptionEcho back a message. Use this when the user wants to repeat a message., inputSchema{ type: object, properties: { message: {type: string, description: The message to echo} }, required: [message] } ) ] # 实现工具逻辑 app.call_tool() async def call_tool(name: str, arguments: dict) - list[TextContent]: if name hello: greeting fHello, {arguments[name]}! return [TextContent(typetext, textgreeting)] elif name echo: return [TextContent(typetext, textarguments[message])] else: raise ValueError(fUnknown tool: {name}) # 启动 server(stdio 模式) async def main(): async with stdio_server() as (read_stream, write_stream): await app.run( read_stream, write_stream, app.create_initialization_options() ) if __name__ __main__: asyncio.run(main() # 配置到 .mcp.json # { # mcpServers: { # my-server: { # command: python, # args: [/path/to/my_server.py] # } # } # } # # Claude 看到的工具 # mcp__my_server__hello(name: str) - Hello, {name}! # mcp__my_server__echo(message: str) - {message} # # 调试 # npx -y modelcontextprotocol/inspector python /path/to/my_server.py # 打开 http://localhost:5173,看工具列表 / 调工具 / 看 JSON-RPC 消息 第 19 讲配套MCP 工具调用的 5 个调试技巧mcp-inspector / stdio echo / 日志 / 重启 / token 检查#!/usr/bin/env bash # MCP 工具调用的 5 个调试技巧 set -e # 技巧 1:mcp-inspector(图形化调试工具) # 启动 inspector 你的 MCP server npx -y modelcontextprotocol/inspector python /path/to/my_server.py # 打开 http://localhost:5173 # 能看到:工具列表 / 工具参数 / 调工具 / 看 JSON-RPC 消息 # 技巧 2:stdio 模式手动 echo(验证 server 能正常启动) # stdio 模式下 Claude Code 通过 stdin/stdout 通信,手动发 JSON-RPC 请求: echo {jsonrpc:2.0,method:tools/list,id:1} | python /path/to/my_server.py # 应该看到 JSON 响应,包含工具列表 # 技巧 3:日志到 stderr(避免污染 stdout) # stdio 模式下 stdout 是 JSON-RPC 消息通道,日志必须打 stderr # 错误示例(污染 stdout): # print(loading config...) # ❌ 错,污染 JSON-RPC 通道 # 正确示例: import sys print(loading config..., filesys.stderr) # ✅ 对,日志走 stderr # 技巧 4:重启 MCP server # Claude Code 启动时加载 .mcp.json,改 .mcp.json 后要重启 Claude Code 才生效 # 重启方法:退出 Claude Code → 重新进入 # 技巧 5:token 检查(API 鉴权失败是常见原因) # GitHub MCP 启动失败?检查 GITHUB_TOKEN 是否有效 # Notion MCP 启动失败?检查 NOTION_API_KEY 是否有效 # 验证方法:用 curl 直接调 API,看是否 401 curl -H Authorization: token ghp_xxx https://api.github.com/user # 401 token 无效,重新生成;200 token 有效⚠️ 常见坑⚠️ MCP server 启动失败API token 错 / 路径错 / 端口占用、先单独跑 server 验证MCP 启动失败排查Claude Code 启动时、MCP server 加载失败看不到工具、常见原因API token 错env 字段填错或 token 过期/ 路径错command 路径不对或 args 路径不存在/ 端口占用HTTP 模式端口被占。修正先单独跑 server 验证——npx -y modelcontextprotocol/server-github(stdio 模式看是否能启动或者 mcp-inspector 启动 server、看是否报错。判断标准MCP 加载失败、你先单独跑过 server 吗?没有、先单独跑。⚠️ stdio 模式下输出日志污染(server 把日志打到 stdout 干扰 JSON-RPC、必须打 stderr)日志污染 stdout陷阱stdio 模式下 stdout 是 JSON-RPC 消息通道、如果 server 用print(loading config...)打日志、日志会污染 stdout,Claude 收到无法解析的输出报错。修正MCP server 所有日志必须打 stderr——Python 用print(..., filesys.stderr),Node.js 用console.error()。判断标准你的 MCP server 有任何print(/console.log(吗?有、改成 stderr。⚠️ MCP 工具名拼错配置 mcp__github__create_issue 调成 mcp__git__create_issue,LLM 报tool not found)工具名前缀拼错陷阱MCP 工具名格式mcp__server-name__tool-name、双下划线分隔。如果 Claude 调成mcp__git__create_issue少写 hub)、报tool not found。修正工具名以 .mcp.json 配置的 server name 为准github→ 工具前缀mcp__github__。判断标准LLM 报 tool not found 时、先看 .mcp.json 里的 server name 是什么、工具名前缀必须严格匹配。⚠️ 远程 MCP server 网络超时用 HTTP / SSE 模式必须设置 timeout、避免阻塞 Claude)HTTP/SSE 网络超时陷阱远程 MCP server网络延迟 / 临时不可用调用超时、Claude 阻塞在工具调用上、用户体验差。修正HTTP / SSE 模式配 timeout——mcp client 默认 timeout 30 秒、可以缩短到 10 秒超时报错给 Claude 让它重试或换方案还可以用 mcp client 的 retry 配置失败重试 2 次。判断标准你的远程 MCP server 有 timeout 配置吗?没有、补 timeout。 一句话备忘MCP 是 Claude Code 连接外部世界的 USB-C——3 种传输方式stdio 本地 / HTTP 远程 / SSE 流式 5 个实战 server(GitHub / Notion / Filesystem / Database / Puppeteer) 自定义 MCP server(Python SDK)、让 Claude 跨越本地文件边界、连接 GitHub / 数据库 / 浏览器 / 任何 API。