Skip to main content
Glama
README.md
# ccc-mcp — Command Claude Code

Локальный MCP-сервер, через который внешний агент Claude ставит задачи вашей установке
Claude Code и получает структурированный отчёт — без копирования текста между окнами.

Сервер универсальный: «текст задачи → Claude Code → структурированный отчёт». Никакой логики
Архитектора/Вайбкодера и разбора паспорта проекта в нём нет.

## ⚠️ Прежде чем подключать

Это не песочница. Мост запускает на вашей машине настоящий `claude`, который правит файлы,
исполняет команды и коммитит — от вашего имени и с вашими правами.

* **Пооперационные разрешения по умолчанию выключены** (`hooksEnabled: false`): внутри уже
  одобренного плана мост не перехватывает `Bash` дочернего процесса.
* **`write_project_file` и `run_git` меняют состояние вне цикла план→одобрение** — это
  осознанное решение, разобранное в [docs/security.md](docs/security.md).
* **Единственная жёсткая граница — `allowedRoots`.** Не указывайте там домашний каталог
  целиком: перечисляйте конкретные проекты.

Модель угроз и куда сообщать об уязвимости — [SECURITY.md](SECURITY.md).

## Что это даёт

Правка кода идёт через обязательный цикл «план → одобрение → выполнение»: дочерний Claude Code
сначала показывает, что собирается сделать, и только явно одобренный план разрешено выполнять.
Всё, что интеллекта не требует — прочитать файл, положить его обратно, посмотреть `git status`,
закоммитить, — доступно напрямую, без запуска дочерней модели.

* **Человеку** — пошаговая установка, подключение и разбор проблем: [SETUP.md](SETUP.md).
* **Вызывающему ИИ-агенту** — императивный протокол одним файлом:
  [AGENT-PROTOCOL.md](AGENT-PROTOCOL.md).
* **Подробности по темам** — в [docs/](docs/), карта ниже в разделе
  [«Документация»](#документация).

## Инструменты

| Инструмент | Назначение |
|---|---|
| `plan_task` | Планирование без изменения файлов (`--permission-mode plan`). Возвращает план, `session_id` и `plan_digest`. |
| `approve_plan` | Явное согласие на выполнение плана. Переводит сессию в `approved`. |
| `execute_task` | Выполнение **одобренного** плана. Возвращает итоговый отчёт. |
| `get_task_status` | Состояние и результат задачи, запущенной в фоне. |
| `cancel_task` | Принудительная остановка зависшей задачи вместе с потомками. |
| `approve_permission_request` | Решение по отдельной операции дочернего Claude Code. Работает только при включённом [контроле разрешений](docs/permissions.md). |
| `list_project_files` | Плоский список файлов и каталогов проекта. Без запуска Claude Code и без плана. |
| `read_project_file` | Прямое чтение текстового файла проекта. Без запуска Claude Code и без плана. |
| `write_project_file` | Прямая перезапись текстового файла проекта целиком. Без запуска Claude Code и без плана. |
| `run_git` | Фиксированный набор git-операций напрямую. Без запуска Claude Code и без плана. |

Границы, поведение и обоснования файловых и git-инструментов — [docs/tools.md](docs/tools.md).

## Протокол в двух словах

```
plan_task  →  показать план человеку  →  approve_plan  →  execute_task
 planned                                    approved      executing → executed
```

* **`execute_task` без одобренного `session_id` невозможен.** Запустить задачу «с нуля», минуя
  план, нельзя — в этом и смысл моста.
* **Повторный `plan_task` сбрасывает одобрение** и меняет `plan_digest`: одобрить один план
  и подменить его другим не получится.
* **`has_open_questions: true` блокирует одобрение.** Модели не хватило данных — она обязана
  выписать вопросы, а не угадать; задайте их пользователю и перепланируйте.
* **Сбой одобрение не сжигает.** После таймаута, отмены или ошибки API сессия остаётся
  `approved`, попытку можно повторить.

Таблица состояний, поля ответа и обоснования — [docs/protocol.md](docs/protocol.md).

## Быстрый старт

Требуется Node.js ≥ 20 и установленный Claude Code (проверено на 2.1.177 и 2.1.268). CLI должен
уметь `--output-format stream-json` — на нём держится наблюдаемость идущей задачи; если версия
его не поддерживает, обход — `streamEvents: false` в конфиге.

**1. Авторизация.** Сервер не работает с вашими учётными данными: дочерний `claude`
аутентифицируется сам.

```bash
claude auth login
```

Проверить — должно прийти `"is_error":false`:

```bash
claude -p "hi" --output-format json
```

**2. Сборка.**

```bash
npm install
npm run build
```

**3. Конфиг.** Без белого списка каталогов сервер не стартует.

```bash
cp ccc-mcp.config.example.json ccc-mcp.config.json
```

Впишите в `allowedRoots` свои каталоги.

**4. Подключение.**

```bash
claude mcp add --scope user ccc-mcp -e CCC_MCP_CONFIG=D:/Projects/ccc-mcp/ccc-mcp.config.json -- node D:/Projects/ccc-mcp/dist/index.js
```

Имя сервера должно идти до `-e` — флаг вариадический и иначе заберёт имя себе. Проверить:
`claude mcp list`.

Claude Desktop, Windows, macOS и разбор проблем подключения — в [SETUP.md](SETUP.md).

## Пример: полный цикл

**Шаг 1 — план.**

```json
{ "name": "plan_task",
  "arguments": { "task_text": "Добавь валидацию email в форму регистрации и покрой её тестами.",
                 "project_dir": "D:\\Projects\\my-project" } }
```

Ответ (сокращённо):

```json
{ "status": "done", "ok": true,
  "session_id": "b1e41519-93c1-4dc3-8eb2-0669513addf9",
  "session_state": "planned", "plan_digest": "a3f19c4b7e02",
  "result_text": "План: 1) добавить схему валидации…",
  "next_step": "План готов, но не одобрен — выполнение пока запрещено…" }
```

**Шаг 2 — показать план человеку и одобрить.** Оба значения берутся из ответа `plan_task`
без изменений.

```json
{ "name": "approve_plan",
  "arguments": { "session_id": "b1e41519-93c1-4dc3-8eb2-0669513addf9",
                 "plan_digest": "a3f19c4b7e02" } }
```

Приходит `session_state: "approved"`.

**Шаг 3 — выполнение.** Claude Code продолжит с уже собранным контекстом и вернёт тот же
`session_id`.

```json
{ "name": "execute_task",
  "arguments": { "task_text": "Выполни план.",
                 "project_dir": "D:\\Projects\\my-project",
                 "session_id": "b1e41519-93c1-4dc3-8eb2-0669513addf9",
                 "permission_mode": "acceptEdits", "model": "opus" } }
```

`project_dir` должен совпадать с тем, для которого строился план: одобрение действует только
для своего проекта.

`permission_mode` — `acceptEdits` (по умолчанию, принимать правки файлов) либо
`bypassPermissions` (не спрашивать вообще, включая запуск команд).

`model` — необязательный, доступен в обоих вызовах: алиас (`opus`, `sonnet`, `haiku`) или полное
имя (`claude-opus-5`). Если не передать, берётся `model` из конфига, а если и там пусто — модель
выбирает сам CLI.

Если пропустить шаг 2, вызов будет отклонён с текстом «план сессии b1e41519… получен, но не
одобрен» и подсказкой, что вызвать дальше.

## Долгие задачи и наблюдаемость

MCP-клиенты обычно обрывают вызов инструмента примерно через минуту, а задача может идти
полчаса. Поэтому `plan_task` и `execute_task` ждут результат не дольше `wait_seconds`
(по умолчанию 20 с). Успели — отдают полный отчёт сразу; не успели — возвращают
`status: "running"` и `process_id`:

```json
{ "name": "get_task_status", "arguments": { "process_id": "6f0c…", "wait_seconds": 30 } }
```

`wait_seconds` при опросе означает «подожди до N секунд, если задача ещё идёт».
`wait_seconds: 0` в `execute_task` — сразу уйти в фон, не дожидаясь ничего. Стоимость известна
только по завершении: пока задача идёт, `total_cost_usd` равен `null`.

Идущая задача не чёрный ящик. В каждом ответе есть объект `progress`: что вызывалось
(`tools_used`, `last_tool_call`), последнее видимое сообщение модели, `idle_seconds` и лента
`recent_events`, — а `next_step` называет словами то, что происходит прямо сейчас (ждёт
разрешения, зависла, выполняет долгий инструмент, ходит по кругу). Поле `wait_ended_reason`
говорит, почему вернулось ожидание: задача закончилась, вышло время или появился запрос
на разрешение.

Поля ответа и таблица `progress` целиком — [docs/protocol.md](docs/protocol.md); устройство
потока событий и пороги диагностики — [docs/internals.md](docs/internals.md).

## Настройка

Сервер ищет конфиг в таком порядке:

1. путь из переменной `CCC_MCP_CONFIG`;
2. `ccc-mcp.config.json` рядом с пакетом;
3. `ccc-mcp.config.json` в текущем каталоге.

Если конфига нет и не задан `CCC_ALLOWED_ROOTS` — сервер **не стартует**: без белого списка
работать небезопасно. В конфиге разрешены комментарии `//` и `/* … */`.

**Белый список каталогов.** `project_dir` из вызова проходит `realpath` (снимаются симлинки и
junction'ы, нормализуется регистр) и только потом сверяется с `allowedRoots`. Отклоняются
относительные пути, обход через `..`, несуществующие каталоги и каталоги-соседи вроде
`D:\Projects-other`.

Наблюдаемостью управляют три ключа: `streamEvents` (килсвитч разбора потока, по умолчанию
`true`), `logProgress` и `logProgressIntervalMs` (сводка живого состояния в лог, по умолчанию
выключена).

Переменные окружения перекрывают файл: `CCC_ALLOWED_ROOTS` (несколько путей через `;`),
`CCC_CLAUDE_BIN`, `CCC_GIT_BIN`, `CCC_MODEL`, `CCC_TIMEOUT_MS`, `CCC_LOG_FILE`,
`CCC_HOOKS_ENABLED` (`1`/`0`), `CCC_STREAM_EVENTS` (`1`/`0`), `CCC_AUTO_APPROVE_COMMANDS`
(несколько команд через `;`).

Все ключи с умолчаниями и пояснениями — в [ccc-mcp.config.example.json](ccc-mcp.config.example.json)
и в разделе «Что стоит настроить» [SETUP.md](SETUP.md).

## Безопасность — коротко

* **Правка файлов силами Claude Code — только по одобренному плану**, привязанному к
  `plan_digest` и каталогу.
* **`write_project_file` и `run_git` — сознательные исключения**: тот же результат достижим
  через обычный цикл, поэтому запрет дал бы не защиту, а неудобство. Каждая операция в логе.
* **Ключ родителя не передаётся**: все `ANTHROPIC_*` и `CLAUDE_*` вычищаются из окружения
  дочернего процесса.
* **Без shell.** `spawn` с `shell: false`, текст задачи и аргументы git — отдельными элементами
  argv, сообщение коммита — через stdin.
* **Белый список каталогов** проверяется до запуска процесса.
* **Таймаут** (`timeoutMs`, 30 минут) снимает зависший процесс вместе с потомками,
  **`maxConcurrent`** не даёт расплодить процессы.

Разбор каждого пункта — [docs/security.md](docs/security.md).

## Документация

| Файл | О чём |
|---|---|
| [SETUP.md](SETUP.md) | Пошаговый рунбук оператора: авторизация, сборка, конфиг, подключение к CLI и Desktop на Windows и macOS, проверка |
| [AGENT-PROTOCOL.md](AGENT-PROTOCOL.md) | Императивный протокол для вызывающего ИИ-агента — файл, который кладут в системный промпт |
| [docs/tools.md](docs/tools.md) | Инструменты вне протокола: файловые и `run_git` — границы, поведение, чего нет и почему |
| [docs/protocol.md](docs/protocol.md) | Протокол целиком: состояния, открытые вопросы, `plan_digest`, долгие задачи, поля ответа |
| [docs/permissions.md](docs/permissions.md) | Пооперационные разрешения (PreToolUse-хуки), `autoApproveCommands` |
| [docs/security.md](docs/security.md) | Модель безопасности и обоснование каждой границы |
| [SECURITY.md](SECURITY.md) | Политика безопасности: модель угроз коротко, поддерживаемые версии, адрес для приватного сообщения об уязвимости |
| [docs/logging.md](docs/logging.md) | Что и как пишется в JSONL-лог, что не пишется никогда |
| [docs/troubleshooting.md](docs/troubleshooting.md) | Полный справочник симптомов и решений |
| [docs/internals.md](docs/internals.md) | Внутреннее устройство: поток событий stream-json, паттерны диагностики, `--sandbox`, что покрывает smoke |
| [CLAUDE.md](CLAUDE.md) | Инструкции Claude Code, работающему **над этим репозиторием** |

## Проверка

```bash
npm run build
npm run smoke -- --no-live  # только проверки без вызовов Claude Code
npm run smoke               # полный прогон, тратит токены
```

Скрипт поднимает сервер как настоящий MCP-клиент и проходит весь протокол вместе с отказами,
мост разрешений, файловые инструменты, листинг и `run_git` на реальном временном репозитории.
Что именно покрывает каждый блок — [docs/internals.md](docs/internals.md).

## Автор

Basil@155 — [me@basil155.ru](mailto:me@basil155.ru), [www.basil155.ru](https://www.basil155.ru)

Код написан в паре с Claude Code (Claude Opus 5).

## Лицензия

MIT — см. [LICENSE](LICENSE).