MCP 2.0 发布:无状态协议打开新生态
Model Context Protocol 2.0 引入无状态设计,标志着 MCP 规范最重要的一次迭代,催生了新工具生态。
Model Context Protocol 2.0 引入无状态设计,标志着 MCP 规范最重要的一次迭代,催生了新工具生态。
周二是 Stateless MCP 日——MCP 2.0 的发布,或者按更正式但不太容易记住的名字叫 2026-07-28 Model Context Protocol 规范。这是自 MCP 首次推出以来最重大的规范变化,也重新激发了我个人对该协议的兴趣。
背景介绍:MCP 是 Model Context Protocol,描述了一种向 LLM 驱动的 Agent 框架公开新工具的标准方式。它由 Anthropic 在 2024 年 11 月引入,在 2025 年大部分时间内引发了巨大的关注热潮,后来当人们发现一个能访问终端和 curl 的 Agent 框架可以用更灵活的方式做大部分 MCP 能做的事情时,被 Skills(另一项 Anthropic 发明)所掩盖。我在 2025 年的总结文章中写过这个。
我现在又回到了 MCP。给一个 Agent 提供一个有网络访问能力的 shell 环境风险重重,需要一个强大的模型来有效驱动这样的环境。MCP 工具更容易审计和控制,足够简单,以至于在笔记本上运行的较小模型仍然能相当好地驱动它们。
新的 stateless MCP 规范也大大降低了为该协议实现客户端和服务器的复杂性。我这周就构建了三个!
演示有状态和无状态 MCP 之间区别的最好例子在 5 月 21 日的博文中,它介绍了新规范的 RC 版本。它包含了一个清晰的前后对比示例。
较旧的有状态 MCP(我将其称为"legacy MCP")需要两个 HTTP 请求——第一个用来初始化会话并获取一个 Mcp-Session-Id,第二个才是实际调用工具:
POST /mcp HTTP/1.1
Content-Type: application/json
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"capabilities": {
},
"clientInfo": {
"name": "my-app",
"version": "1.0"
}
}
}
POST /mcp HTTP/1.1
Mcp-Session-Id: 1868a90c-3a3f-4f5b
Content-Type: application/json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "search",
"arguments": {
"q": "otters"
}
}
}
新的无状态方式使用单一 HTTP 请求,看起来是这样的:
POST /mcp HTTP/1.1
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: search
Content-Type: application/json
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "search",
"arguments": {
"q": "otters"
},
"_meta": {
"io.modelcontextprotocol/clientInfo": {
"name": "my-app",
"version": "1.0"
}
}
}
}
从客户端和服务器实现的角度来看,这干净得多。它也更适合构建可扩展的网络应用程序,因为现在你不需要维护服务器端状态来跟踪那些会话 ID,也不用担心把相同的会话路由到相同的后端机器。
我找不到一个很好的 CLI 工具来交互式地探测 MCP 服务器,所以我让 Codex 帮助构建了我自己的工具。
mcp-explorer 就是结果。它是一个无状态的 Python CLI 工具,所以你甚至不需要安装它就能试用——它可以用 uvx 这样运行:
uvx mcp-explorer list https://agentic-mermaid.dev/mcp
这会查询 Ade Oshineye 的 agentic-mermaid.dev 演示 MCP。上面的命令返回以下工具列表:
execute(code: string, timeoutMs?: integer) - Execute Mermaid SDK code
Run JavaScript in an isolated sandbox; return a value.
describe_sdk(family: string, detail?: string) - Describe Mermaid SDK operations
Return version-matched mutation operations for one diagram family.
render_svg(source: string, options?: object) - Render Mermaid as SVG
Render a Mermaid source string to themeable SVG. Returns { ok, svg }.
render_ascii(source: string, useAscii?: boolean, targetWidth?: integer, options?: object) - Render Mermaid as text
Render a Mermaid source string to text. Returns { ok, text }.
render_png(source: string, scale?: number, background?: string, fitTo?: object, options?: object) - Render Mermaid as PNG
Rasterize a Mermaid source string to PNG. Returns { ok, png_base64 }.
...
然后来检查一个工具:
uvx mcp-explorer inspect render_svg
这会输出大量信息,包括输入和输出的 JSON Schema。
要调用该工具并向其传递参数:
uvx mcp-explorer call \
https://agentic-mermaid.dev/mcp \
render_svg \
-a source 'graph TD; A-->B' \
-a options '{"padding":24}'
{"ok":true,"svg":"<svg xmlns=\"http://www.w3.org/2000/svg\" width=...
要只获取原始 SVG,可以尝试在该命令中添加 | jq .svg -r。我获得了这个图像:
README 中还有几个命令,但你能理解基本思想。我发现构建这样的 CLI 工具是熟悉规范的一种真正高效的方式,即使大部分实际代码是由 Agent 编写的。
第二个项目是 datasette-mcp,一个 Datasette 插件,为任何 Datasette 实例添加了一个 /-/mcp 端点。
这可能是我第四次尝试构建这个插件,但感谢新的 stateless MCP 规范,我终于有了一个感觉很好可以发布的版本。
它只提供三个工具:list_databases()、get_database_schema(database_name) 和 execute_sql(database_name, sql)。它们的功能完全符合你的预期——尽管 execute_sql() 目前是只读的。
把这些接入一个 Agent,或者像 ChatGPT 或 Claude 这样的聊天工具,它们就能获得针对你托管的 Datasette 实例运行 SQL 查询的能力。
到目前为止,我在我的博客的 Datasette 镜像上运行它,地址是 datasette.simonwillison.net/-/mcp。需要花一些工夫才能弄清楚如何把它附加到 ChatGPT 和 Claude 上,但我最终还是做到了。这是一篇新的 TIL,展示了确切的做法。
这是一个共享的 Claude 会话,我在其中问了它:
list tables in simonwillison.net
what has Simon said recently about MCP?
它运行了 7 个单独的 SQL 查询来找出答案。
我的 LLM 工具早就应该有一个官方的 MCP 集成了。新的 alpha llm-mcp-client 插件是我的确切尝试:
llm install llm-mcp-client
llm -T 'MCP("https://datasette.simonwillison.net/-/mcp")' 'count the notes'
这是输出(包括推理跟踪,我使用的是 LLM 0.32rc2):
Considering note count
I see the question "count the notes" is probably asking me to tally up blog notes. It could also mean published notes or drafts, so there's some ambiguity there. I'll need to figure out the total number of notes, likely by querying the count for both published notes and drafts to get a clear answer. Let's execute that count!
以及该提示的 llm logs 的输出。
一旦这个完全成熟,我考虑将其直接引入 LLM core。我还兴奋地期待在 Datasette Agent 和 llm-coding-agent 中试验 MCP。
在 MCP 首次发布的几个月后,我写了《Model Context Protocol has prompt injection security problems》,其中我指出了让最终用户混搭工具的模式把避免数据泄露攻击的责任推给了用户自己。我还没有创造"Lethal Trifecta"这个术语,但那绝对是我想表达的。
然后通用 Agent 带着任意的 shell 和 curl 访问权限出现了,这要安全得多才行!
我对 MCP 的一个越来越欣赏的地方是,相比在开放网络环境中任意执行命令(这是今天大多数通用和编码 Agent 工具的默认方式)来说,更容易推理 Agent 的能力和可能出错的地方。
当我在 LLM 之上构建敏感应用程序时,我计划大力倾向于使用 MCP。
OpenAI's accidental cyberattack against Hugging Face is science fiction that happened - 2026 年 7 月 22 日
A Fireside Chat with Cat and Thariq from the Claude Code team - 2026 年 7 月 21 日
这是 Simon Willison 在 2026 年 7 月 31 日发布的《Stateless MCP has recaptured my interest (and inspired mcp-explorer and datasette-mcp)》。
前篇:OpenAI's accidental cyberattack against Hugging Face is science fiction that happened
赞助我每月 $10,获得每月最重要的 LLM 发展的精选电邮摘要。
付钱让我给你发更少的邮件!