Pico8 Mcp について
Pico8 Mcp は、LLM エージェントが実際の PICO-8 カートを決定論的なロックステップで操作するための MCP サーバーです。スクリーンショット、Lua グローバル変数、メモリの確認に対応し、複数セッションとブラウザーでのライブ表示も備えます。
主な機能
- 01ロックステップでゲームフレームを進行
- 02ボタン操作とシーケンス実行
- 03画像、Lua グローバル変数、メモリの読み取り
- 04リセット、セッション管理、起動チェック
- 05ブラウザーでのプレイのライブ表示
活用シーン
- 01PICO-8 カートのプレイ自動化
- 02ゲーム状態やメモリの調査
- 03ゲームセッションの再実行やリセット
- 04ブラウザーでエージェントの操作を確認
MCP 対応
stdio 経由で、カートの起動、ボタン操作、フレーム進行、画像や状態の読み取りを行うツールを MCP クライアントに提供します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
pico8-mcp
LLM が PICO-8 のカートをインタラクティブにプレイできる MCP サーバーです。ボタンを押し、フレームを決定論的に進め、ピクセル単位で正確なスクリーンショットを確認し、ゲーム変数を読み取ります。実際の PICO-8 バイナリをヘッドレスで実行します。
仕組み
LLM ⇄ MCP (stdio) ⇄ pico8-mcp ⇄ pipes ⇄ pico8 -x cart_instrumented.p8
- カートは
/tmp/pico8-mcp/<session>/にコピーされ、その__lua__セクションの末尾に小さな Lua ハーネスが挿入されます(元のファイルは変更されません)。ハーネスはbtn/btnpをシャドーイングし、_update/_update60をコマンドループに置き換えます。 - 入力は PICO-8 の
serial(0x804, …)stdin チャネルを通じて送信します。デスクトップ版 PICO-8(0.2.7)では、この読み取りには fread のセマンティクスがあり、指定されたlenバイトがちょうど届くまでブロックします。そのため、ドライバーは固定サイズの 8 バイトパケット(<op:1><a:3 hex><b:3 hex>\n)を送信します。これにより、コマンド間でエンジンが停止し、完全なロックステップが実現します。フレームをまとめて実行すると、リアルタイムではなくホストの速度で進みます(30 ms 未満で約 600 ゲームフレーム)。 - 出力は
printh(@を先頭に付けたテキスト行)とserial(0x805, …)(フレームバッファーとパレットのダンプを含む生のバイナリ)を通じて送信され、サーバー側で PNG に変換されます。
要件
- PATH 上の
pico8(またはPICO8_BIN=/path/to/pico8)、バージョン 0.2.x - Node.js ≥ 18
- カートは
_update/_update60を使用し、btn/btnp経由で入力を読み取る必要があります(標準的なカートは対応しています。カスタムのflip()メインループには対応していません)
インストール
npm install && npm run build
opencode の設定(opencode.json):
{
"mcp": {
"pico8": {
"type": "local",
"command": ["node", "/path/to/pico8-mcp/dist/index.js"]
}
}
}
Claude Desktop およびその他の MCP ホスト:同じコマンドで、stdio トランスポートを使用します。
ツール
| ツール | 目的 |
|---|---|
pico8_boot | ロックステップ制御でカートを起動します(ステップを進めるまでゲーム時間は停止します)。決定論的な rnd() 用の seed を指定できます。 |
pico8_step | ボタン(left/right/up/down/o/x)を押し続け、N フレーム進めてスクリーンショットを取得します。 |
pico8_play | {buttons, frames} のステップをスクリプト化し、1 回の呼び出しで順番に実行します。 |
pico8_screen | 現在のフレームのピクセル単位で正確な PNG を取得します(スケール 1~4)。 |
pico8_read | Lua グローバル変数をドット区切りのパスで読み取ります(player.x、objects.1.type など)。 |
pico8_peek | PICO-8 RAM の 16 進ダンプを取得します(0x6000 はフレームバッファー、0x2000 はマップなど)。 |
pico8_reset | 元のファイルから終了して再起動します(カートの編集内容が反映されます)。 |
pico8_shutdown / pico8_sessions | ライフサイクル管理/一覧表示。 |
pico8_boot_check | 変更されていないカートを pico8 -x で N 秒間実行し、起動エラーを報告します(ベンチマーク形式のチェック)。 |
複数のセッションを並行して実行できます。session_id を指定しない場合は、直近の稼働中セッションが使用されます。
ライブビューアー
サーバーは小さなローカル Web ページをホストしているため、LLM のプレイをリアルタイムで確認できます。ブラウザーで http://127.0.0.1:7864/ を開いてください。ゲーム画面(SSE 経由でストリーミング)、現在押されているボタン、各ツール呼び出しとカートの printh 出力のログが表示されます。

- ブラウザーのタブが接続されている間は、まとめて実行するステップが小さなチャンク(デフォルトは 15 フレーム)に分割され、それぞれの後に画面キャプチャが行われます。そのため、長い
pico8_step呼び出しも早送り動画のように再生されます。ビューアーが接続されていない場合、オーバーヘッドはありません。 - 再生は LLM のペースで進みます(通常、リアルタイムよりはるかに高速です)。
環境変数:
| 変数 | デフォルト | 効果 |
|---|---|---|
PICO8_MCP_VIEWER | 1 | 0 に設定すると、ビューアーを完全に無効にします |
PICO8_MCP_VIEWER_PORT | 7864 | リッスンポート(127.0.0.1 のみでバインド) |
PICO8_MCP_VIEWER_CHUNK | 15 | スペクテート中に中間画面をキャプチャする間隔のフレーム数 |
ポートがすでに使用中の場合(たとえば、2 つ目の MCP ホストが稼働している場合)、警告が stderr に表示されてビューアーは無効になりますが、サーバーは通常どおり動作します。
把握しておくべき仕様
- ボタンはステップ間で押されたままになります。
btnp()が呼び出されるのは、新しい押下の最初のフレームだけです。2回タップするには、ボタンを押した状態でステップし、buttons: []でステップしてから、再びボタンを押した状態でステップします。 - スクリーンショットは、最後にステップしたフレームの**
_draw実行後**に撮影されます。 - カートでランタイムエラーが発生すると、
-xプロセスは終了し、エラーテキストがツールの結果に表示されます。pico8_resetで最初からやり直せます。 - ハーネスはGPIOメモリ(
0x5f80–0x5fff)をパケットバッファーとして使用し、btn/btnpのグローバルを上書きします。GPIOを独自に使用するカートや、ハーネスの読み込み前にlocal btn=btnをキャッシュするカートでは、正しく動作しません。
開発
npm run buildを実行してからnode test/mcp-probe.mjs [cart.p8]を実行すると、実際のMCPクライアントを使ったエンドツーエンドのプローブ(起動 → プレイ → 読み取り → シャットダウン)が実行されます。PICO8_BINで別のPICO-8バイナリを指定できます。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。