AI 调用 MCP 的全流程教程(基于 Streamable HTTP)

协议基线:MCP 2025-11-25
更新时间:2026-03-25

1. 先分清三层职责

在实际系统里,通常有这 3 个角色:

  • Host:承载 AI 的应用(例如 Codex CLI、IDE 插件、你自己的 Agent 服务)
  • MCP Client:Host 内部的协议执行器(负责发 initialize/tools/list/tools/call
  • MCP Server:能力提供者(真正执行工具逻辑)

一句话:
模型负责“决策”,MCP Client 负责“调用”,MCP Server 负责“执行”。


2. 全流程总览(从用户到结果)

用户输入
  -> Host 收到请求并交给模型
  -> 模型判断需要工具调用
  -> Host 选择 MCP Server
  -> (首次) initialize + notifications/initialized
  -> tools/list(必要时)
  -> tools/call(JSON 或 SSE)
  -> Host 接收工具结果
  -> 结果回注给模型二次推理
  -> 输出最终自然语言答案给用户

说明:
“如何选哪个 MCP Server”属于 Host 的实现策略。
initialize/initialized/tools/list/tools/call 是协议定义的交互动作。


3. 第 0 步:Host 里先有 MCP Server 配置

以 Codex CLI 为例(TOML):

[mcp_servers.chrome-mcp-server]
url = "http://localhost:12306/mcp"

或命令行添加:

codex mcp add chrome-mcp-server --url http://localhost:12306/mcp
codex mcp list

等价的通用 JSON 配置(很多其他客户端使用):

{
  "mcpServers": {
    "chrome-mcp-server": {
      "url": "http://localhost:12306/mcp"
    }
  }
}

它们语义一致,只是“客户端配置格式”不同。


4. 第 1 步:用户输入到模型解析

用户输入示例:

帮我查询上海明天的天气,并给出穿衣建议

Host 把这些信息一起交给模型:

  • 用户输入
  • 会话上下文
  • 当前可用 MCP server(及可用工具缓存)
  • 策略约束(权限、预算、超时、可访问租户等)

模型产出工具意图(内部形态通常类似):

{
  "need_tool": true,
  "candidate_tool": "weather.get_forecast",
  "arguments_draft": {
    "city": "Shanghai",
    "date": "2026-03-26"
  }
}

5. 第 2 步:Host 选择调用哪个 MCP Server

这一步通常按策略执行,不是协议硬编码。

常见策略顺序:

  1. 看本地缓存中“工具名 -> server”映射
  2. 校验权限、租户、数据域匹配
  3. 比较稳定性、延迟、成本
  4. 命中失败时触发 tools/list 重新发现

如果 server 发了 notifications/tools/list_changed

  • 失效本地缓存
  • 重新拉取工具目录
  • 重新做映射

6. 第 3 步:建立 MCP 会话(initialize)

当该 server 还没有会话时,先初始化。

6.1 请求示例

POST /mcp HTTP/1.1
Host: localhost:12306
Content-Type: application/json
Accept: application/json, text/event-stream

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-11-25",
    "capabilities": {
      "tools": {},
      "resources": {},
      "prompts": {}
    },
    "clientInfo": {
      "name": "codex-cli",
      "version": "x.y.z"
    }
  }
}

6.2 响应要点

  • body 返回 InitializeResult
  • 服务端可能在响应头返回 MCP-Session-Id

示意:

HTTP/1.1 200 OK
Content-Type: application/json
MCP-Session-Id: a4f0a1de-xxxx

6.3 发送 initialized 通知

初始化成功后,客户端必须发送:

{
  "jsonrpc": "2.0",
  "method": "notifications/initialized"
}

通知通常无 id,服务端可回 202 Accepted


7. 第 4 步:拉取工具目录(tools/list)

请求:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list",
  "params": {
    "cursor": null
  }
}

返回内容通常包含:

  • name
  • description
  • inputSchema
  • 可选 outputSchema
  • 可选分页 nextCursor

Host 的关键动作:

  • inputSchema 做参数校验
  • 对参数做类型修正(如日期、枚举、单位)
  • 缓存工具目录以减少后续发现开销

8. 第 5 步:调用工具(tools/call)

请求示例:

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "weather.get_forecast",
    "arguments": {
      "city": "Shanghai",
      "date": "2026-03-26"
    }
  }
}

8.1 Streamable HTTP 下的两种返回形态

服务端可返回:

  1. application/json(一次性返回)
  2. text/event-stream(SSE,流式返回)

8.2 SSE 返回时会发生什么

SSE 可能先发进度通知,再发最终 response。

示意:

event: message
data: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progress":0.5}}

event: message
data: {"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"18-23C, cloudy"}],"isError":false}}

重要点:

  • 断开流不等于取消任务
  • 要取消应发 notifications/cancelled
  • 若服务端支持恢复,可 GET /mcp + Last-Event-ID 续流

9. 第 6 步:结果回注模型并生成最终答复

Host 收到 tools/call 的结果后,会把结果作为新上下文再喂给模型。

模型第二次推理通常做 3 件事:

  1. 提取工具核心信息
  2. 结合用户目标重写成自然语言
  3. 决定是否继续调用下一个工具

例如:

  • 工具原始结果:18-23C, cloudy
  • 模型输出给用户:
    上海明天多云,18~23℃。建议薄外套+长裤,早晚加一层。

10. 第 7 步:错误处理、重试与降级

MCP 调用常见两类错误:

  1. JSON-RPC error
  • 协议错误、参数结构错误、方法不存在
  • 处理:立刻修正请求,不要盲重试
  1. result.isError = true
  • 工具业务执行失败(例如第三方 API 超时)
  • 处理:可重试、切换工具、或让模型改参数后重试

推荐重试策略:

  • 网络类错误:指数退避 + 抖动(如 200ms, 800ms, 1600ms)
  • 幂等工具可自动重试
  • 非幂等工具需幂等键或人工确认

11. 第 8 步:会话管理与收尾

正常情况下会话可复用,减少反复握手成本。

每次请求应携带(如适用):

  • MCP-Session-Id
  • MCP-Protocol-Version

不再需要会话时可主动结束:

DELETE /mcp
MCP-Session-Id: a4f0a1de-xxxx

如果服务端返回 404(会话失效):

  • 重新 initialize
  • 发送 notifications/initialized
  • 恢复业务调用

12. 完整时序图

MCP Server MCP Client Model Host(App) User MCP Server MCP Client Model Host(App) User alt [JSON] [SSE] 自然语言请求 用户输入+上下文+可用工具 建议调用 tool X(args) 执行工具调用计划 initialize InitializeResult + (optional MCP-Session-Id) notifications/initialized tools/list 工具目录(JSON Schema) tools/call(name,args) result progress events final result 工具执行结果 工具结果回注 最终答案 返回结果

13. 最小可观测字段(建议日志)

建议每次调用都记录这些字段,排障效率会明显提升:

  • trace_id
  • conversation_id
  • server_name
  • method(initialize/tools/list/tools/call)
  • request_id(JSON-RPC id)
  • latency_ms
  • retry_count
  • http_status
  • jsonrpc_error_code(若有)
  • is_error(工具业务失败标记)

14. 安全与边界控制

  1. 仅信任白名单 MCP Server
  2. 高风险工具(写库/下单/删除)增加确认门禁
  3. 参数级策略校验(日期范围、金额上限、资源路径)
  4. HTTP 传输启用认证(Bearer/OAuth 等)
  5. 远程服务做 Origin 校验与速率限制
  6. 工具执行设置超时与资源配额

15. 常见误解

误解 1:模型直接调用了后端系统

不是。模型只做决策,真正发请求的是 Host 内的 MCP Client。

误解 2:tools/list 每次都必须调

不是。多数 Host 会缓存,收到 list_changed 再刷新。

误解 3:SSE 断开等于任务取消

不是。取消要走 notifications/cancelled

误解 4:协议规定了“如何选择哪个 server”

不是。选择策略由 Host 实现,协议只定义交互方法与消息格式。


16. 一句话回顾

AI 调用 MCP 的本质是:

  • 模型做“工具决策”
  • MCP Client 做“协议调用”
  • MCP Server 做“能力执行”
  • Host 把结果再次交给模型生成最终用户答案

从工程角度看,关键成功点是:
正确会话生命周期 + 可靠工具目录缓存 + 可恢复流式调用 + 严格错误与安全控制


17. 附录 A:用 curl 手工跑通一遍

下面示例假设你的 MCP endpoint 是:

http://localhost:12306/mcp

17.1 initialize

curl -i -X POST http://localhost:12306/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{
    "jsonrpc":"2.0",
    "id":1,
    "method":"initialize",
    "params":{
      "protocolVersion":"2025-11-25",
      "capabilities":{"tools":{}},
      "clientInfo":{"name":"manual-client","version":"0.0.1"}
    }
  }'

你需要关注两点:

  • 响应 body 是否有 result
  • 响应头是否有 MCP-Session-Id

17.2 notifications/initialized

如果上一步拿到了 session id,后续请求建议带上它:

curl -i -X POST http://localhost:12306/mcp \
  -H 'Content-Type: application/json' \
  -H 'MCP-Session-Id: <SESSION_ID>' \
  -d '{
    "jsonrpc":"2.0",
    "method":"notifications/initialized"
  }'

17.3 tools/list

curl -s -X POST http://localhost:12306/mcp \
  -H 'Content-Type: application/json' \
  -H 'MCP-Session-Id: <SESSION_ID>' \
  -d '{
    "jsonrpc":"2.0",
    "id":2,
    "method":"tools/list",
    "params":{"cursor":null}
  }'

拿到 name + inputSchema 后,再构造工具参数。

17.4 tools/call

curl -s -X POST http://localhost:12306/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -H 'MCP-Session-Id: <SESSION_ID>' \
  -d '{
    "jsonrpc":"2.0",
    "id":3,
    "method":"tools/call",
    "params":{
      "name":"<TOOL_NAME>",
      "arguments":{}
    }
  }'

如果返回 text/event-stream,你会看到逐条事件;最终应有 id=3 的 response。


18. 附录 B:常见排障清单(含 WSL)

18.1 initialize 就失败

优先排查:

  1. URL 是否完整(必须到 /mcp
  2. Server 是否真的在监听该端口
  3. 请求头 Content-Type 是否为 application/json
  4. 是否存在代理、证书或防火墙拦截

18.2 WSL 下 127.0.0.1localhost 不一致

在某些 Windows + WSL 组合场景里,你会遇到:

  • http://localhost:12306/mcp 可通
  • http://127.0.0.1:12306/mcp 不通

这是由本机回环映射、端口转发策略、以及服务绑定地址共同决定的,不是 MCP 协议问题。
实务上遵循两条:

  1. 哪个地址可用就用哪个(优先稳定)
  2. 服务端尽量明确绑定 0.0.0.0 或期望网卡,并配合本机防火墙策略

18.3 tools/call 返回了但模型没给答案

常见原因:

  • Host 没把工具结果回注给模型
  • 工具结果字段结构异常(模型无法消费)
  • 触发了安全策略拦截(高风险工具被阻断)

18.4 如何快速确认是“协议问题”还是“业务问题”

判断原则:

  • 有 JSON-RPC error:先按协议层排查(方法名、参数结构、会话头)
  • result.isError=true:优先排查业务层(第三方 API、鉴权、数据源)

19. 官方规范入口(建议收藏)

  • MCP 基础规范(2025-11-25):https://modelcontextprotocol.io/specification/2025-11-25/basic
  • 生命周期(initialize / initialized):https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle
  • 传输(Streamable HTTP):https://modelcontextprotocol.io/specification/2025-11-25/basic/transports
  • Tools(tools/list / tools/call):https://modelcontextprotocol.io/specification/2025-11-25/server/tools
  • 架构角色(Host / Client / Server):https://modelcontextprotocol.io/specification/2025-11-25/architecture
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐