Skip to content

第 15 章 MCP 服务器:让 Claude 直连外部工具与数据源

第 14 章的 Hooks 解决"在什么时机自动做什么",本章解决"Claude 手里没有这把工具怎么办"。MCP 是 Claude Code 能力扩展的主通道:数据库、GitHub、文件系统、浏览器、搜索引擎,凡是你能写成服务器的工具,都能挂进 Claude 的工具箱。第 16 章的 Skills 给的是工作流指令,而 MCP 给的是真实可调用的工具——两者分工不同,后面会对照讲。

15.1 结论:MCP 是给 Claude Code 接外部工具的标准协议

MCP(Model Context Protocol)是 Anthropic 于 2024-11 发布的开放标准,作用一句话:让 Claude 直连数据库/GitHub/文件系统,不用你手动中转

没有 MCP 时,你想让 Claude 查 PostgreSQL,得自己跑 psql -c "\d orders"、复制结果、粘贴回对话;查 GitHub Issues 得 gh issue list、再贴回去。这条"人肉中转"链路有两个问题:一是信息密度被你的复制粒度截断,Claude 看不到原始结构;二是注意力被低价值操作占用,你成了管道工。

MCP 把这条链路压成一步:Claude 直接调用 mcp__postgres__describe_table("orders"),拿到原始 schema,再决定下一步。你的角色从"管道工"回到"架构师与审查者"——这与第 06 章的核心心法完全一致。

15.2 MCP 是什么:协议定位与与直接 Bash 的区别

MCP 不是 Anthropic 私有 API,而是一份开放协议,任何 server 实现都可被任何 MCP 客户端(Claude Code、Claude Desktop、VS Code、Zed 等)消费。它的定位介于两层之间:

  • 下层:外部系统——PostgreSQL、GitHub API、本地文件系统、Selenium 浏览器、Jira、Notion
  • 上层:Claude 的工具调用——Claude 决定调用哪个工具、传什么参数,MCP 负责把调用路由到下层系统并把结果结构化返回

你可能会问:Claude Code 已经能跑 Bash,psql gh curl 都能直接用,为什么还要 MCP?这正是新人最常踩的认知坑。两者区别如下:

维度直接 BashMCP 服务器
结构化Claude 生成命令字符串,输出是自由文本需要解析工具有显式 schema(参数名、类型、描述),输出结构化
权限隔离Bash 权限是"允许跑这条命令",粒度粗,且一旦放开 psql 就等于放开整个数据库MCP 权限按工具粒度,query 只读、execute 才写,且 server 内部可做 ACL
可复用每个项目重写一遍 psql -h ... -U ... 命令模板一次配置,全团队 clone .mcp.json 即用
跨客户端Bash 命令绑死在 Claude Code 里同一个 MCP server 可被 Claude Desktop、VS Code、Zed 共用
错误处理命令失败靠 Claude 读 stderr 猜server 返回结构化 error code,Claude 能精确决策
凭据管理密码散落在命令历史、env 导出、shell 脚本凭据集中在 .mcp.jsonenv 或 OAuth,不进 shell 历史

一句话:Bash 是"Claude 替你敲命令",MCP 是"给 Claude 一把正经工具"。能写成 MCP 的重复性工具调用,就不该让 Claude 每次重新生成命令字符串。

15.3 四种传输方式对比

MCP server 与客户端之间有四种传输方式,选择取决于 server 跑在哪、是否需要双向通信、是否需要长连接:

传输通道方向适合位置典型场景选用优先级
stdio双向(标准输入/输出)本地子进程文件系统、本地数据库、浏览器自动化本地工具首选
http请求-响应 + 流式升级远程服务托管 server、企业内部 API远程首选(2025 起官方推荐 streamable HTTP)
sse服务端单向推送 + HTTP 上行远程服务(旧)早期远程 server、老版本兼容新部署不再用,仅兼容遗留
ws全双工 WebSocket远程服务、低延迟实时双向、订阅推送需要服务端主动推送时才用

15.3.1 stdio:本地工具的默认选择

stdio 传输下,Claude Code 把 server 当子进程启动,通过标准输入输出收发 JSON-RPC 消息。@modelcontextprotocol/server-postgres@playwright/mcp 都走这条路。

好处:无需开端口,凭据留在本机进程环境,延迟最低。坏处:每个 Claude Code 会话都会起一个子进程,多会话并发要留意资源占用。

15.3.2 http:远程工具的主流选择

http 传输下,Claude Code 通过 HTTP 请求与远程 server 通信,2025 年起 MCP 规范推荐 streamable HTTP(单端点支持 POST 上行 + SSE 流式下行),取代旧的 HTTP+SSE 双端点模式。托管服务(Sentry、Linear、Notion、GitHub Copilot MCP)普遍走这条路。

15.3.3 sse 与 ws:仅在有明确需求时用

sse(Server-Sent Events)是 MCP 早期规范定义的远程传输,用 GET 建立 SSE 流接收服务端推送、POST 上行客户端请求。新部署建议直接用 streamable HTTP,sse 仅在对接遗留 server 时出现。

ws(WebSocket)提供全双工通道,只有在 server 需要主动向 Claude 推送消息(如实时监控告警、长任务进度)时才有意义。绝大多数工具用不上。

决策树:本地工具 → stdio;远程工具 → http;遗留系统 → sse;需要服务端推送 → ws。九成场景落在 stdio 和 http 两种上。

15.4 配置:.mcp.json 与工具命名规则

MCP server 有三种安装范围(官方称 scope),与第 05 章权限层级同理:

Scope配置文件可见范围
local(默认)~/.claude.json 中本项目条目下仅你、仅本项目
project项目根 .mcp.json所有 clone 该仓库的人
user~/.claude.json 顶层 mcpServers仅你、所有项目

团队共享走 project,把 .mcp.json 提交进 Git。claude mcp add 命令会按 --scope 参数写入对应文件,也可以直接手写 .mcp.json

15.4.1 完整 .mcp.json 示例

下面这份 .mcp.json 同时配置了 PostgreSQL(stdio + 连接串作参数)与 GitHub(stdio + env 凭据),覆盖两种最常见的配置形态:

json
{
  "mcpServers": {
    "postgres": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-postgres",
        "postgresql://readonly_user:pass@localhost:5432/shop"
      ]
    },
    "github": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_xxxxxxxxxxxx"
      }
    }
  }
}

字段含义:

  • type —— 传输方式,取值 stdio / http / sse / ws
  • command args —— stdio 专用,Claude Code 启动子进程的命令与参数
  • url —— http/sse/ws 专用,远程端点
  • headers —— http/sse/ws 专用,自定义头(如 Authorization: Bearer <token>)
  • env —— stdio 专用,注入子进程的环境变量

等效 CLI 命令(任选其一):

bash
# 用 CLI 写入 project scope
claude mcp add --scope project --transport stdio postgres -- \
  npx -y @modelcontextprotocol/server-postgres \
  "postgresql://readonly_user:pass@localhost:5432/shop"

claude mcp add --scope project --transport stdio github -- \
  npx -y @modelcontextprotocol/server-github \
  -e GITHUB_PERSONAL_ACCESS_TOKEN=ghp_xxxxxxxxxxxx

15.4.2 工具命名规则:mcp__<server>__<tool>

Claude Code 内部把 MCP 工具按固定格式命名:

text
mcp__<server-name>__<tool-name>

例如配置了名为 postgres 的 server,它暴露的 query 工具,完整名是 mcp__postgres__query。在权限规则、Hook 匹配、调试日志里看到的都是这个全名。配置 server 时起的名字会直接进入工具命名空间,因此:

  • 不要用冲突名字——两个 server 都叫 github 会互相覆盖,后加载的赢
  • 不要与内置工具重名——mcp__bash__run 这种命名虽然技术上可行,但会让权限规则混乱
  • 用语义化短名——postgres github filesystem 即可,不需要 mcp-postgres-prod

15.5 常用 MCP 服务器速查

下表是经过社区验证、可直接 npx 启动的常用 server,核对日期 2026-07-08:

Server 名功能关键配置适用场景
@modelcontextprotocol/server-postgres查询 PostgreSQL(只读 query、schema 描述)连接串作 args让 Claude 探索数据库结构、生成报表 SQL
@modelcontextprotocol/server-githubIssues / PR / 仓库文件读写GITHUB_PERSONAL_ACCESS_TOKEN env让 Claude 读 Issue、改 PR 描述、查 CI 日志
@modelcontextprotocol/server-filesystem受限目录的文件读写允许目录列表作 args给 Claude 沙箱化文件访问,比 Bash 更可控
@modelcontextprotocol/server-brave-searchBrave 搜索引擎BRAVE_API_KEY env联网检索,比 WebSearch 配额独立
@playwright/mcp浏览器自动化(导航、点击、截图)command: npx,无需 tokenE2E 测试、抓取动态页面、视觉验证
@modelcontextprotocol/server-puppetPuppeteer 浏览器类似 Playwright老项目兼容
@modelcontextprotocol/server-fetch抓取 URL 并转 Markdown无需凭据替代 WebFetch,输出更可控
@modelcontextprotocol/server-memory知识图谱式持久记忆本地 JSON 文件跨会话长记忆,补 CLAUDE.md 不足
@modelcontextprotocol/server-sequential-thinking结构化分步推理无需凭据复杂问题拆解,效果见仁见智

完整目录见 Anthropic MCP DirectoryMCP Servers 仓库

配置完成后,Claude Code 在会话启动时自动发现已连接 server 暴露的工具,无需手动声明。Claude 会根据任务自主决定何时调用——你只需要用自然语言描述目标。

15.6 实战:配置 postgres MCP 后用自然语言查表

目标:让 Claude 直连本地 PostgreSQL shop 库,用自然语言查看 orders 表结构。

15.6.1 步骤一:写配置并验证连接

在项目根创建 .mcp.json(内容见 15.4.1 的 postgres 部分),然后启动新会话。首次看到 project-scope server,Claude Code 会弹出批准提示——这是防止克隆恶意仓库时自动启动子进程的安全机制,必须人工确认。

bash
# 列出已配置 server(在 shell 中)
claude mcp list

预期输出:

text
postgres: connected (stdio) — tools: query, list_tables, describe_table

会话内用内置命令 /mcp 查看实时状态(/mcp 是真正内置命令,见第 06 章命令真实性总表):

text
/mcp

预期输出:

text
MCP Servers:
  ● postgres (stdio) — connected
    tools: query, list_tables, describe_table

验证标准:状态显示 connected 且列出工具名。若显示 faileddisconnected,跳到 15.9 失败边界。

15.6.2 步骤二:自然语言提问

在会话里直接说:

text
查看 orders 表结构,并告诉我有哪些外键关联

Claude 的实际执行路径(你能在工具调用日志里看到):

text
→ mcp__postgres__describe_table(table="orders")
← { columns: [
     {name:"id",type:"integer",nullable:false},
     {name:"user_id",type:"integer",nullable:false},
     {name:"amount",type:"numeric(10,2)",nullable:false},
     {name:"created_at",type:"timestamp",default:"now()"}
   ],
   foreign_keys: [
     {column:"user_id",references:"users(id)"}
   ]
 }

Claude 拿到结构化结果后,用自然语言回答你:

text
orders 表有 4 列:id(主键)、user_id(外键 → users.id)、amount(金额,精度 10/2)、
created_at(默认当前时间)。外键只有一个:user_id 关联 users 表的 id。

15.6.3 验证与失败边界

验证:回答中列出的列名、类型、外键,与 psql -d shop -c "\d orders" 输出一致。你可以让 Claude 顺手跑 mcp__postgres__query("SELECT COUNT(*) FROM orders") 交叉验证连通性。

失败边界(逐项排查):

症状根因处理
ECONNREFUSED 127.0.0.1:5432Postgres 没启动或端口不对pg_isready 检查服务,核对连接串端口
password authentication failed for user "readonly_user"连接串里用户名/密码错psql 手工连一次验证凭据,再回填 .mcp.json
permission denied for table orders数据库用户没有该表权限GRANT SELECT ON orders TO readonly_user;,MCP 用户建议只读
npx: command not found本机没装 Node.js 18+装 Node LTS,npx 随附
/mcp 显示 failed 但无详细错误子进程启动即崩溃claude mcp get postgres 看配置;手动跑 npx -y @modelcontextprotocol/server-postgres "连接串" 看报错
工具能列出来但调用超时防火墙、SSL 证书、DB 连接池耗尽查 Postgres 日志 pg_stat_activity,看连接数

安全提醒:连接串里的密码会明文写进 .mcp.json。如果用 project scope 提交 Git,等于把数据库密码推到仓库。15.9 会专门讲这条红线。

15.7 自建 MCP:何时该自建,骨架长什么样

当现有 server 目录满足不了需求,且这个工具会被反复使用(团队内、跨项目),就该考虑自建 MCP server。典型信号:

  • 同一套内部 API,你每周都要让 Claude 查几次(如公司内部的工单系统、监控平台)
  • 某个 Bash 操作复杂到每次都要写 20 行脚本,且参数化后能复用
  • 需要给 Claude 一个比 Bash 更细粒度的权限边界(只读某几个接口)

自建最小 MCP server 的概念骨架(Python,完整实现见第 21 章 MCP SDK):

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

server = Server("my-internal-api")

@server.list_tools()
async def list_tools():
    return [Tool(
        name="search_tickets",
        description="搜索内部工单系统",
        inputSchema={
            "type": "object",
            "properties": {
                "keyword": {"type": "string"}
            },
            "required": ["keyword"]
        }
    )]

@server.call_tool()
async def call_tool(name, arguments):
    if name == "search_tickets":
        # 调用内部 API,返回结构化结果
        results = await fetch_internal_tickets(arguments["keyword"])
        return [TextContent(type="text", text=json.dumps(results))]

if __name__ == "__main__":
    import asyncio
    from mcp.server.stdio import stdio_server
    asyncio.run(stdio_server(server))

关键纪律:

  • 工具要小而专——一个 server 暴露 3-5 个工具,不要堆 50 个,Claude 在工具列表过长时选择准确率下降
  • description 是最重要字段——Claude 靠它判断何时调用,写清楚"做什么、不做什么、参数含义"
  • inputSchema 要严格——必填字段、类型、枚举值都写全,Claude 会按 schema 生成参数
  • 只读与写操作分 server——my-api-readonlymy-api-write 分开,权限规则好写

完整 SDK 详解、TypeScript/Python 双语言实现、测试与发布流程,在第 21 章展开。

15.8 MCP vs Skills vs Hooks:三者分工

这是全书最容易混淆的三件事。初学者常问:"我想让 Claude 自动查数据库,该用 MCP 还是 Skill 还是 Hook?"三者解决的是不同层面的问题:

维度MCP 服务器Skills(第 16 章)Hooks(第 14 章)
本质工具协议,给 Claude 新工具能力包,给 Claude 工作流指令事件钩子,在动作前后自动触发
解决的问题Claude 手里没这把工具Claude 不知道按什么流程做想在某时机自动执行,不等 Claude 决定
触发方Claude 自主决定调用用户输入 /skill-name 或 Claude 主动用系统事件(PreToolUse、PostToolUse 等)自动触发
配置位置.mcp.json~/.claude.json~/.claude/skills/ 或项目 .claude/skills/settings.jsonhooks 字段
执行体外部 server 进程Prompt + 脚本Shell 命令或脚本
典型例子mcp__postgres__query/deep-research /code-review提交前自动跑 npm test
能力边界能调用任何外部系统能编排多步任务,可调用 MCP 工具不进入 Claude 推理,纯外部自动化

决策树:

  • Claude 缺工具(查 DB、调 API、操作浏览器)→ MCP
  • Claude 有工具但不知道流程怎么做(代码审查流程、研究流程)→ Skill
  • 想在某个时机强制执行,不让 Claude 决定(提交前必跑测试)→ Hook

三者经常组合用:Hook 在 PostToolUse 触发 /code-review Skill,Skill 内部调用 mcp__github__create_issue 工具。这是 Claude Code 扩展能力的完整三层栈。

15.9 失败边界:三个最常踩的坑

15.9.1 MCP 服务器崩溃:子进程退出与远程超时

stdio server 崩溃:Claude Code 启动子进程后,若 server 因配置错误、依赖缺失、未捕获异常退出,/mcp 会显示 faileddisconnected。排查步骤:

bash
# 1. 看 Claude Code 的 MCP 日志
cat ~/.claude/logs/mcp-server-postgres.log

# 2. 手动跑 server,直接看 stderr
npx -y @modelcontextprotocol/server-postgres \
  "postgresql://readonly_user:pass@localhost:5432/shop" 2>&1

# 3. 验证 npx 能拉到包
npx -y @modelcontextprotocol/server-postgres --version

http/sse/ws server 超时:远程 server 不在你控制下,常见症状是工具调用挂起 30 秒后超时。排查:

  • curl -v <url> 验证端点可达
  • 检查 headers 里 token 是否过期(OAuth token 一般 1 小时失效,需重新 /mcp 认证)
  • 公司网络代理是否拦截了出站 HTTPS

缓解策略:在 settings.json 配置 MCP 超时与重试(详见第 99 附录),关键任务不要单点依赖远程 server。

15.9.2 工具命名冲突:同名 server 互相覆盖

.mcp.json 里两个 server 同名,JSON 解析阶段就会被后写的覆盖,且无警告。更隐蔽的是:项目 .mcp.json 定义了 github,用户 ~/.claude.json 也定义了 github,两个 scope 同时存在时优先级是 project > user > local(project 覆盖 user 覆盖 local),你以为在用公司的 GitHub server,实际跑的是个人的。

排查命令:

bash
claude mcp get github
# 输出会显示该 server 当前生效在哪个 scope

纪律:server 名带环境后缀,如 github-prod github-personal,物理隔离不同凭据。绝不用 github 这种裸名。

15.9.3 敏感凭据写进 .mcp.json 提交 Git(红线)

这是最严重的一条,触碰第 05 章的红线边界。.mcp.jsonenv 字段的 token、连接串里的密码,一旦 git commit 推到远程仓库,等同于公开泄露。即使仓库是 private,也会被 GitHub 的 secret scanning 扫到并通知管理员,且 Git 历史里永久留存。

正确做法(三选一):

方案一:凭据走 user scope,不进仓库

bash
# 个人凭据写到 user scope,不进 .mcp.json
claude mcp add --scope user --transport stdio github -- \
  npx -y @modelcontextprotocol/server-github \
  -e GITHUB_PERSONAL_ACCESS_TOKEN=ghp_xxx

# 项目 .mcp.json 只写不含凭据的 server,或用占位符

方案二:.mcp.json 用环境变量引用,配 .env

部分 server 支持从进程环境读凭据(不写进 env 字段),此时 .mcp.json 只声明 server,凭据由 shell 或 .env 注入,.env 加入 .gitignore:

json
{
  "mcpServers": {
    "github": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"]
    }
  }
}
bash
# .env(加入 .gitignore)
GITHUB_PERSONAL_ACCESS_TOKEN=ghp_xxx

方案三:OAuth 托管 server,凭据不落地

Sentry、Linear、Notion 等支持 OAuth 的托管 server,token 由 Claude Code 本地管理,不进 .mcp.json。配置时只写 url,首次用 /mcp 走浏览器授权。

已泄露的补救:立即在对应平台 revoke token(GitHub Settings → Developer settings → Personal access tokens → Revoke),轮换密码,然后用 git filter-repo 清理历史(破坏性操作,需团队协调,属第 05 章红线,执行前必须二次确认)。

15.10 小结

MCP 把 Claude Code 从"能跑 Bash 的聊天机器人"升级成"能直连外部系统的 Agent"。四个要点记住即可:

  1. 传输选型:本地 stdio,远程 http,其余两种只在特殊场景用
  2. 配置位置:团队共享走 .mcp.json(project scope),个人凭据走 user scope
  3. 工具命名:mcp__<server>__<tool>,起名别冲突
  4. 三者分工:MCP 给工具,Skill 给流程,Hook 给时机

下一章我们讲 Skills——把一套工作流指令封装成 /skill-name 可调用的能力包,与本章 MCP 工具组合使用,是 Claude Code 扩展能力的完整形态。


下一章:Skills 与自定义命令