Третья часть серии. В первой я разбирал сам движок graphlens — что он делает и как устроен внутри. Во второй гонял бенчмарк на 936 прогонов и смотрел, где граф реально окупается, а где проще остаться с grep. Здесь — про то, что осталось за кадром в обеих частях: движок это ещё не инструмент, и чтобы подключить его к агенту, поверх нужно дописать прилично кода. Вот этот код я и собрал в отдельный продукт. graphlens-mcp ставится одной командой, дальше работает сам. Он в alpha, бесплатный (MIT), и прогнать его на своём проекте можно минут за пять.
Коротко про предыдущие части, чтобы не уходить читать их прямо сейчас. Движок берёт исходники на Python, TypeScript, Go, Rust и PHP и сводит их в один типизированный граф: узлы-символы, рёбра с учётом типов (CALLS, HAS_TYPE, INHERITS_FROM), детерминированные SHA-256 ID, межъязыковые границы. Бенчмарк я ставил на apache/superset — около 400k строк, Python плюс TypeScript, граница между ними проходит по /api/v1/.... Итог второй части: на анализе влияния структурный граф выигрывает у grep по стоимости в 10–23 раза, а на точечных запросах разница почти исчезает.
Откуда боль
Ситуация знакомая каждому, кто запускал кодового агента на большом проекте. Сотни тысяч строк, бэкенд на Python, фронт на TypeScript, где-то легаси, в которое лишний раз лезть не хочется. Спрашиваешь агента, как устроена авторизация или что отвалится при смене сигнатуры метода, и он уходит в цикл: grep, открыть файл, прочитать, перейти по импорту, снова grep. Десятки прочитанных файлов оседают в контексте и тарифицируются на каждом следующем ходу.
Цифру тут любит приводить сам Anthropic: в их инженерном блоге сказано, что определения инструментов и промежуточные результаты могут съесть «50,000+ tokens before an agent reads a request». То есть окно забивается ещё до того, как агент дошёл до самой задачи.
Граф закрывает ровно этот сценарий. Вместо «прочитай файл и поищи глазами» агент задаёт точный вопрос — кто вызывает create_order — и получает короткий структурированный ответ.
Движок — это ещё не продукт
Когда я выкладывал graphlens, ядро я специально сделал узким, и в документации это зафиксировано прямым текстом: движок производит граф-IR и на этом останавливается. Состояние не хранит, базой не владеет, за файловой системой не следит, сам не переиндексируется, эмбеддинги не считает, долгоживущий сервис не поднимает. Адаптеры — чистые продюсеры данных, граф на выходе и всё.
Для движка это правильное решение: маленькое ядро легко тестировать, кэшировать и собирать в композиции. А вот на практике между «есть API» и «работает в связке с агентом» лежит примерно столько же кода, сколько в самом ядре. Кто-то должен написать:
хранилище графа и его сериализацию;
инвалидацию: файл изменился — что переиндексировать;
watcher за файловой системой;
MCP-сервер с инструментами, которые агент умеет звать;
регистрацию сервера в конфиге Claude Code, Cursor и остальных, у каждого свой формат;
навигационный скилл, чтобы агент знал, как этими инструментами вообще пользоваться.
Обычно эту прослойку каждый дописывает под себя сам. Я написал её один раз и оформил отдельным проектом. graphlens-mcp — тонкий рантайм поверх движка: graphlens отвечает за механику (парсинг, стабильные ID узлов, резолверы), graphlens-mcp берёт на себя хранилище, модель свежести и всё, что видит агент.
Установка
Одна команда плюс init:
uv tool install graphlens-mcp # или: pipx install graphlens-mcp cd your-project && graphlens-mcp init
init определяет языки проекта, прогоняет «доктор» по тулчейнам, индексирует код в локальный граф, прописывает MCP-сервер в конфиги ваших агентов (знает форматы Claude Code, Cursor, Windsurf, VS Code/Copilot, Codex CLI; пишет идемпотентно, чужие серверы не трогает) и ставит навигационный скилл. Сам сервер потом поднимает агент из конфига, serve руками звать не нужно. Перезапускаете агента и спрашиваете что-нибудь вроде «что сломается, если поменять сигнатуру create_order».
Из требований — Python ≥ 3.13 (ограничение тянется из graphlens), лицензия MIT, текущая версия 0.1.2.
Флаги init, которые пригодятся: --root <dir>, --agent claude_code --agent cursor (повторяемый), --no-agent, --no-skills, --db <path>, --yes (принять найденных агентов без вопросов).
Что получает агент
Сервер выставляет восемь инструментов. Их немного, и каждый заточен под конкретный вопрос о коде:
Инструмент |
Назначение |
|---|---|
|
Полнотекстовый поиск по именам символов — начинать отсюда |
|
Сниппет исходника + сигнатура + докстринг + позиция узла |
|
Карта символов файла (outline) |
|
Что вызывает функция (исходящие, до |
|
Кто вызывает функцию — основной инструмент анализа влияния |
|
Узлы в пределах N переходов в любом направлении |
|
Не-вызовы: аннотации типов, присваивания |
|
Связи через границы сервисов (HTTP/gRPC/очереди) |
Одна деталь, на которую стоит обратить внимание: каждый ответ несёт статус качества графа (ok или degraded, агрегированный по всем возвращённым узлам), так что агент не примет частичный ответ за полный. Списки ограничены MAX_RESULTS (200) и помечаются флагом truncated — без молчаливого обрезания.
CLI: пять команд
Команда |
Что делает |
|---|---|
|
Определить языки → доктор тулчейнов → полная индексация → настроить агентов → поставить скилл |
|
Запустить MCP-сервер по stdio. Поднимает его агент, не вы ( |
|
Языки, статус тулчейнов, размер и свежесть графа |
|
Полная пересборка (например, после установки нового тулчейна) |
|
Снять регистрацию у агентов; с |
Сценарий: анализ влияния
Ради этого всё и затевалось. Берём типичную задачу перед рефакторингом — что сломается, если поменять сигнатуру create_order.
Без графа агент грепает имя по всему репозиторию, ловит каждое вхождение create_order (включая однофамильцев в тестах и комментариях), читает каждый файл-совпадение целиком, идёт по импортам, перечитывает уже прочитанное. На сложной базе это 27 обращений к инструментам, прежде чем сложится картина. А иногда агент упирается в лимит ходов и до ответа так и не доходит.
С graphlens-mcp цепочка короткая:
search_symbols("create_order") # 1. найти узел get_callers(id, max_depth=5) # 2. кто вызывает — радиус поражения find_references(id) # 3. где ещё упоминается: аннотации, присваивания get_cross_language_calls(id) # 4. бьёт ли фронт в этот эндпоинт через /api/v1/...
get_node_info агент дёргает только там, где реально нужна детализация, а не вычитывает каждый вызывающий файл целиком. Этот же паттерн (search_symbols → get_callers/find_references → суммировать, get_node_info точечно) зашит в навигационный скилл, который ставит init.
Почему граф не протухает на лету
Главное, что отличает готовый продукт от связки «движок + скрипт» — граф остаётся актуальным сам, пока вы правите код.
За свежесть отвечает filesystem watcher: он стартует вместе с serve (отключается флагом --no-watch). Меняется файл на диске — сервер переиндексирует connected set: сам файл плюс те, кто его импортирует, плюс те, кого импортирует он. Делается это одним полным analyze, чтобы межфайловые рёбра пересобрались целиком, а не остались наполовину битыми. Удаление файла вычищает его символы и обновляет импортёров. Поллинга нет, «скелетной» фазы нет: каждая переиндексация отдаёт полный граф, какой резолвер в состоянии построить.
Отдельно закрыт случай правок, сделанных пока сервер был выключен. На старте serve делает one-shot reconcile: сканирует проект, индексирует новые файлы, выкидывает исчезнувшие, обновляет изменённые, и только потом передаёт управление watcher'у.
Сам граф лежит в <project>/.graphlens/graph.db (SQLite). Это регенерируемый кэш, удалять безопасно — reindex соберёт заново. .graphlens/ имеет смысл добавить в ignore вашей VCS.
Сколько это экономит токенов
Цифры. С оговоркой, которую повторю и здесь: это замеры на конкретном кейсе, а не универсальный рейтинг.
Во второй части я гонял graphlens против файлового поиска на apache/superset, меняя у одного и того же агента ровно одно — какой MCP-сервер отдаёт контекст. На сложных задачах (анализ влияния, разрешение неоднозначных имён, полный набор переопределений) получилось так:
Инструмент |
Токены |
Вызовы |
$/задача |
|---|---|---|---|
filesystem (grep+read) |
12596 |
27 |
$0.424 |
graphlens (граф) |
748 |
1 |
$0.018 |
Сокращение токенов примерно на 94%, стоимости — в 10–23 раза, один вызов инструмента против двадцати семи. На простых точечных запросах («где определён класс») разрыв скромнее: 690 токенов против 1780, порядка 61%. Вывод второй части тут без изменений: на точечных справках граф не нужен, grep справляется. Окупается он на структурной работе — рефакторинг, оценка радиуса поражения, трассировка зависимостей.
Соседние инструменты дают тот же порядок величины. В актуальном README CodeGraph (перевалидировано на Claude Opus 4.8, 2026-06-02, медиана четырёх прогонов на семи репозиториях) — 47% меньше токенов, 58% меньше вызовов, 35% дешевле, 46% быстрее; более ранняя сборка README показывала 57%/71%. Независимый недельный обзор Ry Walker Research на четырёх репозиториях намерил 70% медианного сокращения вызовов, 59% по токенам и ответы на 49% быстрее. Везде одно и то же: на структурных вопросах граф режет и токены, и round-trips в разы.
Оговорка, без которой переносить эти цифры на свой проект нельзя: у меня один репозиторий (apache/superset) и 26 задач, cost_usd — это API-эквивалент, а не счёт по подписке, провал засчитан как точность 0. Хотите проверить на своём коде — стенд открыт: github.com/Neko1313/agent-context-bench.
Чего graphlens-mcp не делает
Чтобы не звучало как реклама — статус early. Ядро навигации работает, остальное в развитии. Известные ограничения лежат прямо в документации.
Watcher переиндексирует connected set правки, а не весь проект. Рефакторинг, который рябью расходится через много слоёв косвенности, или новый файл, который сразу импортирует неизменённый, может потребовать полного reindex для точного графа.
Межъязыковые рёбра COMMUNICATES_WITH пересобираются на полном reindex и могут эродировать на инкрементальных правках. Запрос по границам всё ещё резолвит связи, но для точной кросс-языковой картины зовите reindex.
Деградация без тулчейна. Python работает из коробки (ty в комплекте). Для TypeScript нужен Node, для Go/Rust/PHP — их тулчейны. Без них язык репортится как degraded: структура распарсена, вызовы и типы разрешены не полностью. При этом init на таком никогда не падает, а status показывает реальное состояние по каждому языку и подсказывает, чего доставить.
И главное ограничение по сути: graphlens-mcp не считает эмбеддинги и не ищет «по смыслу». Граф структурный и type-aware, а не векторный индекс. Запрос вида «найди код, концептуально похожий на rate limiting, как бы он ни назывался» — это к векторным инструментам. graphlens-mcp про другое: кто вызывает, от чего зависит, что отвалится.
Кому стоит ставить
Ставьте, если регулярно гоняете Claude Code, Cursor или совместимый клиент на большом полиглотном проекте и устали смотреть, как агент жжёт токены на рекурсивный grep по репозиторию. Особенно если часто делаете анализ влияния перед рефакторингом — это ровно тот режим, где граф себя оправдывает.
Не нужно, если проект маленький (десятки файлов — grep отработает мгновенно) или вам в основном нужен семантический поиск по смыслу.
Порог входа нулевой: всё локально, наружу ничего не уходит, MIT, сносится одной командой (graphlens-mcp remove --purge-db). Поставьте на свой основной проект, проверьте, что MCP подхватился в агенте, и сравните число вызовов на одном и том же архитектурном вопросе — с графом и без.
uv tool install graphlens-mcp cd your-project && graphlens-mcp init graphlens-mcp status # проверить языки и свежесть графа
Подытожу без пафоса. graphlens-mcp — это та самая обвязка, которую обычно дописываешь под движок руками: хранилище, watcher, MCP-слой, регистрация у агентов. Собрана в одну команду — поставил, и граф сам держится свежим, пока ты пишешь код. Продукт в alpha, и я говорю это прямо, а не прячу в мелкий шрифт: ядро навигации работает, межъязыковые рёбра и whole-project re-link ещё допиливаю.
Что мне сейчас нужнее всего — независимые прогоны на чужих репозиториях. Поставить и померить — те же пять минут. Issue, цифры с ваших проектов, претензии к гранулярности инструментов несите в репозиторий. Чем больше замеров на разных базах, тем ближе результат, который можно переносить, а не «работает на superset».
Репозиторий: github.com/Neko1313/graphlens-mcp
Движок: github.com/Neko1313/graphlens
Бенчмарк: github.com/Neko1313/agent-context-bench
Комментарии (11)

Firues
28.06.2026 06:49Это решение превосходит mcp сервер codegraph?

Neko1313 Автор
28.06.2026 06:49Зависит от задачи: на рефакторинге и анализе ощутимо дешевле по токенам, на простых точечных запросах примерно схожие цифры с ним. Прямое сравнение с codegraph в части 2

Firues
28.06.2026 06:49То есть, по сути вы сделали тоже самое, что делает semble mcp?

Neko1313 Автор
28.06.2026 06:49И да и нет. Semble - это семантический поиск: он по эмбеддингам находит код, похожий по смыслу на запрос. У меня - структурный граф: реальные рёбра вызовов и типов. Это разные вопросы. "Найди код про аутентификацию" - это к semble. А "кто конкретно вызывает этот метод и что сломается, если я поменяю сигнатуру" - похожесть тут не поможет, нужна именно структура. Эмбеддинг не отличит реальный вызов функции от куска, который просто рядом по смыслу

gybson_63
28.06.2026 06:49Пользуюсь вот этим
Regsorm/code-index-mcp: Rust-native code index MCP server with first-class 1C:Enterprise (BSL) support. Static binary, no runtime. 31 tools — 20 universal + 11 BSL-specific. Tree-sitter AST for 10 languages. Federation across multiple repos. Built for production-scale monorepos.
вполне готовый продукт
Neko1313 Автор
28.06.2026 06:49Продукт, который вы скинули, использует тот же принцип, что и codegraph, и скорее является его полным аналогом и имеет те же проблемы

gybson_63
28.06.2026 06:49Ну да. F12 / Alt-F12. Меня удивляет, что агенты сами не могут использовать это прямо в IDE. Что я вам точно скажу, так это действительно токены значительно экономит.
А поле для творчество обширное. Добавить документацию к каждой функции (они же документированы, как правило), семантический поиск по ней.
mst_72
Ладно, код написан агентами. Ладно можно использовать агентов для улучшения/исправления статьи. Но зачем послностью писать всю статью Клодом и тут же выкладывать на хабро? Это ж не кодовый репозиторий, не жира тикет... Зачем? Неужели не бесят выражения про "честно"????
Neko1313 Автор
Cодержание, замеры, выводы - мои, модель просто собрала всё в читаемый текст. Язык и структура - это редактура, а не авторство. "Честно" - это не самопохвала. За моими процентами 936 прогонов, открытые трейсы и стенд - иди да перепроверь. А за типичным "−40% токенов" строчка в README и всё. Критиковать подачу - это бесплатно. А сделать инструмент и прогнать тыщу замеров - нет.
Djaler
Как будто и этот комментарий тоже попахивает
Neko1313 Автор
А будет критика самого инструмента ?