Files
memo/docs/orders/09-mcp-cold-start.md
T

6.0 KiB
Raw Blame History

Проект: /root/WORK/memo (Kotlin/JVM). Заказ по холодному старту MCP-поиска.

Доказанные дефекты (воспроизведено зондом)

  1. Пустой старт не работает. Команда rm -rf /root/WORK/memo-e2e/*/.memo python3 scripts/mcp_probe.py --cmd "./memo-mcp/build/install/memo-mcp/bin/memo-mcp"
    --call memo_search --args '{"path":"/root/WORK/memo-e2e/infra","query":"основа для разрешения имён в сети","k":3}' возвращает текст коллекции не найдены, потому что selectTargets() оставляет только коллекции, у которых УЖЕ существует .memo/index.db. То есть главный сценарий — агент пишет .md штатными инструментами и сразу ищет — не работает: сначала надо вручную звать CLI index. Ожидаемое поведение: memo_search сам создаёт .memo/index.db и индексирует коллекцию, если индекса ещё нет, и возвращает результаты.

  2. Модель грузится по разу на каждую коллекцию. В toolSearch Embedder(...) создаётся внутри цикла по коллекциям. На трёх коллекциях это три загрузки модели.

Что сделать

Правки ТОЛЬКО в memo-mcp/src/main/kotlin/memo/mcp/McpServer.kt (+ новый тестовый файл). Логику memo-core не менять.

  1. toolSearch(path, query, k, mode):
    • Определить цели так: если File(path) сам является коллекцией (в нём есть *.md напрямую) — цель ровно он; иначе — все коллекции внутри findCollections(File(path)); если и их нет — вернуть коллекции не найдены.
    • Для каждой цели: если <коллекция>/.memo/index.db не существует — создать каталог .memo, Db(...), db.init(), проиндексировать Indexer(db, embedder).indexTree(коллекция). Затем обычный поиск с refresh-хуком.
    • Embedder создать ОДИН РАЗ до цикла по коллекциям и закрыть один раз после (try/finally). Db — по одному на коллекцию, как сейчас.
    • Не глотать ошибки молча: если по коллекции поиск упал, дописать в результат строку ошибка в <коллекция>: <текст> (в конец возвращаемого текста), остальные коллекции всё равно обрабатывать.
  2. toolStatus — оставить как есть (статус по несуществующему индексу законно говорит «нет индекса»).
  3. toolReindex — оставить как есть, но Embedder тоже вынести из цикла (один на все коллекции).

Тест: новый файл memo-mcp/src/test/kotlin/memo/mcp/McpColdStartTest.kt

Ровно 2 теста, имена ровно такие:

  1. searchIndexesCollectionOnColdStart — временный каталог-коллекция с двумя .md (например "# Прокси\nвнутренние домены ходят через шлюз 76.1" и "# Прочее\nсовсем другая заметка про книгу"), модель берётся из MEMO_MODEL_DIR (как в CoreSmokeTest). До вызова .memo НЕ существует. Вызвать toolSearch(dir.absolutePath, "внутренние домены шлюз", 5, SearchMode.HYBRID). Проверить: (а) в ответе нет подстроки "коллекции не найдены"; (б) ответ содержит "76.1"; (в) после вызова File(dir, ".memo/index.db").exists() == true.
  2. searchOnEmptyDirReportsNoCollections — пустой временный каталог без .md: ответ содержит "коллекции не найдены", каталог .memo не создан.

Тесты должны работать без запуска процесса (через toolSearch напрямую).

Обязательная сквозная проверка (приложить вывод)

cd /root/WORK/memo ./gradlew :memo-mcp:installDist -q cp -r /root/WORK/memo-e2e /tmp/memo-cold && rm -rf /tmp/memo-cold/*/.memo /tmp/memo-cold/.memo MEMO_MODEL_DIR=/root/WORK/memo/models/siglip2 python3 scripts/mcp_probe.py
--cmd "./memo-mcp/build/install/memo-mcp/bin/memo-mcp"
--call memo_search --args '{"path":"/tmp/memo-cold/infra","query":"основа для разрешения имён в сети","k":3}' MEMO_MODEL_DIR=/root/WORK/memo/models/siglip2 python3 scripts/mcp_probe.py
--cmd "./memo-mcp/build/install/memo-mcp/bin/memo-mcp"
--call memo_status --args '{"path":"/tmp/memo-cold/infra"}'

Ожидается: поиск отдаёт непустой текст с infra/domains.md (или infra/hosts.md) и без "коллекции не найдены"; status после этого показывает ненулевые файлы и чанки. Также приложить find /tmp/memo-cold -name index.db.

После: ./gradlew test --rerun-tasks — ВСЕ тесты проекта зелёные. Коммит: git add -A && git commit -m "mcp: поиск индексирует коллекцию на холодном старте"

СТРОГИЕ ЗАПРЕТЫ:

  • Не выводить план текстом; сразу правь файлы.
  • Не менять memo-core, memo-cli, memo-watch.
  • Не добавлять зависимости.