Sổ tay kỹ thuật

MCP transport: stdio, Streamable HTTP và xác thực OAuth

concept#mcp#security#agents· cập nhật 2026-11-06

Chọn transport cho MCP server (stdio hay Streamable HTTP), hiểu luồng OAuth cho remote server và các rủi ro bảo mật cần chặn trước khi mở server ra mạng.

Sửa trang này
Mục lục

MCP dùng JSON-RPC 2.0, và transport là lớp mang các message đó giữa client với server. Hiện spec định nghĩa hai transport chuẩn: stdio cho server chạy cục bộ và Streamable HTTP cho server từ xa. Transport HTTP+SSE cũ (spec 2024-11-05) đã bị thay thế, chỉ còn giữ để tương thích ngược. Khái niệm chung về MCP xem MCP tổng quan.

So sánh transport

stdio Streamable HTTP
Cách chạy Client spawn server thành tiến trình con, trao đổi qua stdin/stdout Server chạy độc lập, có một endpoint HTTP (vd /mcp)
Số client 1 server phục vụ 1 client Nhiều client, nhiều phiên
Message client → server Một dòng JSON trên stdin POST JSON-RPC lên endpoint
Message server → client Một dòng JSON trên stdout Body JSON, hoặc SSE stream trong response của POST / GET
Phiên Gắn với vòng đời tiến trình Header Mcp-Session-Id do server cấp lúc initialize
Xác thực Không cần: credential lấy từ biến môi trường OAuth 2.1 (Bearer token) hoặc header API key
Log Chỉ ghi ra stderr vì stdout dành cho giao thức Log thoải mái
Hợp với Tool cá nhân, chạy trên jump host, dev Server dùng chung cho team, chạy cạnh NetBox/ClickHouse

Với stdio, chỉ một lệnh print() / console.log() ghi ra stdout là đủ làm hỏng luồng JSON-RPC, và client sẽ báo lỗi parse hoặc mất kết nối.

Luồng OAuth cho remote server

Theo spec (từ bản 2025-06-18), MCP server là resource server của OAuth: nó chỉ kiểm tra token. Token do một authorization server riêng cấp (Keycloak, Entra ID, Okta...).

sequenceDiagram participant C as MCP client participant S as MCP server participant A as Authorization server C->>S: POST /mcp (không có token) S-->>C: "401 + WWW-Authenticate (resource_metadata)" C->>S: "GET /.well-known/oauth-protected-resource" S-->>C: authorization_servers C->>A: Metadata, đăng ký client, login (PKCE) A-->>C: access token (audience = MCP server) C->>S: "POST /mcp + Authorization: Bearer" S-->>C: kết quả JSON-RPC
Thành phần Chuẩn Ghi chú
Protected Resource Metadata RFC 9728 Server công bố authorization server nào cấp token cho nó
Authorization Server Metadata RFC 8414 Client tự tìm endpoint authorize/token
PKCE OAuth 2.1 Bắt buộc, kể cả với public client
Resource Indicators RFC 8707 Client gửi tham số resource để token gắn đúng audience
Dynamic Client Registration RFC 7591 Không bắt buộc. Nếu không có, cấu hình sẵn client id (Claude Code: --client-id)

Phía server bắt buộc kiểm tra audience của token: chỉ chấp nhận token được cấp cho chính nó. Server không được chuyển tiếp token của client sang API phía sau (spec cấm "token passthrough"). Khi cần gọi NetBox hay router, server dùng credential riêng của nó.

Khai báo trong Claude Code

# stdio: secret qua env
claude mcp add netops -e NETBOX_TOKEN=$NETBOX_TOKEN -- uv run server.py
 
# HTTP có OAuth: thêm xong, vào phiên gõ /mcp để đăng nhập
claude mcp add --transport http netops https://mcp.example.net/mcp
 
# HTTP dùng API key tĩnh qua header
claude mcp add --transport http netops https://mcp.example.net/mcp \
  --header "Authorization: Bearer $MCP_TOKEN"

Rủi ro bảo mật

Rủi ro Mô tả Cách chặn
DNS rebinding Trang web độc hại gọi vào server HTTP đang chạy trên localhost Kiểm tra header Origin, bind 127.0.0.1 thay vì 0.0.0.0, bật xác thực
Token passthrough Server nhận token của client rồi dùng nó gọi API khác Kiểm tra audience, dùng credential riêng của server
Confused deputy Proxy MCP dùng một client id tĩnh cho mọi user, nên user A dùng được quyền đã cấp cho user B Xin consent cho từng client, không bỏ qua bước xác nhận
Prompt injection qua dữ liệu Description của interface, syslog hay ticket chứa câu kiểu "hãy chạy lệnh X" Coi output tool là dữ liệu, tool ghi phải có người duyệt (an toàn agent mạng)
Tool poisoning Server bên thứ ba cài chỉ dẫn độc hại vào description của tool Chỉ cài server tin cậy, đọc tools/list, pin phiên bản
Session hijack Đoán hoặc lộ Mcp-Session-Id Session id ngẫu nhiên, không dùng thay cho xác thực, mỗi request vẫn phải có token
Lộ secret Token nằm trong .mcp.json đã commit Dùng ${VAR} / env, không ghi token thẳng vào file

Khi nào dùng

  • stdio: mặc định cho tool cá nhân và server chỉ đọc chạy ngay trên máy có quyền vào thiết bị. Đơn giản, không phải lo mở cổng.
  • Streamable HTTP + OAuth: khi nhiều người hoặc nhiều agent cùng dùng một server, cần quản lý quyền theo user, cần audit tập trung, hoặc server phải nằm trong vùng mạng quản trị.
  • HTTP + API key tĩnh: chỉ dùng trong mạng nội bộ, tạm thời. Phải xoay vòng key và đặt sau TLS.
  • Server viết bằng TypeScript xem MCP server TypeScript, bằng Python xem FastMCP.