Skip to main content
Glama
bahooo22
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
```