ข้ามไปยังเนื้อหา

Client Interaction

MCP ส่วนใหญ่ไหลทางเดียว: client ถาม server ตอบ tools/list, tools/call, resources/read — request เข้า result ออก แต่ tool ของจริงบางทีก็ไปเจอทางตันกลางทาง:

  • ต้องให้คนตัดสินใจ “จองโต๊ะ 4 หรือ 6 ที่?” “จะ deploy ไป region ไหน?” มีแค่ผู้ใช้เท่านั้นที่ตอบได้
  • ต้องใช้ secret ที่ server ไม่ควรเห็นแบบ plain text API key ของ service ภายนอก, การอนุมัติจ่ายเงิน, OAuth consent
  • ใช้เวลานานเกินกว่าที่ HTTP request เดียวจะเปิดค้างไว้ได้ CI pipeline, bulk import, งานที่ต้องรอ approval

ทุกกรณีข้างต้น server ต้องการอะไรบางอย่างจาก client — แต่ MCP เป็น protocol ที่ stateless และขับเคลื่อนโดย client การตัดสินใจออกแบบข้อเดียวนี้กำหนดรูปร่างของทุกอย่างใน module นี้

ใน revision 2026-07-28 MCP เป็น stateless: ทุก request แบกทุกอย่างที่ server ต้องใช้ไว้ใน _meta และ server ห้ามอนุมานอะไรจาก request ก่อนหน้าบน connection เดียวกัน ผลข้างเคียงที่ทำให้คนที่มาจากยุคเก่า (2025-11-25 และก่อนหน้า) แปลกใจคือ server ส่ง JSON-RPC request ของตัวเองไปหา client ไม่ได้อีกแล้ว ไม่มี channel เปิดค้างที่ elicitation/create หรือ sampling/createMessage จะวิ่งย้อนขึ้นไปได้

sequenceDiagram
  participant U as User
  participant C as Client
  participant S as Server
  C->>S: tools/call (id 1)
  Note over S: ต้องให้ผู้ใช้เลือก region
  S-->>C: InputRequiredResult (inputRequests, requestState)
  C->>U: form: เลือก region
  U-->>C: eu-west-1
  C->>S: tools/call (id 2, args เดิม + inputResponses + requestState)
  S-->>C: final result
server ต้องตอบ — ก็เลยตอบด้วยคำถาม

ดังนั้นแทนที่จะ ส่ง request server จะ return result ที่ขอ input client ไปรวบรวมคำตอบมาแล้ว retry request เดิม พร้อมแนบคำตอบไปด้วย นี่คือ pattern Multi Round-Trip Requests (MRTR) และเป็นกระดูกสันหลังของทุกอย่างด้านล่าง

บทเรียนกลไกแก้ปัญหา
MRTRInputRequiredResult → retry พร้อม inputResponsesคำถามจาก server ไป client แบบใดก็ได้ โดยไม่ต้องมี state ฝั่ง server
Elicitationelicitation/create แบบ form หรือ URLขอข้อมูลหรือ consent จากผู้ใช้
Progress & cancellationnotifications/progress, notifications/cancelled, ปิด streamให้ call ที่ยาวยังมีชีวิตอยู่และหยุดได้
Tasks extensionresultType: "task", tasks/get, tasks/updateงานที่อยู่นานกว่า request
Deprecated featuressampling, roots, loggingควรใช้อะไรแทน

จะเข้าใจง่ายขึ้นถ้าแยกตาม ใคร ที่ server กำลังรอ:

  • รอผู้ใช้ — elicitation คำตอบมาจากคน ผ่าน UI ของ client ภายใต้ MRTR server ไม่ได้รอเลย: มัน return ออกไป แล้ว retry จะพาคำตอบกลับมา
  • รอเวลา — operation ที่รันนาน ส่วนที่เปราะบางคือ connection progress notification ช่วยให้ request เดียวยังมีชีวิตและซื่อสัตย์ ส่วน Tasks extension เปลี่ยนงานให้เป็น handle ที่คงทน poll ได้แม้หลัง reconnect

ทั้งสองแบบทำให้ server ไม่ต้องเก็บ state ต่อ connection state จะเดินทางไปกับ request (requestState) หรือไม่ก็เป็น identifier ชัด ๆ (taskId) ที่ client ส่งมาทุก call

feature ฝั่ง client สามตัวถูก deprecate ใน 2026-07-28 (SEP-2577): sampling (server ขอ completion จาก LLM ของ host), roots (server ถามว่าแตะ directory ไหนได้บ้าง) และ logging (server push log line) ยังใช้ได้ระหว่างช่วง deprecation แต่ server ใหม่ไม่ควรเอามาใช้ บทเรียนสุดท้ายอธิบายว่าทำไมและอะไรมาแทนแต่ละตัว

ทำไม MCP server ใน 2026-07-28 ถึงส่ง elicitation/create เป็น JSON-RPC request ของตัวเองไม่ได้?
ภายใต้ MRTR server ถามคำถามผู้ใช้อย่างไร?
feature คู่ไหนที่รับมือกับกรณี "งานอยู่นานกว่า request เดียว"?