第五篇中,我把资料正文放到外部存储,图中保存版本引用,每次规划前重新组装有效上下文。到这里,智能体已经有了执行循环,也能管理证据,但工具仍然是项目里的本地函数。

当读取文档、搜索资料与保存报告分别由不同服务提供时,我需要重复解决几件事:服务有哪些工具,参数是什么,怎样调用,失败如何返回,以及连接何时关闭。如果每个服务都定义一套格式,Host 的适配代码就会随着工具数量一起增长。

MCP,即 Model Context Protocol,为这些交互提供统一协议。本篇先讲清协议边界,再通过真实 Python SDK 的客户端与服务端验证发现和调用。它并不替应用决定下一步,也不自动让所有工具获得执行权限。

本篇代码使用人工编写的固定教学笔记,不读真实文件,不联网搜索,不调用模型。完整源码与运行命令都在文内,另有 06_mcp_protocol/ 运行副本。

资料核对与本地验证日期:2026-11-06。分别核对 2025-11-25 与 2026-07-28 规范,使用 SDK 1.30.0 与 2.3.0 的独立环境验证,不能把这两个版本的流程混用。

一、MCP 位于模型与工具之间的什么位置

我把一个模型提出的工具调用分成两段理解。

第一段是模型接口:模型收到工具名称、描述和参数 Schema 后,返回准备调用哪个工具、使用什么参数。第二段是程序执行:应用校验调用,找到对应服务,把参数交给工具,接收结果,再按模型接口要求回传。

Function Calling 主要属于第一段,MCP 主要解决第二段中 Client 与 Server 的标准交互。Host 仍需把 MCP 工具描述转换为模型供应商接受的格式,并把模型返回的调用映射为 tools/call。MCP 的工具结果也不能不经适配直接冒充模型消息。资料 1

用户目标

Host:图、策略、上下文与模型适配

模型:提出工具调用

程序:名称、参数、权限、预算与确认

MCP Client:发现与调用

MCP Server:工具实现

结果校验、外存与证据引用

模型接口中的工具调用 ID,用于匹配工具结果消息。MCP JSON-RPC 请求 ID,用于匹配 Client 与 Server 的请求和响应。二者位于不同接口,应用应建立关联,不能认为它们天然是同一个标识。

同理,业务 task_id、LangGraph 检查点 thread_id 和旧版 MCP HTTP 会话 ID 也不是一回事。后续可以把它们记录在执行日志中,但不能用一个传输会话标识证明任务归属。

二、Host、Client 与 Server 的分工

角色本系列中的对应部分主要职责
Host智能体应用管理模型、图、上下文、用户授权与工具策略
ClientHost 内的 MCP 接入组件面向配置的 Server 执行协议交互与连接管理
Server提供资料或文件能力的程序暴露工具、资源、模板,并执行服务端业务校验

Host 可以为多个 Server 创建各自的 Client。Client 是应用中的组件,不一定是另一个独立服务;Server 则可以作为本地子进程运行,也可以通过 HTTP 提供远程能力。资料 1

工具从项目中移到服务端后,校验仍然有两层。Host 判断本次任务能否使用这个工具,Server 判断调用方能否访问具体资源。即使 Host 已检查路径,服务端也应校验自己的最终路径与访问范围。

“发现了工具”只代表程序拿到了描述,不代表已经授权模型调用。工具描述和行为注解来自服务端,需要按信任边界处理;readOnlyHint 等注解不能替代执行策略。资料 2

这个区分也解释了第五篇记忆模块怎样继续发挥作用:工具结果先校验、写入外存并生成引用,然后由上下文组装器选取片段。接入 MCP 不会自动解决结果过大、旧摘要或跨用户读取。

三、Tools、Resources 与 Prompts

能力表达什么常见方法本系列的应用方向
Tools可执行操作tools/list、tools/call搜索资料、读取文档、保存报告
Resources可读取的数据资源resources/list、resources/read固定文档、资料说明、已有产物
Prompts可复用的提示模板prompts/list、prompts/get报告结构或任务引导模板

官方概念通常把 Tools 描述为模型控制、Resources 描述为应用控制、Prompts 描述为用户控制。这是推荐的交互组织方式,协议并不强制应用必须采用某一种 UI。资料 1资料 2

读取同一份资料,可以被设计成按 URI 读取的 Resource,也可以被设计成带过滤条件的 Tool。我会按业务契约选择,而不是仅凭“读取”两个字分类。Resource URI 也不是访问许可,读取时仍要验证身份与范围。

prompts/get 返回模板消息,不表示这些消息已经执行模型调用。工具返回的 structuredContent 是服务端产出的结构化数据,也不同于模型的 Structured Outputs。客户端发现某个能力后,还要确认具体方法、参数和结果形式是否受支持。

本篇只实现一个 Tool,用它观察协议。资料服务、Resources、Prompts 与模型适配留到后续扩展,避免第一次接入就同时引入过多业务。

四、请求、结果与错误怎样对应

MCP 使用 JSON-RPC 2.0。请求包含 id、method 与可选参数,响应使用相同 ID 返回结果或错误。通知没有 ID,也不应收到单独的响应。字符串中的换行需要 JSON 转义;stdio 的消息边界本身使用换行分隔。资料 3资料 6

例如,一个 tools/call 会携带工具名称与参数对象。对于 2026-07-28,下面是包含必要元数据的完整请求示意:

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "read_note",
    "arguments": {"source_id": "control_flow"},
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientCapabilities": {},
      "io.modelcontextprotocol/clientInfo": {
        "name": "example-client",
        "version": "1.0.0"
      }
    }
  }
}

clientInfo 用来描述客户端实现,不是经过认证的用户身份。租户和用户范围必须来自可信凭据或服务配置,不能因为客户端把名字写进 _meta 就信任它。

工具调用失败需要分开处理。协议层错误,例如不支持的方法或版本,进入 JSON-RPC error;工具运行中的业务失败可以进入工具结果,并设置 isError: true。因此 HTTP 成功返回,甚至收到了 result,都不能直接推导出业务成功。资料 2

工具结果中的 content 可以包含文本、图片、资源链接等多种块,不能假定永远只有一段字符串。本例返回文本块,块内是教学函数返回字典的 JSON;它没有声明输出 Schema,也没有返回 structuredContent。

新版结果使用 resultType 区分完成与需要补充输入等状态。complete 表示请求已完成,不代表业务必然成功,还要看 isError。input_required 表示需要按 MRTR,即多轮请求模式,收集输入后再次请求;它不是可直接写入最终报告的资料。资料 3

五、初始化握手与逐请求元数据是两套流程

5.1 2025-11-25:先初始化,再运行

旧版 Client 先发送 initialize,包含支持的协议版本、Client 能力和实现信息。Server 返回采用的版本、自己的能力与实现信息。Client 检查兼容性后发送 notifications/initialized,再进入正常操作。资料 4

Server:旧版或兼容实现 Client:2025-11-25 Server:旧版或兼容实现 Client:2025-11-25 initialize(版本、能力、clientInfo) InitializeResult(版本、能力、serverInfo) notifications/initialized tools/list 工具描述与可选分页游标 tools/call 工具结果或 JSON-RPC 错误

如果 Server 不支持请求中的版本,会返回它支持的另一个版本;Client 不支持响应版本时应断开。本篇旧版 SDK 的 session.initialize() 封装了这段流程,无需调用方再重复发送 initialized 通知。

5.2 2026-07-28:每个请求声明协议信息

新版没有初始化协商握手。每个请求都在 params._meta 中声明协议版本与相关 Client 能力,Server 独立处理请求。clientInfo 是可选实现信息。Server 必须实现 server/discover,但纯新版 Client 不必先发现才能发起其他请求。资料 3资料 5

Server:新版处理路径 Client:2026-07-28 Server:新版处理路径 Client:2026-07-28 server/discover(逐请求 _meta,可选发现) supportedVersions、能力与实现信息 tools/list(本次请求 _meta) resultType=complete,工具列表 tools/call(参数与本次请求 _meta) complete / input_required / error

收到 UnsupportedProtocolVersionError,错误码 -32022,表示对端认识新版交互但不接受该版本。Client 应从返回的支持列表选择共同版本,不能看到错误就直接退回旧版握手。资料 5

支持新旧两代的 Client,在 stdio 上可以先用 server/discover 探测。收到新版结果或可识别的新版错误就继续新版处理;其他错误或合理超时才按规范回退。旧 Server 的未知方法错误不一定固定为某一个错误码。

新版协议的“无状态”是请求处理语义:必要信息不依赖先前连接交互。它不表示服务端不能使用数据库、缓存或长期任务;需要跨请求保留的业务状态,应通过显式标识关联。stdio 子进程与连接也不应直接代表某一次业务会话。

六、stdio、Streamable HTTP 与旧 HTTP+SSE

6.1 stdio:子进程的标准流

Client 启动 Server 子进程,用 stdin 发送消息,从 stdout 读取消息。消息按行分隔,日志写 stderr。一个普通 print() 如果写到 Server 的 stdout,就可能破坏协议帧。资料 6

stdio 适合先验证本地工具服务,但不自动构成权限沙箱。子进程具有什么文件和网络权限,仍由启动环境及操作系统约束。关闭时先关闭输入,等待退出,必要时再终止进程。

6.2 Streamable HTTP:不要只记住“支持 SSE”

项目2025-11-252026-07-28
主要消息入口单一 MCP 路径,POST 发消息单一 MCP 路径,每条请求单独 POST
初始化initialize 握手逐请求元数据,没有该握手
返回形式JSON 或 SSEJSON 或请求范围的 SSE
GET 流可用 GET 打开;不提供时返回 405移除 GET 流,订阅通过 subscriptions/listen 请求
协议会话可分配 MCP-Session-Id移除协议层会话
断流与取消断开本身不应视为取消关闭对应响应流是该请求的取消信号
SSE 重连可选事件重放与 Last-Event-ID不支持该恢复机制

表中的差别来自对应版本的传输规范,不能把旧版恢复与会话机制直接套到新版。资料 7资料 8

新版 HTTP 请求除了 JSON-RPC 正文,还需要携带 MCP-Protocol-Version、Mcp-Method,调用工具时携带对应的 Mcp-Name。正文是元数据的依据,镜像到头中的值必须一致。Accept 要声明同时支持 application/json 与 text/event-stream,只实现 JSON 接收的通用客户端不足以覆盖规范。资料 8

SSE 是消息承载方式,不等于模型 token 流。这里的 SSE 数据可以是 JSON-RPC 进度通知、订阅通知或最终响应。以后 FastAPI 向浏览器发送的任务事件流,会有自己的事件 ID、鉴权与重连契约,不能与 MCP 传输混为一谈。

新版断流的协议语义也不等于外部写入已经撤销。如果保存动作已经提交,取消不能让它自动消失;副作用幂等与结果未知留到第十二篇处理。

6.3 旧 HTTP+SSE 是另一种布局

2024-11-05 的 HTTP+SSE 使用 SSE 接收入口和 POST 发送入口。Client 先 GET 建立 SSE 连接,Server 用 endpoint 事件告知后续 POST 的地址。Streamable HTTP 则在单一 MCP 路径处理消息,返回可以是 JSON 或 SSE。资料 9

因此,看到 text/event-stream 无法判断正在使用哪一种传输。需要同时检查协议版本、入口方法和握手流程。本篇不实现旧 HTTP+SSE 自动回退,也没有验证其互通。

七、SDK 版本与协议日期要分别记录

协议日期描述消息约定,SDK 版本描述某一语言实现。安装了最新 SDK,不代表所有连接都会使用最新协议。

本地检查与运行得到:

Python SDK版本注册表本例客户端入口本例服务端入口
mcp==1.30.0从 2024-11-05 到 2025-11-25 的四个版本ClientSession.initialize()FastMCP
mcp==2.3.0上述四个版本,加 2026-07-28Client,默认 mode="auto"MCPServer

注册表说明实现声明的范围,不等于本篇实测了每个日期、每种传输。这里实际使用的是 2025-11-25 和 2026-07-28,验证 stdio 互通与新版 HTTP 调用。

2.x 的迁移还涉及 Python 字段名改为 snake_case、FastMCP 改名为 MCPServer、传输配置移动,以及 HTTP 客户端依赖从 httpx 变为 httpx2。本篇使用 model_dump(by_alias=True) 输出协议字段,所以仍能看到 inputSchema、isError 等线上的名称。资料 10

还有一个容易误判的细节:新版 SDK 解析旧结果时可以补上默认 resultType="complete"。打印出的 SDK 对象不是原始网络报文,不能仅凭这个字段判断 Server 在线上使用了新版协议。本地验证因此另外检查了原始 stdio 消息。

八、完整实现:观察发现与调用

将下面七个文件保存在同一个目录。两个依赖文件用于两个独立虚拟环境,不能安装到同一个环境中覆盖彼此。本地使用 Python 3.13.13,示例入口使用 Python 3.11 及以上的 asyncio.timeout()。

06_mcp_protocol/
├── teaching_notes.py
├── modern_server.py
├── legacy_server.py
├── modern_client.py
├── legacy_client.py
├── requirements-modern.txt
└── requirements-legacy.txt

8.1 teaching_notes.py:共享的只读教学函数

"""固定教学笔记,只用于验证协议;不执行文件或网络访问。"""


def read_note(source_id: str) -> dict:
    """读取固定教学笔记,当前只接受 source_id=control_flow。"""
    if not isinstance(source_id, str) or not 1 <= len(source_id) <= 64:
        raise ValueError("来源标识必须是 1—64 字符的字符串。")
    if source_id != "control_flow":
        raise ValueError("教学来源不存在。")
    return {
        "source_id": source_id, "revision": 1,
        "content": "教学笔记:计划决定下一步,程序检查预算,观察用于更新证据缺口。",
        "fixture": True,
    }

8.2 modern_server.py:新版与兼容服务端

"""MCP SDK 2.3.0 服务端;支持新版与兼容旧版连接。"""

import argparse

from mcp.server.mcpserver import MCPServer

from teaching_notes import read_note

server = MCPServer("protocol-notes", version="1.0.0")
server.tool()(read_note)


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("--transport", choices=["stdio", "streamable-http"], default="stdio")
    parser.add_argument("--port", type=int, default=8766)
    args = parser.parse_args()
    if args.transport == "stdio":
        # stdout 是协议通道,不在这里打印业务日志。
        server.run(transport="stdio")
    else:
        server.run(transport="streamable-http", host="127.0.0.1", port=args.port)


if __name__ == "__main__":
    main()

8.3 legacy_server.py:旧版服务端

"""MCP SDK 1.30.0 服务端,使用初始化握手。"""

from mcp.server.fastmcp import FastMCP

from teaching_notes import read_note

server = FastMCP("protocol-notes")
server.tool()(read_note)


if __name__ == "__main__":
    server.run(transport="stdio")

8.4 modern_client.py:自动发现与版本回退

"""SDK 2.3.0 客户端:自动识别协议年代,确定性调用只读工具。"""

import argparse
import asyncio
import json
import sys
from importlib.metadata import version
from pathlib import Path

from mcp import Client, StdioServerParameters


async def inspect_server(server, source_id: str) -> dict:
    # 一次连接中复用客户端;超时退出后由上下文管理器释放传输。
    async with Client(server, read_timeout_seconds=10) as client:
        if client.server_capabilities.tools is None:
            raise RuntimeError("服务端未声明 tools 能力。")
        tools, cursor = [], None
        for _ in range(4):
            page = await client.list_tools(cursor=cursor)
            tools.extend(page.tools)
            cursor = page.next_cursor
            if cursor is None:
                break
        if cursor is not None:
            raise RuntimeError("工具列表超过教学页数预算。")
        matching = [tool for tool in tools if tool.name == "read_note"]
        if len(matching) != 1:
            raise RuntimeError("允许的只读工具不存在或名称重复。")
        tool = matching[0]
        # 教学客户端只调用固定允许的工具,没有让模型选择动作。
        result = await client.call_tool("read_note", {"source_id": source_id})
        return {
            "sdk_version": version("mcp"), "protocol_version": client.protocol_version,
            "tool": tool.model_dump(by_alias=True, exclude_none=True),
            "result": result.model_dump(by_alias=True, exclude_none=True),
        }


async def run(args) -> dict:
    if args.url:
        server = args.url
    else:
        server_file = args.server_file or str(Path(__file__).with_name("modern_server.py"))
        server = StdioServerParameters(command=args.server_python, args=[server_file])
    async with asyncio.timeout(20):
        return await inspect_server(server, args.source_id)


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("--url", help="例如 http://127.0.0.1:8766/mcp")
    parser.add_argument("--server-python", default=sys.executable)
    parser.add_argument("--server-file")
    parser.add_argument("--source-id", default="control_flow")
    result = asyncio.run(run(parser.parse_args()))
    print(json.dumps(result, ensure_ascii=False))


if __name__ == "__main__":
    main()

8.5 legacy_client.py:显式初始化

"""SDK 1.30.0 客户端:初始化、发现和调用,不尝试新版发现流程。"""

import argparse
import asyncio
import json
import sys
from datetime import timedelta
from importlib.metadata import version
from pathlib import Path

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client


async def run(args) -> dict:
    server_file = args.server_file or str(Path(__file__).with_name("legacy_server.py"))
    parameters = StdioServerParameters(command=args.server_python, args=[server_file])
    async with asyncio.timeout(20):
        async with stdio_client(parameters) as (read, write):
            async with ClientSession(
                read, write, read_timeout_seconds=timedelta(seconds=10),
            ) as session:
                # initialize() 同时完成版本、能力交换与 initialized 通知。
                initialized = await session.initialize()
                if initialized.capabilities.tools is None:
                    raise RuntimeError("服务端未声明 tools 能力。")
                tools, cursor = [], None
                for _ in range(4):
                    page = await session.list_tools(cursor=cursor)
                    tools.extend(page.tools)
                    cursor = page.nextCursor
                    if cursor is None:
                        break
                if cursor is not None:
                    raise RuntimeError("工具列表超过教学页数预算。")
                matching = [tool for tool in tools if tool.name == "read_note"]
                if len(matching) != 1:
                    raise RuntimeError("允许的只读工具不存在或名称重复。")
                result = await session.call_tool("read_note", {"source_id": args.source_id})
                return {
                    "sdk_version": version("mcp"),
                    "protocol_version": initialized.protocolVersion,
                    "tool": matching[0].model_dump(by_alias=True, exclude_none=True),
                    "result": result.model_dump(by_alias=True, exclude_none=True),
                }


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("--server-python", default=sys.executable)
    parser.add_argument("--server-file")
    parser.add_argument("--source-id", default="control_flow")
    result = asyncio.run(run(parser.parse_args()))
    print(json.dumps(result, ensure_ascii=False))


if __name__ == "__main__":
    main()

8.6 requirements-modern.txt:新版环境

mcp==2.3.0

8.7 requirements-legacy.txt:旧版环境

mcp==1.30.0

客户端复用同一连接完成能力检查、分页发现与调用,限制每次读取等待时间和总运行时间。页数预算不是完整的响应体大小限制;这段程序适用于固定教学 Server。接入不受信任的服务时,仍需增加工具数量、Schema 复杂度与消息体预算,不能直接把收到的列表全部发给模型。

这些 CLI 参数是可信本地运行配置。服务端路径、Python 解释器和 HTTP URL 不应开放给模型任意选择。HTTP 示例仅绑定回环地址,没有生产鉴权,不应直接暴露为公网服务。

九、运行步骤与实际兼容结果

在保存七个文件的目录打开终端:

python3 -m venv .venv-modern
python3 -m venv .venv-legacy
.venv-modern/bin/python -m pip install -r requirements-modern.txt
.venv-legacy/bin/python -m pip install -r requirements-legacy.txt

分别运行同版本组合:

.venv-modern/bin/python modern_client.py
.venv-legacy/bin/python legacy_client.py

再运行跨版本组合:

.venv-modern/bin/python modern_client.py \
  --server-python .venv-legacy/bin/python \
  --server-file legacy_server.py

.venv-legacy/bin/python legacy_client.py \
  --server-python .venv-modern/bin/python \
  --server-file modern_server.py
ClientServer本地 stdio 结果实际协议
SDK 2.3.0SDK 2.3.0 的本例 Server成功发现并调用2026-07-28
SDK 1.30.0SDK 1.30.0 的本例 Server成功初始化并调用2025-11-25
SDK 2.3.0,自动模式SDK 1.30.0 的本例 Server探测后回退成功2025-11-25
SDK 1.30.0SDK 2.3.0 的兼容 Server按旧版路径成功2025-11-25

最后一行验证的是支持旧版行为的 Server,不能推导旧 Client 能连接只实现新版的 Server。新版 Client 连旧 Server 时,stderr 可能出现旧 Server 不认识 server/discover 的校验日志;应结合最终协议版本、结果与退出码判断回退是否成功。

结果 JSON 中,tool 是实际发现的工具描述,result.content 包含教学笔记。用不存在的来源检查业务失败:

.venv-modern/bin/python modern_client.py --source-id missing
.venv-legacy/bin/python legacy_client.py --source-id missing

两种 SDK 的本例 Server 都返回 isError: true。示例客户端负责展示结果,所以这个业务失败仍可正常退出;实际 Host 应把该字段转换为失败观察,不能仅以进程退出码判断任务完成。

HTTP 需要两个终端。在第一个终端启动:

.venv-modern/bin/python modern_server.py \
  --transport streamable-http --port 8766

第二个终端调用:

.venv-modern/bin/python modern_client.py --url http://127.0.0.1:8766/mcp

调用完成后,在服务端终端使用 Ctrl+C 停止服务。若端口已占用,修改 --port 并同步修改 URL。此处 Server 独立运行,HTTP Client 退出不会替调用方结束服务进程。

本地验证共完成 16 组集成检查:四组 SDK 互通、两种业务错误返回、原始新版 stdio 发现及调用、版本错误支持列表、子进程释放、新版 HTTP 调用与响应类型,以及三条 HTTP 头校验路径。原始正常 HTTP 调用实际返回 application/json,本篇未验证 SSE 进度、订阅、断流取消或重连。

额外 HTTP 检查观察到:新版头配旧版正文被新版路径以 400 / -32020 拒绝;缺少 Mcp-Method 也返回 400 / -32020。反过来,旧版头配新版正文,在本例兼容实现中先进入旧会话路径,返回 400 / -32600,提示缺少会话 ID。这是具体实现的路由诊断结果,不应简化成“任何版本冲突都返回同一个错误码”。

这轮使用真实 SDK、真实子进程和本机 HTTP,没有用协议替身代替传输。Python 为 3.13.13,两个环境的 Pydantic 为 2.14.3、AnyIO 为 4.16.0;旧环境 HTTPX 为 0.28.1,新环境 HTTPX2 为 2.16.0。依赖文件锁定 SDK 版本,传递依赖可能随安装时间变化。

这些结果不证明真实模型能够选对工具,也不证明所有外部 Server 都兼容。生产认证、路径权限、消息限额、网络故障、持久任务与写入幂等均不在本轮验收范围。

十、接入已有智能体时保留哪些边界

接入第四篇图时,我会让工具执行节点调用 MCP 适配器,把协议层结果转为既有观察结构,而不让每个节点都直接操作传输。读取型结果校验后交给第五篇外存,状态继续保存版本引用。工具发现和连接管理按服务生命周期组织,不为每轮规划重复启动 Server。

工具注册使用受信任的服务配置标识与工具名建立映射,避免不同 Server 的同名 search 相互覆盖。Server 自报的名称不保证全局唯一,不能单独作为消歧或授权依据。资料 2

下一篇将把这层接入落实为资料与文档工具服务:定义输入输出、适配工具描述、验证路径与参数,并处理工具失败和连接生命周期。读者此时需要记住的工程约束是:先明确正在使用哪一版协议,再选择匹配的 SDK API 和传输行为。

参考资料

以下协议结论来自对应版本的官方规范;兼容结果来自本文所列 SDK 的本地运行,不将“规范要求”写成“所有实现均已支持”。

  1. MCP Architecture,2026-07-28:角色、分层、能力与逐请求模型。
  2. MCP Tools,2026-07-28:工具发现、调用、结果、名称与信任边界。
  3. MCP Base Protocol,2026-07-28:消息类型、结果类型、无状态与必要元数据。
  4. MCP Lifecycle,2025-11-25:旧版初始化、版本与能力交换。
  5. MCP Versioning,2026-07-28:逐请求版本与新旧兼容策略。
  6. MCP stdio,2026-07-28:按行消息、取消与子进程生命周期。
  7. MCP Transports,2025-11-25:旧版 Streamable HTTP、会话与事件恢复。
  8. MCP Streamable HTTP,2026-07-28:新版请求、头字段、订阅与取消。
  9. MCP Transports,2024-11-05:旧 HTTP+SSE 的两个入口与 endpoint 事件。
  10. Python SDK v1 → v2 Migration:服务端改名、客户端自动模式、字段和依赖迁移。
Logo

更多推荐