MCP协议深度解读:功能对比与最佳实践

2026-06-06阅读 0热度 0
MCP协议

MCP 协议说明与接入设计

这次来聊聊 MCP(Model Context Protocol)——这个在 AI 和工具平台之间越来越热门的协议。它到底是个什么玩意儿?怎么接入?认证授权怎么做?工具中心类平台怎么实现最靠谱?下面一一拆解。

MCP协议说明

  • API 域名:https://api.example.com
  • MCP 地址:https://api.example.com/mcp
  • API Key:tc_xxxxxxxx
  • 用户 ID:user_id
  • Session ID:mcp_sess_xxxxx

1. MCP 是什么

MCP 全称是 Model Context Protocol。它要解决什么问题呢?说白了就是:当外面的 AI 客户端想调用平台里的工具时,大家得有个统一的“接头暗号”。具体来说——

  • 客户端怎么发现服务端有什么工具;
  • 客户端怎么知道每个工具需要什么参数;
  • 客户端怎么调用工具;
  • 服务端怎么控制权限,只暴露该给用户看的工具;
  • 服务端怎么把执行结果平平安安返回给客户端。

在工具中心类平台里,MCP 就是用来让外部 AI 客户端调用平台里各类工具的,比如文本处理、文件解析、视频解析、数据查询、内部自动化工具,不一而足。

MCP 本身不是某个简单的 REST 接口,而是一套基于 JSON-RPC 的协议规范。常见的核心方法有三个:

  • initialize
  • tools/list
  • tools/call

另外,很多平台还会额外提供一个非标准的辅助接口:

  • GET /mcp/info

2. MCP 与普通 HTTP 工具调用的区别

很多工具平台同时支持两种调用方式。听起来有点绕?我们拿实际的例子来对比看看。

2.1 普通 HTTP 工具调用

典型的调用方式:

POST /tools/run X-API-Key: tc_xxxxxxxx Content-Type: application/json {"tool_name": "text_summary","input": {"text": "待处理文本"}}

这种方式直观、简单,适合脚本、后端服务、CI/CD 或普通业务系统。说实话,大部分场景下够用了。

2.2 MCP 工具调用

MCP 则更偏向 AI 客户端的协议化调用。客户端先和服务端建立协议会话,然后通过 JSON-RPC 来发现和调用工具。大致流程是:

initialize → tools/list → tools/call

与普通 HTTP 相比,MCP 更关注这些事:工具发现、工具 schema、客户端能力协商、会话上下文、Agent 生态兼容。

3. MCP 常见传输方式

MCP 可以在不同的传输方式上运行。常见的有:

传输方式说明常见场景
Stdio客户端启动本地进程,通过标准输入输出通信本地工具、本地桌面集成
SSE + HTTP使用 SSE 建立服务端推送通道,再通过 HTTP 发送消息早期远程 MCP 实现
Streamable HTTP新版远程 MCP 推荐方式,通过 HTTP 请求和会话头维持上下文云端工具服务、Web 服务
WebSocket通过双向长连接传输 JSON-RPC 消息实时双向通信场景
Stateless HTTP每个请求独立携带 API Key,无持久会话简化实现、调试或兼容模式

对于工具中心类平台,一般推荐的是:Streamable HTTP + 服务端 Session。原因很直白——它适合远程服务,适合 Nginx / API Gateway 袋里,适合 Docker / Kubernetes 部署,能通过 Redis 维护 session,易于横向扩展,运维复杂度也远低于 WebSocket。

4. /mcp/info 是什么

GET /mcp/info 严格来说不是 MCP 标准的 JSON-RPC 方法,而是平台额外提供的辅助说明接口。它的作用主要是返回:

  • MCP 服务名称;
  • MCP 服务地址;
  • 支持的传输方式;
  • 认证方式;
  • 客户端配置示例;
  • 协议版本;
  • 能力说明。

举个例子,访问 GET /mcp/info 可能会返回这样一个 JSON:

{"name": "tool-center-mcp","endpoint": "https://api.example.com/mcp","auth": {"type": "api_key","header": "X-API-Key"},"transports": ["streamable-http"],"protocolVersion": "2024-11-05"}

4.1 /mcp/info 是否需要认证

答案取决于它返回什么内容。如果只返回通用的服务说明,可以公开访问。但如果返回的信息涉及用户相关数据,比如当前用户、API Key、已订阅工具列表、账号权限等,那就必须校验 X-API-Key 了。

推荐的做法是:/mcp/info 默认只返回通用说明;带有 API Key 时,可以额外返回该 Key 能访问的摘要信息。这样既照顾了公开查询的需求,也兼顾了安全。

5. MCP 三个核心方法

MCP 协议流程主要围绕三个核心方法展开,分别是 initializetools/listtools/call

5.1 initialize

initialize 是 MCP 会话的敲门砖。客户端通过它告诉服务端——自己是哪家的客户端、什么版本、支持哪些协议版本、有哪些能力。说白了就是“我来了,这是我的名片”。

请求示例:

{"jsonrpc": "2.0","id": 1,"method": "initialize","params": {"protocolVersion": "2024-11-05","capabilities": {},"clientInfo": {"name": "example-client","version": "1.0.0"}}}

服务端返回自己的能力和信息:

{"jsonrpc": "2.0","id": 1,"result": {"protocolVersion": "2024-11-05","capabilities": {"tools": {}},"serverInfo": {"name": "tool-center","version": "1.0.0"}}}

initialize 的作用不是调用工具,而是建立协议上下文,让双方互相认识一下。

5.2 tools/list

tools/list 用来获取当前会话下用户可以访问的工具列表。请求十分简单:

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

服务端要根据当前 session 对应的用户和 API Key 去查权限,只返回该用户已订阅并且当前可用的工具。这能确保用户看不到不该看的东西。

响应示例:

{"jsonrpc": "2.0","id": 2,"result": {"tools": [{"name": "text_summary","description": "对文本内容进行摘要","inputSchema": {"type": "object","properties": {"text": {"type": "string","description": "需要摘要的文本"}},"required": ["text"]}}]}}

注意:tools/list 无论如何都不能返回用户未订阅的工具。

5.3 tools/call

tools/call 是真正干活的接口——调用某个具体的工具。

请求示例:

{"jsonrpc": "2.0","id": 3,"method": "tools/call","params": {"name": "text_summary","arguments": {"text": "这是一段需要摘要的文本。"}}}

服务端的处理逻辑需要步步谨慎:

1. 根据 session 获取 user_id / api_key_id; 2. 检查 API Key 是否仍然有效; 3. 检查用户是否订阅了 params.name 对应的工具; 4. 检查工具是否 active; 5. 校验 arguments 是否符合工具 schema; 6. 执行工具; 7. 返回结果。

响应示例:

{"jsonrpc": "2.0","id": 3,"result": {"content": [{"type": "text","text": "摘要结果..."}]}}

如果用户未订阅某个工具,应返回权限错误:

{"jsonrpc": "2.0","id": 3,"error": {"code": -32003,"message": "当前用户未订阅该工具"}}

6. 推荐执行顺序

严格来说,/mcp/info 不属于 MCP 会话本身,它是辅助信息接口。整体推荐顺序如下:

可选:GET /mcp/info ↓ 连接或请求 /mcp,携带 X-API-Key ↓ initialize ↓ tools/list ↓ tools/call

更完整的展开是这样的:

1. 用户在控制台创建 API Key; 2. 用户将 API Key 配置到 MCP 客户端; 3. 客户端访问 /mcp/info 或直接连接 /mcp; 4. 服务端验证 X-API-Key; 5. 服务端创建或恢复 MCP session; 6. 客户端发送 initialize; 7. 服务端返回协议能力; 8. 客户端发送 tools/list; 9. 服务端返回当前用户已订阅的工具; 10. 客户端发送 tools/call; 11. 服务端校验权限并执行工具。

7. MCP Session 是什么

MCP session 可以理解为一次客户端与 MCP 服务端之间的协议会话。它保存的信息包括:

  • 当前连接属于哪个用户;
  • 当前连接使用哪个 API Key;
  • 是否已初始化;
  • 客户端信息;
  • 协议版本;
  • 会话创建时间;
  • 最后活跃时间。

一个典型的 session 结构:

{"session_id": "mcp_sess_xxxxx","user_id": 10001,"api_key_id": 20001,"api_key_prefix": "tc_abcd","initialized": true,"client_info": {"name": "example-client","version": "1.0.0"},"protocol_version": "2024-11-05","created_at": "2026-01-01T00:00:00Z","last_seen_at": "2026-01-01T00:10:00Z"}

需要特别点明的是:session 不是浏览器登录 session,也不是 JWT。它是 MCP 协议层的服务端上下文,由服务端来维护。

8. Session 由谁维护

MCP session 的核心状态应由 服务端 来维护。客户端通常只需要保存 session_id,或者保持连接本身,或者保存 Mcp-Session-Id,或者保存请求 ID 用于匹配响应。

服务端需要保存的内容更多:user_id、api_key_id、是否已认证、是否已初始化、客户端信息、权限上下文、会话 TTL、长连接对象(如果是 SSE / WebSocket)。

有个原则非常重要:不能把用户身份和权限完全交给客户端保存,因为客户端不可信。

9. 不同传输方式下的 Session 维护

9.1 SSE + HTTP

常见的流程是客户端通过 GET 建立 SSE 连接,并通过 POST 发送消息,服务端通过 SSE event 返回结果。

内容维护方
session 状态服务端
session_id客户端保存并携带
SSE 连接对象服务端保存
用户身份与权限服务端

9.2 Streamable HTTP

第一次请求携带 X-API-Key,服务端返回 Mcp-Session-Id,后续请求携带这个头即可。

内容维护方
session 数据服务端
Mcp-Session-Id客户端保存并携带
用户身份与权限服务端
请求/响应每次 HTTP 请求

9.3 WebSocket

WebSocket 连接本身就是会话的载体。

内容维护方
WebSocket 连接双方保持
session 状态服务端
用户身份与权限服务端
请求 ID客户端生成,双方匹配

9.4 Stateless HTTP

如果不实现 session,也可以每次请求都携带 API Key。优点是简单、无需 session 存储、请求天然无状态。但缺点也很明显:不容易维护 initialized 状态、不容易记录客户端信息、不完全符合会话型 MCP 语义、对复杂客户端的兼容性较差。

10. 认证与授权

工具中心类平台通常有两套凭证,各管各的:

场景凭证请求头
管理控制台JWTAuthorization: Bearer
工具调用 / MCPAPI KeyX-API-Key: tc_xxxxxxxx

原则很清晰:管理台用 JWT,工具调用和 MCP 用 API Key;不要把 JWT 交给 MCP 客户端,也不要把 API Key 当成前端登录态使用。

11. API Key 应该在哪一步验证

11.1 /mcp/info

如果只返回通用服务说明,可以不验证。如果返回用户相关信息,必须验证 API Key。

11.2 建立 /mcp 会话时

必须验证 X-API-Key。服务端应检查:API Key 是否存在、是否 active、是否过期、所属用户是否 active、是否允许创建 MCP session。验证成功后创建 session。

11.3 initialize

如果 session 已在连接入口创建,initialize 可复用 session 上下文。它主要负责协议协商,不应承担主要权限判断。

11.4 tools/list

必须基于当前 session 的用户身份进行授权过滤。逻辑是:根据 session.user_id 查询 active subscriptions,只返回已订阅且 active 的工具。

11.5 tools/call

必须再次进行实时授权校验。即使 tools/list 已经过滤过,tools/call 仍然不能信任客户端。因为——用户可能手写 tools/call、可能绕过 tools/list、订阅可能在 session 存活期间被取消、API Key 可能在 session 存活期间被吊销、工具可能临时下线。

服务端应检查:session 是否存在、API Key 是否仍 active、是否过期、用户是否仍 active、是否订阅了对应工具、工具是否 active、arguments 是否符合 schema。

12. 推荐的 Session 存储方案

12.1 单实例开发环境

可以用进程内内存,比如 Map。简单、性能高、易调试。缺点是服务重启 session 丢失、多实例无法共享、不适合生产横向扩容。

12.2 生产环境

推荐使用 Redis,键值如 mcp:session:mcp_sess_xxxxx -> JSON。推荐 TTL 设为 30 分钟到 2 小时,每次请求刷新 TTL。Redis 中的 value 示例:

{"session_id": "mcp_sess_xxxxx","user_id": 10001,"api_key_id": 20001,"api_key_prefix": "tc_abcd","initialized": true,"client_info": {"name": "example-client","version": "1.0.0"},"protocol_version": "2024-11-05","created_at": "2026-01-01T00:00:00Z","last_seen_at": "2026-01-01T00:10:00Z"}

13. 推荐实现:Streamable HTTP + Redis Session

推荐的整体架构:

MCP Client → HTTPS → API Gateway / Nginx → MCP Server → Redis: MCP Session → Database: User / API Key / Subscription / Service → Tool Worker

推荐流程:

GET /mcp/info → 返回 MCP 服务说明 POST /mcp initialize + X-API-Key → 验证 API Key → 创建 Redis session → 返回 Mcp-Session-Id POST /mcp tools/list + Mcp-Session-Id → 读取 Redis session → 查询用户已订阅服务 → 返回工具列表 POST /mcp tools/call + Mcp-Session-Id → 读取 Redis session → 实时校验 API Key / 订阅 / 工具状态 → 执行工具 → 返回结果

14. 客户端配置示例

{"mcpServers": {"tool-center": {"url": "https://api.example.com/mcp","headers": {"X-API-Key": "tc_xxxxxxxx"}}}}

几点说明:

  1. url 指向 MCP 入口;
  2. X-API-Key 是用户在控制台创建的 API Key;
  3. 用户必须先订阅工具;
  4. tools/list 只返回已订阅工具;
  5. tools/call 调用未订阅工具应返回权限错误。

15. Nginx 袋里注意事项

如果使用远程 MCP,需要确保袋里支持长连接或流式响应。示例配置:

location /mcp { proxy_pass http://backend_api; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_buffering off; proxy_cache off; proxy_read_timeout 86400s; proxy_send_timeout 86400s; chunked_transfer_encoding off; }

关键点:

  • SSE / Streamable HTTP 通常需要关闭 buffering;
  • 长连接需要较长的 proxy_read_timeout
  • 如果不使用 WebSocket,Upgrade 头不是必须,但保留通常不影响;
  • 如果使用多实例,session 必须放 Redis,不能只放本地内存。

16. 常见错误与处理

16.1 API Key 无效

建议返回:

{"jsonrpc": "2.0","id": 1,"error": {"code": -32001,"message": "API Key 无效或已过期"}}

HTTP 状态码用 401 Unauthorized。

16.2 未订阅工具

建议返回:

{"jsonrpc": "2.0","id": 3,"error": {"code": -32003,"message": "当前用户未订阅该工具"}}

HTTP 状态码用 403 Forbidden。

16.3 工具不存在

建议返回:

{"jsonrpc": "2.0","id": 3,"error": {"code": -32602,"message": "工具不存在或不可用"}}

16.4 参数错误

建议返回:

{"jsonrpc": "2.0","id": 3,"error": {"code": -32602,"message": "工具参数不合法"}}

17. 安全建议

  1. API Key 只展示一次:创建成功时展示完整 Key;后续只展示前缀;不在前端持久化完整 Key。

  2. MCP 不使用 JWT:JWT 用于管理控制台,MCP / 工具调用使用 API Key。

  3. tools/list 按订阅过滤:不暴露未订阅工具,不暴露内部工具。

  4. tools/call 必须实时校验权限:不能因为 session 已认证就跳过权限检查。

  5. Session 设置 TTL:推荐 30 分钟到 2 小时,每次请求刷新 TTL。

  6. API Key 吊销应尽快生效tools/call 时检查 API Key 状态;可在吊销 Key 时清理相关 MCP session。

  7. 记录审计日志:记录调用时间、API Key 前缀、用户 ID、工具名称、成功/失败状态。不记录完整 API Key。

18. 推荐后端伪代码

18.1 初始化 session

async def handle_initialize(request): api_key = request.headers.get("X-API-Key") key_info = verify_api_key(api_key) if not key_info: return jsonrpc_error(request.id, -32001, "API Key 无效或已过期") session_id = create_session_id() session = { "session_id": session_id, "user_id": key_info.user_id, "api_key_id": key_info.id, "initialized": True, "client_info": request.params.get("clientInfo"), "protocol_version": request.params.get("protocolVersion"), } await redis.setex(f"mcp:session:{session_id}", 7200, json.dumps(session)) return response_with_header( jsonrpc_result(request.id, { "protocolVersion": "2024-11-05", "capabilities": {"tools": {}}, "serverInfo": {"name": "tool-center", "version": "1.0.0"}, }), headers={"Mcp-Session-Id": session_id}, )

18.2 获取工具列表

async def handle_tools_list(request): session = await get_session(request.headers.get("Mcp-Session-Id")) if not session: return jsonrpc_error(request.id, -32002, "MCP session 不存在或已过期") subscriptions = get_active_subscriptions(session["user_id"]) tools = build_tools_from_subscriptions(subscriptions) return jsonrpc_result(request.id, {"tools": tools})

18.3 调用工具

async def handle_tools_call(request): session = await get_session(request.headers.get("Mcp-Session-Id")) if not session: return jsonrpc_error(request.id, -32002, "MCP session 不存在或已过期") tool_name = request.params["name"] arguments = request.params.get("arguments", {}) if not is_api_key_active(session["api_key_id"]): return jsonrpc_error(request.id, -32001, "API Key 已失效") if not has_active_subscription(session["user_id"], tool_name): return jsonrpc_error(request.id, -32003, "当前用户未订阅该工具") validate_tool_arguments(tool_name, arguments) result = await run_tool(tool_name, arguments) return jsonrpc_result(request.id, {"content": [{"type": "text", "text": result}]})

19. 最佳实践总结

推荐设计

传输方式:Streamable HTTP 认证方式:X-API-Key Session 存储:Redis Session 标识:Mcp-Session-Id 工具权限:基于用户订阅实时判断

推荐流程

GET /mcp/info —— 可选,用于查看服务说明 POST /mcp initialize + X-API-Key —— 验证 API Key,创建 session,返回 Mcp-Session-Id POST /mcp tools/list + Mcp-Session-Id —— 使用 session.user_id,返回已订阅工具 POST /mcp tools/call + Mcp-Session-Id —— 使用 session.user_id / api_key_id,再次校验 API Key 和订阅,执行工具

核心原则

身份认证可复用 session;关键操作授权必须实时校验。

20. 一句话说明

MCP 是 AI 客户端与工具服务之间的标准协议。对于远程工具平台,推荐使用 Streamable HTTP,通过 X-API-Key 完成首次认证,通过服务端 session 维持上下文,通过 tools/list 暴露已订阅工具,通过 tools/call 调用工具,并在每次关键操作时实时校验 API Key、订阅和工具状态。

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策