取樣與根目錄
處理函式還可以向連線的用戶端多要兩樣東西:由用戶端自己的模型產生的生成結果,也就是取樣(sampling);以及用戶端的工作區資料夾,也就是根目錄(roots)。
兩者在 SDK 支援的每個協定版本上都還能用。但在以它們為基礎做設計之前,先讀一下這段警告:
已於 2026-07-28 規格中棄用
取樣和根目錄自 2026-07-28 起已棄用(SEP-2577)。它們仍然完全可用,並且會在規格中至少保留 12 個月,之後才可能被移除;但新的實作不應該建立在它們之上。建議的遷移方式:不要用取樣,改為直接整合 LLM 供應商的 API;不要用根目錄,改為透過工具參數、資源 URI 或伺服器設定來傳入目錄。整個 SDK 的清單在 已棄用的功能。
取樣:借用用戶端的模型
解析器回傳 Sample(...),工具就會收到生成結果,走的是和 相依性 中執行 Elicit 相同的相依性機制:
server.py
from typing import Annotated
from mcp.server import MCPServer
from mcp.server.mcpserver import Resolve, Sample
from mcp.types import CreateMessageResult, SamplingMessage, TextContent
mcp = MCPServer("Bookshop")
def draft_blurb(title: str) -> Sample:
prompt = f"Write a one-sentence blurb for the book {title!r}."
return Sample(
[SamplingMessage(role="user", content=TextContent(type="text", text=prompt))],
max_tokens=60,
)
@mcp.tool()
async def blurb(title: str, draft: Annotated[CreateMessageResult, Resolve(draft_blurb)]) -> str:
"""Draft a blurb for a book."""
return draft.content.text if draft.content.type == "text" else "No blurb."
Sample(messages, max_tokens=...)對應sampling/createMessage的參數。注入的值是用戶端的CreateMessageResult;如果傳入tools或tool_choice,則會變成CreateMessageResultWithTools。- 用戶端必須宣告了
sampling能力(如果傳入tools或tool_choice,則是sampling.tools)。如果沒有,呼叫會以-32021協定錯誤失敗,而不是送出一個用戶端無法處理的請求。沒有反向通道(back-channel)的 2026 之前的工作階段(session)則會以它一貫的「沒有反向通道」錯誤失敗,因為根本沒有通道可送。 - 在
2026-07-28,請求是在多輪往返(multi-round-trip)流程中傳遞的(多輪往返請求);在2025-11-25則是對用戶端發出的獨立請求。兩種情況下程式碼都一樣,但要注意多輪往返的規則:請求在各輪重試之間必須呈現得完全相同,所以只能用工具的引數和其他穩定的資料來建構它。 - 不要動
include_context:"none"以外的值本身也已棄用(SEP-2596),而且需要一個幾乎沒有用戶端會宣告的能力。
根目錄:這個該放哪裡?
根目錄是用戶端表示伺服器可以操作的資料夾。它們是參考用的指引,不是存取控制機制。解析器回傳 ListRoots():
server.py
from typing import Annotated
from mcp.server import MCPServer
from mcp.server.mcpserver import ListRoots, Resolve
from mcp.types import ListRootsResult
mcp = MCPServer("Bookshop")
def workspace_roots() -> ListRoots:
return ListRoots()
@mcp.tool()
async def catalog_folder(roots: Annotated[ListRootsResult, Resolve(workspace_roots)]) -> str:
"""Pick the folder the catalog export should go to."""
if not roots.roots:
return "No workspace folders shared."
return str(roots.roots[0].uri)
- 注入的
ListRootsResult帶有一個Root清單:每個包含一個file://URI 和一個選填的顯示名稱。 - 把關條件和取樣相同:沒有宣告
roots能力時,呼叫會以-32021失敗,而不會送出請求。
在線路的另一端,用戶端用它已有的回呼來回應這兩種請求:sampling_callback 和 list_roots_callback,說明見 用戶端回呼。
在 2025 世代的連線上
ctx.session.create_message(...) 和 ctx.session.list_roots() 仍然存在,供直接操作工作階段的程式碼使用。它們只在有反向通道的地方才能運作(2025 世代、非無狀態的連線),而且呼叫時會引發棄用警告。上面的解析器標記才是受支援的形式:它們會依協商出的版本挑選傳遞方式,也不會發出警告。
重點回顧
- 從解析器回傳
Sample(...)或ListRoots();工具會像收到其他相依性一樣收到CreateMessageResult或ListRootsResult。 - 用戶端必須宣告對應的能力,否則呼叫會以
-32021失敗,而不會送出請求。 - 兩項功能在
2026-07-28都已棄用:目前完全可用,但不適合新設計。優先選擇供應商 API 而非取樣,優先選擇明確的參數而非根目錄。
回報慢速工具的進度:進度。