コーディングエージェント向け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で起動すると、PATH に bun があればBunで自身を再実行し、なければ TX019 で失敗します。MCPクライアントが起動するため、手動で実行することはほとんどありません。

セットアップ

各クライアントはプロジェクトディレクトリーから text mcp を起動します。ルートファイルをTypeScriptとして実行するには、bunx --bun を使います。

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_routesapp/ 内のページとルートハンドラー、および現在の位置
navigateパスの追加や置換、または back / forward による移動
read_frameルート、サイズ、フォーカス、カーソルを含むテキスト形式のフレーム。styles: true でスパンごとの色と属性を追加
pressキーの組み合わせ:"down"、"ctrl+k"、"shift+tab"、"tab tab enter"、"down*3"
type1文字につき1キーでテキストを入力(最大2,000文字。それ以上は paste を使用)。submit: true で入力後にEnterを押下
paste⌘V と同様の1回の貼り付けイベント
scrollrows(および 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-configtext.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 で開いているブラウザータブには接続できません。
GitHubでこのページを編集