MCP para agentes de programación

text mcp: permite que los agentes de programación naveguen, pulsen teclas y lean fotogramas mediante Model Context Protocol.

text mcp ejecuta tu directorio app/ sin interfaz gráfica, dentro del mismo proceso, y lo sirve mediante el Model Context Protocol para que los agentes de programación puedan usarlo sin DevTools. El agente navega, pulsa teclas, lee fotogramas como texto sin formato y llama a manejadores de ruta.

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

text mcp necesita Bun. Si se inicia con Node, vuelve a ejecutarse con Bun cuando bun está en tu PATH, y falla con TX019 en caso contrario. Los clientes MCP lo inician por ti, así que rara vez lo ejecutas manualmente.

Configuración

Cada cliente inicia text mcp desde el directorio de tu proyecto. Usa bunx --bun para que los archivos de ruta se ejecuten como 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

O inclúyelo en un commit para el equipo:

.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"] }  }}

Para un proyecto en un subdirectorio, añade al final la ruta: ["--bun", "text", "mcp", "apps/console"].

Herramientas

HerramientaDescripción
list_routesPáginas y manejadores de ruta en app/, y la ubicación actual
navigateAñadir o reemplazar una ruta, o ir back / forward
read_frameEl fotograma como texto, con ruta, tamaño, foco y cursor. styles: true añade colores y atributos por span
pressCombinaciones de teclas: "down", "ctrl+k", "shift+tab", "tab tab enter", "down*3"
typeEscribir texto con una pulsación por carácter (hasta 2000; usa paste para más). submit: true pulsa Enter al terminar
pasteUn evento de pegado, como ⌘V
scrollDesplazamiento con la rueda del ratón por rows (y cols). Un <ScrollBox> se desplaza con la rueda sin tener el foco del teclado
resizeEstablecer el tamaño de la cuadrícula en columnas y filas
inspect_treeEl árbol de componentes con sus límites en pantalla y todos los identificadores que pueden recibir el foco
findLímites de cada coincidencia y el componente que hay debajo
wait_forEsperar a que aparezca o desaparezca texto, o a que la app quede inactiva
logsSalida capturada de console.* y errores de React
fetchLlamar a un manejador route.ts dentro del mismo proceso. Los cuerpos se leen hasta maxBytes; los flujos de eventos, durante streamMs, y luego se cancelan
reloadVolver a importar la app después de editar archivos

Las herramientas de entrada devuelven el nuevo fotograma, así que el agente no necesita una llamada independiente a read_frame después de cada tecla. El fotograma actual y la lista de rutas también están disponibles como los recursos text://frame y text://routes.

Un intercambio típico:

→ 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  …

Fotogramas e inactividad

Antes de que cualquier herramienta lea un fotograma, espera a que la app quede inactiva: ningún fotograma programado, ningún fetch en curso y ningún commit ni fotograma durante 50 ms. Así, el agente ve el resultado de su entrada, en lugar de un fotograma a mitad de una actualización.

Un <Spinner> o un gráfico que se actualiza una vez por segundo sigue contando como inactivo entre actualizaciones, por lo que las páginas con animaciones siguen siendo legibles. Una app que se renderiza con una frecuencia superior a una vez cada 50 ms nunca queda inactiva. Las lecturas dejan de esperar tras 1,5 segundos (settleMs cambia este valor), vuelcan el último fotograma y lo marcan como busy. wait_for sin texto espera a la inactividad, con su propio quietMs, y devuelve un error si nunca llega.

Las coordenadas son celdas con índice desde cero: x es la columna, y la fila. Los caracteres anchos, como los CJK y los emojis, ocupan dos columnas.

Errores y registros

stdout transporta el protocolo. La salida de console.* de tu app, las llamadas sueltas a process.stdout.write y los errores de React se envían a logs, numerados para que un agente pueda solicitar solo las entradas nuevas con since. Cuando se han registrado errores desde la última lectura, la cabecera del siguiente fotograma lo indica.

Los fallos se devuelven como errores de herramienta, nunca como un cierre inesperado. Una herramienta que supera el tiempo límite se cancela antes de ejecutar la siguiente llamada, de modo que una llamada lenta nunca escribe en el fotograma de la siguiente llamada. Los errores con un código de Text.js lo conservan, por ejemplo TX007 para una tecla desconocida. Si la app no se carga, cada herramienta explica el motivo. Corrige el archivo y llama a reload.

Opciones

OpciónDescripción
--path <pathname>Primera ruta (por defecto /)
--cols / --rowsTamaño de la cuadrícula (por defecto: viewport en text.config.ts; en su defecto, 100×32)
--theme <name>Tema predefinido
--no-configIgnorar text.config.ts
--verboseEscribir también los registros capturados en stderr

Funcionamiento

text mcp ejecuta tu app del mismo modo que text run: cada módulo de ruta se importa al inicio, el App Router usa un historial en memoria y las llamadas fetch("/api/…") del mismo origen ejecutan tus manejadores dentro del mismo proceso. Los fotogramas se envían a una cuadrícula de celdas fuera de pantalla en lugar de a una terminal. Las páginas renderizadas en el servidor (export const runtime = "server") y sus componentes async function se renderizan dentro del mismo proceso, como en text dev, y el fotograma se lee una vez que se resuelven.

reload desmonta la app, elimina todos los módulos del proyecto de la caché de módulos de Bun (incluidos los archivos fuera de app/), vuelve a explorar app/ y monta de nuevo la app en la ubicación actual.

Para integrar el servidor en tu propio proceso o usar otro transporte:

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();

Límites

  • La app se ejecuta en Bun, no en un navegador. window y document no están definidos, como en text run.
  • Cada servidor ejecuta una app con una cuadrícula. Cada cliente MCP inicia su propio servidor.
  • text mcp ejecuta su propia copia de la app sin interfaz gráfica. No puede conectarse a una pestaña del navegador abierta con text dev.
Editar esta página en GitHub