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

Transports

ทุกอย่างที่คุณเรียนในโมดูลก่อน ๆ — 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
สอง transport หนึ่ง data layer
ประเด็นstdioStreamable HTTP
ใครเปิด serverclient spawn มันรันเอง (เป็น web service)
อายุของ processผูกกับ client ที่ spawn มันอิสระ; หลาย client ใช้ร่วมกัน
client ที่ให้บริการปกติหนึ่งตัวหลายตัวพร้อมกัน
Credentialenvironment variable และไฟล์ในเครื่องOAuth 2.1 bearer token บนทุก request
overhead ของ networkไม่มี — เป็น pipe บนเครื่องเดียวHTTP round trip หนึ่งครั้งต่อ message
เข้าถึงเครื่องของผู้ใช้ได้โดยตรง (filesystem, tool ในเครื่อง)ไม่ได้ เว้นแต่ผู้ใช้อนุญาต
ตัวอย่างทั่วไปfilesystem server, git server, ตัวครอบ CLISentry, SaaS integration, internal API gateway

กฎง่าย ๆ: ถ้า server ต้องใช้ เครื่องของผู้ใช้ (ไฟล์, local database, dev tool) ใช้ stdio ถ้า server อยู่หน้า service ที่ผู้ใช้หลายคนแชร์กัน ใช้ Streamable HTTP

ทุก 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 ล้วน ๆ

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 ไม่ใช่เริ่มจากศูนย์

บทเรียนสิ่งที่คุณจะได้เรียน
stdioframing, กฎของ stdout, shutdown, cancellation, config file ของ host
Streamable HTTPPOST endpoint เดียว, response แบบ JSON กับ SSE, header ที่บังคับ, subscriptions/listen
Building an HTTP servercreateMcpHandler และ mcp.run() ในทางปฏิบัติ, การออกแบบให้ stateless
Backward compatibilityยุค modern กับ legacy, client ตรวจจับได้อย่างไรว่ากำลังคุยกับยุคไหน
อะไรต่างกันระหว่าง transport แบบ stdio กับ Streamable HTTP?
สถานการณ์ไหนที่ควรใช้ transport แบบ stdio?
ทำไม Streamable HTTP ถึง mirror field อย่างชื่อ method ไปเป็น HTTP header?