Deprecated: Sampling, Roots, and Logging
สาม feature ที่กำลังจะจากไป
หัวข้อที่มีชื่อว่า “สาม feature ที่กำลังจะจากไป”revision 2026-07-28 deprecate client feature สามตัวในคราวเดียว (SEP-2577): sampling, roots และ logging พวกมันยังไม่หายไป — feature ที่ถูก deprecate ยังทำงานได้อย่างน้อยสิบสองเดือนตาม feature lifecycle policy และถูกลิสต์ไว้ใน deprecated-features registry ให้ติดตามได้ แต่ implementation ใหม่ไม่ควรเอามาใช้ และของเดิมควรวางแผน migrate
บทนี้ครอบคลุมว่าแต่ละตัวเคยทำอะไร ตอนนี้หน้าตาเป็นอย่างไร และควรใช้อะไรแทน
Sampling
หัวข้อที่มีชื่อว่า “Sampling”เคยทำอะไร
หัวข้อที่มีชื่อว่า “เคยทำอะไร”sampling ให้ server ขอ completion จาก LLM ของ host — “ช่วยสรุป diff นี้ให้หน่อย” — โดยไม่ต้องพ่วง LLM SDK หรือ API key มาด้วย request คือ sampling/createMessage:
{ "method": "sampling/createMessage", "params": { "messages": [ { "role": "user", "content": { "type": "text", "text": "Summarize this changelog in one line: …" } } ], "systemPrompt": "You are terse.", "maxTokens": 100, "modelPreferences": { "hints": [{ "name": "claude" }], "intelligencePriority": 0.8, "speedPriority": 0.5, "costPriority": 0.2 } }}modelPreferences เป็นแค่คำแนะนำ: hints เป็น substring match กับชื่อ model และ priority สามตัว (0–1) ให้ host เลือก model host ยังคงมีมนุษย์อยู่ใน loop — แสดง, แก้ หรือปฏิเสธทั้ง prompt และ completion ได้
ตอนนี้หน้าตาเป็นอย่างไร
หัวข้อที่มีชื่อว่า “ตอนนี้หน้าตาเป็นอย่างไร”ใน 2026-07-28 server ส่ง request ไม่ได้ ดังนั้นที่ เดียว ที่ sampling/createMessage จะปรากฏได้คือใน map InputRequiredResult.inputRequests ภายใต้ MRTR client รัน completion แล้ว return CreateMessageResult ใน inputResponses:
{ "capital": { "role": "assistant", "content": { "type": "text", "text": "The capital of France is Paris." }, "model": "claude-opus-5", "stopReason": "endTurn" }}ค่า includeContext แบบ "thisServer" และ "allServers" ถูก soft-deprecate ตั้งแต่ 2025-11-25 และตอนนี้ deprecate อย่างเป็นทางการ ให้ละ field นี้หรือส่ง "none"
ทำไมถึงถูก deprecate
หัวข้อที่มีชื่อว่า “ทำไมถึงถูก deprecate”สองเหตุผล หนึ่ง statelessness: completion แพง และการบังคับให้มันผ่าน MRTR retry แปลว่า host จ่ายค่า completion แล้วยังต้องส่ง request เดิมทั้งก้อนซ้ำอีก สอง model ของ host ไม่ใช่ model ของ server — คุณภาพ, ค่าใช้จ่าย และ safety policy เป็นของคนที่ถือ API key server ที่ต้องการ LLM ควรเรียกเองมากกว่า
Migration: เรียก provider ของคุณโดยตรง
หัวข้อที่มีชื่อว่า “Migration: เรียก provider ของคุณโดยตรง”import Anthropic from '@anthropic-ai/sdk';
const anthropic = new Anthropic(); // reads ANTHROPIC_API_KEY from the environment
async function summarize(text: string): Promise<string> { const msg = await anthropic.messages.create({ model: 'claude-opus-5', max_tokens: 256, system: 'You are terse.', messages: [{ role: 'user', content: `Summarize in one line:\n\n${text}` }], }); const block = msg.content[0]; return block.type === 'text' ? block.text : '';}
server.registerTool( 'summarize_changelog', { description: 'One-line changelog summary', inputSchema: z.object({ text: z.string() }) }, async ({ text }) => ({ content: [{ type: 'text', text: await summarize(text) }] }));import anthropic
from mcp.server import MCPServer
mcp = MCPServer("changelog")client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY from the environment
@mcp.tool()def summarize_changelog(text: str) -> str: """One-line changelog summary.""" msg = client.messages.create( model="claude-opus-5", max_tokens=256, system="You are terse.", messages=[{"role": "user", "content": f"Summarize in one line:\n\n{text}"}], ) return msg.content[0].textบน stdio key มาจาก environment ที่ host ใช้ launch คุณ บน HTTP มาจาก secret store ของคุณเอง ไม่ว่าทางไหน ตอนนี้ server เป็นเจ้าของการเลือก model, retry และค่าใช้จ่าย
เคยทำอะไร
หัวข้อที่มีชื่อว่า “เคยทำอะไร”roots ให้ server ถาม client ว่าตำแหน่งไหนใน filesystem ที่อนุญาตให้ทำงาน — roots/list return URI เช่น file:///home/me/project — และ notifications/roots/list_changed บอก server เมื่อชุดนั้นเปลี่ยน
ตอนนี้หน้าตาเป็นอย่างไร
หัวข้อที่มีชื่อว่า “ตอนนี้หน้าตาเป็นอย่างไร”roots/list เหลืออยู่แค่ในฐานะ MRTR input request ส่วน notifications/roots/list_changed ถูกถอดทิ้งทั้งหมด (ใน 2026-07-28 ไม่มี notification จาก client ไป server สำหรับเรื่องนี้) ListRootsResult ยังหน้าตาแบบนี้เมื่อกลับมาใน inputResponses:
{ "roots": [{ "uri": "file:///home/me/project", "name": "project" }]}Migration: ระบุ path ให้ชัด
หัวข้อที่มีชื่อว่า “Migration: ระบุ path ให้ชัด”ตัวแทนที่แนะนำเรียบง่ายจนน่าอาย: ส่ง directory เป็น tool argument, resource URI หรือ server configuration
- tool ที่ค้นหาไฟล์รับ parameter
pathแล้ว validate กับ allowlist ที่ config ตอน launch - server ที่ทำงานกับ project เดียวเสมอรับ directory นั้นเป็น CLI argument หรือ environment variable ตอน host spawn — ซึ่งก็คือวิธีที่
npx @modelcontextprotocol/server-filesystem ~/Desktopทำมาตลอด - ไฟล์ที่ model ควร อ่าน เหมาะจะเปิดเป็น resource มากกว่าให้ค้นพบผ่าน roots
path ที่ระบุชัดยัง secure ง่ายกว่าด้วย: คุณ sanitize parameter ได้ แต่ audit สิทธิ์โดยนัยที่ client เคยให้ใน request ก่อนหน้าได้ยาก
Logging
หัวข้อที่มีชื่อว่า “Logging”เคยทำอะไร
หัวข้อที่มีชื่อว่า “เคยทำอะไร”logging ให้ server มี channel ไปยัง log ของ client: client ตั้ง threshold ด้วย logging/setLevel แล้ว server push entry notifications/message ที่มี level (debug ถึง emergency), ชื่อ logger (optional) และ data อะไรก็ได้
ตอนนี้หน้าตาเป็นอย่างไร
หัวข้อที่มีชื่อว่า “ตอนนี้หน้าตาเป็นอย่างไร”logging/setLevel ถูกถอดออก threshold ตอนนี้เป็น ต่อ request อยู่ใน _meta:
{ "_meta": { "io.modelcontextprotocol/logLevel": "info", "io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientCapabilities": {} }}server ต้องไม่ ส่ง notifications/message ให้ request ที่ไม่ได้ใส่ field นี้ และที่ส่งออกไปจะวิ่งบน response stream ของ request นั้น ไม่ใช่บน subscription
Migration: stderr และ OpenTelemetry
หัวข้อที่มีชื่อว่า “Migration: stderr และ OpenTelemetry”- บน stdio log ลง stderr transport สงวน stdout ไว้ให้ protocol message แต่ stderr มีไว้สำหรับ log โดยเฉพาะ host อาจ capture, forward หรือเมินก็ได้ ห้ามเขียน log ลง stdout เด็ดขาด
- บน HTTP ใช้ logging stack ปกติของคุณ และเพื่อ correlate ข้าม service ใช้ OpenTelemetry key
traceparent,tracestateและbaggageใน_metaถูกสงวนไว้สำหรับ W3C trace-context propagation ดังนั้น client ส่ง trace id มาให้ได้ และ span ของคุณจะเรียงต่อกับของเขา:
{ "params": { "name": "get_weather", "arguments": { "location": "Bangkok" }, "_meta": { "traceparent": "00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01", "io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientCapabilities": {} } }}// stdio server: logs go to stderr, never stdoutconsole.error(JSON.stringify({ level: 'info', msg: 'import started', files: urls.length }));import loggingimport sys
# stdio server: configure the root logger to stderr once, at startuplogging.basicConfig(stream=sys.stderr, level=logging.INFO)logging.getLogger("catalog").info("import started: %d files", len(urls))lifecycle เพื่อให้วางแผนได้
หัวข้อที่มีชื่อว่า “lifecycle เพื่อให้วางแผนได้”flowchart LR A["Active"] --> D["Deprecated (12+ เดือน, อยู่ใน registry)"] D --> R["Removed ใน revision ถัดไป"]
feature ที่ถูก deprecate จะระบุทาง migrate และคงอยู่อย่างน้อยสิบสองเดือน (เก้าสิบวันภายใต้ข้อยกเว้นแบบเร่งด่วน) ก่อนจะเข้าข่ายถูกถอด sampling, roots และ logging เข้าสู่สถานะ Deprecated พร้อม 2026-07-28 revision เดียวกันนี้ยังจัด HTTP+SSE transport แบบเก่าและ dynamic client registration เป็น Deprecated ด้วย เช็คหน้า registry เพื่อดูสถานะปัจจุบันก่อนจะสร้างอะไรบนสิ่งที่ถูกทำเครื่องหมาย Deprecated