project-map-mcp
by bahooo22
README.md
# project-map-mcp
Вспомогательный MCP-сервер, который берёт на себя всю механику построения
карты проекта (ID событий, даты, проценты, планы файлов, переходы между
частями, синхронизацию, финализацию), чтобы маленькая локальная модель
(Qwen 3.8-9B) отвечала только за контент — что читать и как классифицировать.
- **Версия сервера:** 1.11.2
- **Поддерживаемая версия промпта:** 4.10.1 (`scan_prompt/4101.txt`)
В начале сессии модель вызывает `map_version()` и сверяет версии сервера и
промпта — актуальный промпт требует сервер **≥ 1.10.7**.
Формат хранения событий: **`map/events.jsonl`** — один JSON-объект на строку,
сервер сам его сериализует. Никакого ручного экранирования кавычек моделью
больше не требуется. Совместимость со старыми `events/*.json` не сохраняется
(это осознанное упрощение) — если нужно перенести старые события, допиши
конвертер.
## Сборка и запуск в Docker
```bash
cd project-map-mcp
# проверьте docker-compose.yml — путь к проекту на хосте в volumes
docker compose up -d --build
```
Проверить, что сервер поднялся:
```bash
curl -i http://localhost:8765/mcp
```
Два порта:
- **8765** — сам MCP-сервер (эндпоинт `/mcp`);
- **8766** — веб-dashboard карты (см. ниже), если не отключён.
## Важно про пути
По умолчанию весь проект монтируется в контейнер как
`<хост>:/projects`, а карта строится по подкаталогу `scan`:
```yaml
volumes:
- "E:/.../Tezam.Parser:/projects"
environment:
MAP_ROOT: /projects/scan # где лежит карта (parts/, map/)
SOURCE_ROOT: /projects # корень для путей внутри событий
```
Пути внутри `parts/part_*.txt` (например `/projects/scan/chat-export-...json`)
должны буквально совпадать с путями внутри контейнера — тот же корень, что
использует `j0hanz/filesystem-mcp`. Меняются через env `MAP_ROOT` /
`SOURCE_ROOT` (или одноимённые поля в конфиге).
## Конфигурация
Параметры сервера задаются в трёх слоях по приоритету
(меньший перезаписывается большим):
```
дефолты в server.py < map_config.toml < env-переменные
```
`map_config.toml` создаётся автоматически при первом запуске и лежит рядом с
картой. Менять конфиг можно не только файлом, но и в рантайме — инструментами
`map_config()` (показать текущие значения и их источники) и
`map_set_config(section, key, value)` (изменить и сохранить в TOML).
Не применяются на лету (нужен рестарт): `server.host`, `server.port`,
`paths.root`, `paths.source_root`.
Основные env-переменные: `MAP_ROOT`, `SOURCE_ROOT`, `PORT`, `MAP_HOST`,
`MAP_DASHBOARD_ENABLED`, `MAP_DASHBOARD_PORT`, лимиты `MAP_MAX_BATCH_BYTES`,
`MAP_MAX_FILES_PER_PACKET`, `MAP_MAX_EVENTS_PER_FILE`, `MAP_SOFT_EVENTS_LIMIT`,
`MAP_MAX_PLAN_THEMES`, `MAP_CHUNKED_MAX_EVENTS_PER_FILE`,
`MAP_CHUNK_CONFIDENCE_THRESHOLD`, и группа embeddings (см. ниже).
Ключевые лимиты по умолчанию: `max_batch_bytes=300000`,
`max_files_per_packet=10` (размер пакета по умолчанию 3),
`max_events_per_file=10`, `max_plan_themes=20`,
`chunked_max_events_per_file=15`.
## Опциональные embeddings
Для семантического поиска по связям событий (`map_rebuild_parent_events`)
можно включить эмбеддинги через локальный эндпоинт LM Studio. По умолчанию
выключено — связи считаются по lexical-пересечению описаний (IDF), а косинусная
близость используется только как fallback при включённых embeddings.
- `MAP_EMBEDDINGS_ENABLED` (default `false`)
- `MAP_EMBEDDINGS_URL` (default `http://localhost:1234/v1/embeddings`)
- `MAP_EMBEDDINGS_MODEL` (default `text-embedding-nomic-embed-text-v1.5@f32`)
- `MAP_EMBEDDINGS_TIMEOUT_SEC` (default `35.0`)
- `MAP_EMBEDDINGS_MIN_SCORE` (default `0.75`)
Логика эмбеддингов вынесена в `embeddings.py` (`embed_batch`, `cosine`).
## Dashboard
Если `MAP_DASHBOARD_ENABLED` (по умолчанию включён), на порту **8766**
поднимается веб-просмотр карты: корень `/` отдаёт HTML-страницу (события,
связи parent/related, прогресс, планы). Рядом — JSON-API:
`/api/status`, `/api/stats`, `/api/events?limit=N`, `/api/events/<id>`,
`/api/plans`, `/api/config` (GET читает, POST меняет конфиг в рантайме).
Отключается `MAP_DASHBOARD_ENABLED=false`, порт — `MAP_DASHBOARD_PORT`.
⚠️ В текущем `docker-compose.yml` проброшен только `8765:8765`, поэтому
dashboard с хоста недоступен, пока не добавите маппинг:
```yaml
ports:
- "8765:8765"
- "8766:8766" # чтобы открыть http://localhost:8766/
```
## Подключение в LM Studio
Откройте `~/.lmstudio/mcp.json` (Program → Install → Edit mcp.json) и добавьте
блок `"project-map"` из `mcp.json.example` к уже существующим записям для
`j0hanz-filesystem` и `mcp-filesystem` — их трогать не нужно, они по-прежнему
нужны для чтения (`read`/`read_file`/`read_multiple_files`/`list`/`stat`/
`search_text`). В Developer → Settings включите "Allow remote MCP", если
сервер не появится в списке инструментов сразу.
⚠️ Сервер протестирован локально на тестовых данных (батчинг, генерация ID,
дат, sync, finalize — см. лог smoke-теста), но не тестировался живьём внутри
LM Studio — если формат `mcp.json` для remote-серверов будет отличаться
(например потребуется `"transport": "http"` явно), поправьте по документации
LM Studio → MCP.
## Инструменты
Полный набор (докстринги — в `server.py`). Модель не выбирает их наугад:
последовательность вызовов задаёт промпт `scan_prompt/4101.txt`.
Версии и конфиг:
- `map_version()` — версия сервера и поддерживаемая версия промпта.
- `map_config()` — текущая конфигурация и её источники.
- `map_set_config(section, key, value)` — изменить параметр в рантайме (+ TOML).
Основной цикл:
- `map_status()` — статус одной строкой, включая активный `batch_id` и планы.
- `map_set_batch_size(n)` — размер пакета, от 1 до 10.
- `map_get_batch()` — следующий пакет файлов (+ компактный `recent_context`).
- `map_plan_file(file_path, themes, confidence)` — зафиксировать план тем для
файла ДО первого события; обязательный первый шаг обработки файла.
- `map_create_event(...)` — создать событие (ID/дату/`parent_event`/confidence
считает сервер).
- `map_complete_batch(batch_id)` — завершить обычный пакет (ровно один раз).
- `map_cancel_batch(batch_id, discard_events, kind)` — отменить зависший пакет
(`kind="normal"` или `"recovery"`).
Анализ и поиск:
- `map_recent_events(limit)` — компактный список последних событий.
- `map_find_by_path(file_path)` — события по пути файла.
- `map_find_related_events(query, limit)` — события по теме.
- `map_find_sparse_events()` — события с пустыми `error_logs`/`fixes`/`related_issues`.
- `map_rebuild_parent_events(min_overlap, force)` — пересчитать `parent_event`
у всех событий (только по явной команде пользователя).
Синхронизация и восстановление:
- `map_delete_events_for_path(file_path)` — убрать события файла в trash и
пометить файл непройденным (активные пакеты сбрасываются).
- `map_sync()` — пересчитать `state.json` по фактическим событиям (может
требовать нескольких вызовов; отказывает при активном пакете с событиями).
- `map_recover_scan(scope, part_id, from_part, to_part)` — собрать список
файлов без событий (`scope="current"|"all"|"range"`).
- `map_recover_get_batch()` / `map_recover_complete_batch(batch_id)` — пакетная
доработка пропусков (в `map_create_event` передавай `recovery=True`).
Финализация:
- `map_finalize()` — собрать итоговые отчёты (только когда обработаны все файлы
и нет активных пакетов).
## Обновление сервера
`server.py` и `embeddings.py` монтируются в контейнер bind-mount'ом (см.
`volumes` в `docker-compose.yml`), поэтому правка кода применяется простым
рестартом:
```bash
docker compose restart
```
Пересборка образа нужна только если изменились зависимости
(`requirements.txt` / `Dockerfile`):
```bash
docker compose up -d --build
```
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues