2026-05-15AIMCPAgent协议架构

MCP协议深度解析:让AI助手真正「操控」外部世界的架构实战

过去一年多,我们看到无数「AI助手」被包装成产品,但它们本质上还是 **文本进、文本出** 的哑终端——能聊天,但不能干活。Cursor 能读写文件,Claude Desktop 能用工具,但这背后依赖的通信协议长期以来都是各家自研、互不兼容。直到去年 Anthropic 正式推出 **MCP(Model Context Protocol)**,一个开放的标

biluo·9426 words

# MCP协议深度解析:让AI助手真正「操控」外部世界的架构实战

过去一年多,我们看到无数「AI助手」被包装成产品,但它们本质上还是 文本进、文本出 的哑终端——能聊天,但不能干活。Cursor 能读写文件,Claude Desktop 能用工具,但这背后依赖的通信协议长期以来都是各家自研、互不兼容。直到去年 Anthropic 正式推出 MCP(Model Context Protocol),一个开放的标准开始改变这个局面。

本文从协议设计角度深入拆解 MCP,然后手把手实现一个能实际干活的 MCP 服务器,涵盖资源管理、工具调用、采样(Sampling)三大核心能力。

MCP 是什么?为什么需要它

MCP 的核心设计目标:让 LLM 通过统一接口访问外部世界——文件系统、数据库、API、代码仓库,所有这些原本需要人类手动操作的东西,AI 应该在指令下直接完成。

传统方案的问题:

  • 每个 AI 平台自研一套 tool-calling 协议,Claude Tools、OpenAI Functions、ChatGPT Plugins 各不相通
  • 开发者每次换模型都要重写 tool integration 层
  • 工具注册分散,没有统一的生命周期管理

MCP 解决的是 协议标准化 + 双向通信 + 有状态会话 三个问题。它基于 JSON-RPC 2.0,采用 stdio(标准输入/输出)或 HTTP + SSE 两种传输层,其中 stdio 是本地 integration 的主流选择。

协议架构:三层抽象

MCP 协议分三层:

`

┌──────────────────────────────────────┐

│ MCP Client │ ← 运行在 AI 主机侧(Claude Desktop、Cursor 等)

│ (发送请求 / 接收响应 / 管理会话) │

└──────────────┬───────────────────────┘

│ JSON-RPC 2.0 over stdio or HTTP/SSE

┌──────────────▼───────────────────────┐

│ MCP Server │ ← 运行在你自己的基础设施上

│ (暴露 Tools / Resources / 采样逻辑) │

└──────────────┬───────────────────────┘

┌──────────────▼───────────────────────┐

│ Your Backend │ ← 文件系统、数据库、GitHub API...

│ (真正执行操作的地方) │

└──────────────────────────────────────┘

`

三个核心原语:

原语 作用 通信方向
**Resources** 向 AI 暴露可读取的数据(文件、API 响应、数据库记录) Server → Client
**Tools** AI 可调用执行的函数(有副作用) Client → Server
**Sampling** AI 请求 Server 帮助它生成内容(LLM-as-a-tool) 双向

实现一个完整的 MCP Server

我们用 TypeScript + Node.js 实现一个管理 GitHub 仓库的 MCP Server,支持:

1. 列出仓库issues(Resource)

2. 创建 issue / 评论(Tool)

3. AI 请求 Server 代为生成回复草稿(Sampling)

项目结构

`

mcp-github-server/

├── package.json

├── tsconfig.json

└── src/

├── index.ts # MCP server 入口

├── server.ts # MCP 服务器逻辑

├── resources.ts # Resource 暴露

├── tools.ts # Tool 定义

└── sampling.ts # Sampling 处理

`

核心:Server 初始化

`typescript

// src/server.ts

import { Server } from '@modelcontextprotocol/sdk/server';

import { StdioServerTransport } from '@modelcontextprotocol/sdk/server-stdio';

import {

CallToolRequestSchema,

ListResourcesRequestSchema,

ListToolsRequestSchema,

ReadResourceRequestSchema,

} from '@modelcontextprotocol/sdk/types';

const server = new Server(

{

name: 'github-mcp-server',

version: '1.0.0',

},

{

capabilities: {

resources: {}, // 声明支持 resources

tools: {}, // 声明支持 tools

sampling: {}, // 声明支持 sampling

},

}

);

`

关键点:Capabilities 是在握手阶段告知客户端我们支持哪些能力,客户端据此决定暴露哪些 UI。缺少这个声明,Claude Desktop 不会显示对应的功能面板。

定义 Resources

`typescript

// src/resources.ts

import { Resource } from '@modelcontextprotocol/sdk/types';

export const githubResources: Resource[] = [

{

uri: 'github://repositories',

name: 'Repositories',

description: 'List of GitHub repositories for the authenticated user',

mimeType: 'application/json',

},

{

uri: 'github://issues/{owner}/{repo}',

name: 'Repository Issues',

description: 'Open issues for a specific repository',

mimeType: 'application/json',

},

];

// Resource handler

server.setRequestHandler(ReadResourceRequestSchema, async (request) => {

const uri = request.params.uri;

if (uri === 'github://repositories') {

const repos = await listRepositories();

return { contents: [{ uri, mimeType: 'application/json', text: JSON.stringify(repos) }] };

}

if (uri.startsWith('github://issues/')) {

const [, , owner, repo] = uri.split('/');

const issues = await listIssues(owner, repo);

return { contents: [{ uri, mimeType: 'application/json', text: JSON.stringify(issues) }] };

}

throw new Error(Unknown resource URI: ${uri});

});

`

模板 URI 模式github://issues/{owner}/{repo} 是模板,客户端需要根据用户上下文填充参数后请求。这比固定 URI 更灵活,但需要文档清晰说明参数格式。

定义 Tools

`typescript

// src/tools.ts

import { Tool } from '@modelcontextprotocol/sdk/types';

export const githubTools: Tool[] = [

{

name: 'create_issue',

description: 'Create a new issue in a GitHub repository',

inputSchema: {

type: 'object',

properties: {

owner: { type: 'string', description: 'Repository owner (user or org)' },

repo: { type: 'string', description: 'Repository name' },

title: { type: 'string', description: 'Issue title' },

body: { type: 'string', description: 'Issue body content (Markdown supported)' },

labels: { type: 'array', items: { type: 'string' }, description: 'Label names to apply' },

},

required: ['owner', 'repo', 'title'],

},

},

{

name: 'add_issue_comment',

description: 'Add a comment to an existing GitHub issue',

inputSchema: {

type: 'object',

properties: {

owner: { type: 'string' },

repo: { type: 'string' },

issue_number: { type: 'number' },

body: { type: 'string', description: 'Comment body (Markdown supported)' },

},

required: ['owner', 'repo', 'issue_number', 'body'],

},

},

];

// Tool handler

server.setRequestHandler(CallToolRequestSchema, async (request) => {

const { name, arguments: args } = request.params;

try {

switch (name) {

case 'create_issue': {

const issue = await createGitHubIssue(args);

return {

content: [

{ type: 'text', text: JSON.stringify({ success: true, issue }) },

],

};

}

case 'add_issue_comment': {

const comment = await addComment(args);

return {

content: [{ type: 'text', text: JSON.stringify({ success: true, comment }) }],

};

}

default:

throw new Error(Unknown tool: ${name});

}

} catch (error) {

return {

content: [{ type: 'text', text: Error: ${error} }],

isError: true,

};

}

});

`

Sampling:让 Server 帮 AI 生成内容

这是 MCP 最有趣的能力。当 AI 发现自己在某些任务上不够擅长时(比如写英文营销文案),它可以请求 MCP Server 调用自己的 LLM 来生成:

`typescript

// src/sampling.ts

import { CreateMessageRequestSchema } from '@modelcontextprotocol/sdk/types';

server.setRequestHandler(CreateMessageRequestSchema, async (request) => {

const { prompt, systemPrompt, maxTokens, temperature } = request.params;

// Server用自己的LLM API生成内容,回传给AI主机

const response = await callMyLLM({

model: 'claude-sonnet-4-20250514',

messages: [

...(systemPrompt ? [{ role: 'system', content: systemPrompt }] : []),

{ role: 'user', content: prompt },

],

max_tokens: maxTokens ?? 1024,

temperature: temperature ?? 0.7,

});

return {

content: [{ type: 'text', text: response.content[0].text }],

model: 'claude-sonnet-4-20250514',

stopReason: 'end_turn',

};

});

`

Sampling 的实际价值场景

  • AI 收到一条中文用户反馈,需要翻译成英文后发到 GitHub Issue → 请求 Sampling 帮忙润色
  • AI 需要对自己生成的技术文档做一次「资深工程师 review」→ Sampling 调用专用模型评分
  • 多 Agent 协作时,主 Agent 分发任务给子 Agent,子 Agent 通过 Sampling 获取主 Agent 的补充上下文

入口文件

`typescript

// src/index.ts

import { StdioServerTransport } from '@modelcontextprotocol/sdk/server-stdio';

import { server } from './server';

async function main() {

const transport = new StdioServerTransport();

await server.connect(transport);

console.error('GitHub MCP Server running on stdio...');

}

main().catch(console.error);

`

配置文件(Claude Desktop 用)

`json

// ~/.config/claude-desktop.json 或者项目内的 .mcp.json

{

"mcpServers": {

"github": {

"command": "node",

"args": ["./dist/index.js"],

"env": {

"GITHUB_TOKEN": "ghp_xxxxxxx"

}

}

}

}

`

深度:协议生命周期与管理

MCP Session 的完整生命周期:

`

1. Transport 连接建立(stdio 或 HTTP/SSE)

2. Client 发送 initialize 请求(包含客户端名、版本、支持的 Capability)

3. Server 回复 initialize,声明自己的 Capability

4. 双方进入 ready 状态,可以互相发请求

5. 正常通信:Client 调用 tools / Server 推送 resources / 双向 sampling

6. 任意一方发送 terminate,或者 transport 断开 → Session 结束

`

Session 管理有几个关键设计

  • **幂等性**:所有请求都有 `method` + `id`,响应通过 `id` 匹配,允许重试
  • **Progress Notification**:长时间操作(如克隆大型仓库)可以分片返回进度,避免超时
  • **Error 格式统一**:所有错误都是 JSON-RPC Error Object,有 `code` 和 `message`,便于调试

实战:连接 Cursor 和 Claude Desktop

Cursor 配置(项目级 .cursor/mcp.json):

`json

{

"mcpServers": {

"github": {

"command": "npx",

"args": ["tsx", "src/index.ts"],

"env": {

"GITHUB_TOKEN": "${GITHUB_TOKEN}"

}

}

}

}

`

配置完成后,在 Cursor 的 AI 聊天框里可以直接说:「帮我看看这个仓库最近有哪些未解决的 bug」,AI 会先通过 ListResources 获取 issues,再通过 ReadResource 读取详细内容,整个过程对用户透明。

调试技巧:在 Claude Desktop 里,按住 Option+Shift+双击 MCP Server 名称,可以打开内部日志面板,查看每条 JSON-RPC 消息的收发详情。这对排查 tool 调用失败特别有用。

为什么 MCP 比 OpenAI Functions 更适合复杂 Agent 场景

维度 OpenAI Functions MCP
适用场景 单模型 API 调用 复杂 Agent 多工具协作
工具发现 Schema 内嵌,扩展困难 Capability 声明,动态发现
资源暴露 无原生支持 Resource 原语,支持模板 URI
双向通信 单向(Client→Server) 双向(Server 可主动推送)
采样能力 Server 可反向生成内容给 AI
传输层 HTTP only stdio + HTTP/SSE,可本地可远程

OpenAI Functions 是 函数调用的格式规范,解决的是「怎么描述一个函数」的问题。MCP 是 完整的 RPC 协议栈,解决的是「怎么构建一个工具生态系统」的问题。两者不在同一层次。

总结:MCP 的生态位

MCP 正在成为 AI Native Tooling 的 USB-C:以前各家设备的充电线和数据接口各不相同,现在一个标准接口搞定一切。对开发者而言,学一个协议,可以同时支持 Claude Desktop、Cursor、Zed、Warp 所有主流 AI 开发工具。

对架构师而言,MCP 的价值在于 把 AI 和真实世界解耦:AI 不需要内置所有工具的集成代码,它只需要会说话(Speak MCP),剩下的由 MCP Server 负责连接具体的业务系统。

这才是 Agent 架构该有的样子。