サンドボックスに鍵を置かずに EmDash の CLI を使う
サイト運営で使っている EmDash へ記事本文を投入する作業を、内蔵の MCP(AI エージェントに外部サービスのツールを見せる規格)経由でエージェントにやらせたところ、記事5本を投入したセッションの消費トークンが58万になり、Claude Code のレートリミットに達してしまいました。
MCP 経由を使ったのは安全のためでしたが、結果的にそれは私の勘違いで、サンドボックスに鍵を置かずに CLI をそのまま使い、本文がモデルの入出力を通らない経路に切り替えることができました。
エージェントは Docker サンドボックス(Docker がホストに用意する使い捨ての実行環境。CLI 名は sbx)で動いています。`sbx secret set-custom` は、サンドボックスの環境変数にはプレースホルダーだけを置き、対象ホスト宛てのリクエストが出た瞬間にホストのプロキシが実トークンへ差し替える EXPERIMENTAL なコマンドです。
投入の経路は3つ
CMS に本文を投入する経路は3つあり、鍵の置き場所と本文がモデルを通るかで分かれます。
- MCP 経由: 鍵はサンドボックスに置かずに済むが、本文はツール呼び出しの引数としてモデルの入出力を通る
- トークン直置き: CLI はそのまま動き本文もモデルを通らないが、鍵の実体がサンドボックスの中にある
- ヘッダ差し替え: 鍵を置かず、本文もモデルを通らない。GitHub の PAT をプロキシが注入する仕組みと同型
ヘッダ差し替えで CLI をそのまま使う
ホスト側で次のコマンドを実行すると、対象のサンドボックスの環境変数にプレースホルダーが入ります。
sbx secret set-custom --sandbox <name> --host shinobiworks.com --env EMDASH_API_TOKEN --placeholder <任意> --value '<token>'CLI の設定ファイルにこのプレースホルダーを書いておくと、対象ホスト宛てのリクエストが出た瞬間にプロキシがヘッダ内のプレースホルダーを実トークンへ差し替えます。差し替えが効くのは登録したホスト宛てのリクエストヘッダだけで、サンドボックスの中で環境変数を出力してもファイルに書き出しても、現れるのはプレースホルダーの文字列だけです。既存のサンドボックスには環境変数が自動では届かないため、コマンドが表示したプレースホルダーを設定ファイルに手で書きます。
設計を変えた失敗
差し替え時に値を解決するコマンドとして --command 'pbpaste' を渡したところ、クリップボードの内容が変わっていて解決に失敗し、エラー応答ではなく接続そのものが切れました(curl の終了コードは 000)。プロキシは差し替えのたびにそのコマンドをホスト側で実行するため、結果が実行のたびに変わりうるコマンドを渡すと、失敗はクライアント側の接続断として現れます。値は --value で直接渡すか、ホストのファイルを読むだけのコマンドにしています。
トークンのスコープ
発行したトークンのスコープは content:read / content:write / schema:read / taxonomies:manage に絞り、admin は持たせていません。この状態で npx emdash whoami は403を返しますが、記事の作成・取得とタクソノミーの操作は通るため、動作確認は実際に使う content get で行います。
本文がモデルを通らない効果
内蔵 MCP 経由で58万トークンに達し、本文の一部が文字化けしたのは、ツール呼び出しの引数に渡した本文が会話のコンテキストとして何度も引用・再構成されたためです。同じ投入作業をヘッダ差し替えの経路でスクリプトに切り替えると、下書き投入と本文の照合を含めて消費は数百トークンに収まります。本文はスクリプトから CMS へ直接送られ、モデルが目にするのは実行結果の要約だけです。
本文がモデルを通らない代わりに、コピー漏れや改変が無いことは別の手段で確かめます。投入済みの記事を CLI で取得し直し、元の markdown と Unicode の NFC 正規化と空白・記号の除去をかけたうえで突き合わせています。
- 5本のうち4本は完全に一致
- 残り1本は番号付きリストの番号だけが往復で振り直されていた(EmDash が番号付きリストを連番に正規化して保存するための差分)