一、开场:为什么我的AI Agent总是个”残疾人”?
大家好,我是老金。
你们有没有这种感觉:
AI Agent听起来很强大,但真正用起来,总感觉缺胳膊少腿?
比如:
- 让它查个天气,它说”我没有联网功能”
- 让它发个邮件,它说”我做不到”
- 让它读个PDF,它说”我不支持”
这不就是个残疾人吗?
我之前也一直被这个问题困扰。
直到我接触了MCP协议。
今天这篇文章,就是MCP协议的完全指南。
内容包括:
- MCP协议是什么?解决什么问题?
- MCP协议架构详解
- MCP Server开发实战
- MCP Client集成实战
- 完整项目示例
- 常见问题与解决方案
- MCP生态现状与未来
看完这篇,你的AI Agent将不再是个”残疾人”,而是全能选手。
二、MCP协议是什么?
2.1 问题背景
在MCP出现之前,给AI Agent扩展能力,是这样的:
GPT-4
↓ 需要什么能力
开发者A写搜索插件
开发者B写邮件插件
开发者C写数据库插件
...
↓ 每个都不同
GPT-4 需要适配所有插件
↓ 噩梦
插件A用"search"接口
插件B用"query"接口
插件C用"find"接口
混乱!不可维护!
每个插件有自己的接口定义,AI需要适配所有插件。
这就是所谓的“Plugin Hell”。
2.2 MCP的定义
MCP(Model Context Protocol) = AI模型的USB接口
就像USB统一了各种设备的连接方式,MCP统一了AI与外部工具的交互方式。
AI Agent
│
│ 统一接口(MCP)
│
┌─────┴─────┐
│ │
Search Email Database
(MCP) (MCP) (MCP)
核心思想:
- 接口标准化:所有工具用同一套协议
- 即插即用:新工具不需要改AI代码
- 双向通信:不只是”调用工具”,还能”接收数据”
- 安全可控:工具调用有明确的权限控制
2.3 MCP vs 传统Plugin
| 维度 | 传统Plugin | MCP |
|---|---|---|
| 接口规范 | 每个插件自定义 | 统一协议 |
| 接入成本 | 高(需要适配每个插件) | 低(一次接入,所有工具可用) |
| 扩展性 | 差(插件多了就乱) | 好(像搭积木一样) |
| 双向通信 | 不支持 | 支持 |
| 工具发现 | 手动配置 | 自动发现 |
| 标准化程度 | 低 | 高(Anthropic主导) |
三、MCP协议架构详解
3.1 核心组件
┌─────────────────────────────────────────────────────────┐
│ MCP Host │
│ (Claude App) │
└─────────────────────────────────────────────────────────┘
│
│ MCP Protocol
│
┌───────────────┬─────────────────────────┬───────────────┐
│ MCP Client │ │ MCP Client │
└───────┬───────┘ └───────┬───────┘
│ │
│ MCP Protocol │ MCP Protocol
│ │
┌───────┴───────┐ ┌───────┴───────┐
│ MCP Server │ │ MCP Server │
│ (File System)│ │ (Web Search) │
└───────────────┘ └───────────────┘
组件说明:
- MCP Host:用户使用的AI应用(如Claude Desktop)
- MCP Client:Host内的客户端,负责与Server通信
- MCP Server:工具提供者,每个Server提供一类工具
- MCP Protocol:通信协议(JSON-RPC 2.0)
3.2 通信流程
1. 初始化
Client → Server: initialize (协议版本、客户端能力)
Server → Client: initialized (确认、Server能力)
- 工具发现 Client → Server: tools/list Server → Client: 工具列表 (name, description, inputSchema)
- 工具调用 Client → Server: tools/call (tool name, arguments) Server → Client: 工具结果 (content, isError)
- 资源访问 (可选) Client → Server: resources/list Client → Server: resources/read (resource URI)
- 提示模板 (可选) Client → Server: prompts/list Client → Server: prompts/get (prompt name, arguments)
3.3 工具定义格式
{
"name": "web_search",
"description": "搜索互联网获取最新信息",
"inputSchema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "搜索关键词"
},
"num_results": {
"type": "integer",
"description": "返回结果数量",
"default": 5
}
},
"required": ["query"]
}
}
四、MCP Server开发实战
4.1 项目结构
my-mcp-server/
├── src/
│ ├── index.ts # 入口文件
│ ├── tools/
│ │ ├── search.ts # 搜索工具
│ │ ├── email.ts # 邮件工具
│ │ └── database.ts # 数据库工具
│ └── types/
│ └── index.ts # 类型定义
├── package.json
├── tsconfig.json
└── README.md
4.2 基础Server实现
import { McpServer } from "@modelcontextprotocol/sdk/server";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio";
import { z } from "zod";
// 创建Server实例 const server = new McpServer({ name: “my-mcp-server”, version: “1.0.0”, });
// 注册搜索工具 server.tool( “web_search”, “搜索互联网获取最新信息”, { query: z.string().describe(“搜索关键词”), num_results: z.number().optional().default(5).describe(“返回结果数量”), }, async ({ query, num_results }) => { // 实现搜索逻辑 const results = await searchEngine.search(query, num_results);
return {
content: [
{
type: "text",
text: JSON.stringify(results, null, 2),
},
],
};
}
);
// 注册邮件工具
server.tool(
“send_email”,
“发送电子邮件”,
{
to: z.string().email().describe(“收件人邮箱”),
subject: z.string().describe(“邮件主题”),
body: z.string().describe(“邮件内容”),
},
async ({ to, subject, body }) => {
try {
await emailClient.send({ to, subject, body });
return {
content: [{ type: “text”, text: “邮件发送成功” }],
isError: false,
};
} catch (error) {
return {
content: [{ type: “text”, text: 发送失败: ${error.message} }],
isError: true,
};
}
}
);
// 启动Server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error(“MCP Server started”);
}
main().catch(console.error);
4.3 资源访问实现
// 注册资源
server.resource(
"customer-data",
"Customers数据库表结构",
async (uri) => {
const tableName = uri.pathname.replace("/", "");
const schema = await db.getTableSchema(tableName);
return {
contents: [
{
uri: uri.toString(),
mimeType: "application/json",
text: JSON.stringify(schema, null, 2),
},
],
};
}
);
// 带参数的动态资源
server.resourceTemplate(
“customer/{id}”,
“单个客户信息”,
async (uri) => {
const customerId = uri.variables.id;
const customer = await db.getCustomer(customerId);
return {
contents: [
{
uri: uri.toString(),
mimeType: "application/json",
text: JSON.stringify(customer, null, 2),
},
],
};
}
);
4.4 提示模板实现
// 注册提示模板
server.prompt(
"analyze_customer",
"分析客户数据",
{
customer_id: z.string().describe("客户ID"),
analysis_type: z
.enum(["summary", "risk", "opportunity"])
.describe("分析类型"),
},
({ customer_id, analysis_type }) => {
return {
description: `分析客户 ${customer_id} 的${analysis_type}情况`,
messages: [
{
role: "user",
content: {
type: "text",
text: `请分析客户ID为 ${customer_id} 的数据,
进行${analysis_type}分析,
包括关键指标、风险点、改进建议。`,
},
},
],
};
}
);
五、MCP Client集成实战
5.1 OpenClaw集成MCP
# config.yaml
mcp:
enabled: true
MCP Server配置
servers:
- name: “filesystem” command: “npx” args: [“-y”, “@modelcontextprotocol/server-filesystem”, “/home/user”]
- name: “web-search” command: “python” args: [“/path/to/search_server.py”] env: SEARCH_API_KEY: “${SEARCH_API_KEY}”
- name: “custom-tools” command: “node” args: [“/path/to/my-mcp-server/dist/index.js”]
安全配置
security: allowed_servers:
- “filesystem”
- “web-search” blocked_tools:
- “delete_file”
- “format_disk”
5.2 Claude Desktop集成MCP
# claude_desktop_config.json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/jin/Projects"]
},
"web-search": {
"command": "uvx",
"args": ["mcp-server-search"],
"env": {
"SEARCH_API_KEY": "your-api-key"
}
},
"slack": {
"command": "node",
"args": ["/path/to/slack-mcp-server/dist/index.js"],
"env": {
"SLACK_BOT_TOKEN": "${SLACK_BOT_TOKEN}",
"SLACK_TEAM_ID": "T0123456789"
}
}
}
}
5.3 编程方式集成
import { Client } from "@modelcontextprotocol/sdk/client";
async function main() { // 创建Client const client = new Client( { name: “my-agent”, version: “1.0.0”, }, { capabilities: { tools: {}, resources: {}, prompts: {}, }, } );
// 连接Server await client.connect( new StdioClientTransport({ command: “node”, args: [“/path/to/my-server/dist/index.js”], }) );
// 列出可用工具 const tools = await client.listTools(); console.log(“可用工具:”, tools.map((t) => t.name));
// 调用工具 const result = await client.callTool({ name: “web_search”, arguments: { query: “OpenClaw AI Agent”, num_results: 3, }, });
console.log(“搜索结果:”, result.content);
// 读取资源 const resources = await client.listResources(); const resourceContent = await client.readResource(resources[0].uri);
// 使用提示模板 const prompts = await client.listPrompts(); const promptResult = await client.getPrompt({ name: “analyze_customer”, arguments: { customer_id: “C001”, analysis_type: “risk”, }, });
// 断开连接 await client.close(); }
main();
六、完整项目示例
6.1 企业知识库MCP Server
// knowledge_base_server.ts
import { McpServer } from "@modelcontextprotocol/sdk/server";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio";
import { z } from "zod";
import { ChromaClient } from "chromadb";
import { OpenAIEmbeddings } from "langchain/embeddings/openai";
// 初始化向量数据库 const chroma = new ChromaClient({ path: “http://localhost:8000” }); const embeddings = new OpenAIEmbeddings();
// 创建Server const server = new McpServer({ name: “knowledge-base”, version: “1.0.0”, });
// 工具1:语义搜索 server.tool( “search_knowledge”, “在企业知识库中搜索相关内容”, { query: z.string().describe(“搜索query”), top_k: z.number().optional().default(5).describe(“返回结果数量”), collection: z.string().optional().default(“documents”).describe(“知识库集合”), }, async ({ query, top_k, collection }) => { try { // 生成query embedding const queryEmbedding = await embeddings.embedQuery(query);
// 查询向量数据库
const collection_obj = chroma.getCollection({
name: collection,
embeddingFunction: embeddings,
});
const results = await collection_obj.query({
queryEmbeddings: [queryEmbedding],
nResults: top_k,
});
// 格式化结果
const formatted = results.documents[0].map((doc, i) => ({
content: doc,
score: results.distances[0][i],
metadata: results.metadatas[0][i],
}));
return {
content: [
{
type: "text",
text: JSON.stringify(formatted, null, 2),
},
],
};
} catch (error) {
return {
content: [{ type: "text", text: `搜索失败: ${error.message}` }],
isError: true,
};
}
}
);
// 工具2:添加文档
server.tool(
“add_document”,
“向知识库添加新文档”,
{
content: z.string().describe(“文档内容”),
metadata: z
.object({
title: z.string(),
source: z.string(),
tags: z.array(z.string()).optional(),
})
.describe(“文档元信息”),
},
async ({ content, metadata }) => {
try {
const collection = chroma.getCollection({
name: “documents”,
embeddingFunction: embeddings,
});
await collection.add({
ids: [crypto.randomUUID()],
documents: [content],
metadatas: [metadata],
});
return {
content: [{ type: "text", text: "文档添加成功" }],
isError: false,
};
} catch (error) {
return {
content: [{ type: "text", text: `添加失败: ${error.message}` }],
isError: true,
};
}
}
);
// 工具3:列出所有文档
server.tool(
“list_documents”,
“列出知识库中的所有文档”,
{
limit: z.number().optional().default(100).describe(“返回数量限制”),
},
async ({ limit }) => {
const collection = chroma.getCollection({
name: “documents”,
embeddingFunction: embeddings,
});
const results = await collection.get({ limit });
return {
content: [
{
type: "text",
text: JSON.stringify(
results.ids.map((id, i) => ({
id,
metadata: results.metadatas[i],
})),
null,
2
),
},
],
};
}
);
// 启动
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
main().catch(console.error);
6.2 在AI Agent中使用
# config.yaml
mcp:
servers:
- name: "knowledge-base"
command: "node"
args: ["/path/to/knowledge_base_server/dist/index.js"]
env:
OPENAI_API_KEY: "${OPENAI_API_KEY}"
agent配置
agent: system_prompt: | 你是一个智能助手,可以访问企业知识库。 可用工具:
- search_knowledge: 搜索知识库
- add_document: 添加文档到知识库
- list_documents: 列出知识库中的文档
当用户询问公司政策、流程、技术文档时,
请先搜索知识库,找到相关信息后再回答。
七、常见问题与解决方案
Q1: MCP Server启动失败?
检查清单:
# 1. 检查Node.js/Python版本
node --version # 需要 18+
python --version # 需要 3.8+
2. 检查依赖安装
npm list @modelcontextprotocol/sdk pip list mcp
3. 检查命令路径
which npx which node
4. 查看错误日志
node server.js 2>&1
Q2: 工具调用超时?
原因:工具执行时间太长。
解决:
# 客户端配置超时
const client = new Client({...}, {
timeout: 30000, // 30秒超时
});
或者在工具实现中返回进度
return { content: [{ type: “text”, text: “处理中,已完成30%…” }], isError: false, progress: 0.3 };
Q3: 安全问题?
建议:
- 限制可用工具(白名单)
- 敏感操作需要二次确认
- 日志记录所有工具调用
- 定期审计权限配置
# config.yaml
mcp:
security:
# 只允许特定工具
allowed_tools:
- "search_knowledge"
- "send_email"
# 禁止危险操作
blocked_tools:
- "delete_all"
- "format_disk"
- "exec_system"
# 需要确认的工具
confirm_tools:
- "send_email"
- "delete_document"
Q4: 多Server冲突?
原因:多个Server定义了同名工具。
解决:使用命名空间
# config.yaml
mcp:
servers:
- name: "knowledge-base"
prefix: "kb_" # 工具名加前缀
command: "node"
args: [...]
- name: "filesystem"
prefix: "fs_" # 避免冲突
command: "node"
args: [...]
八、MCP生态现状与未来
8.1 官方Server
官方提供的MCP Server:
- Filesystem:文件系统操作
- Git:Git版本控制
- Memory:持久化记忆
- SQLite:SQLite数据库
- AWS KB Retrieval:AWS知识库
- Google Maps:地图服务
- Brave Search:网页搜索
8.2 社区Server
社区贡献的Server:
- Slack:Slack消息
- GitHub:GitHub API
- PostgreSQL:PostgreSQL数据库
- Puppeteer:浏览器自动化
- Stripe:支付集成
- Notion:Notion笔记
8.3 未来趋势
趋势1:标准化普及
MCP正在成为AI工具集成的事实标准。
趋势2:企业级支持
会有更多企业级Server:ERP、CRM、数据仓库…
趋势3:工具编排
不只是单个工具调用,而是工作流编排。
九、写在最后:让AI真正”连接”世界
这篇文章,讲的是MCP协议。
我的核心观点:
MCP不只是协议,它是AI Agent的”四肢”。
没有MCP,AI只是个”大脑”,能思考但不能行动。
有了MCP,AI有了”四肢”,能真正感知世界、操作世界。
这就是从”AI助手”到”AI Agent”的跨越。
希望这篇文章,能帮你理解MCP、用好MCP。
让你的AI Agent,真正”活”起来。
完。