> ## Documentation Index
> Fetch the complete documentation index at: https://mcp.developerdoc.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# stdio

<div id="enable-section-numbers" />

在 **stdio** 传输中，客户端将 MCP 服务器作为子进程启动。两端通过该子进程的标准流通信：

* 服务器从 `stdin` 读取 JSON-RPC 消息，并将 JSON-RPC 消息写入 `stdout`。
* 每条消息都是单个 JSON-RPC 请求、通知或响应。
* 消息以换行符分隔，并且 **MUST NOT** 包含嵌入的换行符。
* 服务器 **MAY** 将 UTF-8 字符串写入 `stderr`，用于任何日志目的，包括信息、调试和错误消息。
* 客户端 **MAY** 捕获、转发或忽略服务器的 `stderr` 输出，并且 **SHOULD NOT** 假定 `stderr` 输出表示错误状况。
* 服务器 **MUST NOT** 向其 `stdout` 写入任何不是有效 MCP 消息的内容。
* 客户端 **MUST NOT** 向服务器的 `stdin` 写入任何不是有效 MCP 消息的内容。

标准流是规范通道，但除进程生命周期外，此绑定并不依赖它们。其线格式（在可靠双向字节流上，每行一条以换行分隔的 JSON-RPC 消息）可以不变地用于 Unix domain socket、TCP 连接或任何类似通道。基于此类流构建的[自定义传输](/specification/draft/basic/transports#custom-transports) **SHOULD** 复用本页的成帧方式和消息规则；只有子进程特有的方面（启动、`stderr`、通过关闭流来关停、进程重启）需要特定于通道的等价机制。

## Sending Messages

客户端通过向服务器的 `stdin` 写入 JSON-RPC *请求* 和 *通知* 来发送消息，每行一条消息。客户端 **MUST NOT** 写入 JSON-RPC *响应*。

## Receiving Messages

客户端从 `stdout` 读取服务器消息，每行一条消息。所有消息共享这一个通道；不存在按请求划分的流。

服务器会写入三类消息：

1. 对客户端请求的 *响应*，通过 JSON-RPC `id` 关联。
2. 与正在进行的请求相关的 *通知*，例如 `notifications/progress` 和 `notifications/message`。
3. 为活动的 [`subscriptions/listen`][subscriptions-listen] 请求投递的 *通知*。客户端 **MUST** 使用 `_meta` 中的 `io.modelcontextprotocol/subscriptionId` 字段关联这些通知；请参见 [`SubscriptionsListenRequest`][subscriptions-listen-request]。

服务器 **MUST NOT** 向 `stdout` 写入 JSON-RPC *请求*。服务器到客户端的交互通过 [`InputRequiredResult`][mrtr-input-required] 回复承载；请参见 [Multi Round-Trip Requests][mrtr]。

[mrtr]: /specification/draft/basic/patterns/mrtr

[mrtr-input-required]: /specification/draft/basic/patterns/mrtr#inputrequiredresult

[subscriptions-listen]: /specification/draft/basic/patterns/subscriptions

[subscriptions-listen-request]: /specification/draft/schema#subscriptionslistenrequest

## Request Metadata

stdio 传输的所有请求元数据都内联携带在 JSON-RPC 消息体中。协议版本、客户端身份和按请求提供的能力位于 [`_meta.io.modelcontextprotocol/*`][meta-fields]；方法名和参数位于 JSON-RPC 规定的位置。这里没有标头层。

[meta-fields]: /specification/draft/basic/index#meta

## Cancellation

要取消正在进行的请求，客户端 **MUST** 发送引用该请求 ID 的 `notifications/cancelled` 通知。由于 stdio 是单个共享双向通道，因此没有可关闭的按请求流。服务器 **SHOULD** 在可行时尽快停止已取消请求的工作，并且 **MUST NOT** 再为其发送任何消息。完整规则请参见 [Cancellation][cancellation]。

[cancellation]: /specification/draft/basic/patterns/cancellation

## Shutdown

客户端 **SHOULD** 通过以下步骤发起关停：

1. 关闭写向子进程（服务器）的输入流。
2. 等待服务器退出。
3. 如果服务器未在合理时间内退出，则使用适合操作系统的机制强制终止该进程。

在 POSIX 系统上，强制终止通常会从 [`SIGTERM`][sigterm] 升级到 `SIGKILL`。在 Windows 上，由于 POSIX 信号不可用，客户端可以使用 [`TerminateProcess`][terminateprocess] 或 [Job Objects][job-objects]。

当标准输入关闭或读取返回文件结束时，服务器 **SHOULD** 立即退出。这是主要的优雅关停信号，也是唯一可移植的信号，因此遵守它可以减少强制终止的需要。

服务器 **MAY** 通过关闭其写向客户端的输出流并退出，来发起关停。

## Unexpected Termination

如果服务器进程意外退出，客户端 **SHOULD** 重启它。由于协议是无状态的，任何正在进行的请求都会直接丢失，客户端可以在新的进程上重试它们。活动的 [`subscriptions/listen`][subscriptions-listen] 流也必须在重启后重新建立。

[sigterm]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html

[terminateprocess]: https://learn.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess

[job-objects]: https://learn.microsoft.com/windows/win32/procthread/job-objects

## Backward Compatibility

同时支持现代（按请求元数据）MCP 版本和需要 `initialize` 握手的旧版本的客户端，在发送任何其他请求之前 **SHOULD** 使用 [`server/discover`][server-discover] 进行探测，并在 `_meta` 中设置其首选的现代版本。探测有三种可能结果：

* 服务器返回 `DiscoverResult`：服务器是现代服务器。从 `supportedVersions` 中选择双方共同支持的版本并继续。
* 服务器返回可识别的现代 JSON-RPC 错误，例如 [`UnsupportedProtocolVersionError`][unsupported-version]：服务器是现代服务器，但不支持请求的版本。使用其公布的 `supported` 列表中的某个版本。**不要** 回退到 `initialize`。
* 服务器返回任何其他错误，或未在合理超时时间内响应：服务器是旧版服务器。回退到 `initialize` 握手。

回退 **MUST NOT** 绑定到某个特定错误码：旧版服务器会用实现定义的错误（通常是 `-32601` 或 `-32602`）响应未知的 pre-`initialize` 请求，或者完全不响应。

只支持现代版本的客户端不需要探测，但仍然 **RECOMMENDED** 进行探测：某些旧版服务器不会验证请求是否在 `initialize` 之后到达，并且会按旧版语义处理时代含义不明确的方法（例如 `tools/call`）。探测会改为产生确定性的失败。

时代模型和面向实现者的兼容性矩阵请参见[版本控制：向后兼容性][lifecycle-compat]。

[server-discover]: /specification/draft/schema#discoverrequest

[unsupported-version]: /specification/draft/schema#unsupportedprotocolversionerror

[lifecycle-compat]: /specification/draft/basic/versioning#backward-compatibility-with-initialization-based-versions
