Русский
expand: послойная навигация по оглавлению
expand — инструмент MCP для навигации по оглавлению заметки уровень за уровнем (progressive disclosure). Агент спускается по дереву секций сверху вниз и читает только нужный лист — не загружая ни всю заметку, ни её полное плоское оглавление.
Зачем: это и есть экономия токенов. Прочитать одну секцию вместо всей заметки — во много раз дешевле (порядок величины и воспроизводимый замер — token-economy-bench), и ответ не тонет в хвосте длинного контекста, где у модели падает recall. Подробнее о принципе — Token Economy.
Как работает
expand возвращает прямых детей одного узла оглавления:
- Опусти
toc_path(или передай[]) — получишь секции верхнего уровня. - Передай
toc_pathузла — получишь его подсекции.
Каждый ребёнок несёт: title, level, path (breadcrumb для следующего вызова) и has_children (есть ли вложенность).
Что вернётся, зависит от секции, которую называет toc_path:
- Секция с подсекциями возвращает список детей, как описано выше.
- Секция без подсекций возвращает своё содержимое — тот же текст, что дал бы
note_html(path, toc_path), плюсsection_htmlв структурированном ответе. Второй вызов, чтобы прочитать лист, не нужен: спуск заканчивается чтением. - Флага, который это отключает, нет, и клиенту, которому нужна только структура, он и не нужен: родительский список уже помечает каждого ребёнка через
has_children, так что достаточно остановиться наhas_children: false— и ничего не будет прочитано.
Аргументы. Один из идентификаторов заметки (pid, note_id, path или href — берутся из результатов search) + опциональные toc_path, first и last:
{ "name": "expand", "arguments": { "pid": 42, "toc_path": ["Goroutines"] } }
Ответ — структурированный список детей плюс короткая текстовая сводка («N subsection(s)»); для листа вместо этого приходит содержимое секции.
Рабочий цикл
1. search(query)
→ результаты со сниппетом, breadcrumb и matches[].toc_path
2. expand(pid=N) # верхний уровень оглавления
expand(pid=N, toc_path=[...]) # проваливаемся в нужную ветку
→ повторяем, выбирая ребёнка по смыслу; лист приходит целиком
3. note_html(pid=N, toc_path=[...])
→ читаем секцию, путь к которой уже известен, без спуска
Можно и короче: если search уже вернул точный matches[].toc_path, читай секцию сразу через note_html(toc_path=...). expand нужен, когда хочется осмотреть структуру и навигировать вглубь, не загружая лишнего.
Длинный список: только края
Заметка, в которую что-то дописывает секцию каждый день, через год несёт их сотни, и expand перечислит все. На заметке с 365 датированными секциями это ответ на 41 700 знаков — ради того, чтобы узнать имя последней.
first и last берут только края:
{ "name": "expand", "arguments": { "path": "log.md", "last": 30 } }
{ "name": "expand", "arguments": { "path": "log.md", "first": 5, "last": 30 } }
last: N— N новейших секций. Где тема стоит сейчас.first: N— N старейших. С чего она начиналась.- Вместе — оба края, середина не перечисляется.
Сводка говорит, что список неполный: «newest 30 of 365 subsection(s)», а при обоих краях ставит между ними строку … 330 subsection(s) not listed …. В структурном ответе то же самое числами: total_children и omitted. Список, который выглядит целым, отправил бы вас с уверенностью, что старых секций нет.
Края, которые сошлись или перекрылись, — это просто всё: секция не попадёт в ответ дважды.
Slim search
Раньше search вываливал полный плоский toc каждой заметки. Теперь результаты «тонкие»: структура раскрывается по требованию через expand. Не платишь токенами за оглавление целиком — берёшь ровно тот уровень, что нужен.
expand vs. альтернативы
- vs «прочитать всю заметку». Лист-секция в разы дешевле полной заметки, выигрыш растёт с её размером (числа — замер). Главное — ответ остаётся вверху контекста, а не в «мёртвой зоне» внизу.
- vs
grep -A -B.grepотдаёт ±N строк вокруг лексического совпадения;expandотдаёт цельную секцию по структуре заголовков, а нужную находит по смыслу (через векторныйsearch), а не по строке. И главное —expandработает по MCP над базой, которуюgrepв принципе не достанет: хостед, расшаренной команде, удалённой, чужой. Для одного человека и локального волтаgrepчестно достаточно;expandнужен, когда база большая, общая или удалённая.
Доступ
expand уважает права на заметку: агент видит структуру только того, что ему разрешено читать (per-note access). Лишнего оглавления он не получит.
Федерация
federated_expand делает то же по связанным базам — навигируешь структуру удалённой базы знаний через один MCP-эндпоинт. См. MCP Federation.
Проверь сам
Без зависимостей, только Python 3:
python3 scripts/expand_check.py
Скрипт бьёт по https://trip2g.com/_system/mcp, идёт по оглавлению через expand, читает нужную секцию и печатает таблицу «навигация + чтение vs вся заметка».
Связанное
- MCP-сервер — все методы и доступ
- MCP Federation — federated_expand по связанным базам
- Бенчмарк токонной экономики — числа и воспроизводимый замер
- Token Economy — зачем фокус-чтение
- Fuzzy Pointer — как breadcrumb находит секцию