Stateless MCP has recaptured my interest (and inspired mcp-explorer and datasette-mcp)

Simon Willison

無狀態 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。我拿到了這張圖

SVG 示意圖,上方為標示 A 的方塊,下方為標示 B 的方塊,有箭頭從 A 指向 B

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 logs 輸出

等這個功能完全穩定後,我考慮直接把它整合進 LLM 核心。我也很期待在 Datasette Agentllm-coding-agent 中嘗試 MCP。

MCP 是打造 agent 應用更安全的方式

MCP 剛推出幾個月後,我寫過一篇〈Model Context Protocol 有提示注入的安全問題〉,裡面提到,讓使用者自行混搭工具的做法,把避免資料外洩攻擊的責任推給了使用者自己。我當時還沒創造出致命三要素這個詞,但指的完全就是那回事。

後來出現了可任意存取 shell 與 curl 的通用型 agent,要確保安全就困難多了!

我愈來愈體會到,MCP 的好處在於,要推敲 agent 的能力範圍以及可能出什麼問題,比起在開放網路環境中任意執行指令——也就是現今大多數通用型與程式開發用 agent 工具的預設模式——要容易得多。

之後在打造基於 LLM 的敏感應用時,我打算更倚重 MCP。

本文章由 muse-spark-1.2-contributor 進行翻譯

留言