Files
memo/docs/orders/07-mcp.md
T

4.8 KiB
Raw Blame History

Проект: /root/WORK/memo (Kotlin/JVM). Заказ по MCP-серверу. Контракт уже в docs/orders/07-mcp.md — читать его как исходное ТЗ, а здесь перечислены обязательные требования и известные грабли.

Создать: memo-mcp/build.gradle.kts memo-mcp/src/main/kotlin/memo/mcp/McpServer.kt memo-mcp/src/test/kotlin/memo/mcp/McpProtocolTest.kt

Зависимости модуля memo-mcp

plugins { kotlin("jvm"); application; kotlin("plugin.serialization") version "2.4.10" } application { mainClass.set("memo.mcp.McpServerKt") } dependencies { implementation(project(":memo-core")) implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3") } ВАЖНО: в kotlin("plugin.serialization") версию указать обязательно 2.4.10, иначе сборка упадёт на несовместимости версий плагина и Kotlin. Если сериализация начнёт мешать — НЕ добавляй её, собери JSON строками вручную (ручной JSON-рендер допустим и проще).

McpServer.kt

fun main(args: Array) — читает stdin построчно, на каждый запрос печатает в stdout РОВНО одну строку JSON-RPC 2.0. В stdout НИЧЕГО кроме JSON (включая баннеры/логи) — диагностика только в stderr.

Методы:

  • initialize → {"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"serverInfo":{"name":"memo","version":"0.1.0"}}
  • notifications/initialized → ответ не отправлять (вернуть null)
  • tools/list → 3 инструмента: memo_search {path, query, k=8, mode="hybrid"}, memo_status {path}, memo_reindex {path}
  • tools/call {"name":..., "arguments":{...}} → {"content":[{"type":"text","text":"..."}],"isError":false} Ошибки (нет обязательного аргумента, неизвестный инструмент, исключение) → isError:true + текст, НЕ JSON-RPC error.
  • неизвестный метод → {"jsonrpc":"2.0","id":,"error":{"code":-32601,"message":"Method not found"}}
  • уведомление (нет "id" в запросе) → ответ не отправлять

Тестируемые без процесса функции: handleRequest(line: String): String?, toolSearch(path, query, k, mode): String, toolStatus(path): String, toolReindex(path): String.

Поведение инструментов:

  • Коллекции определять ТАК ЖЕ, как CLI: см. memo-cli/src/main/kotlin/memo/cli/Main.kt — переиспользуй ту логику определения корня и коллекций (если это private — сделай в memo-core отдельный файл memo-core/src/main/kotlin/memo/core/Collections.kt с функциями fun resolveCollection(path: java.io.File): java.io.File и fun findCollections(root: java.io.File): List<java.io.File>, и переключи CLI и MCP на них; CLI при этом должен остаться с зелёными тестами).
  • toolSearch: Searcher с refresh-хуком (indexTree перед поиском), текст ответа — по строке на хит: <path>:<line> <heading> и следом текст чанка; пусто → "ничего не найдено".
  • toolStatus: <коллекция>: файлов <N>, чанков <M>, индекс <ISO>.
  • toolReindex: удалить <коллекция>/.memo целиком и переиндексировать; вернуть переиндексировано файлов: <N>.

McpProtocolTest.kt — ровно 5 тестов, имена ровно такие

  1. initializeHandshake — ответ содержит "2024-11-05" и "memo".
  2. toolsListHasThreeTools — ответ содержит memo_search, memo_status, memo_reindex.
  3. unknownMethodReturns32601 — ответ содержит "-32601".
  4. searchWithoutPathIsError — tools/call memo_search с arguments {} → содержит "isError":true.
  5. notificationProducesNoResponse — handleRequest(уведомление notifications/initialized) == null.

После: ./gradlew :memo-mcp:test --rerun-tasks и ./gradlew :memo-mcp:installDist — зелёные. Коммит: git add -A && git commit -m "mcp: сервер memo_search/memo_status/memo_reindex"

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

  • Не выводить план текстом; сразу создавай файлы.
  • Не трогать логику memo-core, кроме добавления Collections.kt и переключения CLI на него.
  • Ничего в stdout, кроме JSON-RPC строк.