ADR 0165: Стратификация транспорта MCP — stdio, HTTP-first, матрица хостов
Статус: Proposed
Дата: 2026-06-25
Резюме
Стек MCP в экосистеме IOP/CIDE сегодня в основном stdio (хост порождает subprocess). Это корректно для локальных IDE-хостов (Cursor, Claude Desktop), но не покрывает веб-агентов (ChatGPT, Claude в браузере), shared remote MCP и multi-client без fork процесса.
Принято направление: не переписывать тулы; разделить handler (SSOT) и транспорт-адаптер. Сервисы с общим состоянием и удалённым доступом — HTTP-first (Streamable HTTP MCP на loopback или forge API); локальные language/debug драйверы — stdio навсегда; Cascade IDE — stdio для внешнего хоста + loopback HTTP в GUI-процессе (0082).
Связанные ADR
| ADR | Роль |
|---|---|
| 0008 | Контракты MCP, тестируемая инфраструктура |
| 0043 | Восстановление транспорта; граница хост vs IDE |
| 0048 | ACP, mcpServers, авто IDE MCP |
| 0052 | CLI паритет с MCP (--agent-contract) |
| 0082 | Loopback HTTP/SSE в том же процессе GUI (не второй CascadeIDE) |
| 0118 | Agent Notes Core in-proc; TOML SSOT с MCP |
| 0132 | Intercom transport ≠ MCP transport |
| 0142 | Pluggable transport для Intercom |
| 0148 | AEE, verify ladder, native tooling |
Вне репо (смежные решения)
| Документ | Роль |
|---|---|
| MCP-PROTOCOL.md | Транспорт stdio, внешние MCP, --mcp-stdio |
agent-forge: FORGE-ADR-0014 B (AgentForge.Mcp) |
stdio-мост → POST /api/v1/mcp/invoke |
| agent-forge: docs/mcp.md | Forge HTTP API как SSOT тулов |
agent-notes-mcp: ADR 014 (--config TOML) |
Stdio MCP + localhost /health (2.0) |
| kb-public: ChatGPT Desktop stack | ChatGPT не stdio; HTTP connectors / туннель |
1. Контекст
1.1 Два класса MCP-хостов
| Класс хоста | Типичный транспорт | Примеры |
|---|---|---|
| Локальный desktop | stdio (child process) | Cursor, Claude Desktop, VS Code |
| Веб / облако / shared | HTTP / Streamable HTTP | ChatGPT connectors, Claude.ai, удалённый агент |
MCP-спека допускает оба; stdio не «устарел» — он правильный там, где хост владеет жизненным циклом subprocess.
1.2 Текущий стек (2026-06)
| Сервер | Транспорт сегодня | SSOT логики |
|---|---|---|
| Agent Forge | stdio (AgentForge.Mcp) → HTTP :8770 |
Forge API /api/v1/mcp/invoke |
| agent-notes-mcp | stdio + loopback /health |
AIGuiders.AgentNotes.Core |
| Cascade IDE | --mcp-stdio (полный exe) |
IdeMcpToolCatalog / IdeMcpServer |
| roslyn / python / dotnet-debug / build-test | stdio | Локальный процесс + машинные артефакты |
| hybrid-codebase-index | stdio | Локальный индекс |
Проблема не в «всё stdio плохо», а в том, что весь стек только stdio закрывает контур Cursor/IDE, но не ChatGPT, не shared forge для нескольких клиентов одновременно, не лёгкий attach к уже запущенной IDE-сессии.
1.3 Известные боли
| Симптом | Связь |
|---|---|
Второе (третье) окно CIDE при ACP + acp_auto_inject_ide_mcp |
0082 |
ChatGPT / Claude web не запускают command + args |
Нужен HTTP endpoint или mcp-remote + туннель |
| Дублирование forge-тулов в bridge и API | Уже решено в forge: bridge тонкий |
| agent-notes: Cursor vs CIDE vs веб | Core общий (0118); транспорт — нет |
2. Решение
2.1 Три слоя (обязательная модель)
flowchart TB
subgraph hosts ["Хосты"]
Desktop["Desktop host\n(stdio child)"]
Web["Web host\n(HTTP URL)"]
InProc["CIDE in-proc agent"]
end
subgraph adapters ["Транспорт-адаптеры"]
Stdio["stdio MCP process"]
HttpMcp["Streamable HTTP MCP"]
Direct["in-proc call / CLI"]
end
subgraph ssot ["SSOT handlers"]
ForgeApi["Forge API"]
NotesCore["AgentNotes.Core"]
IdeCatalog["IdeMcpToolCatalog"]
LocalBin["roslyn / python / debug"]
end
Desktop --> Stdio
Web --> HttpMcp
InProc --> Direct
Stdio --> ForgeApi
Stdio --> NotesCore
Stdio --> IdeCatalog
Stdio --> LocalBin
HttpMcp --> ForgeApi
HttpMcp --> NotesCore
HttpMcp --> IdeCatalog
Direct --> NotesCore
Direct --> IdeCatalog
Инвариант: tools/list и tools/call реализуются один раз на уровне SSOT; stdio и HTTP — тонкие JSON-RPC фасады.
2.2 Тиры серверов
Tier A — stdio only (не мигрировать на HTTP)
Локальные драйверы машины разработчика:
roslyn-mcp,python-mcp,python-debug-mcp,dotnet-debug-mcp,dotnet-build-test-mcp- Причины: PDB,
netcoredbg, venv, PATH, безопасность (отладчик не экспонировать в сеть)
Для веб-хостов: не подключать напрямую. Допустим только локальный desktop-агент.
Tier B — HTTP-first, stdio-bridge сохранить
| Сервис | HTTP SSOT | Stdio-bridge | Примечание |
|---|---|---|---|
| Agent Forge | :8770 /api/v1/mcp/invoke |
AgentForge.Mcp |
Эталон (FORGE-ADR-0014 B) |
| agent-notes | loopback Streamable HTTP /mcp (целевое) |
agent-notes-mcp --config |
Тот же Core, тот же TOML |
| Cascade IDE | loopback в GUI (0082) | --mcp-stdio для Cursor |
UI/reveal требуют живой сессии |
Tier C — хост-специфичные исключения
- ChatGPT: Custom connector → HTTP URL (forge, notes, позже CIDE loopback через туннель только dev)
- Claude Desktop:
claude_desktop_config.json→command/args(stdio); на Windows MSIX — виртуализированный путь к config - Cursor:
.cursor/mcp.json→ stdio; для forge/notes — bridges как сейчас
2.3 Cascade IDE — два контура (не смешивать)
| Контур | Транспорт | Когда |
|---|---|---|
| External ProcessHost | CascadeIDE.exe --mcp-stdio |
Cursor / Claude Desktop порождают IDE |
| In-GUI ACP / built-in agent | loopback HTTP/SSE в том же процессе | 0082 — без второго окна |
| Headless contract | --agent-contract CLI |
CI, снапшоты (0052) |
Реализация loopback не дублирует каталог тулов: тот же pipeline, что IdeMcpServer.
Настройки (целевые ключи в [mcp]):
[mcp]
# существующие: external_servers_json, acp_auto_inject_ide_mcp, …
# целевое (фаза 3):
loopback_enabled = true
loopback_bind = "127.0.0.1"
loopback_port = 0 # 0 = ephemeral
loopback_token_rotate = "session" # session | launch
acp_ide_mcp_transport = "loopback" # loopback | stdio (default loopback когда GUI жив)
2.4 Agent Forge — нативный HTTP MCP (фаза 1)
Поверх существующего invoke:
- Добавить Streamable HTTP endpoint на forge-server (
/mcpили/api/v1/mcp/stream). ListTools→ тот жеGET /api/v1/capabilities.CallTool→ тот жеPOST /api/v1/mcp/invoke.- Auth:
FORGE_API_TOKEN/ device login (уже есть). AgentForge.Mcpне удалять — остаётся для Cursor/Claude Desktop.
2.5 agent-notes — HTTP рядом с status (фаза 2)
- Handlers уже в Core (0118).
- Поднять Streamable HTTP на loopback (рядом с
/healthиз 2.0). - Stdio-процесс → второй адаптер к тем же handlers.
- CIDE in-proc без изменений контракта
knowledge_path.
2.6 Безопасность loopback / tunnel
| Угроза | Митигация |
|---|---|
| Локальный процесс без auth | 127.0.0.1 only; случайный session token в Authorization |
| Tunnel в ChatGPT (dev) | Отдельные read-only токены; не prod KB; явный opt-in |
| Экспорт debug/roslyn в HTTP | Запрещено (Tier A) |
2.7 Явные non-goals
- Единый HTTP-сервер на весь стек — отклонено (разные trust boundary).
- Убрать stdio — отклонено; desktop-хосты останутся на child process.
- Переписать каждый тул под HTTP — отклонено; только адаптеры.
mcp-remoteповерх всего stdio как архитектура — костыль для ChatGPT; допустим временно, не SSOT.- Смешивать Intercom team transport с MCP — 0132, 0142.
3. Фазы внедрения
| Фаза | Объём | Переписывание тулов |
|---|---|---|
| 0 | Этот ADR + инвентарь серверов | 0 |
| 1 | Forge Streamable HTTP MCP | 0 (invoke уже есть) |
| 2 | agent-notes HTTP MCP + stdio wrapper | 0 (Core есть) |
| 3 | CIDE loopback (0082) | 0 (catalog общий) |
| 4 | Опционально: лёгкий McpSidecar без Avalonia; генератор конфигов Cursor/Claude |
Минимальный |
Критерий готовности фазы 1: ChatGPT connector и Cursor forge-mcp работают параллельно к одному forge API.
4. Матрица хостов (нормативная)
| Хост | Forge | agent-notes | CIDE ide_* |
roslyn/python/debug |
|---|---|---|---|---|
| Cursor | stdio bridge | stdio --config |
stdio --mcp-stdio |
stdio |
| Claude Desktop | stdio в claude_desktop_config.json |
stdio | stdio (тяжёлый; sidecar позже) | stdio |
| ChatGPT / веб | HTTP connector | HTTP + tunnel (dev) | HTTP loopback + tunnel | ❌ |
| CIDE built-in | HTTP → :8770 |
Core in-proc | in-proc / loopback | stdio subprocess |
5. Последствия
Плюсы
- Один контур тулов для desktop и web без форка логики.
- Forge и KB готовы к multi-client и Docker без смены Cursor-конфига.
- CIDE перестаёт плодить полные вторые экземпляры при ACP (0082).
Минусы / долг
- Два транспорта на сервис → тестировать оба пути.
- Документация хостов (Cursor vs ChatGPT vs Claude Desktop) усложняется.
- Windows MSIX paths для Claude Desktop — операционный overhead.
Документы к обновлению при реализации
- MCP-PROTOCOL.md — § транспорт, loopback, матрица хостов
- 0082 — ссылка на 0165 как ecosystem frame
- agent-forge
docs/mcp.md— Streamable HTTP endpoint - agent-notes-mcp README — HTTP + stdio parity
6. Открытые вопросы
- Streamable HTTP vs SSE на forge и CIDE — зафиксировать по фактической поддержке в cursor-agent и MCP SDK .NET (приоритет: Streamable HTTP в спеке 2025+).
- Стабильный порт loopback в
settings.tomlvs ephemeral — нужен ли пользователям для firewall-скриптов. - Multi-window CIDE (0017): один loopback на процесс приложения vs per-window endpoint.
- Публикация forge HTTP за пределы localhost — отдельный ADR (auth, TLS, tenancy).
7. Отклонённые альтернативы
| Альтернатива | Почему нет |
|---|---|
| Только stdio везде | Блокирует ChatGPT и shared remote |
| Только HTTP везде | Desktop-хосты не форкают HTTP child; debug/roslyn не в сеть |
Один monolithic iop-mcp-server |
Смешивает trust boundary; ломает независимый lifecycle forge/notes |
| IPC-прокси во втором CIDE-процессе | 0082 §5 — запасной, не приоритет |