Transports
message เดียวกัน ท่อคนละท่อ
หัวข้อที่มีชื่อว่า “message เดียวกัน ท่อคนละท่อ”ทุกอย่างที่คุณเรียนในโมดูลก่อน ๆ — server/discover, tools/list, tools/call, resources/read, subscriptions/listen — คือ JSON-RPC 2.0 message MCP ไม่เปลี่ยน message เหล่านั้นเมื่อย้ายมันข้ามขอบเขตของเครื่อง สิ่งที่เปลี่ยนคือ transport: binding ที่บอกว่า byte เดินทางจาก process หนึ่งไปอีก process หนึ่งอย่างไร
MCP นิยาม transport ไว้สองแบบ:
- stdio — client เปิด server เป็น child process แล้วคุยผ่าน standard input และ output ของมัน
- Streamable HTTP — server เป็น process อิสระที่อยู่หลัง HTTP endpoint เดียวซึ่งรับ POST
data layer คือชั้นใน; transport คือชั้นนอก SDK ให้คุณลงทะเบียน tool ครั้งเดียวแล้ว serve ผ่าน transport ไหนก็ได้โดยไม่ต้องแตะ handler
flowchart LR
subgraph host["Host (AI application)"]
c1["MCP client"]
c2["MCP client"]
end
c1 -- "stdio: stdin/stdout of a child process" --> s1["Local server (subprocess)"]
c2 -- "Streamable HTTP: POST /mcp" --> s2["Remote server (any host)"]
s1 --- d["JSON-RPC data layer: tools, resources, prompts"]
s2 --- d local หรือ remote? ตารางช่วยตัดสินใจ
หัวข้อที่มีชื่อว่า “local หรือ remote? ตารางช่วยตัดสินใจ”| ประเด็น | stdio | Streamable HTTP |
|---|---|---|
| ใครเปิด server | client spawn มัน | รันเอง (เป็น web service) |
| อายุของ process | ผูกกับ client ที่ spawn มัน | อิสระ; หลาย client ใช้ร่วมกัน |
| client ที่ให้บริการ | ปกติหนึ่งตัว | หลายตัวพร้อมกัน |
| Credential | environment variable และไฟล์ในเครื่อง | OAuth 2.1 bearer token บนทุก request |
| overhead ของ network | ไม่มี — เป็น pipe บนเครื่องเดียว | HTTP round trip หนึ่งครั้งต่อ message |
| เข้าถึงเครื่องของผู้ใช้ | ได้โดยตรง (filesystem, tool ในเครื่อง) | ไม่ได้ เว้นแต่ผู้ใช้อนุญาต |
| ตัวอย่างทั่วไป | filesystem server, git server, ตัวครอบ CLI | Sentry, SaaS integration, internal API gateway |
กฎง่าย ๆ: ถ้า server ต้องใช้ เครื่องของผู้ใช้ (ไฟล์, local database, dev tool) ใช้ stdio ถ้า server อยู่หน้า service ที่ผู้ใช้หลายคนแชร์กัน ใช้ Streamable HTTP
request metadata เดินทางอย่างไร
หัวข้อที่มีชื่อว่า “request metadata เดินทางอย่างไร”ทุก MCP request พก protocol version และ client capability มาใน _meta (ดู JSON-RPC and _meta) สอง transport ขน metadata นั้นต่างกัน:
- stdio ไม่มีชั้น header ทุกอย่าง — version, capability, ตัวตนของ client, method, argument — อยู่ inline ใน JSON-RPC body หนึ่ง message ต่อบรรทัด
- Streamable HTTP body เหมือนเดิมเป๊ะ แต่ mirror บาง field ไปเป็น HTTP header (
MCP-Protocol-Version,Mcp-Method,Mcp-Name) เพื่อให้ load balancer, gateway และเครื่องมือ observability route และตรวจสอบ request ได้โดยไม่ต้อง parse JSON server จะ validate ว่า header กับ body ตรงกัน
การ mirror นั้นเป็นจุดเดียวที่สอง transport แตกต่างกันในระดับ message และมันมีไว้เพื่อ intermediary ล้วน ๆ
Custom transport
หัวข้อที่มีชื่อว่า “Custom transport”framing ของ stdio — JSON-RPC message ที่คั่นด้วย newline หนึ่งตัวต่อบรรทัดบน byte stream สองทางที่เชื่อถือได้ — ไม่ได้ผูกกับ standard stream spec บอกว่า custom transport ที่สร้างบน Unix domain socket, TCP หรือช่องทางคล้ายกัน ควร ใช้ framing นั้นและกฎ message ของ stdio ซ้ำ โดยเปลี่ยนเฉพาะส่วนที่เจาะจงกับ subprocess (การเปิด, stderr, การ shutdown ด้วยการปิด stream, การ restart) ดังนั้นถ้าคุณต้องการ binding แบบที่สามเมื่อไร ให้เริ่มจากกฎของ stdio ไม่ใช่เริ่มจากศูนย์
โมดูลนี้ครอบคลุมอะไร
หัวข้อที่มีชื่อว่า “โมดูลนี้ครอบคลุมอะไร”| บทเรียน | สิ่งที่คุณจะได้เรียน |
|---|---|
| stdio | framing, กฎของ stdout, shutdown, cancellation, config file ของ host |
| Streamable HTTP | POST endpoint เดียว, response แบบ JSON กับ SSE, header ที่บังคับ, subscriptions/listen |
| Building an HTTP server | createMcpHandler และ mcp.run() ในทางปฏิบัติ, การออกแบบให้ stateless |
| Backward compatibility | ยุค modern กับ legacy, client ตรวจจับได้อย่างไรว่ากำลังคุยกับยุคไหน |