三层模型
MCP 的架构由三个角色组成,每个角色的职责严格分离:
Host(宿主)
→ 运行 LLM 推理的应用:Claude Desktop、Claude Code、自研 Agent
→ 管理与一个或多个 MCP Server 的连接
→ 决定把哪些工具/资源暴露给 LLM
Client(客户端,内嵌于 Host)
→ 与单个 MCP Server 保持一个 1:1 的连接
→ 按 JSON-RPC 2.0 协议收发消息
→ 维护会话状态(capabilities、已发现的工具列表)
Server(服务端,独立进程)
→ 暴露三类能力:Tools / Resources / Prompts
→ 通过标准输入输出(stdio)或 HTTP 与 Client 通信
→ 一个 Server 可以同时被多个 Host 连接
Host 是用户看到的 AI 应用,Client 是应用内部的协议适配层,Server 是工具的提供方。
三类能力
MCP Server 暴露三类能力:
Tools(工具) → LLM 主动调用的功能(action)
→ 示例:搜索 Jira、执行 SQL、发送邮件
→ 由 LLM 在推理过程中决定何时调用
Resources(资源)→ LLM 可读取的数据源(data)
→ 示例:当前 Sprint 状态、代码库文件树
→ Host 决定何时注入到上下文
Prompts(提示词)→ 预定义的 Prompt 模板(template)
→ 示例:Bug 分析报告模板、代码 Review 模板
→ 用户或 Host 直接调用,填入参数后生成完整 Prompt
传输方式
Client 与 Server 之间的通信支持三种传输方式:
stdio(标准输入输出)
→ Server 作为子进程运行,通过 stdin/stdout 交换 JSON-RPC 消息
→ 最简单,本地开发首选
→ Claude Code 接入 MCP Server 的默认方式
HTTP + SSE(Server-Sent Events)
→ Server 作为独立 HTTP 服务运行
→ Client → Server:HTTP POST
→ Server → Client:SSE 流(支持 Server 主动推送)
→ 适合远程 Server、多 Client 共享
Streamable HTTP(新)
→ HTTP POST + 可选 SSE 流
→ 同时支持同步调用和流式推送
→ 2025 年规范更新后的推荐远程方案
本文 demo 使用 stdio 传输,最直观地展示协议本身。
完整协议交换
下面是用真实 MCP Server 跑出的 8 轮 JSON-RPC 消息,从头到尾展示一次完整的协议交互。
第 1 步:initialize(能力协商)
每次会话的第一条消息,双方交换自己支持的能力。
Client → Server(请求):
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"roots": {"listChanged": true},
"sampling": {}
},
"clientInfo": {
"name": "demo-client",
"version": "1.0.0"
}
}
}
Server → Client(响应):
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"experimental": {},
"prompts": {"listChanged": false},
"resources": {"subscribe": false, "listChanged": false},
"tools": {"listChanged": false}
},
"serverInfo": {
"name": "mcp-protocol-demo",
"version": "1.13.1"
}
}
}
解读:
protocolVersion:两端协商使用的协议版本capabilities:双方各自声明支持什么。Server 这里说tools.listChanged: false,意味着工具列表不会动态变化,Client 不需要订阅变更通知id字段:initialize是请求-响应类型,有id
initialize 完成后,Client 发一条通知(notification)确认就绪:
{"jsonrpc": "2.0", "method": "notifications/initialized"}
注意这条消息没有 id 字段——这是 JSON-RPC 的 Notification 类型,fire-and-forget,不等响应。
第 2 步:tools/list(工具发现)
请求:
{"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {}}
响应:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "echo",
"description": "Repeats the input message back. Useful for testing connectivity.",
"inputSchema": {
"type": "object",
"properties": {
"message": {"type": "string", "description": "The message to echo back"}
},
"required": ["message"]
}
},
{
"name": "add",
"description": "Adds two numbers and returns the result.",
"inputSchema": {
"type": "object",
"properties": {
"a": {"type": "number", "description": "First number"},
"b": {"type": "number", "description": "Second number"}
},
"required": ["a", "b"]
}
}
]
}
}
解读: inputSchema 是标准 JSON Schema,Host 把它传给 LLM 作为工具定义。LLM 读这个 Schema 决定什么时候调用工具、填什么参数——和 Function Calling 的 schema 结构完全一致。
第 3-4 步:tools/call(工具调用)
echo 调用:
// 请求
{
"jsonrpc": "2.0", "id": 3, "method": "tools/call",
"params": {"name": "echo", "arguments": {"message": "Hello from MCP client!"}}
}
// 响应
{
"jsonrpc": "2.0", "id": 3,
"result": {
"content": [{"type": "text", "text": "Echo: Hello from MCP client!"}],
"isError": false
}
}
add 调用:
// 请求
{
"jsonrpc": "2.0", "id": 4, "method": "tools/call",
"params": {"name": "add", "arguments": {"a": 42, "b": 58}}
}
// 响应
{
"jsonrpc": "2.0", "id": 4,
"result": {
"content": [{"type": "text", "text": "42 + 58 = 100"}],
"isError": false
}
}
解读: 响应结构里有两个重要字段:
content:数组,支持多个内容块(text / image / resource)isError:布尔值。工具执行失败时设为true,结果里写错误信息。工具报错是正常响应(result),不是 JSON-RPC 协议错误(error),让 LLM 能读到错误详情并自适应
第 5-6 步:resources/list + resources/read
列举资源:
// 响应
{
"result": {
"resources": [{
"name": "Server Information",
"uri": "info://server-info",
"description": "Metadata about this MCP server: name, version, capabilities",
"mimeType": "application/json"
}]
}
}
读取资源:
// 请求
{"method": "resources/read", "params": {"uri": "info://server-info"}}
// 响应
{
"result": {
"contents": [{
"uri": "info://server-info",
"mimeType": "text/plain",
"text": "{\"name\": \"mcp-protocol-demo\", \"version\": \"1.0.0\", ...}"
}]
}
}
解读: URI scheme 是自定义的(info://),Server 自己定义格式。常见 scheme:file://(本地文件)、jira://(Jira 工单)、github://(代码仓库)。Resources 是数据层,不执行动作,只读取。
第 7-8 步:prompts/list + prompts/get
列举模板:
{
"result": {
"prompts": [{
"name": "summarize",
"description": "Summarize a piece of text concisely",
"arguments": [
{"name": "text", "description": "The text to summarize", "required": true},
{"name": "max_words", "description": "Maximum words in the summary", "required": false}
]
}]
}
}
渲染模板(填入参数):
// 请求
{
"method": "prompts/get",
"params": {
"name": "summarize",
"arguments": {
"text": "MCP defines a standard protocol for connecting AI models to tools and data sources.",
"max_words": "20"
}
}
}
// 响应
{
"result": {
"description": "Summarization prompt",
"messages": [{
"role": "user",
"content": {
"type": "text",
"text": "Summarize the following text in at most 20 words:\n\nMCP defines a standard protocol for connecting AI models to tools and data sources."
}
}]
}
}
解读: Prompts 是服务端维护的 Prompt 模板。Host 调用 prompts/get 得到渲染后的消息列表,可以直接用于构建 LLM 的 messages。企业用途:统一维护各类业务分析模板,所有 Agent 共用同一份。
JSON-RPC 2.0 消息类型总结
MCP 用的是标准 JSON-RPC 2.0,消息分三类:
请求(Request):有 id,需要响应
{"jsonrpc":"2.0", "id": N, "method": "...", "params": {...}}
响应(Response):有 id,与请求对应
{"jsonrpc":"2.0", "id": N, "result": {...}} ← 成功
{"jsonrpc":"2.0", "id": N, "error": {...}} ← JSON-RPC 级错误
通知(Notification):无 id,fire-and-forget
{"jsonrpc":"2.0", "method": "notifications/initialized"}
工具执行失败不使用 error 响应——那是 JSON-RPC 传输层的错误(如方法不存在)。工具执行失败通过 result.isError: true 表达,让 LLM 能读到错误内容并做出决策。
运行本文 Demo
conda activate llm_base
pip install mcp
cd llm-in-action/mcp-02-protocol
# 方式 A:命令行查看原始 JSON-RPC 消息(8 步协议交互)
python demo_protocol_client.py
# 方式 B:MCP Inspector 可视化界面(需要 Node.js)
npx @modelcontextprotocol/inspector python demo_mcp_server.py
参考资料
- MCP 协议规范
- JSON-RPC 2.0 规范
- 本系列完整 Demo 代码:mcp-02-protocol
欢迎访问 PrimeSkills —— 一个精心策划的 AI Agent 与技能市场,所有内容均经过真实企业级工作流验证。没有噱头,只有真正有效的东西。
更多实用知识和有趣产品,欢迎访问我的个人主页