| 1 | # ADR 0082: ACP и MCP IDE — одна копия процесса (loopback HTTP/SSE вместо второго `CascadeIDE --mcp-stdio`) |
| 2 | |
| 3 | **Статус:** Proposed |
| 4 | **Дата:** 2026-04-20 |
| 5 | ## Связанные ADR |
| 6 | |
| 7 | | ADR | Роль | |
| 8 | |-----|------| |
| 9 | | [0048](0048-cursor-acp-chat-ide-parity-and-mcp-tool-surface.md) | чат Cursor ACP, `mcpServers`, авто-подмешивание IDE MCP | |
| 10 | | [0016](0016-agent-client-protocol-external-agent.md) | ACP, stdio, границы с MCP | |
| 11 | | [0008](0008-mcp-contracts-and-testable-infrastructure.md) | MCP IDE как контур | |
| 12 | | [0038](0038-agent-facade-ai-provider-and-tool-orchestration.md) | фасад агента | |
| 13 | | [0043](0043-mcp-transport-recovery-human-agent-parity.md) | транспорт MCP; ортогонально ACP, но полезно при сбоях | |
| 14 | |
| 15 | ### Вне ADR |
| 16 | |
| 17 | | Документ | Роль | |
| 18 | |----------|------| |
| 19 | | [`externals/acp-csharp/.../McpServer.cs`](../../externals/acp-csharp/src/AgentClientProtocol/Schema/McpServer.cs) | вендор ACP SDK (McpServer) | |
| 20 | |
| 21 | --- |
| 22 | ## Контекст |
| 23 | |
| 24 | При включённом **`acp_auto_inject_ide_mcp`** в `session/new` подмешивается **`StdioMcpServer`** с тем же бинарём, что и GUI, и аргументами **`--mcp-stdio`**. Процесс **`cursor-agent`** поднимает **отдельный** экземпляр Cascade IDE как MCP-сервер по stdio. |
| 25 | |
| 26 | Это **два разных процесса**: у второго — свой жизненный цикл, **нет** общего `MainWindowViewModel`, открытых вкладок редактора и прочего состояния «той» сессии, в которой пользователь ведёт чат. |
| 27 | |
| 28 | **Важно:** режим **`--mcp-stdio` в текущей реализации не headless** — стартует полноценный Avalonia desktop lifetime с **`MainWindow`** и тем же `MainWindowViewModel`, параллельно поднимается MCP на stdio ([`App.axaml.cs`](../../App.axaml.cs): `RunMcpStdio` → окно + `RunMcpServerAsync`). На экране получается **вторая полная копия приложения**; при мультиоконной конфигурации workspace это легко выглядит как **несколько лишних окон** (например три), дублирующих chrome отдельного экземпляра. Инструменты `ide_*` обслуживает **эта** вторая копия, а не окно, где открыт чат с ACP — отсюда расхождение с ожиданием «агент управляет **этим** окном». |
| 29 | |
| 30 | В [0048 § последствия](0048-cursor-acp-chat-ide-parity-and-mcp-tool-surface.md) уже зафиксировано: дублирование процессов допустимо; оптимизация «один процесс» — **отдельное** архитектурное решение. Этот ADR — как раз оно. |
| 31 | |
| 32 | --- |
| 33 | |
| 34 | ## Проблема |
| 35 | |
| 36 | 1. **Паритет состояния:** пользователь и агент должны опираться на **один и тот же** контекст IDE (файлы, фокус, выделение), когда речь о командах `ide_*`. |
| 37 | 2. **Лишний процесс и дублирование UI:** второй `CascadeIDE` — не фоновый хост, а **полный второй экземпляр** с окнами; лишняя память, диск, точка отказа; путаница при отладке и визуальный шум («какой процесс смотрю в Task Manager», «зачем ещё одно главное окно»). |
| 38 | 3. **Текущий stdio-путь остаётся валидным** для внешних хостов (Cursor запускает IDE только с `--mcp-stdio`) — новое решение **не** обязано его ломать. |
| 39 | |
| 40 | --- |
| 41 | |
| 42 | ## Решение (направление) |
| 43 | |
| 44 | <a id="adr0082-p1"></a> |
| 45 | |
| 46 | ### 1. Цель |
| 47 | |
| 48 | Для сессии **чата с Cursor ACP внутри GUI Cascade IDE** подмешивание **`cascade-ide`** в `McpServers` должно по умолчанию (или по явному флагу) указывать агенту на **MCP-сервер в том же процессе**, что и окно чата — без запуска второго `CascadeIDE.exe`. |
| 49 | |
| 50 | <a id="adr0082-p2"></a> |
| 51 | |
| 52 | ### 2. Транспорт: loopback HTTP или SSE |
| 53 | |
| 54 | В схеме Agent Client Protocol уже есть не только `stdio`, но и **`http`** / **`sse`** (`url` + `headers`). Направление реализации: |
| 55 | |
| 56 | - В **основном процессе** IDE поднять **локальный** endpoint MCP (совместимый с тем, что ожидает клиент MCP в **cursor-agent** для выбранного типа сервера): например **`127.0.0.1`**, динамический или конфигурируемый порт, только **loopback** (не `0.0.0.0`). |
| 57 | - В **`MergeForAcpNewSession`** (или эквиваленте при формировании списка для ACP) генерировать **`HttpMcpServer` или `SseMcpServer`** с этим `url` и при необходимости **`headers`** (см. §3). |
| 58 | |
| 59 | Выбор **streamable HTTP vs SSE** — зафиксировать при реализации по фактической поддержке в **cursor-agent** и в используемой библиотеке MCP на стороне IDE (единый контракт с существующим `IdeMcpServer` / `McpServer.Create`). |
| 60 | |
| 61 | <a id="adr0082-p3"></a> |
| 62 | |
| 63 | ### 3. Безопасность |
| 64 | |
| 65 | - Только **localhost**; не слушать внешние интерфейсы без отдельного решения. |
| 66 | - **Секрет сеанса:** передавать в `headers` (например `Authorization`) **одноразовый или короткоживущий токен**, выданный GUI при старте ACP-сессии, чтобы другой локальный процесс не мог подключиться соседним PID без знания токена. |
| 67 | - Порт: избегать фиксированного глобального порта, конфликтующего с другими приложениями; при необходимости — выбор свободного порта + запись в снимок для `session/new`. |
| 68 | |
| 69 | <a id="adr0082-p4"></a> |
| 70 | |
| 71 | ### 4. Сосуществование со stdio |
| 72 | |
| 73 | - Режим **`--mcp-stdio`** в отдельном процессе **сохранить** для сценария «внешний хост (Cursor) запускает IDE как MCP» ([MCP-PROTOCOL.md](../../MCP-PROTOCOL.md)). |
| 74 | - Для ACP внутри IDE: переключатель настроек или эвристика «если уже главное окно — loopback; иначе stdio» — уточнить в реализации; допустимы явные ключи в **`[mcp]`** (например транспорт для авто-подмешивания в ACP). |
| 75 | |
| 76 | <a id="adr0082-p5"></a> |
| 77 | |
| 78 | ### 5. Альтернатива (не приоритет): прокси во втором процессе |
| 79 | |
| 80 | Оставить второй процесс, но научить его **проксировать** вызовы в главный по IPC. Выше по сложности, дублирует контракты; рассматривать только если loopback в **cursor-agent** окажется неподъёмным. |
| 81 | |
| 82 | --- |
| 83 | |
| 84 | ## Последствия |
| 85 | |
| 86 | - Появится **второй путь** хостинга MCP в IDE: наряду с **stdio-only** в отдельном процессе — **в процессе GUI** (инициализация при старте ACP-сессии или лениво), с корректным **shutdown** при смене провайдера / закрытии чата. |
| 87 | - Документация [MCP-PROTOCOL.md](../../MCP-PROTOCOL.md) и подсказки Environment Readiness — обновить, когда появится стабильный флаг/порт. |
| 88 | - **Тесты:** интеграционные сценарии «один процесс» не должны регрессить сценарий внешнего `--mcp-stdio`. |
| 89 | |
| 90 | --- |
| 91 | |
| 92 | ## Открытые вопросы |
| 93 | |
| 94 | 1. Какой тип **`McpServer`** в `session/new` гарантированно поддерживает **cursor-agent** для IDE MCP (приоритет проверки экспериментом). |
| 95 | 2. Нужна ли **стабильная привязка** порта в пользовательских настройках для файрвола/скриптов. |
| 96 | 3. Поведение при **нескольких окнах** Cascade IDE: один endpoint на процесс приложения vs привязка к окну — уточнить с моделью [0017](0017-multi-window-workspace-and-agent-surfaces.md). |
| 97 | |