Привет, Хабр!
Мы живем в удивительное время. Попросить LLM написать для нас код стало так же естественно, как гуглить ошибку. Но у этой магии есть предел. Попросите модель написать quickSort
, и она справится блестяще. А теперь попросите ее: «Добавь метрики Prometheus в метод processOrder
в нашем проекте».
И тут магия рушится. LLM — это гениальный, но страдающий амнезией стажер. Она знает все языки мира, но не имеет ни малейшего понятия о вашем проекте. Она не знает, какой у вас логгер, как вы обрабатываете ошибки и что у вас уже есть готовый MetricsService
. В лучшем случае вы получите общий, неидиоматичный код. В худшем — сломаете половину логики.
Стандартный RAG (Retrieval-Augmented Generation) — это как дать стажеру доступ к одному файлу. Полезно, но картину целиком он все равно не увидит. А что, если мы могли бы дать ему не просто файл, а полный доступ к знаниям тимлида-архитектора? Что, если бы LLM могла видеть не просто строки кода, а всю паутину связей, зависимостей и паттернов вашего проекта?
Сегодня я расскажу о проекте code-graph-rag-mcp — это не просто очередной RAG-пайплайн. Это полноценный MCP-сервер, который строит граф знаний вашего кода и дает LLM «архитектурное зрение», превращая ее из простого кодера в настоящего цифрового ассистента.
Чтобы построить систему, которая была бы быстрой, локальной и умной, пришлось принять несколько ключевых архитектурных решений. Давайте разберем каждое из них.
Можно было бы поднять обычный Express/Fastify сервер с REST-эндпоинтами. Но это плохой выбор для такой задачи.
Проблема: REST — это протокол без состояния (stateless). Каждый запрос — новая история. А нам нужна постоянная, «живая» связь между LLM и нашим кодом. LLM должна иметь возможность задавать уточняющие вопросы в рамках одной сессии, сохраняя контекст.
Решение: @modelcontextprotocol/sdk
. Это специализированный протокол, созданный Anthropic именно для таких задач. Он работает поверх WebSocket или IPC, обеспечивая постоянное соединение. Это позволяет LLM не просто «дергать» эндпоинты, а вести полноценный диалог с инструментами, кэшировать результаты и строить сложные цепочки вызовов. Это нативный язык общения для Claude.
Граф кода — значит, нужна графовая база данных, верно? Не всегда.
Проблема: Профессиональные графовые СУБД (Neo4j, TigerGraph) — это тяжеловесные серверные решения. Они требуют отдельной установки, настройки и потребляют много ресурсов. Для локального инструмента, который каждый разработчик запускает на своей машине, это избыточно.
Решение: better-sqlite3
и расширение sqlite-vec
. Это гениальное в своей простоте решение:
Zero-Configuration: SQLite — это просто файл. Никаких серверов, портов и паролей. Запустил — и работает.
Производительность: better-sqlite3
— одна из самых быстрых реализаций SQLite для Node.js. Для локальных задач ее скорости более чем достаточно.
Все в одном: Расширение sqlite-vec
добавляет векторный поиск прямо в SQLite! Нам не нужно поднимать отдельную векторную базу (Chroma, Weaviate), что радикально упрощает стек. Граф связей и семантические векторы живут в одном файле.
Как разобрать код на десятке языков и не сойти с ума?
Проблема: Регулярные выражения — хрупкий и ненадёжный способ парсинга кода. Они ломаются на любой нестандартной конструкции. Использовать отдельные парсеры для каждого языка (Babel для JS, AST для Python) — сложно и громоздко.
Решение: web-tree-sitter
. Это универсальный парсер, который:
Сверхбыстрый: Написан на C и скомпилирован в WebAssembly.
Устойчив к ошибкам: Если в коде есть синтаксическая ошибка (а она есть почти всегда в процессе редактирования), Tree-sitter не падает, а строит частичное дерево. Это критически важно для инструмента, работающего в реальном времени.
Мультиязычный: Достаточно подключить готовую грамматику для нужного языка, и он работает. Это позволяет проекту легко поддерживать JS, TS, Python и добавлять новые языки в будущем.
А теперь самое главное. Где и как живет этот граф? Может, для этого нужна тяжелая графовая СУБД вроде Neo4j? Нет, и это осознанное решение.
Проблема: Профессиональные графовые СУБД — это избыточность для локального инструмента. Они требуют отдельной установки, настройки и потребляют много ресурсов.
Решение: Гениальная простота SQLite. Мы эмулируем графовую структуру с помощью двух обычных реляционных таблиц. Это классический подход, известный как "список смежности" (Adjacency List).
В файле project.db создаются всего две таблицы:
entities (Сущности) — это УЗЛЫ (NODES) нашего графа.
Каждая строка в этой таблице — это отдельная сущность в коде: функция, класс, переменная, интерфейс.
Хранятся ее имя, тип, путь к файлу и координаты в коде.
relationships (Отношения) — это РЁБРА (EDGES) нашего графа.
Каждая строка — это связь между двумя сущностями (sourceId → targetId).
Самое важное здесь — тип связи:
calls: функция A вызывает функцию B.
extends: класс Cat наследует класс Animal.
implements: класс UserService реализует интерфейс IUserService.
imports: файл A импортирует сущность из файла B.
Как этот граф строится?
Этот процесс автоматизирован с помощью агентной системы:
CollectorAgent сканирует файлы, с помощью Tree-sitter парсит их в AST и находит все узлы (сущности), записывая их в таблицу entities.
AnalysisAgent снова проходит по AST, но теперь ищет связи между уже найденными узлами. Находит вызов функции — создает ребро calls. Видит extends — создает ребро extends. И так далее, наполняя таблицу relationships.
В результате, без внешних зависимостей и сложных серверов, мы получаем полную, подробную и готовую к запросам карту всего нашего проекта в одном файле.
Индексация большого проекта — сложный процесс. Его можно реализовать как один большой скрипт, но это плохая идея.
Проблема: Монолитный индексатор сложно отлаживать и масштабировать. Если на этапе анализа зависимостей произойдет сбой, весь процесс остановится.
Решение: Декомпозиция на агентов, каждый со своей зоной ответственности:
Collector Agent: «Разведчик». Быстро сканирует файлы и строит базовый AST. Его задача — собрать сырые данные.
Analysis Agent: «Аналитик». Берет сырые данные и обогащает их, находя связи: кто кого вызывает, кто от кого наследуется.
Semantic Agent: «Лингвист». Создает векторные эмбеддинги для семантического поиска.
Refactoring Agent: «Техлид». Ищет дубликаты, анализирует сложность и находит «узкие места». Такой подход позволяет распараллелить работу, сделать систему отказоустойчивой и легко добавлять новые виды анализа в будущем.
╔════════════════════╗ ╔════════════════════╗
║ Claude Desktop ║<═════║ MCP Server ║
║ (или другой клиент)║ ║ (на Node.js + SDK) ║
╚════════════════════╝ ╚═════════╦══════════╝
║ (Запросы через 13 инструментов)
▼
╔════════════════════════════════════════════════════════════════════════╗
║ База знаний (Knowledge Base) ║
║ ┌────────────────────────────────┐ ║
║ │ SQLite файл (project.db) │ ║
║ │ │ ║
║ │ • Граф кода (таблицы) │ ║
║ │ • Векторы (sqlite-vec) │ ║
║ └────────────────────────────────┘ ║
╚═══════════════════════════════════════╦════════════════════════════════╝
║ (Построение и обновление)
┌──────────────────┐ ┌─────────────┴────────────┐ ┌──────────────────────────┐
│ Кодовая база ├─────▶│ Парсинг (Tree-sitter) ├─────▶│ Агентная система │
│ (JS, TS, Python) │ └──────────────────────────┘ │ (Collector, Analyzer...) │
└──────────────────┘ └──────────────────────────┘
Сервер предоставляет 13 специализированных инструментов, которые LLM может использовать для анализа вашего проекта:
Основные: get_entities
, semantic_search
, find_similar_code
, get_entity_details
, search_by_pattern
.
Анализ связей: get_relationships
, analyze_dependencies
, get_call_graph
, impact_analysis
.
Рефакторинг: suggest_refactoring
, find_duplicates
, analyze_complexity
, find_hotspots
.
Метрика | Нативный Claude | MCP CodeGraph | Улучшение |
---|---|---|---|
Время выполнения | 55.84 с | <10 с | 5.5x быстрее |
Потребление памяти | Зависит от процесса | ~65MB | Оптимизировано |
Количество функций | Базовые паттерны | 13 инструментов | Комплексный анализ |
Точность | На основе паттернов | Семантическая | Превосходящая |
Технические характеристики:
Скорость индексации: 100+ файлов в секунду.
Время ответа на запросы: <100 мс.
Запрос в Claude Desktop:
> «Что сломается, если я изменю интерфейс IUserService
?».
Что происходит «под капотом»:
LLM видит ключевые слова «изменю» и «интерфейс» и вызывает инструмент impact_analysis
с аргументом IUserService
.
Сервер мгновенно выполняет запрос к своему графу в SQLite: «Найти все сущности, которые реализуют или напрямую зависят от IUserService
».
Сервер возвращает список классов (UserService
, AdminController
) и файлов, которые будут затронуты.
LLM получает этот структурированный список и генерирует человекочитаемый ответ: «Изменение IUserService
затронет класс UserService
, который его реализует, и AdminController
, который использует его для инъекции зависимостей. Вам потребуется обновить реализацию в этих файлах».
Это не просто поиск по тексту. Это глубокий анализ, основанный на понимании структуры кода.
Начать работу проще простого.
Установка:
npm install -g @er77/code-graph-rag-mcp
Настройка Claude Desktop:
npx @modelcontextprotocol/inspector add code-graph-rag \
--command "npx" \
--args "@er77/code-graph-rag-mcp /path/to/your/codebase"
После этого просто выберите code-graph-rag
в списке инструментов в Claude и начинайте задавать вопросы о своем проекте.
Проект code-graph-rag-mcp
— это шаг от «LLM как генератора текста» к «LLM как члена команды». Предоставляя модели глубокий контекст через графы знаний, мы открываем совершенно новые возможности для автоматизации рутинных задач, анализа сложных систем и безопасного рефакторинга.
Выбранный технологический стек — MCP, Tree-sitter и SQLite — не случаен. Он является результатом поиска баланса между производительностью, простотой использования и мощностью. Это локальный, приватный и невероятно быстрый инструмент, который может стать вашим незаменимым помощником в разработке.
Попробуйте сами и дайте своей LLM «суперсилу» — знание вашего кода.