第 20 章 · MCP 客户端集成实战
本章目标:把写好的 MCP Server 接入真实客户端——掌握 Claude Desktop 的 mcpServers 配置、Claude Code 的
mcp add命令、stdio 与远程服务器的配置差异,并能用 Python 写出程序化调用的客户端。
14.1 在 Claude Desktop 中配置本地服务器
Claude Desktop 通过一个 JSON 配置文件管理 MCP 服务器。打开 claude_desktop_config.json(菜单 File → Settings → Developer → Edit Config),添加 mcpServers 字段:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/yourname/Documents",
"/Users/yourname/Desktop"
]
}
}
}逐个字段解读:
| 字段 | 含义 | 注意点 |
|---|---|---|
键名 filesystem | 你给这个服务器起的显示名 | 会出现在工具名前缀里 |
command | 启动服务器的可执行程序 | npx、python、uv 或编译好的二进制 |
args | 命令行参数数组 | 上例限定了只允许访问两个目录 |
env | 注入子进程的环境变量 | 放 API Key 等密钥(见 14.3) |
保存后完全退出并重启 Claude Desktop(不是关窗口)。配置正确的话,输入框右下角会出现工具图标,点开能列出该服务器暴露的所有工具。
最小权限
上例中 args 里列出的目录就是 filesystem server 的全部可见范围。永远不要配置成整个用户根目录或 /——这是 MCP 安全的第一道闸门。
14.2 stdio 与远程服务器的配置差异
本地服务器走 stdio 传输:客户端把它作为子进程拉起,通过标准输入输出通信,所以需要 command + args。远程服务器走 Streamable HTTP:它已经在别处运行,只需要一个 URL。
{
"mcpServers": {
"local-notes": {
"command": "python",
"args": ["/path/to/server.py"]
},
"remote-docs": {
"url": "https://mcp.example.com/mcp",
"headers": {
"Authorization": "Bearer <token>"
}
}
}
}选择建议:个人工具、访问本机文件用 stdio;团队共享能力(内部知识库查询、CI 状态等)部署成 HTTP 服务,一处维护多方使用。
14.3 环境变量与密钥传递
服务器经常需要 API Key。正确做法是写在配置的 env 字段里,由客户端注入子进程环境:
{
"mcpServers": {
"brave-search": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
"env": {
"BRAVE_API_KEY": "你的密钥"
}
}
}
}官方文档特别提醒过一个 Windows 坑:如果日志报错中出现 ${APPDATA} 字样,说明服务器没有拿到展开后的路径变量,需要在 env 里手动补上展开值。
安全红线:
- 配置文件含明文密钥,不要提交到 Git 仓库;
- 密钥只经环境变量进入服务器进程,不要写死在 server.py 源码里;
- 团队分发时提供
config.example.json模板,真实配置各自本地填写。
14.4 在 Claude Code 中用命令行管理
Claude Code 把同样的配置做成了 CLI 命令,不用手动编辑 JSON:
# 添加一个 stdio 本地服务器
claude mcp add notes -- python /path/to/server.py
# 添加带环境变量的服务器
claude mcp add brave-search -e BRAVE_API_KEY=sk-xxx -- npx -y @modelcontextprotocol/server-brave-search
# 添加远程 HTTP 服务器
claude mcp add --transport http docs https://mcp.example.com/mcp
# 查看 / 删除
claude mcp list
claude mcp remove notes-- 之后的部分就是启动命令本身,语义与 JSON 配置一一对应。
14.5 工具不出现?排查清单
配置后客户端里看不到工具,按命中率从高到低排查:
# ① 手工运行服务器命令,确认它能正常启动不报错
npx -y @modelcontextprotocol/server-filesystem ~/Documents
# ② 查看 Claude Desktop 的 MCP 日志(macOS)
tail -f ~/Library/Logs/Claude/mcp*.log- JSON 语法错误:多逗号、少引号是最常见原因,用任意 JSON 校验器过一遍;
- 重启不彻底:Claude Desktop 必须从托盘完全退出再启动才会重读配置;
- 依赖缺失:
npx需要 Node.js;Python 服务器注意是否装在了正确的虚拟环境里; - 路径错误:
server.py用相对路径时,工作目录取决于客户端,一律写绝对路径; - 服务器启动即崩溃:看 ② 的日志输出,通常是缺依赖或密钥未设置。
14.6 用 Python 编写程序化客户端
除了现成客户端,你也可以在自己的应用里直接调用 MCP 服务器。官方 SDK 同时是一个完整的 MCP 客户端库:
import asyncio
from mcp import Client
async def main() -> None:
# URL 形式连接 Streamable HTTP 传输的服务器
async with Client("http://localhost:8000/mcp") as client:
# 列出服务器提供的所有工具
tools = await client.list_tools()
for t in tools:
print("工具:", t.name, "-", t.description)
# 调用第 13 章写的 add 工具
result = await client.call_tool("add", {"a": 1, "b": 2})
print(result.structured_content) # {'result': 3}
asyncio.run(main())先以 HTTP 方式启动上一章的服务器,再运行客户端:
mcp run server.py --transport streamable-http # 终端 1
python my_client.py # 终端 2几个关键点:
async with Client(...)负责完整生命周期——建立连接、initialize 握手、能力协商、退出清理都在这一步完成;- URL 连接的是 HTTP 传输;
Client同样支持把本地脚本作为 stdio 子进程拉起,参数形式与 Claude Desktop 配置一致; - 需要精细控制请求/通知收发等底层行为时,SDK 还提供 Low-Level 的会话 API(位于
mcp.client.session模块),日常场景用上面的高层接口即可。
这就是把 MCP 能力嵌入自己产品的最小路径——你的应用此时就是一个 MCP Host。
本章小结
- Claude Desktop 在
claude_desktop_config.json的mcpServers下配置服务器,改完必须彻底重启; - 本地服务器配
command+args(stdio),远程服务器配url(Streamable HTTP); - 密钥放
env字段,配置文件不入库;Windows 注意${APPDATA}展开问题; - Claude Code 提供
claude mcp add/list/remove命令化等效操作; - 排查顺序:手工起服务器 → 看 mcp 日志 → 查 JSON 语法 → 查依赖与绝对路径;
from mcp import Client十几行代码即可让任何 Python 应用成为 MCP 宿主。
🛠️ 动手实践
- 把第 13 章的笔记服务器接入 Claude Desktop,验证工具列表出现,并故意删掉配置文件里的一个逗号观察报错现象。
- 用
claude mcp add把同一个服务器添加进 Claude Code,对比两种方式生成的最终配置结构是否一致。 - 扩展本章的 Python 客户端:列出工具后自动调用其中每一个的"无参调用"或跳过必填参数的工具,并打印每个工具的结构化返回。
完成练习后,进入,学习把服务器安全地跑在生产环境。
完成后进入下一章:MCP 安全与生产实践。