MCP服务器究竟如何通信?— 从底层理解JSON-RPC、stdio和Streamable HTTP

在将文件系统、数据库或内部API连接到ChatGPT或Claude等AI应用程序时,我们经常听到“MCP服务器”这个词。由于其名称中包含“协议”,它可能看起来像是一种替代TCP或HTTP的新网络规范,或者仅仅是REST API附加了一个工具列表。

准确地说,MCP(Model Context Protocol)是AI应用程序与外部功能之间的应用层RPC规范。它使用现有操作环境中熟悉的进程标准输入/输出或HTTP进行传输,使用JSON-RPC 2.0作为消息信封,并使用JSON Schema作为工具的输入/输出契约。

本文以2026年7月28日发布的最新稳定规范为基础,整理了MCP服务器的角色、实际字节流、HTTP头和正文、SSE响应、模式标准、认证和错误处理,达到现有IT人员能够绘制数据包流的水平。

图:MCP消息层和传输层分离的结构

首先是结论:MCP是什么,不是什么

将MCP与现有技术进行比较,可以总结如下:

问题 准确答案
— —
MCP是否取代HTTP? 不。它在远程传输中使用HTTP。
MCP是否有自己的数据格式? 有。它将MCP定义的method、params、result和_meta放入JSON-RPC 2.0信封中。
序列化格式是什么? UTF-8 JSON。图像和音频可以作为MIME类型和Base64数据嵌入到JSON中。
输入参数规范是什么? JSON Schema,如果省略$schema,则默认方言为2020-12。
是否需要WebSocket? 不。标准传输是stdio和Streamable HTTP。WebSocket仅在创建自定义传输时可选。
它是REST API吗? 不。它是一个调用tools/list、tools/call等方法的RPC,而不是以资源为中心的HTTP API。
它与gRPC相同吗? 目的有些相似,但它不强制使用Protobuf二进制文件和HTTP/2流。
MCP服务器是LLM吗? 不。它是一个适配器或服务,用于向LLM公开工具、资源和提示。

重要的区别在于数据层和传输层。

MCP 데이터 계층
  JSON-RPC 2.0
  MCP 메서드와 메시지 의미
  도구·리소스·프롬프트 스키마
  오류와 메타데이터

MCP 전송 계층
  stdio
  Streamable HTTP
  또는 의미를 보존하는 custom transport

图:MCP的Host、Client、Server与数据、传输层关系 · 根据官方MCP架构文档重构

因此,“MCP是否使用HTTP?”这个问题的答案是:远程MCP使用HTTP,但MCP本身的含义并不依赖于HTTP。

Host、Client、Server的角色

MCP结构中出现了三个角色:

사용자
  ↓
Host 애플리케이션
  ├─ MCP Client A ── MCP Server: 파일 시스템
  ├─ MCP Client B ── MCP Server: GitHub
  └─ MCP Client C ── MCP Server: 사내 데이터베이스

Host是包含对话UI、LLM和权限授权屏幕的整个应用程序。MCP Client是与特定MCP Server通信的协议组件。MCP Server将外部系统作为MCP功能(如工具、资源、提示)公开。

例如,提供`query_database`工具的MCP服务器可能不是数据库本身。它更像一个适配器,负责应用认证和SQL策略,调用现有数据库驱动程序,然后以MCP格式返回结果。

通用消息信封是JSON-RPC 2.0

无论传输方式是stdio还是HTTP,正文消息都使用JSON-RPC 2.0。请求大致具有以下结构:

{
  "jsonrpc": "2.0",
  "id": 42,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": {
      "location": "Seoul"
    },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": {
        "name": "example-client",
        "version": "1.0.0"
      },
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}

每个字段的作用都很明确:

字段 含义
— —
jsonrpc JSON-RPC版本。MCP使用”2.0″。
id 连接请求和响应的关联ID。在进行中的请求之间必须是唯一的。
method 要执行的MCP方法名称
params 方法参数
_meta 协议版本、客户端功能等MCP元数据

响应返回相同的`id`。

{
  "jsonrpc": "2.0",
  "id": 42,
  "result": {
    "resultType": "complete",
    "content": [
      {
        "type": "text",
        "text": "서울의 현재 기온은 27°C입니다."
      }
    ],
    "isError": false
  },
  "_meta": {
    "io.modelcontextprotocol/serverInfo": {
      "name": "weather-server",
      "version": "2.1.0"
    }
  }
}

通知没有`id`。因为它是接收方不发送响应的消息。

{
  "jsonrpc": "2.0",
  "method": "notifications/progress",
  "params": {
    "progress": 70,
    "total": 100
  }
}

图:JSON-RPC请求、响应、通知的字段和关联 · 根据官方MCP架构文档重构

也就是说,MCP并非在JSON之上随意放置数据,没有任何规则。它必须遵循JSON-RPC 2.0的请求、响应和通知格式,并且其中的MCP方法和数据类型必须遵循MCP规范和官方模式。

2026规范的核心变化:请求是单位,而非连接

过去的MCP资料中,经常出现客户端通过`initialize`请求初始化连接,服务器颁发会话ID,然后服务器再向客户端发送JSON-RPC请求的流程。如果是在解释2025年规范,当时这是正确的。

然而,2026-07-28规范已改为无状态、按请求模型。

과거 모델
연결 수립 → initialize → capability 협상 → 세션 상태 유지 → 여러 호출

현재 모델
각 요청 = 프로토콜 버전 + capability + 필요한 인증·메타데이터를 자체 포함

服务器不应仅仅因为TCP连接或stdio进程相同就推断协议版本、客户端身份或能力。如果需要维护长期工作状态,则必须通过明确的标识符(如`requestState`、`subscription ID`)来表示。

目前,两个必需的请求元数据是:

"_meta": {
  "io.modelcontextprotocol/protocolVersion": "2026-07-28",
  "io.modelcontextprotocol/clientCapabilities": {}
}

`clientInfo`和日志级别等是可选的。如果缺少必需的元数据,服务器将以JSON-RPC -32602 Invalid params拒绝,在HTTP传输中,还会同时使用HTTP 400。

这一变化的好处是,更容易将请求发送到负载均衡器后面的不同实例或以无服务器方式处理。另一方面,如果旧版SDK和最新服务器混用,其行为可能大相径庭,因此实现者必须确认支持的规范日期。

stdio传输:一行一个JSON消息

本地MCP服务器最简单的方式是stdio。客户端将MCP服务器作为子进程运行,并使用以下通道:

Client ── child stdin  ──> MCP Server
Client <── child stdout ── MCP Server
Client <── child stderr ── 로그

线缆格式是在可靠的双向字节流上,每行一个UTF-8 JSON-RPC消息。

{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{"_meta":{...}}}

{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"search","arguments":{"q":"MCP"},"_meta":{...}}}

规则很严格:

  • 消息以换行符分隔,消息内部不得包含实际的换行符。JSON字符串中的换行符应转义为`n`。
  • 服务器的stdout只能写入有效的MCP消息。
  • 日志、调试输出、堆栈跟踪发送到stderr。
  • 所有响应都混合在一个stdout通道中,因此通过`id`匹配请求和响应。
  • 进度通知也通过同一通道发送,并与进行中的请求或订阅ID关联。
  • 取消通过`notifications/cancelled`通知指定请求ID。

stdio的这种帧定方式并非只能在操作系统标准流中使用。也可以创建自定义传输,将“一行一个JSON”的规则应用于Unix域套接字或TCP。但这并非标准的stdio传输,而是重用了相同帧定方式的用户定义传输。

图:stdio传输的请求、响应、日志通道和换行帧定 · 根据官方MCP stdio规范重构

Streamable HTTP:每个请求一个POST

远程MCP服务器的标准传输是Streamable HTTP。最新规范的核心如下:

POST /mcp  ── JSON-RPC 요청 1 ──> JSON 한 개 또는 요청 범위 SSE
POST /mcp  ── JSON-RPC 요청 2 ──> JSON 한 개 또는 요청 범위 SSE
POST /mcp  ── JSON-RPC 알림   ──> 202 Accepted

服务器提供一个MCP端点,所有客户端消息都作为新的HTTP POST请求发送。请求正文只包含一个JSON-RPC对象。不应考虑使用JSON数组进行批量处理,或将多个JSON-RPC消息放入一个POST请求中。

实际请求类似于:

POST /mcp HTTP/1.1
Host: mcp.example.com
Content-Type: application/json
Accept: application/json, text/event-stream
Authorization: Bearer eyJ...
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: get_weather

{
  "jsonrpc": "2.0",
  "id": 42,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": {"location": "Seoul"},
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}

这里值得注意的是,一些值在HTTP头和JSON正文中是重复的。

HTTP头 正文来源 目的
— — —
MCP-Protocol-Version _meta.io.modelcontextprotocol/protocolVersion 规范版本选择
Mcp-Method method 代理、WAF、观测工具无需解析正文即可路由
Mcp-Name params.name或params.uri 识别目标工具、资源或提示

正文是语义的真相来源,服务器会验证头和正文是否一致。如果版本不一致,它将返回HTTP 400和HeaderMismatch JSON-RPC错误。

工具模式中特定原始类型字段可以声明`x-mcp-header`,以复制为`Mcp-Param-{Name}`头。这对于负载均衡器根据区域或租户等值进行路由非常有用,但密码、令牌和个人信息不应放在头中,因为它们容易暴露给中间设备和日志。

对于无法用安全ASCII头值表示的值(如中文),使用UTF-8字节的Base64编码和以下哨兵格式:

Mcp-Name: =?base64?{Base64EncodedValue}?=

为什么叫Streamable HTTP?

服务器根据请求的性质以两种方式之一响应:

短响应:application/json

HTTP/1.1 200 OK
Content-Type: application/json

{"jsonrpc":"2.0","id":42,"result":{"resultType":"complete",...}}

有进度响应:text/event-stream

HTTP/1.1 200 OK
Content-Type: text/event-stream

data: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progress":50}}

data: {"jsonrpc":"2.0","id":42,"result":{"resultType":"complete","content":[...]}}

SSE是依赖于该POST请求的响应流。它在发送进度通知后,必须以最终的JSON-RPC响应结束。如果客户端关闭此SSE连接,服务器必须将该请求视为已取消。

如果希望接收长期工具列表更改或资源更改,不是打开单独的GET流,而是发送`subscriptions/listen`请求并保持其响应流。在2026规范中,过去的独立GET SSE端点和协议会话已被移除。也不支持使用`Last-Event-ID`恢复SSE流的功能。

因此,在运营环境中,需要检查反向代理的SSE缓冲、空闲超时、最大请求时间以及连接终止传播。虽然HTTP/1.1也可以实现,但考虑到多个并发流和连接效率,从基础设施角度检查HTTP/2支持也很有价值。然而,MCP规范本身并不强制要求HTTP/2。

图:Streamable HTTP的按请求JSON响应和SSE流分支 · 根据官方MCP Streamable HTTP规范重构

如何发现和调用工具

客户端无需预先硬编码MCP服务器提供的工具。它们在运行时通过`tools/list`发现。

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}

服务器返回工具名称、描述和输入模式。

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "resultType": "complete",
    "tools": [
      {
        "name": "get_weather",
        "description": "지역의 현재 날씨를 조회합니다.",
        "inputSchema": {
          "type": "object",
          "properties": {
            "location": {
              "type": "string",
              "description": "도시 이름"
            }
          },
          "required": ["location"],
          "additionalProperties": false
        }
      }
    ]
  }
}

Host将此描述和模式告知LLM,如果模型建议调用工具,则在经过策略和用户批准后发送`tools/call`。MCP不强制模型的判断或批准UI。

JSON Schema标准化到何种程度?

在MCP中,“是否有格式?”这个问题需要分为两个层面来回答。

首先,MCP协议消息类型以官方TypeScript模式作为真相来源,并由此生成JSON Schema。SDK实现者可以根据此模式匹配请求和响应类型。

其次,每个工具的`inputSchema`和可选的`outputSchema`也是JSON Schema。如果省略`$schema`,则解释为JSON Schema 2020-12。实现必须支持2020-12,如果使用不同的方言,则必须通过`$schema` URI明确指定。

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    }
  },
  "required": ["limit"],
  "additionalProperties": false
}

JSON Schema不仅可以验证类型,还可以验证必填字段、范围、字符串模式、枚举值和嵌套结构。然而,有模式并不意味着自动安全。自动获取外部URL的`$ref`可能导致SSRF或供应链问题,过度的`oneOf`、`allOf`和递归引用可能会消耗验证器资源。官方规范也禁止自动解引用外部网络`$ref`,并建议限制深度、时间子模式数量。

结果数据只能是文本吗?

工具结果的`content`可以混合多种类型:

{
  "resultType": "complete",
  "content": [
    {"type": "text", "text": "분석 결과입니다."},
    {
      "type": "image",
      "data": "iVBORw0KGgoAAA...",
      "mimeType": "image/png"
    },
    {
      "type": "resource_link",
      "uri": "file:///reports/result.json",
      "name": "result.json",
      "mimeType": "application/json"
    }
  ],
  "structuredContent": {
    "riskScore": 82,
    "severity": "high"
  },
  "isError": false
}

文本是JSON字符串,图像和音频是Base64数据和MIME类型,文件或网络资源则通过URI链接或嵌入式资源表示。机器可处理的结果可以在`structuredContent`中以JSON值返回,并通过`outputSchema`进行验证。

这里,`structuredContent`与LLM通过模式约束解码生成的“结构化输出”是不同的概念。它仅仅是MCP服务器返回的工具结果数据。

每次将大容量二进制文件以Base64形式放入正文会导致大小增加约33%,并增加内存使用量。对于大文件,更合适的做法是返回受访问控制的资源URI或单独的对象存储URL,让客户端在需要时读取。

HTTP状态码和JSON-RPC错误是不同层次

在Streamable HTTP中,错误存在于两个层次:

HTTP 계층
  인증 실패, 잘못된 Origin, 지원하지 않는 endpoint,
  헤더 불일치, 전송 자체의 실패

JSON-RPC/MCP 계층
  파싱 실패, 잘못된 요청, 존재하지 않는 method,
  잘못된 params, tool 실행 오류

典型的JSON-RPC标准错误如下:

代码 含义
— —
-32700 解析错误
-32600 无效请求
-32601 方法未找到
-32602 无效参数
-32603 内部错误

MCP还定义了诸如头不匹配-32020、缺少所需客户端能力-32021、不支持的协议版本-32022等错误。

如果工具本身正常执行但发生了业务错误,可以使用HTTP 200和正常JSON-RPC响应中的`isError: true`。例如,“支付卡被拒绝”与网络传输失败不同。在监控中,仅查看HTTP成功率可能会错过MCP工具的业务失败。

认证在HTTP中使用OAuth 2.1系列

MCP认证是可选的,但如果基于HTTP的传输支持认证,建议遵循最新的MCP授权规范。核心是MCP服务器作为OAuth资源服务器运行。

MCP Client
  ├─ Protected Resource Metadata 조회
  ├─ Authorization Server Metadata 조회
  ├─ OAuth 2.1 + PKCE로 사용자 승인
  └─ Authorization: Bearer <access-token>
                         ↓
                    MCP Server

该规范结合了OAuth 2.1草案、RFC 6750 Bearer Token、RFC 8414 Authorization Server Metadata、RFC 9728 Protected Resource Metadata、RFC 8707 Resource Indicators等。客户端不得将令牌放入查询字符串中,并且所有受保护的HTTP请求都必须包含`Authorization: Bearer`头。服务器必须验证令牌的受众是否是自身。

stdio不遵循此HTTP OAuth流程,建议在进程环境中接收凭据。但这并不意味着API密钥可以以明文形式留在配置文件或日志中。需要单独的运营控制,例如操作系统密钥链、秘密管理器和最小权限环境变量注入。

与REST、OpenAPI、gRPC、WebSocket的比较

技术 主要作用 传输·编码 与MCP的区别
— — — —
REST API HTTP资源操作 HTTP + 主要JSON MCP提供预定义的RPC方法和AI工具发现约定
OpenAPI HTTP API的静态规范 YAML或JSON文档 MCP定义了运行时tools/list和调用/结果消息
JSON-RPC 2.0 RPC消息信封 传输独立JSON MCP在此信封之上标准化了方法和语义
gRPC 强类型远程调用 HTTP/2 + Protobuf MCP以人类可读的JSON和JSON Schema为中心
WebSocket 全双工连接传输 基于帧 不是MCP的默认传输;是自定义传输的候选
SSE 服务器到客户端流式传输 HTTP text/event-stream 在Streamable HTTP中用于按请求的进度通知和最终响应

将现有REST API连接到MCP时,无需放弃这些API。通常的做法是将MCP服务器作为薄适配器,在内部调用现有的REST或gRPC。

LLM Host
  → MCP Client
  → MCP Server
  → 기존 REST/gRPC/DB/Queue

MCP与其说是创建新后端系统的技术,不如说是为AI应用程序发现和调用这些系统功能提供了一个通用接口。

实际部署前需要检查的候选项目

当现有IT组织审查MCP服务器时,建议首先检查以下项目:

1. 传输选择

  • 如果Host直接在一台计算机上运行进程,stdio更简单。
  • 如果连接多个用户和远程服务器,Streamable HTTP更适合。
  • 对于自定义传输,首先需要计算失去标准客户端兼容性和观测工具的成本。

2. 规范版本和SDK兼容性

  • 验证服务器和客户端是否都支持2026-07-28无状态模型。
  • 区分依赖`initialize`、`MCP-Session-Id`和GET SSE的旧版实现。
  • 测试头和正文中的协议版本不匹配。

3. 模式质量

  • 为所有工具定义具体的`inputSchema`。
  • 如果可能,使用`additionalProperties: false`、长度/范围/枚举约束。
  • 为重要的机器可处理结果提供`outputSchema`和`structuredContent`。
  • 对外部`$ref`、递归和复杂组合模式设置资源限制。

4. 权限和安全措施

  • 根据令牌范围最小化工具列表。
  • 分离读写工具,并对删除、支付、权限更改进行用户批准。
  • 不要信任LLM生成的参数;在服务器端再次验证。
  • 检查stdio服务器继承的环境变量和文件权限。

5. HTTP操作项

  • 通过Origin验证和localhost绑定防止DNS重绑定。
  • 验证OAuth受众、范围和令牌过期。
  • 测试SSE缓冲、空闲超时以及连接终止和取消传播。
  • 记录`Mcp-Method`和`Mcp-Name`,但不要记录敏感的`Mcp-Param-*`。

6. 可靠性和可观测性

  • 通过JSON-RPC `id`连接端到端跟踪。
  • 将HTTP错误、JSON-RPC错误和`isError: true`作为单独的指标进行汇总。
  • 区分可重试的读取操作和重复执行危险的写入操作。
  • 测试超时、取消以及部分进度通知后的失败。

总结

从底层看MCP服务器,它并非神秘的AI专用网络。

의미와 메시지
  MCP method + JSON-RPC 2.0

도구 계약
  JSON Schema 2020-12 기본

로컬 전송
  UTF-8 newline-delimited JSON over stdio

원격 전송
  HTTP POST + application/json 또는 request-scoped SSE

인증
  HTTP는 OAuth 2.1 계열, stdio는 실행 환경의 자격증명

MCP的价值不在于发明新的套接字或序列化格式。它在于结合现有标准,为AI Host创建了一个通用的契约,使其能够发现工具、理解类型、调用工具并接收结果。

操作员需要记住三个核心点:将MCP数据层和传输层分开看待,不要混淆最新规范的无状态请求模型和旧版会话模型,即使有模式,也要在服务器外部和内部共同强制执行权限、验证、批准和可观测性。

参考资料


Comments

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注