Pi MCP Adapter — экономим контекст при работе с MCP-серверами
📂 Исходный код на GitHubРасширение для агента Pi: один прокси-инструмент вместо сотни, ленивый запуск серверов, кэш описаний, подтверждение опасных вызовов, скрипты на JavaScript и OAuth
Pi MCP Adapter — расширение для агента Pi, которое даёт доступ к MCP-серверам и почти не тратит контекст. Смысл простой: вместо всех описаний инструментов в системный текст попадает один прокси-вызов примерно на 200 токенов. Всё остальное агент находит поиском и запускает только тогда, когда инструмент действительно понадобился.
Проект написан на TypeScript, распространяется как npm-пакет, лицензия MIT.
Какую проблему решает адаптер
Описания инструментов в MCP очень подробные. Один сервер может занять больше 10 тысяч токенов. И вы платите за это в любом случае, даже если не вызываете ни один его инструмент. Подключите несколько серверов — и до начала разговора половина контекстного окна уже занята.
Mario Zechner разобрал эту проблему в статье «что, если MCP вам не нужен». Его совет был простой: отказаться от MCP и писать маленькие CLI-инструменты вместо него.
Но в экосистеме MCP есть базы данных, браузеры и внешние API. Отказываться от них не хочется. Адаптер оставляет доступ ко всему этому, но убирает раздувание контекста: агент платит только за те инструменты, до которых дошёл сам.
Установка
pi install npm:pi-mcp-adapter
После установки перезапустите Pi. Нужен Node.js версии 20 или новее.
Для агента DeepSeek Harness есть сторонний мост pi2dsh: он запускает этот же адаптер без изменений и переводит его MCP-вызовы в формат DSH.
Что происходит при первом запуске
Адаптер сам читает стандартные файлы MCP. Дополнительная настройка нужна только если таких файлов у вас нет.
| Что уже есть у вас | Что произойдёт |
|---|---|
.mcp.json или ~/.config/mcp/mcp.json |
Pi начнёт использовать файл сразу. Первый вариант удобно держать в проекте и делиться с командой, второй — для всех проектов сразу. |
| Только конфиги конкретного агента (Cursor, Claude Code, Codex и другие) | Запустите /mcp-adapter setup. Мастер покажет, что нашёл, даст выбрать нужные серверы и сначала покажет точные изменения в файлах, а уже потом запишет их. |
| Ничего | Запустите /mcp-adapter setup и выберите, где создавать конфиг: в проекте или глобально. |
Если удобнее терминал, ту же задачу решает pi-mcp-adapter init: он находит конфиги других агентов и дописывает недостающие импорты в ~/.pi/agent/mcp-adapter.json.
Быстрый старт
Обычный файл .mcp.json в проекте:
{
"mcpServers": {
"chrome-devtools": {
"command": "npx",
"args": ["-y", "chrome-devtools-mcp@1.6.0"]
}
}
}
Агент ищет нужный инструмент по описанию:
mcp({ search: "screenshot" })
Ответ — список подходящих инструментов с параметрами:
chrome_devtools_take_screenshot
Take a screenshot of the page or element.
Parameters:
format (enum: "png", "jpeg", "webp") [default: "png"]
fullPage (boolean) - Full page instead of viewport
И вызывает его:
mcp({ tool: "chrome_devtools_take_screenshot", args: { format: "png" } })
Два вызова вместо двадцати шести инструментов в контексте.
Файлы конфигурации
| Файл | Зачем |
|---|---|
~/.config/mcp/mcp.json |
Общий конфиг MCP для всех проектов |
~/.agents/mcp.json, ~/.agents/mcp/mcp.json |
То же самое, но без привязки к одному инструменту |
.mcp.json |
Общий конфиг внутри проекта |
<каталог агента>/mcp-adapter.json |
Глобальные настройки адаптера, импорты и переопределения (~/.pi/agent/mcp-adapter.json по умолчанию) |
.pi/mcp-adapter.json |
Настройки и переопределения адаптера внутри проекта |
Собственные файлы Pi — <каталог агента>/mcp.json и .pi/mcp.json — адаптер не читает вообще. Так Pi и адаптер гарантированно не запустят один и тот же сервер дважды.
Если у вас уже есть конфиги конкретных агентов, их можно подключить явно:
{
"imports": ["cursor", "claude-code", "claude-desktop", "opencode"],
"mcpServers": { }
}
Поддерживаются cursor, claude-code, claude-desktop, opencode, vscode, windsurf и codex. Общие файлы MCP при этом загружаются автоматически, импорты нужны только для форматов, которые ещё не покрыты.
Когда сервер запускается
По умолчанию серверы ленивые: они не подключаются, пока агент не вызовет их инструмент. Метаданные инструментов адаптер хранит на диске, поэтому поиск и описание работают без живого подключения.
Режим можно задать для каждого сервера отдельно через поле lifecycle:
| Режим | Поведение |
|---|---|
lazy |
Не подключается при старте. Подключается на первом вызове инструмента. После простоя отключается. Режим по умолчанию. |
eager |
Подключается при старте. Сам не переподключается. Простоя по умолчанию нет. |
keep-alive |
Подключается при старте и всегда доступен. Обновляет список инструментов во время проверок доступности. |
lazy-keep-alive |
Не подключается при старте, но после первого запуска остаётся живым. Подходит для серверов, которые долго стартуют. |
Время простоя задаёт поле idleTimeout, по умолчанию 10 минут.
Отдельная деталь: если сервер запускается через npx, адаптер находит настоящий исполняемый файл и запускает его напрямую. Родительский npm-процесс на 143 МБ при этом не поднимается.
Прямые инструменты
По умолчанию все инструменты доступны только через прокси. Для части из них это неудобно: агент каждый раз ищет то, что всегда использует.
Поле directTools поднимает выбранные инструменты в общий список агента — рядом с read, bash, edit:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"directTools": ["search_repositories", "get_file_contents"]
}
}
}
| Значение | Что делает |
|---|---|
true |
Регистрирует все инструменты сервера как отдельные инструменты Pi |
["tool_a", "tool_b"] |
Регистрирует только перечисленные, имена в исходном виде |
Не задано или false |
Только прокси. Так по умолчанию |
Каждый прямой инструмент стоит примерно 150–300 токенов в системном тексте. Поэтому для набора из 5–20 инструментов это нормально, а для сервера на 75 и больше — уже дорого. Адаптер в таком случае печатает предупреждение, но инструменты всё равно регистрирует.
Есть промежуточный вариант: directTools: "search". Инструменты регистрируются с настоящими схемами, но неактивны и включаются сами после первого удачного mcp({ search }). Годятся для больших серверов, из которых нужна только часть.
Списки includeTools и excludeTools позволяют оставить только нужное, а searchKeywords добавляет слова для поиска, которых нет в описаниях инструментов.
Подтверждение опасных вызовов
Инструмент можно оставить в списке, но запретить запускать его без подтверждения. За это отвечает approveTools:
{
"settings": {
"approveTools": ["github_delete_*", "notion_update_*"]
},
"mcpServers": {
"github": { "approveTools": ["delete_*", "merge_pull_request"] },
"docs": { "approveTools": false }
}
}
Значение "destructive" спрашивает перед любым инструментом, который может изменить или удалить данные. Без вопроса пройдут только те инструменты, которые сервер сам помечает как безопасные для чтения или как неразрушающие.
Когда вопрос появился, доступны четыре ответа: разрешить один раз, разрешить на эту сессию, разрешить весь сервер на эту сессию или запретить. В разрешениях сохраняются только имена сервера и инструмента вместе с хешами определения и аргументов — сами аргументы, результаты и секреты не сохраняются.
Защита контекста от больших ответов
Один огромный ответ способен занять всё окно и раздуть файл сессии. Адаптер режет такие ответы по умолчанию:
- Текст ограничен 50 КиБ и 2000 строками. Остаток сохраняется во временный файл, путь к нему попадает в результат, и агент может прочитать этот файл.
- Картинки проходят без изменений. Ограничение касается только текста.
- Двоичные данные размером до 10 МиБ превращаются в временные файлы. На одну сессию положено 100 МиБ и 10 000 файлов, при закрытии сессии они удаляются.
- Подробности ответа сохраняются как есть, пока не превышают 16 КиБ.
Отключить урезание текста можно настройкой outputGuard: false или переменной окружения MCP_OUTPUT_GUARD=0.
Скрипты вместо цепочки вызовов
Одиночный вызов, поиск и проверка статуса делаются через mcp. А вот задачи из нескольких шагов удобнее писать обычным JavaScript. За это отвечает инструмент mcpScript, который выключен по умолчанию:
{ "settings": { "scriptMode": true } }
Скрипт получает готовые функции и возвращает один результат:
const { items } = await tools.search({ query: "search issues", server: "github" });
const candidate = items[0];
if (!candidate) return { error: "No matching tool" };
const details = await tools.describe({ path: candidate.path });
if (details.error) return details;
const result = await tools.call(details.path, { query: "is:open label:bug" });
if (!result.ok) return result;
emit({ tool: details.path, completed: true });
return result.data;
Скрипт может крутиться в цикле, находить несколько инструментов, вызывать их параллельно, фильтровать результаты и сводить всё в один ответ. Это обычный JavaScript: циклы, Promise, свои функции.
Под капотом изолированная среда QuickJS/WASM: 64 МиБ памяти, лимит вывода 16 МиБ, никаких глобальных объектов Node.js, файловой системы, сети, таймеров и процессов. По умолчанию скрипту дают 30 секунд. Не дождавшись, воркер останавливают принудительно — даже если скрипт завис в бесконечном цикле. Текст ошибки обрезается до 64 КиБ.
К скриптам прилагается скилл mcp-scripting с подробным описанием приёмов.
Установка сервера по одной ссылке
Если сервер ещё не описан в конфиге, его можно добавить прямо в момент работы:
mcp({ action: "install", url: "https://example.com/mcp" })
Адаптер проверит адрес, подключится и сохранит новую запись. Имя возьмёт из домена. Ошибочный адрес, совпадение имён и неудачное подключение в конфиг не попадают. Через server можно задать имя, а через target: "project" — записать в конфиг проекта.
Для агентов без интерфейса установку можно запретить настройкой allowInstall: false.
Серверы из репозитория и доверие к ним
Сервер, описанный в файлах проекта, не запускается просто из-за того, что вы открыли репозиторий. Это касается и серверов, пришедших через импорты, плагины и пакеты.
Если проект не помечен как доверенный, адаптер блокирует такие серверы. В доверенной интерактивной сессии он показывает файл-источник, команду или адрес и спрашивает один раз перед первым подключением. Ответ сохраняется по каноническому пути проекта, имени сервера и полному определению. Изменили определение — спросит снова.
Для агентов без интерфейса неодобренные серверы просто пропускаются. Разрешить их осознанно можно только в глобальном конфиге: "projectServers": "allow".
Как адаптер устроен внутри
- В контексте один инструмент
mcpпримерно на 200 токенов вместо сотен. - Серверы ленивые: подключение на первом вызове, а не на старте.
- Метаданные инструментов лежат на диске, поэтому поиск, список и описание работают без подключения.
- Аргументы проверяет сам MCP-сервер, а не адаптер.
- Для удалённых серверов список инструментов обновляется во время проверок доступности, перед вводом пользователя и перед очередным ходом агента.
- Есть необязательный журнал протокола в формате JSONL. В него не попадают содержимое ответов, подсказки, аргументы, результаты и данные авторизации.
Ещё несколько возможностей
- Аутентификация. Токены OAuth лежат в системном хранилище и привязаны к адресу сервера, поэтому токен от одного сервера не примет другой. Документ OAUTH.md описывает модель безопасности.
- Установка и отключение серверов. Командами
/mcp-adapter enableи/mcp-adapter disableможно убрать сервер в проекте, не трогая исходные файлы конфига. - Общие процессы между сессиями. Запустите сервер под rmcp-mux и укажите сокет вместо команды — тогда процесс переживёт завершение сессии.
- Интерактивные интерфейсы серверов. Поддерживается стандарт MCP UI. На macOS окно открывается нативно через Glimpse, если он установлен, иначе — в браузере.
- Поиск по смыслу. С ключом System One адаптер умеет искать инструменты смыслом, а не по словам. Авторы проверили приём на 12 обычных запросах и 95 инструментах с ресурсами. Нужный инструмент оказался на первом месте в 10 случаях из 11, где ответ вообще возможен, и на втором — один раз. Обычный поиск по словам справился в 5 случаях. Это небольшая проверка на одной локальной сборке, переносить её числа на другие наборы нельзя.
- Готовый пример. В каталоге examples/interactive-visualizer лежит минимальный сервер с графиком и двусторонними сообщениями.
Ограничения
Автор честно перечисляет их в README:
- Общие серверы между сессиями в самом адаптере не поддерживаются. Каждая сессия Pi поднимает свои процессы.
- Поддержка sampling в MCP работает только с текстом. Картинки, аудио и инструменты внутри запроса отклоняются с явной ошибкой.
- Адаптер не проверяет аргументы вместо сервера. Если сервер не проверил вход сам, ошибка всплывёт позже и, возможно, не там, где ожидаешь.
Итог
Если у вас в проекте три-четыре MCP-сервера, адаптер решает бытовую проблему: агент перестаёт отдавать часть контекста на описания инструментов, которые в конкретном диалоге не используются. Стоит только помнить, что это расширение под Pi, а не универсальная прослойка между любым агентом и любым сервером.