Третья часть серии. В первой я разбирал сам движок 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 (принять найденных агентов без вопросов).

Что получает агент

Сервер выставляет восемь инструментов. Их немного, и каждый заточен под конкретный вопрос о коде:

Инструмент

Назначение

search_symbols

Полнотекстовый поиск по именам символов — начинать отсюда

get_node_info

Сниппет исходника + сигнатура + докстринг + позиция узла

get_file_structure

Карта символов файла (outline)

get_callees

Что вызывает функция (исходящие, до max_depth)

get_callers

Кто вызывает функцию — основной инструмент анализа влияния

get_neighbors

Узлы в пределах N переходов в любом направлении

find_references

Не-вызовы: аннотации типов, присваивания

get_cross_language_calls

Связи через границы сервисов (HTTP/gRPC/очереди)

Одна деталь, на которую стоит обратить внимание: каждый ответ несёт статус качества графа (ok или degraded, агрегированный по всем возвращённым узлам), так что агент не примет частичный ответ за полный. Списки ограничены MAX_RESULTS (200) и помечаются флагом truncated — без молчаливого обрезания.

CLI: пять команд

Команда

Что делает

graphlens-mcp init

Определить языки → доктор тулчейнов → полная индексация → настроить агентов → поставить скилл

graphlens-mcp serve

Запустить MCP-сервер по stdio. Поднимает его агент, не вы (--no-watch отключает watcher)

graphlens-mcp status

Языки, статус тулчейнов, размер и свежесть графа

graphlens-mcp reindex

Полная пересборка (например, после установки нового тулчейна)

graphlens-mcp remove

Снять регистрацию у агентов; с --purge-db — удалить локальный граф

Сценарий: анализ влияния

Ради этого всё и затевалось. Берём типичную задачу перед рефакторингом — что сломается, если поменять сигнатуру 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_symbolsget_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)


  1. mst_72
    28.06.2026 06:49

    Ладно, код написан агентами. Ладно можно использовать агентов для улучшения/исправления статьи. Но зачем послностью писать всю статью Клодом и тут же выкладывать на хабро? Это ж не кодовый репозиторий, не жира тикет... Зачем? Неужели не бесят выражения про "честно"????


    1. Neko1313 Автор
      28.06.2026 06:49

      Cодержание, замеры, выводы - мои, модель просто собрала всё в читаемый текст. Язык и структура - это редактура, а не авторство. "Честно" - это не самопохвала. За моими процентами 936 прогонов, открытые трейсы и стенд - иди да перепроверь. А за типичным "−40% токенов" строчка в README и всё. Критиковать подачу - это бесплатно. А сделать инструмент и прогнать тыщу замеров - нет.


      1. Djaler
        28.06.2026 06:49

        Как будто и этот комментарий тоже попахивает


        1. Neko1313 Автор
          28.06.2026 06:49

          А будет критика самого инструмента ?


  1. Firues
    28.06.2026 06:49

    Это решение превосходит mcp сервер codegraph?


    1. Neko1313 Автор
      28.06.2026 06:49

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


      1. Firues
        28.06.2026 06:49

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


        1. Neko1313 Автор
          28.06.2026 06:49

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


  1. gybson_63
    28.06.2026 06:49

    1. Neko1313 Автор
      28.06.2026 06:49

      Продукт, который вы скинули, использует тот же принцип, что и codegraph, и скорее является его полным аналогом и имеет те же проблемы


      1. gybson_63
        28.06.2026 06:49

        Ну да. F12 / Alt-F12. Меня удивляет, что агенты сами не могут использовать это прямо в IDE. Что я вам точно скажу, так это действительно токены значительно экономит.

        А поле для творчество обширное. Добавить документацию к каждой функции (они же документированы, как правило), семантический поиск по ней.