使用说明
MCP Project RAG Server
Node.js/TypeScript MCP-сервер для локального RAG по нескольким проектам с хранением чанков в ChromaDB.
Что уже есть
- MCP-сервер на официальном TypeScript SDK с поддержкой
stdioи Streamable HTTP. - Простой встроенный web UI для просмотра проектов и чанков индекса в обязательной тёмной теме.
- Реестр локальных проектов с явной регистрацией путей.
- Индексация кода и документации по чанкам.
- Persisted file state с
mtime,size,contentHash,chunkIdsиchunkHashesдля инкрементальной реиндексации. - Project-level lock для mutating операций, чтобы не смешивать параллельные
reindex/update/delete/register. - Atomic write для
projects.jsonиindex-state/*.json. - Разделение данных по проектам через отдельные Chroma collections.
- Двухэтапный поиск: retrieval в Chroma + локальный neural rerank.
- Сборка контекста под задачу агента через MCP tool
context.build. - Python-референс сохранён в
legacy/python-reference.
Критический разбор требований
- Нужен жизненный цикл индекса: полная переиндексация, обработка удалений и rename-файлов, а позже инкрементальные обновления.
- Нужна строгая фильтрация файлов: без неё в индекс попадут
dist,coverage, lock-файлы и сгенерированный код. - Нужна политика контекстного бюджета: RAG должен уметь не просто искать, а собирать компактный контекст под лимит.
- Нужен lifecycle локальных моделей: кэш, прогрев, fallback и контроль памяти.
- Нужны наблюдаемость и диагностика: статусы индексации, размеры коллекций, время поиска и ошибки файловой системы.
- Нужны будущие ограничения безопасности: сейчас проект ориентирован на локальное/внутреннее использование, без auth и ACL.
- Нужна дальнейшая оптимизация incremental indexing: теперь проект уже не читает всю collection на каждый
reindex, но файловая система всё ещё сканируется целиком, а для гарантии корректностиcontentHashпересчитывается по содержимому файла на каждом incremental run.
Архитектура
projects.register: регистрирует локальный проект.index.run: сканирует проект, инкрементально переиндексирует только изменившиеся файлы и удаляет чанки для исчезнувших файлов. При первом запуске выполняется полная сборка индекса.search.query: делает семантический поиск с rerank.context.build: собирает готовый контекст для агента.
Ключевые слои:
ProjectRegistryхранит метаданные проектов вdata/projects.json.ProjectIndexStateCacheхранит persisted состояние файлов и их chunk manifest вdata/index-state/<projectId>.json.ProjectOperationLockсериализует mutating операции на уровне конкретногоprojectId.FileDiscoveryServiceобходит файловую систему с учётом.gitignore, project-level excludes, exclude paths/extensions и лимита размера файла.ChunkingServiceрежет код по окнам строк, а документацию по абзацам.TransformersEmbeddingFunctionстроит локальные эмбеддинги через@xenova/transformers.NeuralRerankerделает второй этап ранжирования.ChromaProjectStoreизолирует проекты по коллекциямrag_project_<projectId>.ContextBuilderServiceсобирает стандартизированный контекст для MCP-ответа.
Быстрый старт
- Скопируйте пример конфига и при необходимости настройте
.env:
cp .env.example .env
- Если хотите локальный запуск без Docker, установите зависимости:
npm install
- Для запуска через Docker Compose:
docker compose up --build
Сервисы будут доступны так:
- ChromaDB:
http://127.0.0.1:8000 - MCP server:
http://127.0.0.1:3123/mcp - Web UI:
http://127.0.0.1:3123/ui
- Для локального MCP-клиента без Docker:
npm run dev:stdio
- Для локального Streamable HTTP без Docker:
$env:MCP_TRANSPORT="http"
npm run dev:http
Docker Compose
В репозитории есть готовые:
Compose поднимает два сервиса:
chromaс постоянным volume для векторной БДrag-serverс Node.js MCP-сервером
По умолчанию текущий репозиторий монтируется в контейнер как /workspace/current-project. Это сделано специально: чтобы сервер внутри контейнера мог индексировать локальный код, проект должен быть примонтирован внутрь контейнера как bind mount.
Если нужно подключать другие локальные проекты, добавьте новые bind mounts в rag-server.volumes, например:
volumes:
- ./:/workspace/current-project:ro
- /absolute/path/to/another-project:/workspace/another-project:ro
После этого регистрируйте проект в MCP уже по контейнерному пути, например /workspace/another-project.
Конфигурация
Проект в текущем виде рассчитан прежде всего на локальный или внутренний контур разработки. Публиковать его как внешний публичный сервис без отдельного слоя аутентификации, авторизации и network hardening не предполагается.
Сервер автоматически читает переменные из .env в корне проекта. Переменные окружения процесса имеют приоритет над значениями из файла.
MCP_TRANSPORT=stdio|httpMCP_HTTP_HOST=127.0.0.1MCP_HTTP_PORT=3123MCP_HTTP_PATH=/mcpMCP_DATA_DIR=./dataCHROMA_URL=http://127.0.0.1:8000EMBEDDING_MODEL=Xenova/all-MiniLM-L6-v2RERANK_MODEL=Xenova/all-MiniLM-L6-v2MAX_CONTEXT_CHARS=12000
Сервер также автоматически использует служебные директории внутри MCP_DATA_DIR:
projects.jsonдля реестра проектовindex-state/для persisted file state (mtime,size,contentHash,chunkIds,chunkHashes)models/для локального кэша моделей
Правило по путям
- Код, документация и примеры не должны содержать абсолютные локальные пути текущего окружения.
- В репозитории допускаются только относительные пути внутри проекта или нейтральные placeholders вроде
/absolute/path/to/project. - Нельзя публиковать пути вида домашнего каталога разработчика, рабочей папки машины или иного environment-specific location.
Основные MCP tools
projects.listprojects.registerprojects.unregisterindex.runsearch.querycontext.build
Web UI
В HTTP-режиме сервер также поднимает простой интерфейс:
GET /ui— тёмная панель просмотра, создания, редактирования, удаления и реиндексации проектовGET /api/projects— список зарегистрированных проектов и краткая сводка по индексуPOST /api/projects— регистрация нового проекта из браузераGET /api/projects/{projectId}— подробности проекта и preview чанков из текущего индекса- если index inspection временно недоступен, UI показывает warning прямо в списке проектов и отдельный
indexErrorв карточке проекта вместо подмены пустым индексом - browser API также возвращает timestamp последней ошибки inspection/reindex через diagnostics-поля, чтобы UI мог показывать свежесть проблемы
PUT /api/projects/{projectId}— редактированиеrootPathиdescriptionпроектаDELETE /api/projects/{projectId}— удаление проекта и его коллекции из индексаPOST /api/projects/{projectId}/reindex— ручной запуск реиндексации проекта; после первого полного прогона используется инкрементальный режим с persisted file state и пересчётомcontentHashдля защиты от stale indexPOST /api/projects/{projectId}/search— семантический поиск из браузера, принимает{ "query": string, "limit"?: number }POST /api/projects/{projectId}/context— сборкаcontext.buildчерез browser UI, принимает{ "query": string }
Проверка
npm run check
npm run test
npm run test:e2e
npm run build
Последний smoke-status:
GET /uiотдаётся успешно;POST /api/projectsи повторныйPOST /api/projects/{projectId}/reindexдают переходfull -> incremental;- второй
reindexвозвращаетunchangedFileCount=1для неизменённого smoke-файла; - MCP
initializeиtools/call search.queryуспешно проходят поверх/mcp. npm run test:e2eпрогоняет browser-level UI smoke через Playwright.