MAST
MAST — Monorepo AST Search Tool
MAST — это поисковый движок по коду, который работает либо как MCP-сервер (для ИИ-ассистентов), либо как автономный CLI. Он разбирает файлы TypeScript и JavaScript с помощью настоящего AST-парсера (tree-sitter), сохраняет полученный граф символов и фрагменты кода в SQLite и отвечает на запросы лексическим поиском BM25, объединённым с ранкером точных совпадений деклараций через Reciprocal Rank Fusion.
Основной принцип дизайна: возвращать ровно тот код, который нужен ассистенту, и ничего больше. Вместо чтения целых файлов MAST возвращает конкретную функцию, интерфейс или объявление типа, соответствующее запросу, — экономя токены, уменьшая шум в контексте и позволяя ИИ-инструментам навигировать по большим кодовым базам, не утопая в нерелевантном содержимом.
Содержание
Related MCP server: codeix
Зачем нужен MAST?
Когда ИИ-ассистенту нужно понять код, наивный подход — читать целые файлы. Это тратит токены (большая часть файла из 200 строк нерелевантна вопросу), раздувает контекстное окно и заставляет модель на каждом вызове отделять сигнал от шума.
MAST предлагает другой подход:
Разбиение на уровне AST — каждая функция, класс, интерфейс и псевдоним типа — это отдельный фрагмент. Ассистент получает точное объявление, которое ему нужно, а не файл, в котором оно находится.
Ранжированный поиск — BM25 (FTS5) обрабатывает запросы по ключевым словам и идентификаторам; ранкер точных совпадений деклараций («ранкер D») ловит запросы по точным именам символов, которые триграммный токенизатор BM25 может ранжировать непоследовательно. Оба объединяются через Reciprocal Rank Fusion, так что фрагмент, найденный обоими ранкерами, получает более высокий ранг, чем тот, который нашёл только один из них.
Структурные запросы — «кто вызывает эту функцию?», «что реализует этот интерфейс?», «что импортирует этот файл?» — получают ответы из заранее построенного графа символов, а не из grep по исходникам. Ответы мгновенны и структурно корректны.
JIT-обнаружение устаревания — при каждом чтении MAST проверяет, изменился ли файл на диске с момента последней индексации. Если изменился, файл прозрачно пере-парсится в фоне до возврата результата. Индекс никогда не устаревает без ведома ассистента.
Учёт токенов — каждый ответ инструмента включает
_statsс количеством возвращённых токенов и контрафактической оценкой «сколько бы стоил наивный полный файл», что даёт конкретную меру эффективности с течением времени.
Требования
Node.js ≥ 22 (репозиторий фиксирует версию, с которой ведётся разработка, в
.nvmrc)Набор инструментов C++ для двух нативных модулей (
better-sqlite3,tree-sitter). Предварительно собранные бинарники покрывают большинство платформ; когда ни один не соответствует ABI вашего Node,node-gypсобирает из исходников, и для этого нужны:macOS —
xcode-select --installDebian/Ubuntu —
sudo apt install build-essential python3Windows — установите рабочую нагрузку «Разработка классических приложений на C++» из Visual Studio Build Tools
Никаких сервисов, никаких API-ключей, никакой сети во время запросов. Всё — локальный SQLite.
Установка
Как dev-зависимость проекта, который вы хотите индексировать, — рекомендуется, потому что версия тогда фиксируется в вашем lockfile вместе со всем остальным:
pnpm add -D @spikedpunch/mast # or: npm i -D / yarn add -DИли глобально, если вам нужен один mast для множества копий репозиториев:
pnpm add -g @spikedpunch/mastПроверка:
mast --versionБыстрый старт
Три команды от нуля до поискового индекса:
cd /path/to/your/project
mast init # write .mast/, then run the first full index
mast status # confirm it is fresh
mast search "createUser" # search itmast search выводит соответствующее объявление, а не файл, в котором оно находится:
$ mast search "compareVersions" -n 1
src/cli/upgrade-cmd.ts:39 compareVersions function (exported)
/** Semver compare, prerelease-aware. Returns <0, 0, or >0. */
export function compareVersions(a: string, b: string): number {
...
}
270 tokens returned vs 2140 to read the files whole — 87% savedПоследняя строка — это реальный учёт, а не лозунг: каждый ответ несёт _stats с тем, что
было возвращено, и верхнюю границу стоимости чтения указанных файлов целиком. Для маленького
файла экономия может быть отрицательной, и MAST честно это говорит, а не округляет в свою
пользу.
Ответ, за который MAST не может поручиться полностью, говорит об этом на той же поверхности, где показывает результат. Файл, изменённый после индексации, помечается, потому что тело, напечатанное под ним, — старое:
! 1 of 2 results are from files that changed since indexing —
the code shown below may be out of date. Run `mast index` to refresh.
src/a.ts:1 alphaFunction function (exported) [STALE]А пустой ответ различает две причины, по которым он может быть пустым:
$ mast search "kept_symbol"
no matches (mast indexes TypeScript, JavaScript, and Markdown only —
a symbol in any other language is invisible to it, not absent from the repo)
$ mast search "anything" # in a directory with no index
nothing is indexed at this path — this is not evidence the symbol is absent.
run `mast index` first, or check `mast status` for the path being used.Сузьте запрос с помощью --type, --language, --exported, --file, -n:
mast search "greet" --type method --exported -n 5
mast search "config" --file "src/store/**"Поддерживайте актуальность по мере работы — или позвольте git-хуку делать это:
mast index --incremental # reindex only what changed
mast install-hooks # reindex automatically after commits and checkoutsВсё, что поставляется с вашей сборкой, читается офлайн, так что вам никогда не придётся выяснять, какие документы соответствуют вашей версии:
mast docs # list the topics
mast docs spec # the full behavioural specification
mast skill # the instructions to paste into an agent promptИспользование из ИИ-ассистента
MAST говорит на MCP через stdio. mast serve — команда сервера; конфигурация ниже
отличается только тем, где каждый инструмент хранит свой файл конфигурации.
Если вы установили MAST как dev-зависимость, а не глобально, замените mast на
npx @spikedpunch/mast (или pnpm exec mast) в любом из этих примеров.
Claude Code
claude mcp add mast -- mast serveДобавьте --scope project, чтобы записать .mcp.json в репозиторий, и ваша команда
подхватит его из копии репозитория.
Claude Desktop
~/Library/Application Support/Claude/claude_desktop_config.json на macOS,
%APPDATA%\Claude\claude_desktop_config.json на Windows:
{
"mcpServers": {
"mast": {
"command": "mast",
"args": ["serve"],
"env": { "MAST_STATE_DIR": "/absolute/path/to/your/project/.mast" }
}
}
}Claude Desktop не запускается в каталоге вашего проекта, поэтому MAST_STATE_DIR должен
быть абсолютным. CLI и интеграции с редакторами ниже выводят его из рабочего каталога.
Cursor
.cursor/mcp.json в проекте или ~/.cursor/mcp.json глобально:
{
"mcpServers": {
"mast": { "command": "mast", "args": ["serve"] }
}
}VS Code (GitHub Copilot)
.vscode/mcp.json:
{
"servers": {
"mast": { "type": "stdio", "command": "mast", "args": ["serve"] }
}
}Windsurf
~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"mast": { "command": "mast", "args": ["serve"] }
}
}Zed
settings.json:
{
"context_servers": {
"mast": { "command": { "path": "mast", "args": ["serve"] } }
}
}Любой другой MCP-клиент
Запустите mast serve через stdio из корня проекта. Он объявляет одиннадцать инструментов
чтения и не требует аргументов, кроме serve.
Расскажите ассистенту, как им пользоваться
Регистрация сервера даёт модели инструменты; она не говорит ей, когда их использовать
или как читать помеченный ответ. mast skill выводит инструкции, написанные для этого, —
вставьте их в свой системный промпт, CLAUDE.md, .cursorrules или файл навыка:
mast skill # print it
mast skill --install # splice it into this project's agent config files
mast skill --install --dry-run--install записывает только в файлы, которые уже существуют — CLAUDE.md,
AGENTS.md, .cursorrules, .windsurfrules, .github/copilot-instructions.md — и пишет
внутри помеченного блока, так что повторный запуск после обновления заменяет предыдущую
копию, а не добавляет вторую. Он никогда не запускается сам по себе и никогда не создаёт
файл конфигурации, который вы не хранили раньше.
Обновление
mast upgradeЭта команда проверяет наличие более новой версии и выводит точную команду для того, как вы установили MAST, — она не обновляет на месте, потому что CLI не может надёжно отличить глобальную установку от dev-зависимости, а ошибка в догадке запустит не ту команду в вашем репозитории.
Что важнее, она сообщает то, чего ваш пакетный менеджер не может: меняет ли обновление
схему индекса. Когда меняет, MAST отбрасывает индекс и перестраивает его при следующем
serve или index. Ничего не теряется, что нельзя перестроить, — индекс — это производное
состояние, — но для большого монорепозитория это минуты, и лучше знать об этом заранее,
чем обнаружить как необъяснимую остановку.
Использование MAST в монорепозитории
Один индекс в корне репозитория обычно правильный. Межпакетные импорты разрешаются, так
что mast_callers находит вызывающих в соседних пакетах — это и есть причина использовать
инструмент для монорепозитория, а не один индекс на пакет.
Что индексируется. .ts, .tsx, .js, .jsx и .md, за вычетом node_modules,
dist, build, coverage, .next, .turbo, .mast и тестовых файлов. Переопределите
с помощью --extensions и --exclude в mast init или отредактируйте .mast/config.json.
Другие языки не индексируются, и это важно. MAST разбирает только TypeScript и
JavaScript. Символ, определённый на Python, Go, Java или Rust, отсутствует в индексе, что
выглядит ровно как отсутствие в репозитории. Относитесь к пустому результату как к «MAST
не нашёл это», а не как к «этого не существует» — mast skill говорит это и модели.
Добавьте .mast/ в .gitignore. Это производное состояние, оно большое и
машино-специфично.
Пользовательское расположение индекса не запоминается между запусками. --state-dir
применяется только к той команде, которой вы его передали. Путевые настройки намеренно
никогда не считываются обратно из сохранённой конфигурации — абсолютный путь, записанный
предыдущим запуском (или предыдущим контейнером), может указывать туда, где больше ничего
нет, или, что хуже, туда, что принадлежит другому проекту. Чтобы закрепить пользовательское
расположение, поместите его в систему контроля версий или в окружение:
// mast.config.json, at the project root
{ "state_dir": ".cache/mast" }export MAST_STATE_DIR=/absolute/path/to/indexПорядок разрешения: --state-dir → MAST_STATE_DIR → mast.config.json → .mast.
mast status выводит разрешённый каталог и прямо говорит, когда там ничего не
индексировано.
Масштаб. Холодная индексация VS Code — 8 653 файла, 152 969 фрагментов — занимает около двух минут и создаёт каталог состояния размером 794 МБ. Инкрементальная переиндексация изменённого файла занимает миллисекунды.
Справочник CLI
mast init [path]
Инициализирует MAST для проекта и выполняет первоначальную полную индексацию.
Options:
--state-dir <dir> Where to write index state (default: <path>/.mast)
--extensions <ext,...> File extensions to index (default: .ts,.tsx,.js,.jsx,.md)
--exclude <pattern,...> Glob patterns to exclude
--no-index Create config only; skip initial indexingЗачем: Создаёт структуру каталога состояния, записывает config.json и выполняет полный
проход разбора + извлечения символов. Один запуск заранее означает, что последующие
инкрементальные запуски будут обрабатывать только изменённые файлы.
mast search <query> [path]
Ищет в индексе и выводит читаемые результаты.
Options:
-n, --limit <n> Max results, 1-50 (default: 10)
-t, --type <kind> function | method | class_shell | interface | type | export | block | doc
-l, --language <lang> typescript | javascript | markdown
-e, --exported Only exported symbols
-f, --file <glob> Restrict to files matching a glob
--state-dir <dir> State directory
--json Emit the raw MCP response instead of textЗачем: самый быстрый способ проверить, что на самом деле содержит индекс, и тот же путь
кода, который использует MCP-инструмент mast_search, — он диспетчеризуется через
зарегистрированный обработчик, а не перереализует ранжирование, поэтому результаты CLI и
ассистента не могут разойтись. Флаги устаревания и усечения выводятся над результатами;
пустой результат, который пуст потому, что индекс был занят, говорит об этом.
Для скриптов mast query mast_search '{...}' даёт побайтно идентичный MCP-вывод.
mast index [path]
Строит или обновляет индекс.
Options:
--state-dir <dir> State directory
--incremental Only reindex files changed since last run
--show-progress Print indexing progress to stderr
--checker Opt-in TypeScript-checker pass: upgrades heuristic potential_matches
into verified caller edges (or drops non-call-site noise). Can take
tens of seconds on a large monorepo — not part of the default path.Почему инкрементально: Инкрементальный путь сравнивает текущий манифест файлов с сохранёнными mtime. Обрабатываются только устаревшие, добавленные или удалённые файлы — для большой кодовой базы это сокращает время индексации с секунд до миллисекунд в большинстве запусков.
mast serve
Запускает MCP-сервер через stdio.
Options:
--state-dir <dir> State directory
--no-startup-reindex Skip the startup staleness check (not recommended)
--watch Watch source files and incrementally reindex on change
(interactive use; not needed in the container ladder)Сервер реализует четырёхступенчатую лестницу запуска, чтобы MCP-клиенты получали работоспособный сервер менее чем за секунду даже для больших проектов. Подробности см. в разделе Лестница запуска.
mast status [path]
Выводит состояние индекса.
Options:
--state-dir <dir> State directory
--json Output as JSONСообщает last_indexed, indexed_files, chunk_count, stale_files, parse_errors,
write_errors, index_fresh и freshness_cause. Используйте это для диагностики, почему
результаты поиска выглядят устаревшими.
mast metrics [path]
Показывает метрики эффективности токенов.
Options:
--since <window> Time window: 7d, 24h, 30m (default: 7d)
--rollup Collapse raw rows older than --keep-days into daily roll-ups
--vacuum Delete daily roll-up rows older than --keep-days
--keep-days <n> Retention days (default: 7 for rollup, 90 for vacuum)
--state-dir <dir> State directoryВыводит таблицу с выравниванием по колонкам: имя инструмента, количество вызовов,
возвращённые токены, средняя длительность и коэффициент эффективности. Периодически
используйте --rollup + --vacuum, чтобы база данных метрик не росла бесконечно.
mast install-hooks [path]
Устанавливает git-хуки post-commit / post-checkout, которые автоматически запускают
mast index --incremental, чтобы индекс оставался свежим между коммитами и переключениями
веток без ручного шага.
mast query <tool> [json] [path]
Вызывает любой MCP-инструмент чтения напрямую, с побайтно идентичным MCP-транспорту выводом.
Options:
--state-dir <dir> State directory
--json Emit the exact single-line MCP response (default pretty-prints)mast query mast_callers '{"symbol":"resolveConfig"}'
mast query mast_project_skeleton '{}'Зачем: поверхность для скриптов и отладки. mast search — читаемая парадная дверь к
одному инструменту; эта команда достигает всех одиннадцати и возвращает ровно то, что
получил бы ассистент, — так что расхождение между тем, что видите вы, и тем, что видела
модель, невозможно. Указание несуществующего инструмента выводит список существующих.
mast docs [topic]
Выводит документацию, поставляемую с установленной сборкой, — readme, spec или
skill. Без аргументов перечисляет темы с версиями, к которым они относятся.
Зачем: устраняет шаг, на котором читатель ищет свою версию, а затем находит документацию
для другой. Что выводит mast docs, то и делает бинарник в вашем node_modules.
mast skill [path]
Распечатайте инструкции MAST для вставки в системный промпт агента, CLAUDE.md, .cursorrules или файл навыка.
Options:
--install Splice into this project's existing agent config files
--dry-run With --install, report what would change without writingЗачем: регистрация MCP-сервера даёт модели инструменты, но не суждение — когда искать, а не читать, что код-токены в запросе лучше прозы, и как читать флаг устаревания или усечения. Это также сообщает модели, что пустой результат означает «MAST не нашёл», а не «этого не существует», что является самым важным, что нужно понять о поисковом инструменте.
mast upgrade [path]
Проверяет наличие новой версии; выводит, как её установить и сколько это будет стоить.
Зачем: он определяет, как был установлен MAST, и выводит соответствующую команду, а не выполняет её, потому что CLI не может надёжно отличить глобальную установку от зависимости разработки. Он также сообщает, приводит ли обновление к изменению схемы индекса — что вынуждает выполнить полную переиндексацию при следующем serve, — и ваш пакетный менеджер не может вам этого сказать.
Справочник инструментов MCP
MAST регистрирует 11 инструментов на MCP-сервере. Каждый инструмент чтения включает блок _stats:
{
tool: string,
tokens_returned: number,
tokens_full_file_upper_bound: number,
files_referenced: string[],
efficiency_ratio: number, // 1 - (returned / full_file)
duration_ms: number,
}mast_search
Лексический поиск BM25 + точное совпадение объявлений по индексированной кодовой базе.
{
query: string, // natural language or identifier
limit?: number, // max results (default 10, max 50)
language?: "typescript" | "javascript" | "markdown" | null,
file_pattern?: string | null, // glob: "src/api/**"
chunk_type?: "function" | "method" | "class_shell" | "interface" | "type" | "export" | "block" | "doc" | null,
only_exported?: boolean
}Возвращает: { results[], suggestions?, _stats }. Каждый результат включает file_path, start_line, end_line, content, chunk_type, symbol_name, parent_symbol, is_exported, match_score (оценка BM25, отрицательная; null, когда совпадение получено только от ранжировщика D), rank, match_snippet и необязательную подсказку related, когда метод и его класс-оболочка совпали (возвращается только результат с более высоким рейтингом). suggestions присутствует, возможно пустой, только когда results пуст — это подсказка «вы имели в виду» при нулевом результате.
Зачем: grep и glob находят точные строки и требуют, чтобы вызывающий уже знал шаблон. mast_search ранжирует по релевантности, объединяя два сигнала с помощью рангового слияния по обратной частоте:
BM25 (FTS5, токенизация триграммами) — универсальный лексический ранжировщик; обрабатывает ключевые слова и совпадения по подтокенам/в стиле camelCase.
Ранжировщик D (точное совпадение объявлений) — прямое совпадение с собственным
symbol_nameчанка (полное имя или последний сегмент через точку, без учёта регистра). Ловит точные запросы символов, которые триграммная оценка BM25 может занижать. Управляется ключом конфигурацииdeclaration_exact_ranker(по умолчанию включён); когда он выключен,mast_searchработает только на BM25.
Чанк, по которому согласованы оба ранжировщика, превосходит тот, который нашёл только один из них. file_pattern и language ограничивают пул, из которого черпают оба ранжировщика, поэтому ограниченный поиск никогда не вернёт файл вне области видимости. file_pattern — это глоб, сопоставляемый тем же примитивом, который применяет exclude_patterns во время индексации: * не пересекает /, ** пересекает, ? — один символ, не являющийся /, сопоставление чувствительно к регистру, а всё остальное — ., _, - — литерально.
mast_project_skeleton
Все экспортируемые символы, сгруппированные по файлам, опционально ограниченные каталогом.
{
directory?: string | null, // path prefix: "src/api"
max_depth?: number, // max subdirectory depth (default unlimited)
file_pattern?: string | null // glob filter on file paths
}Возвращает: { files: [{ file_path, exports: string[] }], _stats }.
Зачем: перед навигацией по кодовой базе ассистенту нужна ориентация — «что здесь есть?». Читать каждый файл, чтобы найти его экспорты, расточительно. mast_project_skeleton возвращает карту «файл → экспортируемые имена» в пределах каталога за один вызов, позволяя ассистенту составить мысленную модель подсистемы, не открывая ни одного файла.
mast_exports
Все экспортируемые символы из одного файла с сигнатурами типов и TSDoc.
{
file_path: string // relative to project root
}Возвращает: { file_path, exports: [{ name, kind, signature, line, doc }], _stats }.
Зачем: это естественное продолжение mast_project_skeleton. Как только ассистент узнал, какой файл релевантен, mast_exports даёт полные сигнатуры без тел функций — достаточно, чтобы понять публичный интерфейс модуля, не платя за реализацию.
Методы намеренно опущены (они появляются через mast_signature для родительского класса), поэтому результат остаётся сфокусированным на публичном контракте модуля.
mast_signature
Объявление, TSDoc и разрешённый контекст типов параметров для именованного символа.
{
symbol: string, // e.g. "handleLogin", "AuthService"
file_path?: string | null // narrow to a specific file
}Возвращает: массив SignatureResult, каждый с symbol, file_path, line, signature, doc, params, return_type и type_context.
type_context заполняется автоматически: определённые пользователем имена типов в PascalCase, встречающиеся в сигнатуре, разрешаются в их собственные сигнатуры через трёхприоритетный поиск — сначала тот же файл, затем именованные импорты, затем глобальный запасной вариант экспортируемых типов. Длинные сигнатуры обрезаются до 500 символов. Это означает, что один вызов mast_signature даёт ассистенту полную картину типов для функции без необходимости отдельных запросов.
Зачем: когда ассистент видит function processOrder(order: Order, ctx: RequestContext): Promise<Result>, знание сигнатур Order, RequestContext и Result необходимо для понимания того, что делает функция. Вместо трёх дополнительных вызовов инструментов mast_signature разрешает их встроенно.
mast_callers
Кто вызывает данный символ, с разделением на подтверждённых вызывающих (из графа символов) и потенциальные совпадения (из полнотекстового поиска по идентификаторам).
{
symbol: string,
file_path?: string | null,
transitive?: boolean, // walk the full call chain (default false)
include_potential?: boolean // include identifier_fts matches (default true)
}Возвращает: { verified_callers[], potential_matches[], summary: { verified_count, potential_count, transitive, checker_classified_non_call_site, checker_classified_different_declaration }, _stats }.
Зачем: анализ влияния перед рефакторингом требует знания, кто зависит от символа. Подтверждённые вызывающие разрешаются через граф (окончательно, без ложных срабатываний из-за коллизий имён). Потенциальные совпадения — это совпадения по полнотекстовому поиску идентификаторов, где вызов не удалось статически разрешить; они могут быть ложными срабатываниями, но их стоит проверить. Разделение этих двух категорий позволяет ассистенту рассуждать об уверенности: если verified_count равен 3, а potential_count — 0, объём рефакторинга хорошо понятен. Если potential_count равен 15, неопределённость выше. Запуск mast index --checker повышает некоторые потенциальные совпадения до подтверждённых рёбер (или отбрасывает шум, не являющийся местами вызовов) — счётчики checker_classified_* сообщают, сколько именно, и равны 0, если проход проверки никогда не запускался.
mast_dependencies
Все импорты, записанные для файла.
{
file_path: string
}Возвращает: { file_path, imports: [{ module, symbols[], is_external, resolved_path? }], _stats }.
Зачем: понимание поверхности зависимостей файла — первый шаг к рассуждению о том, что он делает. Внешние импорты (без resolved_path) помечаются, чтобы ассистент знал границу разрешения. Внутренние импорты включают разрешённый путь, чтобы вызывающие могли проследить цепочку.
mast_implementors
Все конкретные классы, реализующие данный интерфейс, со списками их методов.
{
interface_name: string
}Возвращает: { results: [{ class_name, file_path, line, methods[] }], _stats }.
Зачем: в кодовой базе с внедрением зависимостей ответ на вопрос «что здесь на самом деле выполняется?» — это interface_name → implementors. Вместо поиска по implements InterfaceName MAST хранит явные рёбра IMPLEMENTS в графе во время индексации, что делает поиск мгновенным и структурно корректным.
mast_rename_impact
Составной чек-лист рефакторинга для переименования символа: места объявлений, подтверждённые вызывающие, потенциальные совпадения и реэкспорты из баррелей — одним вызовом.
{
symbol: string,
file_path?: string | null
}Возвращает: { symbol, declaration_sites[], verified_callers[], potential_matches[], barrel_exports[], summary: { declaration_count, verified_count, potential_count, barrel_count, checklist, checker_classified_non_call_site, checker_classified_different_declaration }, _stats }.
Зачем: переименование затрагивает не только места вызовов — реэкспорты из баррелей (export { Foo } from './foo', возможно, с псевдонимом) также нужно обновить, и их легко пропустить при простом поиске вызывающих. mast_rename_impact объединяет механику mast_callers с обнаружением баррельных реэкспортов, так что ассистент получает один чек-лист вместо трёх отдельных запросов.
mast_reindex
Запускает синхронную переиндексацию из MCP-сеанса.
{
full?: boolean // force full reindex (default: incremental)
}Возвращает: { files_indexed, files_skipped, chunks_added, chunks_removed, parse_errors, write_errors, duration_ms }.
Зачем: длительные сеансы редактирования накапливают устаревание — новые символы и файлы не будут найдены mast_search, пока они не проиндексированы (JIT-обработка устаревания сохраняет корректность координат строк уже проиндексированных файлов при чтении, но не может обнаружить совершенно новый файл или символ). mast_reindex позволяет ассистенту обновить индекс по требованию — например, после крупного рефакторинга — не выходя из MCP-сеанса. Флаг full доступен, если есть подозрение на повреждение инкрементального состояния.
mast_status
Снимок состояния индекса.
// no inputsВозвращает: { state_dir, last_indexed, indexed_files, chunk_count, stale_files, parse_errors, write_errors, index_fresh, freshness_cause, seed_commit? }.
index_fresh равен true, только когда stale_files = 0 и индекс запускался хотя бы раз. freshness_cause равен "phase1_stale", когда остаются устаревшие файлы, и null, когда всё свежо. stale_files подсчитывает изменённые файлы, файлы на диске, которых вообще нет в индексе, и проиндексированные файлы, которые исчезли с диска, — то же число, которое сообщает mast status, из того же источника.
Зачем: перед длительным агентным рабочим процессом, зависящим от точной навигации по коду, ассистент может вызвать mast_status, чтобы подтвердить свежесть индекса или, если это не так, сообщить пользователю количество устаревших файлов.
mast_efficiency
Отчёт об экономии токенов за текущий сеанс или за всё время.
{
scope: "session" | "global",
since_minutes?: number // global scope: restrict to last N minutes
}Возвращает: { scope, window_started_at, tokens_returned, tokens_full_file_upper_bound, efficiency_ratio, calls_total, calls_by_tool, tokenizer, counterfactual }.
Поле counterfactual — это читаемое предложение: «С наивным чтением полных файлов это стоило бы ~14 200 токенов; сэкономлено ~11 400 токенов (80,3%).»
Зачем: эффективность токенов — это вся причина существования MAST, но без измерения это просто утверждение. Каждый вызов инструмента асинхронно записывает возвращённые токены в metrics (отправил и забыл, < 1 мс). mast_efficiency агрегирует эти записи, чтобы ценность точной навигации по коду была конкретной и проверяемой.
Конфигурация
MAST читает конфигурацию из mast.config.json в корне проекта, переменных окружения или флагов CLI. Приоритет (от высшего к низшему): флаг CLI → переменная окружения MAST_STATE_DIR → mast.config.json → встроенные значения по умолчанию.
Ключ | По умолчанию | Описание |
|
| Каталог для всего состояния индекса (относительно корня проекта) |
|
| Расширения исходных файлов для индексации |
|
| Glob-шаблоны для пропуска |
|
| Константа Reciprocal Rank Fusion (выше = более плоское ранжирование) |
|
| Включить рангер D (точное совпадение объявления) в |
|
| Количество строк, выше которого объявление разбивается на перекрывающиеся подчанки |
|
| Строки исходного кода до/после границ AST, включаемые в сохранённое содержимое |
|
| Максимальный уровень ATX-заголовка ( |
Пример mast.config.json:
{
"state_dir": ".mast",
"exclude_patterns": ["node_modules/**", "dist/**", "**/*.test.ts"],
"declaration_exact_ranker": true,
"context_lines": 5
}MAST_STATE_DIR — переопределяет каталог состояния без изменения mast.config.json. Полезно в CI или Docker-средах, где корень проекта доступен только для чтения.
Как это работает
Индексация
runIndex обходит проект с помощью fast-glob, вычисляет манифест на основе mtime и сравнивает его с сохранённым манифестом, чтобы найти устаревшие, добавленные и удалённые файлы. Для каждого файла, требующего обработки:
Разбор —
tree-sitterразбирает файл в конкретное синтаксическое дерево. Грамматика TypeScript используется для.tsи.tsx; грамматика JavaScript — для.jsи.jsx. Markdown-файлы разбиваются на чанки по заголовкам (markdown_heading_depth), а не разбираются с помощью tree-sitter.Чанкинг — экстрактор разлагает CST на типизированные чанки:
function,class_shell(объявление класса плюс сигнатуры членов, без тел),method(отдельные методы),interface,type,export,blockиdoc(разделы markdown). Классы всегда разлагаются так, чтобы поиск отдельного метода не возвращал всё тело класса.Подчанки — объявления длиннее
chunk_split_thresholdстрок разбиваются на перекрывающиеся сегменты, чтобы ни один чанк не был слишком большим для полезного самодостаточного результата поиска.Граф символов — символы, импорты и рёбра (IMPLEMENTS, PARENT_OF, POTENTIAL_CALL) записываются в SQLite. Стратегия двухпроходной записи (сначала все файлы, затем рёбра) гарантирует, что рёбра могут ссылаться на символы, определённые в файле, разобранном позже в том же запуске.
FTS — содержимое чанков записывается в виртуальную таблицу FTS5 с триграммным токенизатором, что обеспечивает поиск по подтокенам и camelCase. Таблица
identifier_ftsс токенизатором unicode61 обрабатывает точные поиски идентификаторов для потенциальных совпаденийmast_callers.
Индексация — это единая фаза: чанки/граф/FTS обновляются вместе за один проход runIndex; отдельного этапа эмбеддингов нет.
Ранжированный поиск (BM25 + рангер D через RRF)
Запрос проходит через два рангера:
BM25 (FTS5): Запрос сопоставляется с chunk_fts с использованием встроенного ранжирования BM25 в SQLite, поверх триграммного токенизатора. Фильтры по шаблону файла и языку передаются в этот запрос как SQL-предикаты против таблицы files (не как предикаты FTS MATCH, потому что LIKE в SQLite FTS5 по непроиндексированным столбцам ненадёжен с MATCH). Оценки BM25 в SQLite отрицательные — более отрицательное значение означает более сильное совпадение; match_score в mast_search сохраняет этот знак.
Рангер D (точное объявление): Прямой SQL-предикат против chunks.symbol_name — совпадение полного имени или последнего сегмента после точки, без учёта регистра, с детерминированным порядком. Управляется ключом конфигурации declaration_exact_ranker (по умолчанию включён).
RRF-слияние: Два ранжированных списка объединяются с помощью Reciprocal Rank Fusion:
score(chunk) = Σ 1 / (k + rank(chunk))с значением по умолчанию k = 60. Чанк, появляющийся на ранге 1 в обоих списках, получает вдвое больше очков, чем чанк, появляющийся только в одном. Чанки, появляющиеся только в одном списке, всё равно получают хорошие очки — ни один сигнал не доминирует.
JIT-проверки устаревания
Каждый инструмент чтения (search, exports, signature, callers, dependencies, implementors) вызывает jitRefreshFile перед возвратом результатов. Эта функция:
Читает сохранённое mtime файла из таблицы
files.Вызывает
stat()для файла на диске.Если mtime на диске новее, захватывает
structure.lockи немедленно переразбирает файл.
Это означает, что ассистент, редактирующий файл и сразу запрашивающий его, всегда увидит текущую версию, не дожидаясь плановой переиндексации. (JIT-устаревание обрабатывает файлы, уже известные индексу; совершенно новый файл или символ всё ещё требует mast_reindex или следующей плановой/наблюдаемой переиндексации, чтобы стать обнаружимым.)
Стартовая лестница
mast serve начинает принимать MCP-соединения менее чем за 1 секунду через четырёхступенчатую лестницу:
Step 1 Bootstrap state directory; copy Docker seed layer if present;
best-effort remove orphaned pre-vector-store state < 500ms
Step 2 Schema version check; open SQLite < 1s
Step 3 Register all 11 MCP tools; open stdio transport < 500ms
Step 4 Background incremental reindex asyncВсе инструменты готовы к работе сразу после завершения шага 3 — нет окна запуска с ограниченной функциональностью. Когда предварительно собранный seed-индекс доступен в /opt/mast-seed, он копируется в каталог состояния на шаге 1 — фоновая переиндексация на шаге 4 затем обрабатывает только файлы, изменённые с момента сборки seed.
Модель конкурентности
Один advisory lock координирует параллельных писателей:
structure.lock— удерживаетсяrunIndexи JIT-переразборами. Предотвращает одновременное изменение графа SQLite двумя писателями.
Блокировка использует proper-lockfile (POSIX advisory locks через файл-маркер .lock). Таймаут устаревшей блокировки в 10 секунд предотвращает блокировку системы упавшим процессом. Инструменты чтения никогда не захватывают блокировку записи — они могут видеть кратковременно несогласованное состояние во время параллельной переиндексации и в этом случае возвращают file_busy_returning_stale_cache: true.
Структура хранения
.mast/
graph.db SQLite — symbols, edges, imports, chunks, FTS5 tables, metrics
file_manifest.json mtime snapshot from the last index run
index.json schema version, file count, chunk count, last_indexed
config.json resolved config written at init/serve time
structure lock marker (proper-lockfile target)Эффективность токенов
Каждый вызов инструмента асинхронно записывает количество токенов в metrics. Запись включает:
tokens_returned— фактические токены в ответе (токенизатор Anthropic CL100k)tokens_full_file_upper_bound— сколько стоило бы наивное чтение всего файла (когда это можно вычислить)duration_ms,session_idиstatus
metrics_daily агрегирует их по (day, tool_name) со скользящим средним для длительности и итоговыми суммами для количества токенов. Upsert сводки использует инкрементальную формулу среднего, чтобы не хранить все сырые строки бесконечно:
avg_duration_ms = (old_avg * old_n + new_val) / (old_n + 1)Используйте mast metrics --since 7d для читаемой таблицы или mast_efficiency из MCP-сессии для машиночитаемого JSON-резюме с повествованием counterfactual.
История
MAST изначально объединял BM25 с векторным поиском на основе эмбеддингов (LanceDB + локальная модель эмбеддингов ONNX). Измерения не подтвердили целесообразность его сохранения: векторное хранилище было удалено 2026-08-06 согласно решению M2 (см. ADR 003). Система до удаления — включая конвейер эмбеддингов и инструменты оценки, которые его измеряли — сохранена в git-теге mast-pre-vector-delete для тех, кто захочет воспроизвести эти доказательства.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables querying and analyzing code relationships by building a lightweight graph of TypeScript and Python symbols. Supports symbol lookup, reference tracking, impact analysis from diffs, and code snippet retrieval through natural language.
- AlicenseNot gradedqualityCmaintenanceFast semantic code search for AI agents — find symbols, references, and callers across any codebase.9Apache 2.0
- AlicenseNot gradedqualityBmaintenanceIndexes codebases and lets AI agents retrieve precise code snippets (functions, classes, routes) instead of reading entire files, reducing token usage and improving accuracy.457MIT
- AlicenseAqualityAmaintenanceToken-safe code search for AI agents: queries the language-server index (clangd / Roslyn / tsserver / pyright) instead of grep and returns a token-capped file:line list — ~20x fewer tokens. Symbol-level editing + a grep→index rewrite hook. Local-only, no IDE.1611MIT
Related MCP Connectors
Code intelligence for coding agents: semantic, AST, graph, and full-text search. 279+ languages.
Provide your AI coding tools with token-efficient access to up-to-date technical documentation for…
Enterprise code intelligence for M&A, security audits, and tech debt. Hosted server with 200k free.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/SpikedPunchVictim/mast'
If you have feedback or need assistance with the MCP directory API, please join our Discord server