IT · Model Context Protocol

Transport layer — stdio і Streamable HTTP

Як MCP доставляє JSON-RPC між Client і Server

Урок 4

План заняття

  1. 01 Вступ: Transport layer і JSON-RPC
  2. 02 Локальний MCP Server (stdio)
  3. 03 Віддалений Server (Streamable HTTP)
  4. 04 Аутентифікація для Remote MCP
  5. 05 Порівняння stdio vs Streamable HTTP
  6. 06 Deprecated: HTTP+SSE
  7. 07 Три transport в одному коді

Блок 1

Вступ: Transport layer

JSON-RPC, client-server і канал доставки

Вступ

Client-Server Architecture

Вступ

Структура JSON-RPC

Request (client → server): який tool обрано і з якими аргументами.

{
  "jsonrpc": "2.0",
  "method": "get_weather",
  "params": { "city": "Paris" },
  "id": 1
}
  • method — що викликати
  • params — аргументи tool
  • id — зіставлення відповіді

Вступ

JSON-RPC Response

{
  "jsonrpc": "2.0",
  "result": 20,
  "id": 1
}

Вступ

Що таке Transport layer

Transport layer — рівень MCP, який відповідає за фізичну доставку JSON-RPC повідомлень між Client і Server. Протокол визначає що передається; transport — як воно доходить від однієї програми до іншої: через який канал, на якій машині, за яким механізмом.

Аналогія: JSON-RPC — текст листа, transport — спосіб доставки. Той самий лист можна передати кур'єром по кімнаті або поштою через інтернет.

  • stdio — локально на одному ПК через stdin/stdout
  • Streamable HTTP — по мережі через HTTP (POST + GET)

Блок 2

Локальний MCP Server

stdio transport

Локальний stdio

Як це працює

Локальний stdio

Що таке stdio

stdio = standard input / standard output. Це не мережевий протокол — стандартні потоки ОС у кожного процесу: stdin (вхід), stdout (вихід), stderr (логи).

Це байтові труби в пам'яті між двома програмами на одному ПК — без TCP, без IP, без HTTP. Усередині просто текст JSON, по одному повідомленню на рядок.

Локальний stdio

command і args

Host сам стартує процес сервера при підключенні:

{
  "mcpServers": {
    "my-server": {
      "command": "python",
      "args": ["path/to/server.py"],
      "env": { "API_KEY": "your_key" }
    }
  }
}

Локальний stdio

Один Client — один subprocess

Host запускає програму як дочірній процес — наче node server.js у терміналі.

  • 1 Host, 5 серверів у конфігу → 5 окремих subprocess
  • Cursor і Claude Desktop → 2 subprocess, той самий server.js Своя пам'ять і stdin/stdout — стан не спільний

Локальний stdio

Чому stdio не масштабується

Один спільний сервер на всю команду через stdio — не працює.

Streamable HTTP

1 сервер слухає порт

100 клієнтів підключаються → працює

stdio

100 клієнтів → 100 процесів

кожен spawn() → неефективно

  • stdio — лише для desktop і локальної роботи Для спільного командного сервера — Streamable HTTP

Локальний stdio

Мінімальний код (stdio)

from fastmcp import FastMCP

mcp = FastMCP("Cool MCP Server")

if __name__ == "__main__":
    mcp.run()  # transport="stdio"

Блок 3

Віддалений MCP Server

Streamable HTTP

Streamable HTTP

Як це працює

Streamable HTTP

HTTP transport локально

Той самий transport на http://127.0.0.1:8000/mcp — сервер запускається окремо, Client підключається по url.

Зручно для MCP Inspector і коли один процес обслуговує кілька клієнтів на localhost.

Streamable HTTP

Конфігурація: url

{
  "mcpServers": {
    "remote-server": {
      "url": "https://mcp.example.com/mcp"
    },
    "local-http": {
      "url": "http://127.0.0.1:8000/mcp"
    }
  }
}

Client не запускає subprocess — з'єднується з уже працюючим HTTP-сервером.

Streamable HTTP

Мінімальний код (HTTP)

if __name__ == "__main__":
    mcp.run(
        transport="streamable-http",
        host="127.0.0.1",
        port=8000
    )

Блок 4

Аутентифікація

Remote MCP + OAuth

Аутентифікація

Як це працює

Аутентифікація

Приклад з Bearer token

{
  "mcpServers": {
    "todos": {
      "url": "https://mcp.example.com/mcp",
      "headers": {
        "Authorization": "Bearer <access_token>"
      }
    }
  }
}

Remote без auth — лише для dev на localhost. У production auth обов'язковий.

Блок 5

Порівняння

stdio vs Streamable HTTP

Порівняння

stdio

Характеристика
✓ Простота — без мережі, портів, TLS
✓ Ідеально для desktop Host
✓ Client керує життєвим циклом процесу
✗ Один subprocess на одне з'єднання
✗ Не підходить для спільного командного сервера

Порівняння

Streamable HTTP

Характеристика
✓ Один процес — багато клієнтів
✓ Деплой у хмару, Docker, Kubernetes
✓ Сесії через Mcp-Session-Id
✗ Складніша інфраструктура
✗ Auth обов'язковий у production

Порівняння

Коли що обирати

  • Локальна розробка, desktop-агент → stdio
  • Спільний сервер для команди → Streamable HTTP
  • Хмарний MCP з OAuth → HTTP + auth
  • MCP Inspector на localhost → HTTP на 127.0.0.1

Блок 6

Deprecated HTTP+SSE

HTTP → SSE → Streamable HTTP

Deprecated

Повна картина

Чому в MCP з'явився Streamable HTTP і чому HTTP+SSE — legacy.

  • Крок 1 — звичайний HTTP/1.1
  • Крок 2 — SSE: відкрите з'єднання і два endpoint в MCP
  • Крок 3 — Streamable HTTP: один endpoint і chunked-відповідь

Крок 1

Звичайний HTTP/1.1

Клієнт ──── запит ────► Сервер
Клієнт ◄─── відповідь ── Сервер
✓ з'єднання закрито

Клієнт запитав → сервер відповів → з'єднання закрилось.

Проблеми:

  • Немає стримінгу — чекаєш увесь відповідь цілком, поганий UX
  • Сервер не може сам надіслати дані клієнту без нового запиту
  • Довгі операції — якщо AI «думає» 30 секунд, з'єднання просто висить і ти не знаєш, що відбувається

Крок 2

SSE в MCP · канал 1

Слухаємо сервер — тримаємо з'єднання відкритим:

# Канал 1 — слухаємо сервер
Клієнт ──── GET /sse ─────────────► Сервер
Клієнт ◄════ тримаємо відкритим ════ Сервер

Крок 2

SSE в MCP · канал 2

Надсилаємо команди окремим POST — відповідь приходить через перший канал:

# Канал 2 — надсилаємо команди
Клієнт ──── POST /message ────────► Сервер

# Відповідь приходить через ПЕРШИЙ канал
Клієнт ◄─── результат ────────────── Сервер
  • Два endpoint — складно підтримувати
  • З'єднання SSE треба тримати постійно
  • Якщо SSE впав — усе ламається

Крок 3

Streamable HTTP

HTTP/1.1 вміє слати відповідь кусками (chunked) — це і використовує сучасний MCP transport.

Клієнт ──── POST /mcp ─────────────► Сервер
Клієнт ◄─── chunk 1 ──────────────── Сервер
Клієнт ◄─── chunk 2 ──────────────── Сервер
Клієнт ◄─── chunk 3 ──────────────── Сервер
✓ з'єднання закрито

Один endpoint, один запит, відповідь стримом — простіше і надійніше, ніж два канали SSE+POST.

Підсумок

HTTP vs SSE vs Streamable HTTP

Звичайний HTTP SSE Streamable HTTP
Endpoint 1 2 1
З'єднання Закривається Постійне Закривається
Стримінг ✗ ✓ ✓
У MCP Старий Старий Новий 2025

Аналогія

Три підходи простими словами

  • Звичайний HTTP — подзвонив, запитав, поклав слухавку
  • SSE — два телефони: один завжди слухає, другим говориш ти
  • Streamable HTTP — один телефон: подзвонив, відповідають поступово, поклав слухавку

Блок 7

Три transport в коді

Один параметр — різний канал

Три transport

Перемикання transport

# stdio (за замовчуванням)
mcp.run()

# SSE (legacy)
mcp.run(transport="sse", host="127.0.0.1", port=8000)

# Streamable HTTP
mcp.run(transport="streamable-http", host="127.0.0.1", port=8000)

Фінал заняття

Підсумки

На цій лекції ми розібрали transport layer MCP: локальний stdio (subprocess, command/args) і мережевий Streamable HTTP (url, сесії, auth для remote).

При stdio кожне з'єднання Client↔Server — окремий процес; HTTP дозволяє одному серверу обслуговувати багато клієнтів.

У наступній лекції перейдемо до практики: створимо власний локальний stdio MCP-сервер на Python.