第11章:MCP —— Agent 世界的"USB 接口"
一句话:理解 MCP 协议,让你的 Agent 能连接任何外部工具和服务,就像 USB-C 让所有设备都能互联互通。
本章目标
- 理解 MCP 是什么、为什么需要它
- 掌握三种 MCP 连接方式(stdio / HTTP/SSE / SDK 内置)
- 学会连接现成的 MCP Server(GitHub、文件系统、数据库等)
- 理解 MCP 工具命名规则和工具搜索机制
- 区分 MCP、自定义工具、Skills 三者的关系
前置知识
- 需要先看完第10章(自定义工具)
11.1 MCP 是什么?
先说个故事
假设你买了一部新手机,想给它充电。你翻遍抽屉,找到了 5 根不同的充电线 —— Micro USB、Lightning、USB-C、某个不知名品牌的专属接口...
这就是 AI 工具集成在 MCP 出现之前的状况。
每个 AI 平台都有自己的工具接口规范。你想让 AI 连 GitHub?写一套代码。想连数据库?再写一套。想连 Slack?又一套。每个工具供应商也得为每个 AI 平台分别做适配。
MCP(Model Context Protocol,模型上下文协议) 就是 AI 世界的 USB-C。
一个标准,统一所有
MCP 是 Anthropic 在 2024 年底发明的一个开放标准协议。它定义了 AI Agent 和外部工具之间的通信方式。简单说:
- MCP 之前:每个 AI 要和每个工具单独对接,N 个 AI + M 个工具 = N x M 种对接方式
- MCP 之后:所有 AI 都说同一种"语言",所有工具也说同一种"语言",只需要 N + M 种适配
MCP 之前(混乱的世界):
Claude ──专用接口──→ GitHub
Claude ──专用接口──→ Slack
Claude ──专用接口──→ 数据库
GPT ──专用接口──→ GitHub
GPT ──专用接口──→ Slack
GPT ──专用接口──→ 数据库
Gemini ──专用接口──→ GitHub
...(排列组合,爆炸!)
MCP 之后(统一的世界):
Claude ──┐ ┌──→ GitHub MCP Server
GPT ──┤── MCP 协议 ──├──→ Slack MCP Server
Gemini ──┘ └──→ 数据库 MCP Server
谁在用 MCP?
MCP 虽然是 Anthropic 发明的,但现在已经成为行业标准:
- Anthropic:Claude Code、Claude Agent SDK 原生支持
- OpenAI:2025 年 3 月宣布在 ChatGPT 和 Agent SDK 中支持 MCP
- Google:Gemini 和 ADK(Agent Development Kit)支持 MCP
- Microsoft:Copilot Studio 支持 MCP
- 社区生态:MCP SDK 的月下载量超过 9700 万次
这意味着什么?你现在学会用 MCP 连接工具,这些工具以后在任何 AI 平台上都能用。学一次,到处用。
MCP 的本质
用大白话说,MCP 就是一个"翻译协议":
- Agent 想用某个外部工具(比如查 GitHub Issue)
- Agent 按照 MCP 格式发出请求:"嘿,帮我列出最近的 Issue"
- MCP Server(GitHub)收到请求,翻译成 GitHub API 调用
- 拿到结果后,再按 MCP 格式返回给 Agent
- Agent 拿到结果,继续干活
Agent 不需要知道 GitHub API 怎么调,就像你用 USB-C 充电不需要知道电路板怎么设计一样。
11.2 MCP 的三种连接方式
MCP 支持三种不同的"连线方式",适用于不同场景。我们一个一个来看。
方式一:stdio(标准输入输出)—— 最常用
什么是 stdio?
stdio 就是"标准输入输出"的缩写。说人话就是:Agent 在你的电脑上启动一个小程序(MCP Server),然后通过"管道"和它对话。
工作原理:
你的 Agent 程序
│
│ 启动子进程
▼
MCP Server 进程(比如 GitHub MCP Server)
│
│ Agent 通过 stdin 发送 JSON 请求
│ MCP Server 通过 stdout 返回 JSON 结果
▼
来回对话,直到任务完成
生活比喻: 两个人坐在同一个房间里传纸条。速度快,不需要网络,但两个人必须在同一台机器上。
代码示例:
import { query } from "@anthropic-ai/claude-agent-sdk";
// stdio 方式连接文件系统 MCP Server
for await (const message of query({
prompt: "列出 /Users/me/projects 目录下的所有文件",
options: {
mcpServers: {
// "filesystem" 是你给这个 MCP Server 起的名字
filesystem: {
command: "npx", // 用 npx 来运行
args: [
"-y", // 自动确认安装
"@modelcontextprotocol/server-filesystem", // MCP Server 的 npm 包名
"/Users/me/projects" // 允许访问的目录
]
}
},
// 允许 Agent 使用这个 MCP Server 的所有工具
allowedTools: ["mcp__filesystem__*"]
}
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
stdio 配置的三个关键字段:
| 字段 | 含义 | 示例 |
|---|---|---|
command |
用什么命令启动 MCP Server | "npx" 或 "node" 或 "python" |
args |
命令的参数 | ["-y", "@modelcontextprotocol/server-filesystem", "/path"] |
env |
传给 MCP Server 的环境变量 | { GITHUB_TOKEN: "xxx" } |
什么时候用 stdio?
- MCP Server 跑在你本地(最常见的情况)
- 用
npx直接运行 npm 包发布的 MCP Server - 你自己写了一个 MCP Server,在本地测试
方式二:HTTP/SSE(网络通信)—— 远程服务
什么是 HTTP/SSE?
HTTP 你肯定知道,就是浏览器上网用的协议。SSE(Server-Sent Events)是一种服务器向客户端推送消息的技术。合在一起:
- Agent 通过 HTTP POST 发送请求给远程 MCP Server
- MCP Server 通过 SSE 把结果流式推送回来
生活比喻: 打电话给远方的人。比传纸条慢一点,但可以跨越距离。
代码示例:
import { query } from "@anthropic-ai/claude-agent-sdk";
// HTTP 方式连接远程 MCP Server
for await (const message of query({
prompt: "查一下 Claude Code 的文档中关于 Hooks 的说明",
options: {
mcpServers: {
"claude-code-docs": {
type: "http", // 指定连接类型为 HTTP
url: "https://code.claude.com/docs/mcp" // 远程 MCP Server 的地址
}
},
allowedTools: ["mcp__claude-code-docs__*"]
}
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
HTTP/SSE 配置的关键字段:
| 字段 | 含义 | 示例 |
|---|---|---|
type |
连接类型,必须是 "http" |
"http" |
url |
远程 MCP Server 的 URL | "https://example.com/mcp" |
headers |
HTTP 请求头(用来传认证信息等) | { "Authorization": "Bearer xxx" } |
什么时候用 HTTP/SSE?
- MCP Server 部署在云端(不在你本地)
- 团队共享的 MCP Server(多个人共用一个服务)
- 需要通过网络访问的第三方 MCP 服务
带认证的 HTTP 示例:
mcpServers: {
"my-api": {
type: "http",
url: "https://api.example.com/mcp",
headers: {
"Authorization": "Bearer " + process.env.API_TOKEN
}
}
}
方式三:SDK 内置(代码内定义)—— 上一章学过的
这是什么?
就是上一章学的 createSdkMcpServer()。你直接在代码里定义工具,不需要启动额外的进程或连接远程服务。
import { query, createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";
// 用代码创建一个 MCP Server
const myTools = createSdkMcpServer({
tools: [
tool(
"get_weather",
"查询城市天气",
{ city: z.string().describe("城市名称") },
async ({ city }) => ({
content: [{ type: "text", text: `${city}今天晴,25度` }]
})
)
]
});
for await (const message of query({
prompt: "今天北京天气怎么样?",
options: {
mcpServers: {
weather: myTools // 直接传入代码创建的 MCP Server
},
allowedTools: ["mcp__weather__*"]
}
})) {
// 处理消息
}
什么时候用 SDK 内置?
- 工具逻辑比较简单,直接写在代码里最方便
- 不想额外安装/启动 MCP Server
- 你的应用专属的自定义工具
三种方式对比总结
| 特性 | stdio | HTTP/SSE | SDK 内置 |
|---|---|---|---|
| MCP Server 在哪 | 本地进程 | 远程服务器 | 代码里 |
| 需要网络吗 | 不需要 | 需要 | 不需要 |
| 启动方式 | 自动启动子进程 | 连接已运行的服务 | 直接在内存中 |
| 适合场景 | 用现成的 MCP Server | 云端/共享服务 | 自定义工具 |
| 配置复杂度 | 低 | 中 | 低 |
| 生活比喻 | 同屋传纸条 | 打电话 | 自言自语 |
11.3 连接现成的 MCP Server
MCP 生态已经非常丰富了。社区有成百上千个现成的 MCP Server,拿来就能用。这里列出最常用的几个:
官方维护的 MCP Server
| MCP Server | 做什么的 | npm 包名 |
|---|---|---|
| GitHub | 管理 GitHub Issues、PR、仓库 | @modelcontextprotocol/server-github |
| 文件系统 | 安全地读写本地文件 | @modelcontextprotocol/server-filesystem |
| PostgreSQL | 查询 PostgreSQL 数据库 | @modelcontextprotocol/server-postgres |
| SQLite | 查询 SQLite 数据库 | @modelcontextprotocol/server-sqlite |
| Brave Search | 用 Brave 搜索引擎搜网页 | @modelcontextprotocol/server-brave-search |
| Puppeteer | 浏览器自动化(爬虫、截图) | @modelcontextprotocol/server-puppeteer |
| Memory | 持久化记忆存储 | @modelcontextprotocol/server-memory |
| Google Maps | 地图和地理位置查询 | @modelcontextprotocol/server-google-maps |
社区热门 MCP Server
| MCP Server | 做什么的 |
|---|---|
| Slack MCP | 发消息、管理 Slack 频道 |
| Notion MCP | 读写 Notion 文档 |
| Linear MCP | 管理 Linear 项目和 Issue |
| Sentry MCP | 查看错误日志和监控报告 |
| Docker MCP | 管理 Docker 容器 |
怎么找更多 MCP Server?
- 官方仓库:https://github.com/modelcontextprotocol/servers
- MCP Hub:社区维护的 MCP Server 目录
- npm 搜索:在 npm 上搜索
mcp-server关键词
小贴士:MCP 生态发展非常快,几乎每天都有新的 MCP Server 发布。你想让 AI 连什么服务,先搜搜有没有现成的 MCP Server,大概率有人已经做好了。
11.4 实战:用 GitHub MCP Server 管理项目
这是本章最重要的实战环节。我们来做一个能管理 GitHub 项目的 Agent。
第一步:准备 GitHub Token
GitHub MCP Server 需要一个 Personal Access Token(个人访问令牌)来访问你的 GitHub 账号。
获取步骤:
- 打开 https://github.com/settings/tokens
- 点击 "Generate new token (classic)"
- 勾选需要的权限(至少需要
repo权限) - 生成后复制 Token
设置环境变量:
# macOS / Linux
export GITHUB_TOKEN="ghp_你的Token放这里"
# 或者写入 .env 文件
echo 'GITHUB_TOKEN=ghp_你的Token放这里' >> .env
第二步:创建项目
mkdir github-agent && cd github-agent
npm init -y
npm install @anthropic-ai/claude-agent-sdk dotenv
第三步:编写代码
创建 github-agent.ts:
import { query } from "@anthropic-ai/claude-agent-sdk";
import "dotenv/config";
// 确保 GITHUB_TOKEN 已设置
if (!process.env.GITHUB_TOKEN) {
console.error("请先设置 GITHUB_TOKEN 环境变量!");
console.error("export GITHUB_TOKEN=ghp_你的Token");
process.exit(1);
}
async function main() {
console.log("正在启动 GitHub Agent...\n");
for await (const message of query({
prompt: "列出 anthropics/claude-code 仓库最近的 3 个 Issue,告诉我每个 Issue 的标题和状态",
options: {
mcpServers: {
// 配置 GitHub MCP Server(stdio 方式)
github: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-github"],
env: {
GITHUB_TOKEN: process.env.GITHUB_TOKEN!
}
}
},
// 允许使用 GitHub MCP Server 的指定工具
allowedTools: [
"mcp__github__list_issues",
"mcp__github__get_issue"
]
}
})) {
// 处理不同类型的消息
switch (message.type) {
case "assistant":
// Agent 的回复(可能包含思考过程和工具调用)
if (typeof message.content === "string") {
console.log("Agent:", message.content);
} else if (Array.isArray(message.content)) {
for (const block of message.content) {
if (block.type === "text") {
console.log("Agent:", block.text);
} else if (block.type === "tool_use") {
console.log(`\n[调用工具] ${block.name}`);
console.log(`[参数] ${JSON.stringify(block.input, null, 2)}\n`);
}
}
}
break;
case "result":
if (message.subtype === "success") {
console.log("\n--- 任务完成 ---");
console.log(message.result);
} else {
console.error("\n--- 任务失败 ---");
console.error(message.error);
}
break;
}
}
}
main().catch(console.error);
第四步:运行
npx tsx github-agent.ts
你会看到类似这样的输出:
正在启动 GitHub Agent...
[调用工具] mcp__github__list_issues
[参数] {
"owner": "anthropics",
"repo": "claude-code",
"state": "open",
"per_page": 3
}
Agent: 以下是 anthropics/claude-code 仓库最近的 3 个 Issue:
1. **#1234 - 支持自定义快捷键** (open)
状态:打开中
2. **#1233 - Windows 上的路径解析问题** (open)
状态:打开中
3. **#1232 - 建议添加暗色主题** (open)
状态:打开中
--- 任务完成 ---
第五步:进阶 —— 让 Agent 干更多事
让我们扩展这个 Agent,让它能创建 Issue 和回复评论:
import { query } from "@anthropic-ai/claude-agent-sdk";
import "dotenv/config";
async function githubAgent(task: string) {
for await (const message of query({
prompt: task,
options: {
mcpServers: {
github: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-github"],
env: {
GITHUB_TOKEN: process.env.GITHUB_TOKEN!
}
}
},
// 用通配符允许所有 GitHub 工具
allowedTools: ["mcp__github__*"],
// 给 Agent 一些行为指导
systemPrompt: `你是一个 GitHub 项目管理助手。请注意:
1. 操作前先确认用户意图
2. 创建 Issue 时使用清晰的标题和描述
3. 回复评论时保持专业和友善
4. 列出信息时使用格式化的表格或列表`
}
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
}
// 示例:列出 Issue
await githubAgent("列出我的仓库 myname/myproject 中所有打开的 Issue");
// 示例:创建 Issue
await githubAgent(`
在 myname/myproject 仓库创建一个新 Issue:
标题:添加用户登录功能
描述:需要实现基本的用户名密码登录,包括注册、登录、登出功能。
标签:enhancement
`);
// 示例:回复评论
await githubAgent("在 myname/myproject 的 Issue #42 上回复:'这个问题已经修复了,请更新到最新版本试试。'");
11.5 实战:用文件系统 MCP Server
文件系统 MCP Server 允许 Agent 安全地访问你指定的目录。注意关键词:安全地。
为什么不直接用内置的 Read/Write 工具?
内置工具可以读写任何文件,权力太大了。文件系统 MCP Server 可以限制 Agent 只能访问你指定的目录,更安全。
基本用法
import { query } from "@anthropic-ai/claude-agent-sdk";
async function fileAgent(task: string) {
for await (const message of query({
prompt: task,
options: {
mcpServers: {
filesystem: {
command: "npx",
args: [
"-y",
"@modelcontextprotocol/server-filesystem",
// 只允许访问这个目录(安全限制)
"/Users/me/projects/my-app"
]
}
},
allowedTools: ["mcp__filesystem__*"]
}
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
}
// 让 Agent 分析项目结构
await fileAgent("分析这个项目的目录结构,告诉我它是什么类型的项目");
// 让 Agent 整理文件
await fileAgent("找出所有的 .log 文件,告诉我它们的大小和最后修改时间");
// 让 Agent 创建文件
await fileAgent("在项目根目录创建一个 .gitignore 文件,包含常见的 Node.js 忽略规则");
指定多个目录
你可以在 args 中传多个路径,允许 Agent 访问多个目录:
filesystem: {
command: "npx",
args: [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/me/projects/frontend", // 前端项目
"/Users/me/projects/backend", // 后端项目
"/Users/me/documents" // 文档目录
]
}
Agent 只能在这些目录里操作,其他目录一律访问不了。这就是"最小权限原则"的体现。
11.6 同时连接多个 MCP Server
真正强大的 Agent 通常需要连接多个工具。MCP 天然支持同时连接多个 Server。
完整示例:GitHub + 文件系统 + 数据库
import { query } from "@anthropic-ai/claude-agent-sdk";
async function superAgent(task: string) {
for await (const message of query({
prompt: task,
options: {
mcpServers: {
// 工具1:GitHub 项目管理
github: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-github"],
env: {
GITHUB_TOKEN: process.env.GITHUB_TOKEN!
}
},
// 工具2:文件系统操作
filesystem: {
command: "npx",
args: [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/me/projects"
]
},
// 工具3:SQLite 数据库查询
database: {
command: "npx",
args: [
"-y",
"@modelcontextprotocol/server-sqlite",
"--db-path",
"/Users/me/data/app.db"
]
}
},
// 精确控制每个 Server 的工具权限
allowedTools: [
"mcp__github__list_issues", // GitHub:只允许列出 Issue
"mcp__github__get_issue", // GitHub:只允许查看 Issue 详情
"mcp__filesystem__*", // 文件系统:允许所有操作
"mcp__database__query" // 数据库:只允许查询,不允许修改
]
}
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
}
// 一个任务里用到多个工具
await superAgent(`
帮我做以下事情:
1. 查看 GitHub 上 myname/myproject 仓库最近的 5 个 Issue
2. 从本地数据库中查询最近一周的用户反馈
3. 综合以上信息,在本地文件系统中生成一份周报(保存为 weekly-report.md)
`);
不同 Server 的工具如何共存?
每个 MCP Server 的工具都有唯一的名称,格式是 mcp__<服务器名>__<工具名>。所以即使两个 Server 都有叫 query 的工具,它们也不会冲突:
mcp__github__query → GitHub 的查询工具
mcp__database__query → 数据库的查询工具
Agent 会根据上下文自动选择正确的工具。你让它"查数据库",它就用 mcp__database__query;你让它"查 GitHub",它就用 mcp__github__query。
11.7 MCP 工具命名规则
这部分很重要,理解了命名规则,你就知道怎么精确控制 Agent 能用哪些工具。
命名格式
mcp__<服务器名>__<工具名>
其中:
<服务器名> = 你在 mcpServers 配置中给 Server 起的 key 名
<工具名> = MCP Server 提供的工具的名称
示例:
mcpServers: {
github: { ... }, // 服务器名 = "github"
mydb: { ... }, // 服务器名 = "mydb"
"my-files": { ... } // 服务器名 = "my-files"
}
// 对应的工具名:
// mcp__github__list_issues
// mcp__github__create_issue
// mcp__github__get_issue
// mcp__mydb__query
// mcp__mydb__execute
// mcp__my-files__read_file
// mcp__my-files__write_file
通配符
当你不想一个一个列出所有工具时,用通配符 *:
allowedTools: [
"mcp__github__*", // 允许 github 服务器的所有工具
"mcp__database__query", // 只允许 database 服务器的 query 工具
"mcp__slack__send_message" // 只允许 slack 服务器的 send_message 工具
]
建议:
- 开发/测试阶段:用
mcp__xxx__*通配符,方便调试 - 生产环境:明确列出每个工具,最小权限原则
工具搜索(Tool Search)—— 当工具太多时
如果你连了好多 MCP Server,每个 Server 又有几十个工具,工具描述加起来可能会占用很多上下文空间。这时候可以开启"工具搜索"功能:
Agent 不再一次性加载所有工具描述,而是根据需要按需搜索合适的工具。
配置方法:
for await (const message of query({
prompt: "帮我查一下最近的 GitHub Issue",
options: {
mcpServers: { /* 你的 MCP Servers */ },
allowedTools: ["mcp__github__*", "mcp__slack__*", "mcp__notion__*"],
env: {
// 配置工具搜索
ENABLE_TOOL_SEARCH: "auto" // 默认值:当工具描述超过上下文 10% 时自动开启
}
}
})) {
// ...
}
ENABLE_TOOL_SEARCH 的可选值:
| 值 | 行为 |
|---|---|
"auto" |
当 MCP 工具描述超过上下文的 10% 时自动开启(默认) |
"auto:5" |
自定义阈值,5% 时开启 |
"true" |
始终开启工具搜索 |
"false" |
禁用,所有工具描述一次性全部加载 |
什么时候需要工具搜索?
- 连了 5 个以上的 MCP Server
- 单个 MCP Server 提供了 50 个以上的工具
- Agent 的回答质量下降(可能是工具描述占了太多上下文)
大多数情况下,用默认的 "auto" 就够了,SDK 会自动帮你决定。
11.8 用配置文件管理 MCP Server
除了在代码里配置,你还可以用 .mcp.json 配置文件来管理 MCP Server。
创建 .mcp.json
在你的项目根目录创建 .mcp.json 文件:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
},
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"]
},
"database": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-sqlite", "--db-path", "./data/app.db"]
}
}
}
使用配置文件
SDK 会自动加载项目根目录下的 .mcp.json,你的代码可以更简洁:
import { query } from "@anthropic-ai/claude-agent-sdk";
// 不需要在代码里配置 mcpServers 了,SDK 会自动从 .mcp.json 加载
for await (const message of query({
prompt: "列出 GitHub Issue 并生成报告",
options: {
allowedTools: ["mcp__github__*", "mcp__filesystem__*"]
}
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
配置文件 vs 代码配置
| 方式 | 优点 | 缺点 |
|---|---|---|
.mcp.json 文件 |
可以团队共享、版本管理;代码更简洁 | 不够灵活,不能动态配置 |
| 代码里配置 | 灵活,可以根据条件动态选择 | 代码冗长 |
建议: 固定不变的 MCP Server 用 .mcp.json,需要动态配置的用代码。
11.9 MCP vs 自定义工具 vs Skills
学到这里,你可能有点困惑:MCP、自定义工具(createSdkMcpServer)、Skills,这三个东西有什么区别?什么时候用什么?
三者的本质区别
┌─────────────────────────────────────────────────────┐
│ Agent 的完整能力 │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │
│ │ MCP Server │ │ 自定义工具 │ │ Skills │ │
│ │ (外部工具) │ │ (内部工具) │ │ (知识) │ │
│ │ │ │ │ │ │ │
│ │ 标准化接口 │ │ 代码内定义 │ │ Markdown │ │
│ │ 可复用 │ │ 应用专属 │ │ 文档 │ │
│ │ 社区生态 │ │ 灵活定制 │ │ 教程 │ │
│ └──────────────┘ └──────────────┘ └─────────────┘ │
│ │
│ 提供"能力"(能做什么) 提供"知识"(怎么做) │
└─────────────────────────────────────────────────────┘
详细对比
| 维度 | MCP Server | 自定义工具 | Skills |
|---|---|---|---|
| 是什么 | 标准化的外部工具接口 | 代码里直接定义的工具 | 教 Agent 怎么做事的知识文档 |
| 定义方式 | 独立进程 / 远程服务 | createSdkMcpServer() + tool() |
.claude/skills/ 目录下的 Markdown 文件 |
| 解决什么问题 | 连接外部服务和工具 | 实现应用特有的功能 | 教 Agent 遵循特定流程和规范 |
| 可复用性 | 高(任何 AI 都能用) | 低(只在你的应用里用) | 中(可以跨项目复用) |
| 社区生态 | 丰富(成百上千个) | 无(你自己写的) | 可以分享给团队 |
| 类比 | USB 设备(即插即用) | 焊在主板上的芯片 | 说明书/操作手册 |
什么时候用什么?
用 MCP Server 的场景:
- 需要连接外部服务(GitHub、Slack、数据库等)
- 已经有现成的 MCP Server 可用
- 希望工具能跨项目、跨平台复用
用自定义工具的场景:
- 工具逻辑是你的应用独有的(比如查询你公司的内部 API)
- 工具需要访问应用的内部状态
- 不想额外安装/管理 MCP Server
用 Skills 的场景:
- 需要教 Agent 遵循特定的工作流程
- 需要给 Agent 提供专业知识
- 需要规范 Agent 的行为方式
它们可以一起用!
这三者不是互斥的,而是互补的。一个强大的 Agent 通常会同时使用三种方式:
import { query, createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";
// 自定义工具:查询公司内部数据
const internalTools = createSdkMcpServer({
tools: [
tool(
"query_internal_api",
"查询公司内部用户数据",
{ userId: z.string() },
async ({ userId }) => {
const data = await fetch(`https://internal.api/users/${userId}`);
return { content: [{ type: "text", text: JSON.stringify(await data.json()) }] };
}
)
]
});
for await (const message of query({
prompt: "分析用户 U12345 的问题,在 GitHub 上创建对应的 Issue",
options: {
mcpServers: {
// MCP Server:连接 GitHub
github: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-github"],
env: { GITHUB_TOKEN: process.env.GITHUB_TOKEN! }
},
// 自定义工具:查询内部数据
internal: internalTools
},
allowedTools: [
"mcp__github__*",
"mcp__internal__*"
],
// Skills 通过 settingSources 自动加载 .claude/skills/ 目录下的文件
settingSources: ["project"]
}
})) {
// 处理消息
}
在这个例子中:
- MCP Server(GitHub) 提供了操作 GitHub 的能力
- 自定义工具 提供了查询公司内部数据的能力
- Skills(通过 settingSources 加载)告诉 Agent 创建 Issue 时应该遵循什么规范
11.10 常见问题和调试技巧
问题1:MCP Server 启动失败
症状: 报错 "Failed to start MCP server" 或类似错误。
排查步骤:
# 1. 先手动运行 MCP Server,看看能不能正常启动
npx -y @modelcontextprotocol/server-github
# 2. 检查 Node.js 版本(需要 18+)
node -v
# 3. 检查 npx 是否可用
npx --version
# 4. 如果是权限问题,尝试清缓存
npm cache clean --force
问题2:工具调用没反应
症状: Agent 说"我没有合适的工具来完成这个任务"。
排查:
// 检查 allowedTools 是否正确
// 错误写法(少了前缀):
allowedTools: ["list_issues"]
// 正确写法:
allowedTools: ["mcp__github__list_issues"]
// 或者用通配符:
allowedTools: ["mcp__github__*"]
问题3:认证失败
症状: 报错 "401 Unauthorized" 或 "403 Forbidden"。
排查:
// 确保环境变量正确传递
mcpServers: {
github: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-github"],
env: {
// 确保这个值不是 undefined
GITHUB_TOKEN: process.env.GITHUB_TOKEN!
}
}
}
// 调试:打印看看环境变量有没有值
console.log("Token:", process.env.GITHUB_TOKEN ? "已设置" : "未设置!");
问题4:工具太多,Agent 选错工具
解决方案:
// 方案1:缩小 allowedTools 范围
allowedTools: [
"mcp__github__list_issues", // 只给它需要的工具
"mcp__github__get_issue"
]
// 方案2:在 systemPrompt 中给出指导
systemPrompt: "当用户让你查看 Issue 时,使用 mcp__github__list_issues 工具"
// 方案3:开启工具搜索
env: { ENABLE_TOOL_SEARCH: "true" }
动手练习
练习1:GitHub Issue 管理 Agent
目标: 做一个能管理 GitHub Issue 的 Agent。
要求:
- 连接 GitHub MCP Server
- 能列出指定仓库的 Issue
- 能根据关键词搜索 Issue
- 能创建新 Issue
- 输出格式化的 Issue 列表
提示代码框架:
import { query } from "@anthropic-ai/claude-agent-sdk";
async function issueManager(command: string) {
for await (const message of query({
prompt: command,
options: {
mcpServers: {
github: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-github"],
env: { GITHUB_TOKEN: process.env.GITHUB_TOKEN! }
}
},
allowedTools: ["mcp__github__*"],
systemPrompt: `你是一个 GitHub Issue 管理助手。
- 列出 Issue 时使用表格格式
- 创建 Issue 时使用 Conventional Commits 风格的标题
- 每次操作后给出简短的确认信息`
}
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
}
// 你的测试代码:
await issueManager("列出 owner/repo 仓库中标签为 bug 的所有 Issue");
练习2:文件整理 Agent
目标: 做一个能帮你整理文件的 Agent。
要求:
- 连接文件系统 MCP Server
- 指定一个目录,让 Agent 分析其中的文件
- 按文件类型分类统计(多少个 .ts 文件、多少个 .json 文件等)
- 找出超过 1MB 的大文件
- 生成一份整理报告
提示:
- 使用
@modelcontextprotocol/server-filesystem - 在 args 中传入你想整理的目录路径
- 使用 systemPrompt 指导 Agent 的输出格式
练习3:多功能 Agent
目标: 同时连接 3 个 MCP Server,做一个全能 Agent。
要求:
- 连接 GitHub MCP Server(管理代码)
- 连接文件系统 MCP Server(读写文件)
- 连接 SQLite MCP Server(查询数据)
- 让 Agent 完成一个跨工具的任务:
- 从数据库查出最近的错误日志
- 在本地文件系统生成错误报告
- 在 GitHub 上创建对应的 Issue
提示:
- 使用多个 mcpServers 配置
- 使用精确的 allowedTools 控制权限
- 在 prompt 中清晰描述任务流程
本章小结
恭喜你读完了这一章!让我们回顾一下关键知识点:
MCP 是什么:Model Context Protocol,AI 世界的 USB-C 标准。它让 Agent 能用统一的方式连接任何外部工具和服务。
三种连接方式:
- stdio:本地进程通信,最常用,用
command+args配置 - HTTP/SSE:远程服务器通信,用
type: "http"+url配置 - SDK 内置:代码内直接定义,用
createSdkMcpServer()创建
- stdio:本地进程通信,最常用,用
丰富的生态:GitHub、文件系统、数据库、搜索引擎...成百上千个现成的 MCP Server 等你使用。
工具命名规则:
mcp__<服务器名>__<工具名>,支持*通配符。工具搜索:当工具太多时,用
ENABLE_TOOL_SEARCH让 Agent 按需加载工具。配置方式:代码配置和
.mcp.json文件配置两种方式。三者关系:MCP 提供标准化外部工具接口,自定义工具提供应用内部能力,Skills 提供操作知识和规范。三者互补,不是竞争关系。
下一章预告
下一章我们要学 第12章:Hooks —— 在 Agent 干活的每个节点插一脚。
你有没有想过这些问题:
- Agent 每次调用工具前,我能不能先检查一下?
- Agent 每次执行完操作后,我能不能记个日志?
- Agent 做了危险操作时,我能不能紧急叫停?
Hooks 就是干这个的。它让你在 Agent 工作流程的每个关键节点都能插入自己的逻辑,就像流水线上的"质检站"。
下一章见!