درس ۲۴ از ۳۳

State و Streamable HTTP (State and StreamableHTTP)

عنوان اصلی: State and StreamableHTTP

هدف یادگیری: مدیریت sessionهای stateful روی Streamable HTTP با Mcp-Session-Id.

مفاهیم کلیدی: header Mcp-Session-Id، ساخت session، خاتمه session (HTTP DELETE، HTTP 404)، حالت stateless، توکن Bearer در OAuth.

«Session» مکالمه stateful بین یک client و یک server است که از initialize شروع می‌شود. برای پشتیبانی state، server می‌تواند در زمان init یک session id اختصاص دهد با ست کردن Mcp-Session-Id: <uuid> روی پاسخ HTTP InitializeResult. id باید globally unique، cryptographically secure، و فقط ASCII قابل‌مشاهده (0x21–0x7E) باشد. وقتی اختصاص یافت، client باید آن را روی هر request بعدی echo کند.

Server می‌تواند دلخواه terminate کند و به request با آن id با 404 Not Found پاسخ دهد. Client باید با شروع یک session تازه (InitializeRequest جدید، بدون session id) واکنش نشان دهد. Client می‌تواند صراحتاً session را تمام کند با ارسال DELETE /mcp با header Mcp-Session-Id — server می‌تواند با 405 Method Not Allowed پاسخ دهد اگر terminate سمت client را اجازه ندهد.

زیرمجموعه‌ای از MCP serverها روی Streamable HTTP stateless اجرا می‌شوند — بدون session id، هر request مستقل. این برای deploymentهای serverless/edge توصیه می‌شود.

Authentication: Streamable HTTP از auth استاندارد HTTP پشتیبانی می‌کند — Bearer token، API key، header سفارشی. spec MCP استفاده از OAuth 2.1 با PKCE را برای دریافت Bearer token توصیه می‌کند.

هشدار امنیتی برجسته (Streamable HTTP)

⚠️ هشدارهای امنیتی Streamable HTTP — این‌ها MUST هستند، نه SHOULD:

  1. Validation Origin header — Server باید header Origin را روی هر اتصال validate کند تا حمله DNS rebinding ناممکن شود. در DNS rebinding، یک سایت مخرب در browser قربانی، DNSای می‌سازد که به 127.0.0.1 resolve می‌شود و به MCP server محلی شما request می‌فرستد. اگر Origin را چک نکنید، browser قربانی می‌تواند پشت شما به MCP server محلی شما حمله کند.

  2. Bind به 127.0.0.1، نه 0.0.0.0 — server محلی باید به 127.0.0.1 گوش دهد، نه 0.0.0.0. در غیر این صورت، server محلی روی شبکه LAN قابل دسترسی است و هر کس روی Wi-Fi کافه می‌تواند به آن وصل شود.

  3. هر اتصال را authenticate کنید — Bearer token یا API key یا OAuth 2.1 + PKCE. Mcp-Session-Id به‌تنهایی auth نیست؛ صرفاً session correlation است.

  4. Mcp-Session-Id cryptographically random — از sequential یا قابل‌حدس استفاده نکنید. این auth-adjacent است.

اگر در Iran یک server دارید که توسعه‌دهنده داخل شرکت روی laptop اجرا می‌کند و laptop گاهی به Wi-Fi عمومی وصل می‌شود، هر چهار قاعده بالا حیاتی‌اند.

مثال عملی — wire (جریان session id)

# Client init
POST /mcp HTTP/1.1
{"jsonrpc":"2.0","id":1,"method":"initialize",...}

# Server response
HTTP/1.1 200 OK
Mcp-Session-Id: 1868a90c-7e8d-4c3b-a1f2-9b4e6d5a7c8f
Content-Type: application/json
{"jsonrpc":"2.0","id":1,"result":{...}}

# All subsequent client requests
POST /mcp HTTP/1.1
Mcp-Session-Id: 1868a90c-7e8d-4c3b-a1f2-9b4e6d5a7c8f
MCP-Protocol-Version: 2025-06-18
{"jsonrpc":"2.0","id":2,"method":"tools/list"}

# Client ends session
DELETE /mcp HTTP/1.1
Mcp-Session-Id: 1868a90c-7e8d-4c3b-a1f2-9b4e6d5a7c8f

اشتباهات رایج

  • ذخیره state session در حافظه فرایند و load-balance کردن میان replicaها بدون sticky session.
  • استفاده از session id sequential یا قابل‌حدس. آن‌ها auth-adjacent هستند — cryptographically random بسازید.
  • bind به 0.0.0.0 روی laptop developer. به 127.0.0.1 bind کنید مگر اینکه واقعاً منظورتان باشد.
  • اسکیپ کردن validation Origin. DNS rebinding یک exploit واقعی است.