本文聚焦 MCP Gateway 的上下游通信:客户端、网关、后端 MCP Server 如何交换消息,以及网关需要负责哪些治理
1. MCP 与网关的位置
MCP(Model Context Protocol)让 AI 客户端通过统一协议发现和使用外部能力:
- Tools:可执行动作,如查询订单、创建工单、调用内部 API;
- Resources:可读取上下文,如知识库、文件、配置;
- Prompts:可复用提示词模板。
MCP 客户端与服务端以 UTF-8 编码的 JSON-RPC 2.0 通信。网关对上是稳定的 MCP Server,对下可以路由、聚合多个 MCP Server 或内部系统。
AI Client / IDE / Agent
│ MCP / JSON-RPC
▼
MCP Gateway
│ 路由、认证、鉴权、审计、限流、协议适配
▼
多个 MCP Server / 内部 API / 数据库
2. JSON-RPC 的统一消息格式
请求 Request
请求必须带 id,用来关联响应。
{
"jsonrpc": "2.0",
"id": "req-001",
"method": "tools/call",
"params": {}
}
成功响应 Response
响应的 id 与请求一致,业务结果放进 result。
{
"jsonrpc": "2.0",
"id": "req-001",
"result": {}
}
通知 Notification
通知不带 id,接收方不返回响应;适合初始化完成、工具列表变化、进度更新等事件。
{
"jsonrpc": "2.0",
"method": "notifications/initialized"
}
协议错误 Error
请求格式、方法或参数不合法等协议层问题,用顶层 error 返回。
{
"jsonrpc": "2.0",
"id": "req-001",
"error": {
"code": -32602,
"message": "Invalid params",
"data": { "field": "orderId", "reason": "required" }
}
}
3. 连接与初始化
调用顺序应为:initialize → 初始化响应 → notifications/initialized → 正常业务调用。初始化时协商版本和能力;之后只能使用双方已协商的能力。
客户端初始化
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": {
"name": "company-agent",
"version": "1.0.0"
}
}
}
网关返回能力
网关只应声明真正支持且允许当前调用方使用的能力。
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-06-18",
"capabilities": {
"tools": { "listChanged": true },
"resources": { "listChanged": true }
},
"serverInfo": {
"name": "company-mcp-gateway",
"version": "1.0.0"
},
"instructions": "敏感写操作需要用户确认。"
}
}
{
"jsonrpc": "2.0",
"method": "notifications/initialized"
}
4. Tool 交流格式
工具发现:tools/list
客户端先获得工具清单。网关可在此执行多服务聚合、工具名规范化、租户和 RBAC 过滤。
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}
建议对外暴露带业务前缀的稳定工具名,避免下游服务重名:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "order.query_order",
"title": "查询订单",
"description": "根据订单号查询订单状态、金额和收货信息。仅允许读取当前租户订单。",
"inputSchema": {
"type": "object",
"properties": {
"orderId": {
"type": "string",
"description": "订单号,例如 ORD-20260726-001"
}
},
"required": ["orderId"],
"additionalProperties": false
}
}
]
}
}
工具定义应至少说明:
| 字段 | 约定 |
|---|---|
name | 稳定、唯一、机器使用的标识;不要随意改名。 |
title | 面向人的短名称。 |
description | 何时可调用、会做什么、权限与副作用;模型主要靠它选择工具。 |
inputSchema | JSON Schema,声明必填字段、类型、枚举和边界。 |
outputSchema | 可选但推荐,为稳定结果提供结构化约束。 |
工具调用:tools/call
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "order.query_order",
"arguments": {
"orderId": "ORD-20260726-001"
}
}
}
工具成功结果
content 供模型和用户阅读;structuredContent 供程序稳定解析。网关推荐同时返回两者。
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "订单 ORD-20260726-001 已支付,金额 ¥99.00。"
}
],
"structuredContent": {
"orderId": "ORD-20260726-001",
"status": "PAID",
"amount": 99.0,
"currency": "CNY"
},
"isError": false
}
}
工具执行失败
当工具调用格式正确、但下游 API 或业务执行失败时,使用 result.isError: true,不要伪装成协议错误。
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "未找到订单 ORD-20260726-001。请确认订单号,或查询最近订单。"
}
],
"isError": true
}
}
5. Resources 与 Prompts
Resource
Resource 是可读取、可引用的上下文,不是执行动作。URI 是稳定标识。
{
"jsonrpc": "2.0",
"id": 4,
"method": "resources/read",
"params": {
"uri": "company://knowledge/refund-policy"
}
}
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"contents": [
{
"uri": "company://knowledge/refund-policy",
"mimeType": "text/markdown",
"text": "# 退款政策\n..."
}
]
}
}
Prompt
Prompt 是参数化提示词模板,例如生成售后回复。它不应成为绕过用户确认来执行高风险操作的通道。
{
"jsonrpc": "2.0",
"id": 5,
"method": "prompts/get",
"params": {
"name": "reply_to_refund_request",
"arguments": { "tone": "professional" }
}
}
6. 网关约定
命名与路由
对外命名采用 <domain>.<action>:
order.query_order
order.create_refund
crm.search_customer
knowledge.search
网关内部维护下游映射,不将服务地址、实现类和内部敏感参数暴露给客户端:
order.query_order → order-server / tools/call / query_order
网关内部上下文
这些字段不必全部成为 MCP 协议字段,但网关处理每个请求都应记录、校验并安全传递:
{
"requestId": "gw-01J...",
"traceId": "trace-...",
"tenantId": "tenant-a",
"principal": { "id": "user-123", "roles": ["support"] },
"toolName": "order.query_order",
"timeoutMs": 10000,
"idempotencyKey": "仅写操作可选"
}
身份、租户和角色必须从认证上下文获得;**不能信任模型在 arguments 中自己填写的 userId、role、tenantId**。
读写工具治理
| 级别 | 示例 | 建议策略 |
|---|---|---|
| 只读 | order.query_order | 权限校验、审计、限流。 |
| 低风险写 | ticket.create | 展示关键入参,按产品策略确认。 |
| 高风险写 | payment.refund、user.delete | 必须显式用户确认、幂等键、强审计;默认拒绝批量操作。 |
错误语义
| 场景 | 返回形式 |
|---|---|
| JSON-RPC 格式/参数错误 | 顶层 error,如 -32602 Invalid params。 |
| 工具不存在 | 顶层 error。 |
| 工具已被正确调用但业务失败 | result.isError: true。 |
| 身份无权限 | 统一拒绝,且不泄露资源是否存在。 |
| 下游超时 | result.isError: true,给出可重试提示,不暴露内部地址。 |
7. 传输方式
stdio
适合本地部署:客户端启动服务端子进程,通过 stdin / stdout 逐行传 JSON-RPC。stdout 只能输出合法 MCP 消息,日志写到 stderr。
Streamable HTTP
适合远程网关:客户端使用 POST /mcp 提交一条 JSON-RPC 消息;服务端返回一个 JSON 或 SSE 流。后续请求要带协商后的 MCP-Protocol-Version;若服务端返回会话 ID,还需带 Mcp-Session-Id。
POST /mcp HTTP/1.1
Accept: application/json, text/event-stream
Content-Type: application/json
MCP-Protocol-Version: 2025-06-18
Authorization: Bearer <token>
{ "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { ... } }









