コーディングエージェント向け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 projecttext mcp にはBunが必要です。Nodeで起動すると、PATH に bun があればBunで自身を再実行し、なければ TX019 で失敗します。MCPクライアントが起動するため、手動で実行することはほとんどありません。
セットアップ
各クライアントはプロジェクトディレクトリーから text mcp を起動します。ルートファイルをTypeScriptとして実行するには、bunx --bun を使います。
OpenCode
{ "$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または、チーム用にコミットします。
{ "mcpServers": { "textjs": { "command": "bunx", "args": ["--bun", "text", "mcp"] } }}Cursor
{ "mcpServers": { "textjs": { "command": "bunx", "args": ["--bun", "text", "mcp"] } }}VS Code
{ "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 でスパンごとの色と属性を追加 |
press | キーの組み合わせ:"down"、"ctrl+k"、"shift+tab"、"tab tab enter"、"down*3" |
type | 1文字につき1キーでテキストを入力(最大2,000文字。それ以上は paste を使用)。submit: true で入力後にEnterを押下 |
paste | ⌘V と同様の1回の貼り付けイベント |
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 がなく、50msの間コミットもフレームもない状態です。そのため、エージェントが見るのは更新途中のフレームではなく、入力の結果です。
<Spinner> や1秒に1回更新されるチャートも、更新の合間はアイドル状態と見なされるため、アニメーションのあるページも読み取れます。50msより短い間隔でレンダリングするアプリは、アイドル状態になりません。読み取りは1.5秒で待機を打ち切り(settleMs で変更可能)、最新のフレームをフラッシュして busy とマークします。テキストを指定しない wait_for は、独自の quietMs でアイドル状態を待ち、アイドル状態にならなければエラーを返します。
座標はゼロ始まりのセル単位で、x が列、y が行です。CJK文字や絵文字などの幅の広い文字は2列を使います。
エラーとログ
stdoutはプロトコルの通信に使います。アプリの console.* 出力、意図せず呼ばれた process.stdout.write、Reactエラーは代わりに logs に送られ、エージェントが since で新しいエントリーのみを要求できるよう番号が付けられます。前回の読み取り以降にエラーが記録されていれば、次のフレームヘッダーにその旨が表示されます。
失敗はツールエラーとして返され、クラッシュにはなりません。タイムアウトしたツールは次の呼び出しが実行される前にキャンセルされるため、遅い呼び出しが次の呼び出しのフレームに入力することはありません。Text.jsのコードが付いたエラーはそのコードを保持します。たとえば、不明なキーには TX007 が付きます。アプリの読み込みに失敗すると、すべてのツールがその理由を説明します。ファイルを修正して reload を呼び出します。
オプション
| オプション | 説明 |
|---|---|
--path <pathname> | 最初のルート(デフォルトは /) |
--cols / --rows | グリッドサイズ(デフォルトは text.config.ts の viewport、未指定なら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で実行されます。
text runと同様に、windowとdocumentは未定義です。 - 各サーバーは1つのグリッドで1つのアプリを実行します。各MCPクライアントがそれぞれサーバーを起動します。
text mcpはアプリの独立したヘッドレスコピーを実行します。text devで開いているブラウザータブには接続できません。