Локальный MCP-сервер для Notion AI и других MCP-клиентов, который даёт агенту полноценные руки на твоём ПК: работу с файлами, точечные патчи, живые персистентные терминалы и Git.
by Claude & KilDoom
- 💻 Изолированные персистентные терминалы — агент параллельно держит dev-сервер, сборку и тесты в разных сессиях, сохраняя
cwdи состояние. - 🛡️ Снапшоты и аудит — перед каждым изменением файла создаётся бэкап, каждое действие пишется в журнал.
- 📁 Файлы и Grep — чтение срезами, безопасные патчи (
oldStr → newStr), поиск по содержимому и glob-поиск файлов. - 🔀 Управление Git — структурированные
status,diff,commit,log,branchбез парсинга сырого вывода моделью. - 📂 Профили воркспейсов — переключение между проектами «на лету» без перезапуска сервера.
- ⚡ Транспорт Streamable HTTP (stateless) — один POST = запрос и ответ в том же соединении. Нет висящих каналов и сессий — отваливаться и утекать нечему. Старый SSE-эндпоинт оставлен как fallback для legacy-клиентов.
Требуется Bun v1.1+.
# 1. Клонируем и устанавливаем зависимости
git clone https://github.com/KilDoomWise/notcode
cd notcode
bun install
# 2. Первичная настройка (сгенерит токен и выведет конфиг клиента)
bun run setup
# 3. Запуск сервера
bun run start💡
bun run setupвыдаст готовый URL и Bearer-токен — вставь их в настройки MCP-клиента.
Проверить, что всё работает:
bun run check # typecheck + smoke (тулы) + e2e (живой коннект: /mcp и legacy /sse)| Режим | Описание |
|---|---|
paranoic |
Доступ строго в пределах корня воркспейса. |
auto (по умолчанию) |
Корень + явно разрешённые папки (workspace_allow). |
bypass |
Полная автономность агента без подтверждений. |
В любом режиме ты защищён постфактум:
- Снапшоты — автосохранение файла перед записью (
fs_restoreдля отката; сам откат тоже делает бэкап). - Аудит-лог — история всех действий в
~/.notcode/audit.jsonl, включая отклонённые попытки.
Раньше модель могла одним вызовом notcode_set_mode перевести себя в bypass, а workspace_allow — разрешить любую папку на диске. Теперь эти тулы закрыты флагами и по умолчанию отключены. Управляет только человек из CLI:
bun run src/index.ts mode bypass # сменить режим
bun run src/index.ts security # посмотреть флаги
bun run src/index.ts security runtime-mode on # разрешить агенту менять режим
bun run src/index.ts security runtime-workspace on # разрешить агенту расширять доступФайлы
fs_read_file— чтение со срезами строк, UTF-8/UTF-16, защита от бинарников.fs_write_file— атомарная запись со снапшотом.fs_patch_file— точечный патч (oldStr→newStr) с dry-run и терпимостью к CRLF.fs_list_dir— дерево каталога с размерами.fs_search_content— grep по коду с контекстными строками.fs_find_files— поиск файлов по glob.fs_snapshots/fs_restore— список бэкапов и откат.fs_watch_start/fs_watch_poll/fs_watch_list/fs_watch_stop— отслеживание внешних изменений.
Терминал
terminal_exec— быстрая одноразовая команда.terminal_open/terminal_run/terminal_read/terminal_write/terminal_list/terminal_close— персистентные сессии с сохранённымcwd, фоновыми процессами и вводом в stdin.
Git: git_status, git_diff, git_commit, git_log, git_branch.
Система: notcode_status, notcode_audit, notcode_set_mode.
Воркспейсы: workspace_list, workspace_use, workspace_add, workspace_allow.
MCP-аннотации (readOnlyHint, destructiveHint) намеренно не отдаются клиенту: из-за их смены Notion AI блокировал тулы с ошибкой «tool has changed its operation type» и не показывал кнопку повторного одобрения. Если клиент всё равно заклинил — bun run src/index.ts fix.
| Команда | Описание |
|---|---|
bun run setup |
Первичная настройка и параметры подключения |
bun run start |
Запуск MCP-сервера (Streamable HTTP + Bearer) |
bun run dev |
Запуск в режиме разработки (watch) |
bun run status |
Статус, текущий режим и лимиты |
bun run token |
Посмотреть или пересоздать токен (--reset) |
bun run audit 30 |
Последние 30 записей журнала |
bun run typecheck |
Строгая проверка типов |
bun run smoke |
Проверка всех тулов без сервера |
bun run e2e |
Живой коннект: POST /mcp, tools/call, legacy SSE + heartbeat |
bun run check |
Всё вышеперечисленное одной командой |
| Переменная | Назначение |
|---|---|
NOTCODE_PORT |
Порт сервера (перекрывает конфиг) |
NOTCODE_HOST |
Адрес прослушивания, по умолчанию 127.0.0.1 |
NOTCODE_LOG_LEVEL |
debug / info / warn / error / silent |
WORKSPACE_ROOT |
Корень воркспейса при первом setup |
E2E_PORT |
Порт для bun run e2e (по умолчанию 3999) |
src/
├─ index.ts # HTTP-транспорт (/mcp + legacy /sse), авторизация, CLI
├─ mcp.ts # регистрация тулов в MCP-сервере
├─ config.ts # конфиг, профили, токен, флаги безопасности
├─ tools/ # сами тулы (fs / terminal / git / meta)
└─ utils/
├─ sandbox.ts # проверка путей по режиму безопасности
├─ fs-atomic.ts # атомарная запись (tmp + rename)
├─ snapshot.ts # бэкапы и откаты
├─ audit.ts # журнал действий
├─ terminal-manager.ts# сессии терминала
├─ watch-manager.ts # наблюдатели ФС
├─ proc.ts # корректное убийство дерева процессов
├─ lock.ts # Mutex для гонок по файлам
└─ logger.ts # логи только в stderr
Важное правило: stdout никогда не используется под логи — он зарезервирован под протокол.
| Эндпоинт | Назначение |
|---|---|
POST /mcp |
Основной. Stateless Streamable HTTP: один запрос — один JSON-ответ. |
GET /mcp |
Отвечает 405: серверных пушей нет, висящий стрим не нужен. |
GET /sse + POST /messages |
Legacy-транспорт (спека 2024-11-05) для старых клиентов. |
GET /health |
Проверка живости, единственный эндпоинт без токена. |
GET /status |
Режим, тулы, алиасы, активные сессии и пути эндпоинтов. |
Почему stateless. Раньше единственным транспортом был SSE: клиент держал открытым GET /sse, а вызовы шли отдельными POST /messages?sessionId=…. Каждое такое соединение — сессия со своим экземпляром MCP-сервера и heartbeat-таймером. Если клиент отваливался молча (обычная история для облачных клиентов вроде Notion AI), сессия оставалась «живой» до таймаута простоя, упиралась в лимит и провоцировала цикл переподключений и спам в логах.
Теперь каждый POST /mcp самодостаточен: сервер собирается, отвечает и закрывается в рамках одного запроса. Сессий не существует — значит, нечему утекать, зависать и вытесняться. Конфиг перечитывается на каждый запрос, поэтому смена режима, алиасов и воркспейса подхватывается без перезапуска.
Пути эндпоинтов меняются в ~/.notcode/config.json: sse.mcpPath, sse.ssePath, sse.messagesPath.
- Проверь, что сервер жив:
curl http://127.0.0.1:3000/health→{"ok":true}. - Проверь токен:
bun run tokenи сравни с настройками клиента. - Проверь URL в клиенте: основной путь —
/mcp, а не/sse. Точный адрес печатается при старте сервера. - Прогони
bun run e2e— он воспроизводит и новый handshake, и legacy-SSE с heartbeat. - Если между клиентом и сервером есть nginx/Cloudflare: для
/mcpдостаточно обычного проксирования; для legacy/sseвыключи буферизацию и поднимиproxy_read_timeoutвыше интервала heartbeat. - Логи:
NOTCODE_LOG_LEVEL=debug bun run start.
~/.notcode/
├── config.json # Настройки, токены и профили
├── audit.jsonl # Журнал выполненных действий
└── snapshots/ # Автоматические бэкапы файлов
Если config.json окажется битым, сервер не молча создаст новый токен, а отложит файл в config.json.broken-<время> и скажет об этом явно.