無狀態 MCP 重燃我的興趣(並催生了 mcp-explorer 與 datasette-mcp)
原文由 Simon Willison 于 發布,訂閱此部落格
星期二是Stateless MCP 日——也就是 MCP 2.0 正式推出的日子,或者用更正式但沒那麼好記的名稱來說,是2026-07-28 版 Model Context Protocol 規範。這是 MCP 規範自問世以來最重大的改動,也讓我對這個協定重新燃起了興趣。
先補點背景:MCP 是 Model Context Protocol,它定義了一種標準方式,讓 LLM 驅動的 agent 框架能夠取用新工具。它最早是在2024 年 11 月由 Anthropic 推出,在 2025 年的大部分時間裡引發了巨大的關注熱潮,隨後則在一定程度上被Skills(同樣是 Anthropic 的發明)蓋過了鋒頭——因為大家發現,只要讓 agent 擁有可存取終端機與 curl 的執行環境,就能以更靈活的方式完成 MCP 能做的大部分事情。這點我在2025 年回顧裡有寫過。
現在我又重新關注起 MCP。讓 agent 擁有可上網的 shell 環境風險很高,而且需要夠強大的模型才能有效駕馭。MCP 工具則更容易稽核與控管,也夠簡單,即使是在筆電上執行的小型模型也能駕馭得不錯。
新的無狀態 MCP 規範也大幅降低了為這個協定實作客戶端與伺服端的複雜度。這週我就做了三個!
無狀態 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"
}
}
}
}無論從客戶端還是伺服端的實作角度來看,這都簡潔多了。也更適合用來打造可擴展的網頁應用,因為現在你不需要在伺服器端維持狀態來追蹤那些 session ID,也不必擔心要把同一個 session 導向同一台後端機器。
mcp-explorer
我一直找不到好用的 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-mcp,這是一個 Datasette 外掛,會在任何 Datasette 實例上加入 /-/mcp 端點。
這大概是我第四次嘗試做這個外掛了,但多虧新的無狀態 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-client
我的 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):
正在思考筆記數量
我看到「count the notes」這個問題,大概是想統計部落格筆記的數量。也可能是指已發布的筆記或草稿,所以有點模糊。我得想辦法算出筆記總數,很可能會去查詢已發布筆記和草稿的數量來得到明確答案。來執行這個統計吧!
共有 151 則筆記。
等這個功能完全穩定後,我考慮直接把它整合進 LLM 核心。我也很期待在 Datasette Agent 和 llm-coding-agent 中嘗試 MCP。
MCP 是打造 agent 應用更安全的方式
MCP 剛推出幾個月後,我寫過一篇〈Model Context Protocol 有提示注入的安全問題〉,裡面提到,讓使用者自行混搭工具的做法,把避免資料外洩攻擊的責任推給了使用者自己。我當時還沒創造出致命三要素這個詞,但指的完全就是那回事。
後來出現了可任意存取 shell 與 curl 的通用型 agent,要確保安全就困難多了!
我愈來愈體會到,MCP 的好處在於,要推敲 agent 的能力範圍以及可能出什麼問題,比起在開放網路環境中任意執行指令——也就是現今大多數通用型與程式開發用 agent 工具的預設模式——要容易得多。
之後在打造基於 LLM 的敏感應用時,我打算更倚重 MCP。
隨機一篇部落格
留言
登入後參與討論