MCP для агентов программирования

text mcp: дайте агентам программирования возможность переходить по приложению, нажимать клавиши и читать кадры через Model Context Protocol.

text mcp запускает ваш каталог app/ без графического интерфейса, внутри процесса, и предоставляет к нему доступ по протоколу Model Context Protocol, чтобы агенты для написания кода могли использовать его без DevTools. Агент перемещается по маршрутам, нажимает клавиши, читает кадры как обычный текст и вызывает обработчики маршрутов.

bunx --bun text mcp              # serve ./app over stdiobunx --bun text mcp apps/console # another project

Для text mcp нужен Bun. При запуске через Node он перезапускает себя через Bun, если bun есть в вашем PATH, а иначе завершается с ошибкой TX019. Клиенты MCP запускают его за вас, поэтому вручную вы запускаете его редко.

Настройка

Каждый клиент запускает text mcp из каталога вашего проекта. Используйте bunx --bun, чтобы файлы маршрутов выполнялись как TypeScript.

OpenCode

opencode.jsonjson
{  "$schema": "https://opencode.ai/config.json",  "mcp": {    "textjs": {      "type": "local",      "command": ["bunx", "--bun", "text", "mcp"],      "enabled": true    }  }}

Claude Code

claude mcp add textjs -- bunx --bun text mcp

Или добавьте конфигурацию в репозиторий для команды:

.mcp.jsonjson
{  "mcpServers": {    "textjs": { "command": "bunx", "args": ["--bun", "text", "mcp"] }  }}

Cursor

.cursor/mcp.jsonjson
{  "mcpServers": {    "textjs": { "command": "bunx", "args": ["--bun", "text", "mcp"] }  }}

VS Code

.vscode/mcp.jsonjson
{  "servers": {    "textjs": { "type": "stdio", "command": "bunx", "args": ["--bun", "text", "mcp"] }  }}

Для проекта в подкаталоге допишите путь: ["--bun", "text", "mcp", "apps/console"].

Инструменты

ИнструментОписание
list_routesСтраницы и обработчики маршрутов в app/, а также текущее местоположение
navigateДобавление или замена пути, переход back / forward
read_frameКадр в виде текста с маршрутом, размером, фокусом и курсором. styles: true добавляет цвета и атрибуты для каждого span
pressСочетания клавиш: "down", "ctrl+k", "shift+tab", "tab tab enter", "down*3"
typeВвод текста с нажатием клавиши для каждого символа (до 2000; для большего объёма используйте paste). submit: true нажимает Enter после ввода
pasteОдно событие вставки, как ⌘V
scrollПрокрутка колёсиком мыши на rows (и cols). <ScrollBox> прокручивается колёсиком без клавиатурного фокуса
resizeУстановка размера сетки в столбцах и строках
inspect_treeДерево компонентов с границами на экране и всеми id элементов, способных получить фокус
findГраницы каждого совпадения и компонент под ним
wait_forОжидание появления или исчезновения текста либо перехода приложения в состояние покоя
logsПерехваченный вывод console.* и ошибки React
fetchВызов обработчика route.ts внутри процесса. Тела читаются до maxBytes; потоки событий читаются в течение streamMs, затем отменяются
reloadПовторный импорт приложения после изменения файлов

Инструменты ввода возвращают новый кадр, поэтому агенту не нужен отдельный вызов read_frame после каждой клавиши. Текущий кадр и список маршрутов доступны и как ресурсы text://frame и text://routes.

Типичный обмен:

→ navigate { "path": "/deployments" }→ press { "keys": "down down enter" }← route: /deployments/dpl_6m3ty8  (route /deployments/[id])  title: "Deployment dpl_6m3ty8 · Edge Console"  size: 100×32  frame: 6  idle  focus: _txr_c_ ScrollBox [4,12 92×18]    ▼ Edge Console   Overview   Deployments   Logs   Settings    ← Deployments  /  dpl_6m3ty8   Ready    Production  …

Кадры и состояние покоя

Прежде чем прочитать кадр, любой инструмент ждёт перехода приложения в состояние покоя: нет запланированного кадра, нет выполняющегося fetch, а за последние 50 мс не было ни коммита, ни кадра. Поэтому агент видит результат своего ввода, а не кадр посреди обновления.

<Spinner> или график, обновляющийся раз в секунду, всё равно считается находящимся в покое между обновлениями, поэтому страницы с анимацией остаются читаемыми. Приложение, которое рендерится чаще, чем раз в 50 мс, никогда не переходит в состояние покоя. Через 1,5 с чтение прекращает ожидание (settleMs меняет этот срок), выводит последний кадр и помечает его как busy. wait_for без текста ждёт состояния покоя со своим значением quietMs и возвращает ошибку, если покой так и не наступает.

Координаты задаются в ячейках с отсчётом от нуля: x — столбец, y — строка. Широкие символы, такие как CJK и эмодзи, занимают два столбца.

Ошибки и журналы

stdout передаёт данные протокола. Вывод console.* вашего приложения, посторонние вызовы process.stdout.write и ошибки React вместо этого попадают в logs с нумерацией, чтобы агент мог запросить только новые записи через since. Если с момента последнего чтения были записаны ошибки, заголовок следующего кадра сообщает об этом.

Сбои возвращаются как ошибки инструментов и не приводят к аварийному завершению. Инструмент, превысивший время ожидания, отменяется до запуска следующего вызова, поэтому медленный вызов никогда не вводит текст в кадр следующего вызова. Ошибки с кодом Text.js сохраняют его, например TX007 для неизвестной клавиши. Если приложение не загружается, каждый инструмент объясняет причину. Исправьте файл и вызовите reload.

Параметры

ПараметрОписание
--path <pathname>Начальный маршрут (по умолчанию /)
--cols / --rowsРазмер сетки (по умолчанию: viewport в text.config.ts, иначе 100×32)
--theme <name>Предустановка темы
--no-configИгнорирование text.config.ts
--verboseЗапись перехваченных журналов ещё и в stderr

Принцип работы

text mcp запускает ваше приложение так же, как text run: все модули маршрутов импортируются заранее, App Router использует историю в памяти, а вызовы fetch("/api/…") к тому же источнику запускают ваши обработчики внутри процесса. Кадры отправляются во внеэкранную сетку ячеек вместо терминала. Отрендеренные на сервере страницы (export const runtime = "server") и их компоненты async function рендерятся внутри процесса, как в text dev, и кадр считывается после их завершения.

reload размонтирует приложение, удаляет все модули проекта из кеша модулей Bun (включая файлы вне app/), повторно сканирует app/ и монтирует приложение в текущем местоположении.

Чтобы встроить сервер в собственный процесс или использовать другой транспорт:

import { createTextMcpServer } from "@textjs/app/mcp";import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";const { server, controller } = createTextMcpServer({ root: process.cwd() });await server.connect(new StdioServerTransport());void controller.start();

Ограничения

  • Приложение работает в Bun, а не в браузере. window и document не определены, как и в text run.
  • Каждый сервер запускает одно приложение с одной сеткой. Каждый клиент MCP запускает собственный сервер.
  • text mcp запускает собственную копию приложения без графического интерфейса. Он не может подключиться к вкладке браузера, открытой через text dev.
Изменить эту страницу на GitHub