Граф кода одной командой: ставим graphlens-mcp в проект и перестаём жечь токены на grep. claude code.. claude code. graphlens.. claude code. graphlens. llm.. claude code. graphlens. llm. mcp.. claude code. graphlens. llm. mcp. python.. claude code. graphlens. llm. mcp. python. tree-sitter.. claude code. graphlens. llm. mcp. python. tree-sitter. граф кода.. claude code. graphlens. llm. mcp. python. tree-sitter. граф кода. искусственный интеллект.. claude code. graphlens. llm. mcp. python. tree-sitter. граф кода. искусственный интеллект. кодовые агенты.. claude code. graphlens. llm. mcp. python. tree-sitter. граф кода. искусственный интеллект. кодовые агенты. оптимизация токенов.. claude code. graphlens. llm. mcp. python. tree-sitter. граф кода. искусственный интеллект. кодовые агенты. оптимизация токенов. Программирование.. claude code. graphlens. llm. mcp. python. tree-sitter. граф кода. искусственный интеллект. кодовые агенты. оптимизация токенов. Программирование. статический анализ кода.

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

Автор: Neko1313

Источник