
Code Mode 完全ガイド:Cloudflareの提案からローカル開発の全ユースケース実践まで
最終更新:2026-02-21 Code Modeの原理、プラットフォーム設定、8つの実践ユースケース、オープンソースサーバー選定を網羅。プロンプトテンプレート付き。
目次
1. Code Modeとは?
1.1 Cloudflare 2025/9提案のMCP新パラダイム:パラダイムシフトの背景
2025年9月、CloudflareはブログにてCode Modeの記事を公開した:「Code Mode: give agents an entire API in 1,000 tokens」。この記事では、AI Agentが数千ものAPIエンドポイントを持つ大規模サービスを操作する際、従来のTool Callingが限界を迎えているという核心的な問題が指摘されている。
問題の本質:
MCP(Model Context Protocol)はAnthropicが主導するオープン標準で、AI Agentが外部ツールやAPIに安全に接続できるようにするものだ。従来のMCPでは、各APIエンドポイントを独立した「ツール」として記述する——名前、パラメータ形式、戻り値の型、すべて揃えて。エンドポイントが少ない場合は問題ない。しかしCloudflareには2,500以上のエンドポイントがあり、ツールの記述をコンテキストに詰め込むだけで117万Token以上が必要になる。
AIが何も始めないうちに、コンテキストウィンドウがすでに埋め尽くされてしまう。
Code Modeの解答:
Cloudflareの解法はシンプルだ——AIにすべてのAPIの詳細を覚えさせるのではなく、AIを「自分でドキュメントを調べてスクリプトを書けるエンジニア」に変える。この新しいアプローチはCode Mode(コードモード)と呼ばれ、AI Agent領域におけるパラダイムシフトといえる。
核心的な考え方はシンプルだ:
AIに2,500個のボタンを与えるのではなく、説明書とパソコンを1台渡す。
1.2 2つのコアツール:search()とexecute()の設計哲学
Code Modeは、巨大なAPIインターフェース全体をわずか2つのツールに集約する:
search(code) — AIの「ドキュメント検索担当」
- AIがJavaScriptを書いて、サーバー側のOpenAPI specでエンドポイントを検索・フィルタリングする。
- 例:AIがファイアウォール関連のAPIを調べたい場合、以下のようなコードを書く:
// AIが生成するsearchコード
const results = endpoints.filter(ep =>
ep.path.includes('firewall') || ep.description.includes('WAF')
);
return results.map(ep => ({
method: ep.method,
path: ep.path,
summary: ep.summary
}));
- サーバーは条件に合致するエンドポイントの要約だけを返す。2,500件全部の完全な記述ではない。
execute(code) — AIの「コード実行エンジン」
- AIが完全なJavaScriptを書いて、実際にAPIを呼び出し、レスポンスを処理し、複数の操作を連鎖させる。
- コードはサーバー側のV8隔離サンドボックスで実行され、最終結果のみが返される。
// AIが生成するexecuteコード
const zones = await api.get('/zones');
const myZone = zones.find(z => z.name === 'example.com');
const rules = await api.get(`/zones/${myZone.id}/firewall/rules`);
return {
zone: myZone.name,
activeRules: rules.filter(r => r.enabled).length,
totalRules: rules.length
};
2つのモードの主な違い:
| 比較項目 | 従来のTool Calling | Code Mode |
|---|
| AIの役割 | ボタン操作員(ツール選択 → パラメータ入力) | プログラマー(要件理解 → スクリプト作成) |
| 探索方法 | 完全なツールリストを受動的に受け取る | 必要なエンドポイントを能動的に検索 |
| 実行方法 | 操作ごとに1回のJSON呼び出し | 単一スクリプトですべての操作を完了 |
| コンテキスト消費 | エンドポイント数に比例して線形増加 | 常時約1,000トークン固定 |
| エラー処理 | 各ステップで中断の可能性、最初からやり直し | スクリプト内蔵のtry-catchで一括処理 |
1.3 99.9%のトークン節約という数字(1.17M → 1069トークン)
Cloudflareはブログで実測データを公開している:
| 指標 | 従来のMCP | Code Mode | 節約率 |
|---|
| ツール記述トークン数 | 1,170,000 | 1,069 | 99.91% |
| ツール数 | 2,500+ | 2 | 99.92% |
| タスク完了に必要なやり取り回数 | 数十回 | 2-4回 | ~90% |
| 1回の操作のコンテキスト負荷 | 数十万トークン | 数百トークン | ~99% |
これは理論値ではない。CloudflareがDNS、CDN、WAF、Workers、R2など自社の完全なAPIで実測した結果だ。
なぜこれほど節約できるのか?
- ツール記述が非常にシンプル: 従来の方法では各エンドポイントの名前、パス、HTTPメソッド、すべてのパラメータと戻り値の形式を記述する必要があった。Code Modeでは「コード文字列を受け取り、結果を返す」2つのツールだけでいい。それだけだ。
- オンデマンドロード: AIはすべてのAPIを一度に見る必要がない。必要なものを必要なときに調べる。
- 結果の精製: コードがサンドボックス内で不要な情報をフィルタリングし、AIが本当に必要な精髄だけを返す。
1.4 Anthropic公式の認定と採用
これはCloudflare1社だけの話ではない。MCPの発明者であるAnthropicも「Code execution with MCP」を発表し、このモードを正式に認定した。
Anthropicの研究結論はCloudflareと一致している:
LLMがコードを書いてツールを呼び出す方が、構造化されたツール呼び出しを逐一使うよりもはるかに効率的だ。
Code Modeはある企業の実験から業界の共識へと変わった。今後のMCPサーバーは数百の独立したツールではなくexecute_codeを提供する方向に傾くだろう。
継続的な進化: 2026年2月20日、Cloudflareは@cloudflare/codemode v0.1.0をリリースした。このSDKはCode Modeをruntime-agnosticモジュールとして書き直したもので、他のプラットフォームも直接採用できる。コミュニティ側でもportofcontext/pctxなどのオープンソースフレームワークが次々と登場しており、エコシステムは急速に拡大している。
2. 技術原理:HTMLがコンテキストウィンドウを溢れる問題をどう解決するか
2.1 従来のスクレイピングの古い問題(2MB HTML問題)
具体的なユースケースで説明しよう:AIにウェブページのタイトルと主要なコンテンツをスクレイピングさせるとする。
従来のフロー:
- AIが
fetch_url("https://example.com")ツールを呼び出す - ツールがページのHTMLソースコード全体を返す
- AIが受け取るのは
<div>、<script>、<style>、<nav>が混在する2MBのソースコード - AIは自分のトークン(あなたが支払う計算リソース)を使ってこの2MBを「読む」必要がある
- トークンが瞬時に枯渇し、AIはコンテキスト制限を超えるか、品質が著しく低下する
実際の数値感覚:
| ページ種別 | HTMLサイズ | 推定トークン数 | Claude Sonnetでの料金換算 |
|---|
| シンプルなブログ | 100KB | ~25,000 | ~$0.075 |
| ニュースサイトトップ | 500KB | ~125,000 | ~$0.375 |
| ECサイト商品ページ | 2MB | ~500,000 | ~$1.50 |
| SPAアプリ(レンダリング後) | 5MB+ | ~1,250,000 | ~$3.75 |
本当に必要な「タイトルと主要コンテンツ」は200トークンかもしれない。つまり、トークンの99.98%がHTMLタグ、CSS、JavaScript、ナビゲーションに浪費されている。
2.2 従来のMCPの「コンテキスト溢れ」問題
スクレイピングの問題は氷山の一角だ。従来のMCPアーキテクチャでは「コンテキスト溢れ」は深刻な構造的問題だ:
ユースケース1:大規模API操作
AIにCloudflareを操作させたい?ツールの記述だけで117万トークンを消費する。AIが何も始めないうちに「記憶喪失」になる——コンテキストがツールの記述で埋め尽くされ、あなたの要件を処理するスペースが残らない。
ユースケース2:多ステップの自動化
AIに「50件のログを確認 → エラーを見つける → 分類して集計」させたい?従来の方法では:
read_logツール呼び出し50回(毎回完全なJSONのやり取り)- 毎回の戻り値がコンテキストに積み重なる
- 20件目になるとAIはすでに1件目の内容を忘れている
- 最終的にAIがハルシネーションを起こすか、クラッシュする
ユースケース3:バッチファイル処理
AIにプロジェクトの100ファイルをリファクタリングさせたい?従来の方法では:
read_file呼び出し100回- コンテキストに数十万行のコードが詰まる
- AIはファイルを混同したり、修正を漏らしたり、一貫性のない変更を生成しやすくなる
根本的な問題: 従来のMCPはAIに自分の高価な「頭脳」(コンテキストウィンドウ)を使って大量の生データを処理させている。まるでトップクラスの弁護士に千ページの文書を自分でコピーさせるようなもの——効率が極めて低く、コストが極めて高い。
2.3 Code Modeのサンドボックス解析メカニズム(V8 Dynamic Worker)
Code Modeの解法は美しい:AIにコードを書かせて雑務を処理し、AI自身は整理された結果だけを受け取る。
アーキテクチャ図:
flowchart TD
A["👤 ユーザー"] --> B["🤖 AIモデル"]
B -->|"search() / execute()"| C["📡 MCP Server"]
C --> D["🔒 V8隔離サンドボックス<br/>Dynamic Worker"]
D --> E["AIが書いたコード"]
E --> E1["OpenAPI specを検索"]
E --> E2["APIを呼び出す"]
E --> E3["レスポンスを解析"]
E --> E4["不要な情報をフィルタリング"]
E1 & E2 & E3 & E4 --> F["✨ 精製済み結果<br/>(数百トークン)"]
F --> B
style D fill:#0f3460,stroke:#5dade2,stroke-width:2px
style F fill:#1a5c2a,stroke:#2ecc71,stroke-width:2px
V8隔離サンドボックスの特性:
CloudflareはWorkersと同じV8隔離環境(Dynamic Workerとも呼ばれる)を使用しており、セキュリティ特性は以下の通り:
| 特性 | 説明 |
|---|
| メモリ隔離 | 毎回の実行は独立したV8 Isolate内で行われ、他プロセスのメモリにアクセスできない |
| ファイルシステムなし | サンドボックス内にファイルシステムへのアクセス権限がない |
| ネットワーク制御 | 事前に認可されたAPIエンドポイントのみアクセス可能 |
| 環境変数の隔離 | サーバーの環境変数やシークレットが漏洩しない |
| タイムアウト機構 | コード実行に時間上限があり、無限ループを防止 |
| 実行後即破棄 | 実行完了後にサンドボックスが自動的に破棄され、痕跡を残さない |
スクレイピングを例にした完全なフロー:
- ユーザー:「Hacker Newsのトップページから上位30件の記事タイトルとリンクをスクレイピングして」
- AIがコードを生成:
import requests
from bs4 import BeautifulSoup
resp = requests.get("https://news.ycombinator.com")
soup = BeautifulSoup(resp.text, "html.parser")
items = soup.select(".titleline > a")[:30]
result = [{"title": a.text, "link": a["href"]} for a in items]
print(json.dumps(result, ensure_ascii=False, indent=2))
- コードがサンドボックスで実行:HTMLをダウンロード(500KB)→ サンドボックス内で解析 → 30件のデータを抽出
- AIに返される結果:クリーンなJSON配列、約200トークン
500KBのHTMLはAIのコンテキストに入らない。 AIはスクリプトの作成に数百トークン、結果の読み取りに数百トークンを使うだけだ。
2.4 比較表:従来のMCP vs Code Mode
| 比較項目 | 従来のMCP | Code Mode MCP |
|---|
| ツール数 | 数千の独立したツール(APIエンドポイントごとに1つ) | 2つだけ(search + execute)、または1つ(execute_code) |
| ツール記述のトークン消費 | エンドポイント数に比例して線形増加(百万単位) | 固定 ~1,000トークン、APIの規模に無関係 |
| AIの役割 | ツール操作員(ツール選択 → パラメータ入力) | プログラマー(要件理解 → スクリプト作成) |
| APIの探索方法 | 受動的:完全なツールリストを受け取る | 能動的:コードを書いてOpenAPI specを検索 |
| 実行方法 | 操作ごとにJSON形式のツール呼び出し1回 | 単一スクリプトですべての操作を完了(ループ、条件分岐含む) |
| チェーン操作能力 | 複数ターンの対話が必要、1回の対話で1操作 | 1つのコード内で多ステップの連鎖を完了 |
| データフィルタリング | AIが自分のトークンですべての戻りデータを読む | コードがサンドボックス内でフィルタリング、精髄だけを返す |
| セキュリティ | サーバーの実装次第 | 強制隔離(V8 / Docker / Podman) |
| エラー処理 | 各ステップで中断の可能性、最初からやり直し | スクリプト内蔵のtry-catchで例外を自己処理 |
| 適用可能なAPI規模 | 小規模(<100エンドポイント)ならまあまあ | あらゆる規模に対応、APIが大きいほど優位性が明確 |
3. Claude CodeでCode Modeを使う
3.1 公式MCP登録(Cloudflare):OAuth設定を含む完全な手順
Claude CodeはMCPをネイティブにサポートしており、登録はコマンド1行でできる。
ステップ1:Cloudflare MCPを追加する
claude mcp add --transport http cloudflare https://mcp.cloudflare.com/mcp
ステップ2:OAuth認証を完了する
Claude Codeのインタラクティブインターフェースで入力:
/mcp
これによりCloudflare OAuth 2.1の認証フローが開始される。ブラウザでログインと認可を完了すれば、Claude Codeはあなたの代わりにCloudflare APIを操作できるようになる。
ステップ3:自然言語でコマンドを実行する
example.comの現在のDNSレコードを確認してください
AIが自動的に:
search()を呼び出してDNS関連のAPIエンドポイントを見つけるexecute()を呼び出してすべてのDNSレコードを一覧するスクリプトを書く- 整理済みの結果を返す
詳細設定(任意):操作可能なzoneを限定する
OAuthはデフォルトでアカウント下のすべてのzoneを認可する。範囲を絞りたい場合はAPIトークン認証に変更:
- Cloudflare Dashboard → API Tokensで権限を制限したトークンを作成(zoneと権限を指定)
- トークンをMCP設定に入力:
{
"mcpServers": {
"cloudflare": {
"url": "https://mcp.cloudflare.com/mcp",
"transport": "http",
"headers": {
"Authorization": "Bearer YOUR_SCOPED_TOKEN"
}
}
}
}
注意: Zoneのアクセス範囲はCloudflare側のトークン権限によって決まる。MCP JSONの設定ではない。
3.2 コミュニティMCP登録(Replicate、jx-codes、elusznik):各インストールコマンド
Replicate Code Mode MCP
AIがReplicate上のモデル(画像生成、動画生成など)をコードで操作できるようにする:
claude mcp add "replicate-code-mode" -- npx -y replicate-mcp@alpha --tools=code
登録後、AIが画像や動画を生成する際に自分でSDKを呼び出すコードを書くようになる。ツールのパラメータを逐一入力する必要がなくなる。
jx-codes/codemode-mcp(JS/Deno軽量プロキシ)⚠️ メンテナンス終了
注意: このプロジェクトはメンテナンスが終了しており、作者はjx-codes/lootboxの開発に移行している。以下のコマンドは引き続き使用できるが、更新はされない。積極的にメンテナンスされている複数MCP統合ソリューションが必要な場合はpctx(下記参照)の利用を推薦する。
複数の従来MCPサーバーをCode Modeに統合したい上級ユーザーに適している:
# インストール
npm install -g @jx-codes/codemode-mcp
# Claude Codeに登録
claude mcp add "codemode-proxy" -- npx @jx-codes/codemode-mcp --config ./codemode.json
設定ファイル例 codemode.json:
{
"upstreamServers": [
{
"name": "filesystem",
"command": "npx",
"args": ["@modelcontextprotocol/server-filesystem", "/path/to/project"]
},
{
"name": "github",
"command": "npx",
"args": ["@modelcontextprotocol/server-github"]
}
],
"sandbox": {
"timeout": 30000,
"allowNetwork": false
}
}
portofcontext/pctx(オープンソース model-agnostic Code Modeフレームワーク)🆕
2025年11月に登場したオープンソースプロジェクトで、特定のモデルに縛られない。The New Stackでも紹介された。コアはRust製で、Denoサンドボックス実行環境を内蔵(10秒タイムアウト、ファイルシステムアクセス禁止、ネットワークは設定済みMCPホストのみ)。TypeScriptコンパイラも搭載(typescript-go採用、型チェック< 100ms)。Claude、GPT、Gemini、任意のローカルモデルに対応し、vendor lock-inなし。
pctxが提供する3つのMCPツール:
| ツール | 機能 |
|---|
list_functions() | 利用可能な全関数のTypeScript namespaceを一覧表示 |
get<em>function</em>details(functions) | 関数の完全なTypeScript署名とJSDocドキュメントを取得 |
execute(code) | DenoサンドボックスでTypeScriptを実行し、{ success, stdout, output, diagnostics }を返す |
macOSインストール手順(brew環境):
# 1. pctx CLIをインストール
brew install portofcontext/tap/pctx
# 2. 設定ファイルを初期化(プロジェクトディレクトリで実行)
pctx mcp init
# 3. 統合したいupstream MCPサーバーを追加
# HTTP MCPサーバー(StripeやCloudflareなど)
pctx mcp add stripe https://mcp.stripe.com --bearer "${STRIPE_MCP_KEY}"
# stdio MCPサーバー(memoryやfilesystemなど)
pctx mcp add memory --command "npx -y @modelcontextprotocol/server-memory"
# 4. 接続テスト
pctx mcp list
その他のインストール方法:
# npmグローバルインストール
npm i -g @portofcontext/pctx
# cURLワンコマンドインストール
curl --proto '=https' --tlsv1.2 -LsSf https://raw.githubusercontent.com/portofcontext/pctx/main/install.sh | sh
# アップデート
brew upgrade pctx # brew
npm upgrade -g @portofcontext/pctx # npm
pctx-update # cURLインストールの場合はこちら
Claude Codeでの設定:
claude mcp addにはスコープが3種類ある:
| スコープ | 書き込み先 | 適用範囲 |
|---|
--scope user | ~/.claude.json | グローバル、すべてのプロジェクトで利用可能 |
--scope local(デフォルト) | ~/.claude.json | 現在のプロジェクトのみ(個人プライベート、gitには含まれない) |
--scope project | .mcp.json(プロジェクトルート) | プロジェクトレベル、gitに含まれ、チームで共有可能 |
方法1:CLIコマンド(グローバル、個人利用推薦)
# 追加(グローバル、すべてのプロジェクトで利用可能)
claude mcp add pctx --scope user -- pctx mcp start --stdio
# 更新:一旦削除してから再追加
claude mcp remove pctx && claude mcp add pctx --scope user -- pctx mcp start --stdio
# 設定を確認
claude mcp get pctx
claude mcp list
方法2:.mcp.json(--scope project、チーム共有向き)
プロジェクトルートに.mcp.jsonを作成し、gitにコミットしてチーム全体で共有:
{
"mcpServers": {
"pctx": {
"type": "stdio",
"command": "pctx",
"args": ["mcp", "start", "--stdio"]
}
}
}
注意: --stdioモードには作業ディレクトリにpctx.jsonが必要だ。先にpctx mcp initで作成すること。しないと起動に失敗する。pctx.jsonが別のパスにある場合は--configで指定:
"args": ["mcp", "start", "--stdio", "--config", "/path/to/pctx.json"]
Cursorでの設定(~/.cursor/mcp.json):
{
"mcpServers": {
"pctx": {
"command": "pctx",
"args": ["mcp", "start", "--stdio"]
}
}
}
pctx.json設定ファイルの例:
{
"name": "my-ai-agent",
"version": "1.0.0",
"servers": [
{
"name": "stripe",
"url": "https://mcp.stripe.com",
"auth": {
"type": "bearer",
"token": "${env:STRIPE_MCP_KEY}"
}
},
{
"name": "gdrive",
"url": "https://mcp.gdrive.example.com",
"auth": {
"type": "headers",
"headers": { "x-api-key": "${keychain:gdrive-api-key}" }
}
},
{
"name": "memory",
"command": "npx -y @modelcontextprotocol/server-memory"
}
]
}
pctxはシークレットを安全に取得する3つの方法をサポートしている:
| 構文 | ソース | 例 |
|---|
${env:NAME} | 環境変数 | ${env:STRIPE<em>MCP</em>KEY} |
${keychain:NAME} | macOS Keychain | ${keychain:mcp-api-key} |
${command:CMD} | 外部コマンドのstdout | ${command:op read op://vault/item/field} |
# macOS Keychainにシークレットを保存
security add-generic-password -s pctx -a my-key -w "your-secret-value"
Python SDKのインストールと使い方:
pctxはCLI(Claude Code / CursorのMCPサーバーとして使用)に加え、Python SDKも提供している。PythonでエージェントからCode Modeを直接呼び出せる。
# 基本インストール(Python >= 3.10が必要)
pip install pctx-client
# またはuvを使う場合
uv add pctx-client
# AIフレームワークとの連携(必要に応じて選択)
pip install "pctx-client[langchain]" # LangChain
pip install "pctx-client[openai]" # OpenAI Agents SDK
pip install "pctx-client[crewai]" # CrewAI
pip install "pctx-client[pydantic-ai]" # Pydantic AI
動作方法:まずpctx startでHTTPサーバーを起動し、その後Pythonから接続する:
# ターミナル1:pctx HTTPサーバーを起動(デフォルトポート8080)
pctx start
# ターミナル2:Pythonエージェントを実行
python main.py
from pctx_client import Pctx, tool
# カスタムツールを定義
@tool
def get_weather(city: str) -> str:
"""Get weather information for a given city."""
return f"Sunny in {city}!"
# pctxサーバーに接続
p = Pctx(tools=[get_weather])
await p.connect()
# 各フレームワークで使用可能なツールを取得
langchain_tools = p.langchain_tools() # LangChain
openai_tools = p.openai_agents_tools() # OpenAI Agents SDK
crewai_tools = p.crewai_tools() # CrewAI
2つのモードの違い:
pctx mcp start --stdio:MCPサーバーとして動作、Claude Code / Cursorで使用pctx start:HTTPサーバーとして動作、Python SDKで使用(デフォルトポート8080)
適したユースケース: 複数のMCPサーバーを統合する複雑なワークフロー。単一ツール呼び出しのシンプルなユースケースには不向きで、pctxがかえってオーバーヘッドを増やす。
elusznik/mcp-server-code-execution-mode(Pythonコンテナサンドボックス)
ローカル開発で最もお薦めのCode Modeサーバーだ。rootlessコンテナ(Podman / Docker)でPythonコードを実行し、run_pythonツール1つだけを公開する。セキュリティが最高レベル(メモリ/CPU/PID制限、capability drop、タイムアウト機構)。
注意: このプロジェクトはまだPyPIに公開されていないため、uv tool installとpip installはどちらも失敗する。以下のuvx --from git+を使ったインストールを使うこと。
macOSインストール手順(brew + uv環境):
# 1. コンテナ実行環境をインストール(2択、Podmanの方が軽量でdaemon不要のため推薦)
brew install podman
podman machine init && podman machine start
# またはbrew install --cask docker
# 2. PythonベースイメージをPull(一度だけ)
podman pull python:3.13-slim
# またはdocker pull python:3.13-slim
# 3. MCPサーバーを直接起動(cloneは不要)
uvx --from git+https://github.com/elusznik/mcp-server-code-execution-mode mcp-server-code-execution-mode run
Claude Codeに永続的に設定する(推薦):
方法1:CLIコマンド(グローバル、~/.claude.jsonに書き込み)
# 追加(グローバル、すべてのプロジェクトで利用可能)
claude mcp add code-execution --scope user -e MCP_BRIDGE_RUNTIME=podman -- \
uvx --from git+https://github.com/elusznik/mcp-server-code-execution-mode \
mcp-server-code-execution-mode run
# 更新:一旦削除してから再追加
claude mcp remove code-execution && claude mcp add code-execution ...
方法2:.mcp.jsonを編集する(プロジェクトレベル、--scope project)
{
"mcpServers": {
"code-execution": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/elusznik/mcp-server-code-execution-mode",
"mcp-server-code-execution-mode",
"run"
],
"env": {
"MCP_BRIDGE_RUNTIME": "podman"
}
}
}
}
ローカル開発方法(ソースコードを変更する必要がある場合):
git clone https://github.com/elusznik/mcp-server-code-execution-mode.git
cd mcp-server-code-execution-mode
uv sync
uv run python mcp_server_code_execution_mode.py
macOSでよくある問題:
| 問題 | 解決策 |
|---|
| Podman権限エラー | podman machine initを実行して起動する |
| Docker Desktopのファイル共有 | Settings → Resources → File Sharingに~/MCPsを追加 |
uvxが見つからない | uvがPATHにあることを確認し、ターミナルを再起動するかsource ~/.zshrc |
| コンテナのイメージがPullできない | 手動でpodman pull python:3.13-slimを実行 |
3.3 プロンプトの書き方を変える(従来の書き方 vs Code Modeの書き方)
Code Modeはプロンプトの習慣をそれほど変える必要はない。AIが自動的にsearchとexecuteを使う。ただし、少し調整するとAIをより効率的に誘導できる:
従来のプロンプト:
Cloudflareの設定を確認して、WAFルールを修正してください。
Code Mode最適化プロンプト:
search()とexecute()ツールを使えます。
まずCloudflareのWAF関連エンドポイントを検索し、
次に現在のWAFルールを一覧するスクリプトを書いて、
最後に高リスクIPからのリクエストをブロックするルールを1件追加してください。
比較表:
| 比較項目 | 従来のプロンプト | Code Mode最適化プロンプト |
|---|
| 誘導の明確さ | 曖昧(「なんとかして」) | 明確に誘導(「検索 → スクリプト → 実行」) |
| AIの効率 | 複数回の確認が必要な場合がある | 一発で完了 |
| 結果の品質 | AIがステップを見落とす可能性がある | ステップが明確で見落としにくい |
上級テクニック:CLAUDE.mdまたはSystem Promptに誘導を追加する
Code Modeを頻繁に使う場合は、プロジェクトのCLAUDE.mdに以下を追加できる:
## Code Mode使用ガイドライン
- APIの探索にはsearch()を優先的に使い、エンドポイントのパスを推測しない
- execute()スクリプトを書く際は、エラー処理(try-catch)を含める
- バッチ操作の場合は、まず少量のバッチでテストし、問題がなければ全件実行
- 結果を返す際は重要な情報だけを保持し、完全なAPIレスポンスをコンテキストに詰め込まない
4. CursorでCode Modeを使う
4.1 MCP設定方法(mcp.json設定例)
CursorもMCPをサポートしている。プロジェクトルートに.cursor/mcp.jsonを作成する:
Cloudflare Code Mode:
{
"mcpServers": {
"cloudflare": {
"url": "https://mcp.cloudflare.com/mcp",
"transport": "http"
}
}
}
elusznikローカル Code Mode:
{
"mcpServers": {
"code-exec": {
"command": "mcp-server-code-execution-mode",
"args": [],
"env": {
"CONTAINER_RUNTIME": "docker"
}
}
}
}
jx-codesプロキシモード(複数MCPを連携): ⚠️ メンテナンス終了、lootbox参照
{
"mcpServers": {
"codemode-proxy": {
"command": "npx",
"args": ["@jx-codes/codemode-mcp", "--config", "./codemode.json"]
}
}
}
elusznikローカル Code Mode(uvx方式):
{
"mcpServers": {
"code-execution": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/elusznik/mcp-server-code-execution-mode",
"mcp-server-code-execution-mode",
"run"
],
"env": {
"MCP_BRIDGE_RUNTIME": "podman"
}
}
}
}
4.2 Cursor Rulesとの連携テクニック(.cursorrulesの例)
Cursorは.cursorrulesでAIの動作を誘導できる。以下はCode Mode向けの最適化ルールだ:
# Code Mode使用ルール
## 基本原則
- APIエンドポイントを調べる必要がある場合は、必ずsearch()ツールで検索する。APIパスを推測しない
- 多ステップの操作が必要な場合は、完全なスクリプトを書いてexecute()で一度に完了させる
- 大量の生データをコンテキストに詰め込まない——スクリプト内でフィルタリングと要約を行う
## コードスタイル
- execute()内のコードはエラー処理を含める必要がある
- console.log()またはprint()で構造化された結果を出力する(JSON形式を優先)
- バッチ操作の前に少量でテストする
## セキュリティ原則
- コード内にシークレットやTokenをハードコーディングしない
- 変更操作の前に現在の状態を一覧表示する(先に確認、後で変更)
- 破壊的な操作は必ず確認を求める
4.3 Human-in-the-loopメカニズムと安全確認
Code ModeでローカルファイルやクラウドサービスをContent操作する場合、安全確認メカニズムが重要だ:
Claude Codeのセキュリティメカニズム:
Claude Codeには権限システムが内蔵されている。デフォルトでは、AIがMCPツールを実行する前に確認を求める。自分で調整することもできる:
# 現在の権限設定を確認
claude config list
# 特定のMCPツールを自動実行に許可する(上級ユーザー向け)
# .claude/settings.jsonで設定
Cursorのセキュリティメカニズム:
CursorはAgentモードでAIが実行しようとしている操作を表示する。次のことができる:
- 承認(Accept)
- 拒否(Reject)
- 修正してから承認
推薦のセキュリティ戦略:
| 操作タイプ | 推薦戦略 |
|---|
| 読み取り専用操作(search、参照) | 自動実行に設定可 |
| 変更操作(設定更新、ファイル変更) | 手動確認が必要 |
| 破壊的操作(削除、リセット) | 強制手動確認 + 事前バックアップ |
| ネットワーク操作(スクレイピング、外部API) | 対象URLの手動確認が必要 |
5. 8つのユースケース教学
以下の各ユースケースには:問題背景 → MCP選択理由 → 完全な操作手順 → 実行可能なコード例 → 期待される出力形式が含まれている
5.1 ユースケース1:大規模APIとのやり取り(Cloudflare 2500+エンドポイント)
問題背景:
あなたはサイト管理者で、Cloudflareで複数のドメインを管理している。やりたいことは:
- すべてのドメインのDNSレコードを確認する
- 特定のドメインにWAFルールを追加する
- 過去24時間のトラフィック分析を確認する
従来の方法ではAPIドキュメントを調べ、エンドポイントを見つけ、パラメータ形式を把握し、逐一呼び出す必要があった。Code Modeを使えば、AIが自分で処理する。
MCPの選択: cloudflare/mcp(公式、V8隔離、99.9%のトークン節約)
完全な操作手順:
# ステップ1:Cloudflare MCPを登録
claude mcp add --transport http cloudflare https://mcp.cloudflare.com/mcp
# ステップ2:認証
# Claude Codeで/mcpと入力し、OAuthフローを完了する
プロンプト例:
私のすべてのCloudflareドメインの状態を確認したいです。以下をお願いします:
1. すべてのzoneとその状態を一覧表示
2. example.comについて、すべてのDNSレコードを一覧表示
3. WAFルールを1件追加:User-Agentに"BadBot"を含むリクエストをブロック
AIが生成するsearchコード例:
// zone と DNS 関連の API エンドポイントを検索
const results = endpoints.filter(ep =>
ep.path.includes('/zones') &&
(ep.tags.includes('Zone') || ep.tags.includes('DNS'))
);
return results.slice(0, 10).map(ep => ({
method: ep.method,
path: ep.path,
summary: ep.summary
}));
AIが生成するexecuteコード例:
// 1. すべてのzoneを一覧表示
const zonesResp = await api.get('/zones');
const zones = zonesResp.result.map(z => ({
name: z.name,
status: z.status,
plan: z.plan.name
}));
// 2. example.comのDNSレコードを取得
const myZone = zonesResp.result.find(z => z.name === 'example.com');
const dnsResp = await api.get(`/zones/${myZone.id}/dns_records`);
const dns = dnsResp.result.map(r => ({
type: r.type,
name: r.name,
content: r.content,
ttl: r.ttl
}));
// 3. WAFルールを追加
const wafRule = await api.post(`/zones/${myZone.id}/firewall/rules`, {
body: JSON.stringify([{
filter: { expression: 'http.user_agent contains "BadBot"' },
action: "block",
description: "Block BadBot user agent"
}])
});
return { zones, dns, wafRuleCreated: wafRule.success };
期待される出力:
{
"zones": [
{ "name": "example.com", "status": "active", "plan": "Pro" },
{ "name": "example.org", "status": "active", "plan": "Free" }
],
"dns": [
{ "type": "A", "name": "example.com", "content": "93.184.216.34", "ttl": 300 },
{ "type": "CNAME", "name": "www.example.com", "content": "example.com", "ttl": 300 },
{ "type": "MX", "name": "example.com", "content": "mail.example.com", "ttl": 3600 }
],
"wafRuleCreated": true
}
5.2 ユースケース2:新プロジェクトの包括的設計(ゼロからのアーキテクチャ設計)
問題背景:
ゼロからNext.jsフルスタックアプリケーションを構築したい。必要なもの:
- プロジェクトの雛形(フォルダ構造、設定ファイル)
- DBスキーマ(PostgreSQL)
- APIルート設計
- 基本的な認証システム
以前はAIに「まずフォルダを作成して、次に設定ファイルを書いて、次にスキーマを書いて...」と段階的に指示する必要があった。Code Modeなら、1つのスクリプトですべての初期化を完了できる。
MCPの選択: elusznik/mcp-server-code-execution-mode(ローカル実行、ファイルシステムへのアクセス可)
完全な操作手順:
# ステップ1:MCPをインストール
uv tool install mcp-server-code-execution-mode
# ステップ2:Claude Codeに登録
claude mcp add "code-exec" -- mcp-server-code-execution-mode
# ステップ3:空のプロジェクトディレクトリを作成
mkdir my-nextjs-app && cd my-nextjs-app
プロンプト例:
Next.js 15フルスタックアプリケーションを構築したいです。機能は:
- ユーザー認証(email + password)
- PostgreSQLデータベース(Drizzle ORM使用)
- APIルート(RESTfulスタイル)
execute_codeを使って以下の作業を一度に完了するスクリプトを書いてください:
1. 完全なフォルダ構造を生成
2. すべての設定ファイルを書き込む(tsconfig、next.config、drizzle.config)
3. DBスキーマ定義ファイルを作成
4. 基本的な認証APIルートを作成
5. 作成したすべてのファイルのリストを表示
AIが生成するコード例:
import os
import json
PROJECT_ROOT = "/workspace/my-nextjs-app"
# フォルダ構造を定義
dirs = [
"src/app/api/auth/login",
"src/app/api/auth/register",
"src/app/api/auth/logout",
"src/app/(dashboard)",
"src/components/ui",
"src/lib",
"src/db",
"public",
]
for d in dirs:
os.makedirs(os.path.join(PROJECT_ROOT, d), exist_ok=True)
# package.jsonを書き込む
package_json = {
"name": "my-nextjs-app",
"version": "0.1.0",
"private": True,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate"
},
"dependencies": {
"next": "^15.0.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"drizzle-orm": "^0.35.0",
"postgres": "^3.4.0",
"bcrypt": "^5.1.0"
},
"devDependencies": {
"typescript": "^5.6.0",
"drizzle-kit": "^0.26.0",
"@types/node": "^22.0.0",
"@types/react": "^19.0.0"
}
}
with open(os.path.join(PROJECT_ROOT, "package.json"), "w") as f:
json.dump(package_json, f, indent=2)
# DBスキーマを書き込む
schema_content = '''import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
export const users = pgTable("users", {
id: uuid("id").primaryKey().defaultRandom(),
email: text("email").notNull().unique(),
passwordHash: text("password_hash").notNull(),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
});
export const sessions = pgTable("sessions", {
id: uuid("id").primaryKey().defaultRandom(),
userId: uuid("user_id").references(() => users.id).notNull(),
expiresAt: timestamp("expires_at").notNull(),
createdAt: timestamp("created_at").defaultNow().notNull(),
});
'''
with open(os.path.join(PROJECT_ROOT, "src/db/schema.ts"), "w") as f:
f.write(schema_content)
# 作成したすべてのファイルを一覧表示
created_files = []
for root, dirs_list, files in os.walk(PROJECT_ROOT):
for file in files:
rel_path = os.path.relpath(os.path.join(root, file), PROJECT_ROOT)
created_files.append(rel_path)
print(f"{len(created_files)}件のファイルを作成しました:")
for f in sorted(created_files):
print(f" - {f}")
期待される出力:
8件のファイルを作成しました:
- drizzle.config.ts
- next.config.ts
- package.json
- src/app/api/auth/login/route.ts
- src/app/api/auth/register/route.ts
- src/db/index.ts
- src/db/schema.ts
- tsconfig.json
5.3 ユースケース3:ローカル大規模プロジェクトのリファクタリング(数万行コードのバッチ変更)
問題背景:
200個のTypeScriptファイルを含むプロジェクトがあり、以下が必要だ:
moment.jsの使用箇所をすべてdayjsに置き換える- すべてのimport文を更新する
- 日付フォーマットのAPI差異を調整する
- 変更がTypeScriptのコンパイルを壊していないことを確認する
従来のAIでは各ファイルを逐一読んで、使用方法を理解し、変更を提案する必要があった——ファイルを読むだけで数十万トークンが必要だ。
MCPの選択: elusznik/mcp-server-code-execution-mode(ローカル実行、ファイルシステムに直接アクセス、Pythonスクリプトをサポート)
完全な操作手順:
# ステップ1:MCPが登録済みであることを確認
claude mcp list # code-execが表示されるはず
# ステップ2:プロジェクトディレクトリでClaude Codeを起動
cd /path/to/your/project
claude
プロンプト例:
このプロジェクトは現在moment.jsを使っていますが、すべてdayjsに移行したいです。
execute_codeを使って以下を完了するPythonスクリプトを書いてください:
1. すべての.tsと.tsxファイルをスキャンして、momentを使用している箇所を見つける
2. import moment from 'moment'をimport dayjs from 'dayjs'に変更する
3. moment()の呼び出しをdayjs()に変更する
4. .format('YYYY-MM-DD')などはそのまま保持する(dayjsの形式も同じ)
5. .toISOString()はそのまま保持する
6. .diff()の使用方法をdayjsの.diff()に変換する
7. 変更したファイルとそれぞれの変更数を出力する
AIが生成するコード例:
import os
import re
from pathlib import Path
PROJECT_ROOT = "/workspace/project"
EXTENSIONS = {".ts", ".tsx"}
# 置換ルール
replacements = [
# import文
(r"import\s+moment\s+from\s+['\"]moment['\"]", "import dayjs from 'dayjs'"),
(r"import\s+\*\s+as\s+moment\s+from\s+['\"]moment['\"]", "import dayjs from 'dayjs'"),
(r"const\s+moment\s*=\s*require\s*\(\s*['\"]moment['\"]\s*\)", "import dayjs from 'dayjs'"),
# 関数呼び出し
(r"\bmoment\(\)", "dayjs()"),
(r"\bmoment\(([^)]+)\)", r"dayjs(\1)"),
# 型
(r"\bmoment\.Moment\b", "dayjs.Dayjs"),
(r"\bMoment\b(?=\s*[;,\)\]\}>])", "Dayjs"),
]
results = []
for root, _, files in os.walk(PROJECT_ROOT):
# node_modulesをスキップ
if "node_modules" in root:
continue
for fname in files:
fpath = Path(root) / fname
if fpath.suffix not in EXTENSIONS:
continue
with open(fpath, "r", encoding="utf-8") as f:
original = f.read()
modified = original
change_count = 0
for pattern, replacement in replacements:
new_content, count = re.subn(pattern, replacement, modified)
change_count += count
modified = new_content
if change_count > 0:
with open(fpath, "w", encoding="utf-8") as f:
f.write(modified)
rel_path = os.path.relpath(fpath, PROJECT_ROOT)
results.append({"file": rel_path, "changes": change_count})
print(f"\n===== リファクタリング完了 =====")
print(f"計{len(results)}ファイル、{sum(r['changes'] for r in results)}箇所を変更\n")
for r in sorted(results, key=lambda x: -x["changes"]):
print(f" [{r['changes']:3d}箇所] {r['file']}")
期待される出力:
===== リファクタリング完了 =====
計47ファイル、182箇所を変更
[ 12箇所] src/utils/date-helpers.ts
[ 8箇所] src/components/DatePicker.tsx
[ 7箇所] src/pages/dashboard/analytics.tsx
[ 6箇所] src/services/scheduler.ts
[ 5箇所] src/hooks/useTimer.ts
...
AIのトークン消費: スクリプト作成約500トークン + 結果読み取り約300トークン = 約800トークンで47ファイルのリファクタリングを完了。従来の方法では50,000+トークンが必要だった。
5.4 ユースケース4:ウェブスクレイピング(静的ページ + JavaScript レンダリングページ)
問題背景:
技術系ニュースサイトからタイトル、リンク、概要をバッチ収集して、毎日のニュースダイジェストを作りたい。対象:
- Hacker News(静的HTML)
- TechCrunch(JavaScriptレンダリングが必要なSPA)
MCPの選択: elusznik/mcp-server-code-execution-mode(ネットワークアクセスを有効にすれば外部ウェブページをスクレイピングできる)
完全な操作手順:
# ステップ1:MCPが登録済みでネットワークが許可されていることを確認
# elusznikの設定でネットワークアクセスを有効化
claude mcp add "code-exec" -- mcp-server-code-execution-mode --allow-network
プロンプト例(静的ページ):
execute_codeを使ってHacker Newsのトップページから上位30件の記事を
スクレイピングして、タイトル、リンク、スコアをJSON形式で返してください。
AIが生成するコード例(静的ページ):
import requests
from bs4 import BeautifulSoup
import json
resp = requests.get("https://news.ycombinator.com", timeout=10)
soup = BeautifulSoup(resp.text, "html.parser")
articles = []
rows = soup.select("tr.athing")
for row in rows[:30]:
title_el = row.select_one(".titleline > a")
score_row = row.find_next_sibling("tr")
score_el = score_row.select_one(".score") if score_row else None
if title_el:
articles.append({
"rank": len(articles) + 1,
"title": title_el.text.strip(),
"link": title_el.get("href", ""),
"score": int(score_el.text.split()[0]) if score_el else 0
})
print(json.dumps(articles[:10], ensure_ascii=False, indent=2))
print(f"\n... 計{len(articles)}件の記事")
期待される出力:
[
{
"rank": 1,
"title": "Show HN: I built a local-first spreadsheet engine in Rust",
"link": "https://github.com/example/spreadsheet-rs",
"score": 342
},
{
"rank": 2,
"title": "Why SQLite is the most deployed database",
"link": "https://sqlite.org/mostdeployed.html",
"score": 289
}
]
... 計30件の記事
プロンプト例(JavaScriptレンダリングページ):
TechCrunchはSPAなので、JavaScriptのレンダリングが必要です。
execute_codeでplaywrightを使ってTechCrunchのトップページから最新10件の記事をスクレイピングしてください。
AIが生成するコード例(JSレンダリングページ):
import asyncio
from playwright.async_api import async_playwright
import json
async def scrape_techcrunch():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
await page.goto("https://techcrunch.com", wait_until="networkidle")
articles = await page.evaluate('''
() => {
const items = document.querySelectorAll("article.post-block");
return Array.from(items).slice(0, 10).map(item => ({
title: item.querySelector("h2")?.textContent?.trim() || "",
link: item.querySelector("h2 a")?.href || "",
excerpt: item.querySelector(".post-block__content")?.textContent?.trim() || "",
author: item.querySelector(".river-byline__authors")?.textContent?.trim() || "",
}));
}
''')
await browser.close()
return articles
articles = asyncio.run(scrape_techcrunch())
print(json.dumps(articles, ensure_ascii=False, indent=2))
トークン消費の比較:
| 方法 | トークン消費 | 処理時間 |
|---|
| 従来のfetch + AIがHTMLを解析 | ~125,000トークン | 遅い(AIがHTMLを読む) |
| Code Modeスクリプト | ~600トークン | 非常に速い(サンドボックスがHTMLを処理) |
5.5 ユースケース5:データ処理(1GB CSVのクリーニングと統計分析)
問題背景:
1GBのEC取引記録CSVファイルがあり、以下が必要だ:
- データクリーニング(空値の削除、フォーマットの修正)
- 月別売上の集計
- Top 10人気商品を見つける
- サマリーレポートを出力する
1GBのCSVをAIのコンテキストに入れるのは完全に不可能だ。
MCPの選択: elusznik/mcp-server-code-execution-mode(ローカル実行、大きなファイルを直接読み取れる)
プロンプト例:
大きなCSVファイル /data/transactions.csv(約1GB)があります。
カラムは:date, product_id, product_name, quantity, unit_price, customer_id
execute_codeを使ってPythonスクリプトを書いてください:
1. データを読み込んでクリーニング(空値行の削除、日付フォーマットの修正)
2. 月別売上合計を計算
3. Top 10人気商品を見つける(総売上高でソート)
4. 基本統計情報を計算(総注文数、総売上高、平均注文単価)
5. 構造化されたJSON形式でサマリーを出力
AIが生成するコード例:
import pandas as pd
import json
from datetime import datetime
# 大きなファイルをチャンクで読み込む(メモリ枯渇を防ぐ)
chunks = pd.read_csv(
"/data/transactions.csv",
chunksize=100_000,
parse_dates=["date"],
dtype={"product_id": str, "customer_id": str}
)
# 集計用コンテナを初期化
monthly_revenue = {}
product_sales = {}
total_orders = 0
total_revenue = 0.0
valid_rows = 0
invalid_rows = 0
for chunk in chunks:
# クリーニング:空値を削除
before = len(chunk)
chunk = chunk.dropna(subset=["date", "product_id", "quantity", "unit_price"])
invalid_rows += before - len(chunk)
valid_rows += len(chunk)
# 各取引の金額を計算
chunk["amount"] = chunk["quantity"] * chunk["unit_price"]
# 月別売上
chunk["month"] = chunk["date"].dt.to_period("M").astype(str)
for month, group in chunk.groupby("month"):
monthly_revenue[month] = monthly_revenue.get(month, 0) + group["amount"].sum()
# 商品別売上
for _, row in chunk[["product_id", "product_name", "amount"]].iterrows():
pid = row["product_id"]
if pid not in product_sales:
product_sales[pid] = {"name": row["product_name"], "total": 0}
product_sales[pid]["total"] += row["amount"]
total_orders += len(chunk)
total_revenue += chunk["amount"].sum()
# Top 10人気商品
top10 = sorted(product_sales.items(), key=lambda x: -x[1]["total"])[:10]
# レポートを組み立てる
report = {
"summary": {
"total_orders": total_orders,
"valid_rows": valid_rows,
"invalid_rows_removed": invalid_rows,
"total_revenue": round(total_revenue, 2),
"avg_order_value": round(total_revenue / total_orders, 2) if total_orders > 0 else 0,
},
"monthly_revenue": dict(sorted(monthly_revenue.items())),
"top10_products": [
{"rank": i + 1, "id": pid, "name": info["name"], "revenue": round(info["total"], 2)}
for i, (pid, info) in enumerate(top10)
]
}
print(json.dumps(report, ensure_ascii=False, indent=2))
期待される出力:
{
"summary": {
"total_orders": 8234567,
"valid_rows": 8201234,
"invalid_rows_removed": 33333,
"total_revenue": 456789012.34,
"avg_order_value": 55.68
},
"monthly_revenue": {
"2025-01": 35678901.23,
"2025-02": 38901234.56,
"2025-03": 42345678.90
},
"top10_products": [
{ "rank": 1, "id": "P001", "name": "ワイヤレスBluetoothイヤホン", "revenue": 12345678.90 },
{ "rank": 2, "id": "P042", "name": "メカニカルキーボード", "revenue": 9876543.21 }
]
}
ポイント: 1GBのCSVはAIのコンテキストに入らない。AIはスクリプトの作成に約800トークン、サマリー結果の読み取りに約500トークンを使うだけだ。
5.6 ユースケース6:自動化ワークフロー(スケジュール + 条件トリガー)
問題背景:
以下の自動化ワークフローを構築したい:
- 毎朝9時にGitHubのopen issueを確認する
- 7日以上返答がないissueがあれば、自動的に
staleタグを付ける - 結果のサマリーをSlackに送信する
MCPの選択: jx-codes/codemode-mcp(GitHub MCP + Slack MCPを連携)⚠️ メンテナンス終了、pctxへ移行推薦
完全な操作手順:
# ステップ1:codemode-mcpをインストール(引き続き使用可能だが更新なし)
npm install -g @jx-codes/codemode-mcp
# ステップ2:upstreamサーバーを設定
# codemode.jsonを作成(下記参照)
# ステップ3:Claude Codeに登録
claude mcp add "codemode" -- npx @jx-codes/codemode-mcp --config ./codemode.json
プロンプト例:
execute_codeを使って以下のワークフローを完了するスクリプトを書いてください:
1. GitHub APIを使ってyelban/my-projectのすべてのopen issueを確認
2. 7日以上新しいコメントがないissueを見つける
3. これらのissueに"stale"タグを付ける
4. サマリーメッセージを組み立てる
5. Slackの#dev-alertsチャンネルにサマリーを送信
AIが生成するコード例:
import { Octokit } from "@octokit/rest";
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
const REPO_OWNER = "yelban";
const REPO_NAME = "my-project";
const STALE_DAYS = 7;
// 1. すべてのopen issueを確認
const { data: issues } = await octokit.issues.listForRepo({
owner: REPO_OWNER,
repo: REPO_NAME,
state: "open",
per_page: 100,
});
// 2. 7日以上返答がないものを見つける
const now = new Date();
const staleIssues = issues.filter(issue => {
const lastActivity = new Date(issue.updated_at);
const daysSince = (now.getTime() - lastActivity.getTime()) / (1000 * 60 * 60 * 24);
return daysSince > STALE_DAYS && !issue.labels.some(l => l.name === "stale");
});
// 3. staleタグを付ける
for (const issue of staleIssues) {
await octokit.issues.addLabels({
owner: REPO_OWNER,
repo: REPO_NAME,
issue_number: issue.number,
labels: ["stale"],
});
}
// 4. Slackメッセージを組み立てる
const summary = {
text: `🔔 Stale Issues レポート`,
blocks: [
{
type: "section",
text: {
type: "mrkdwn",
text: `*計${staleIssues.length}件のissueがstaleとしてマークされました*\n\n` +
staleIssues.map(i =>
`• <${i.html_url}|#${i.number}> ${i.title} (${Math.floor((now.getTime() - new Date(i.updated_at).getTime()) / 86400000)}日未更新)`
).join("\n")
}
}
]
};
// 5. Slackに送信
const slackResp = await fetch(process.env.SLACK_WEBHOOK_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(summary),
});
console.log(JSON.stringify({
totalOpen: issues.length,
newlyStale: staleIssues.length,
slackSent: slackResp.ok,
}, null, 2));
期待される出力:
{
"totalOpen": 23,
"newlyStale": 5,
"slackSent": true
}
5.7 ユースケース7:複雑なクロスサービス自動化オーケストレーション(GitHub + DB + Slack連携)
問題背景:
あなたは技術リードで、毎週開発進捗レポートが必要だ。内容は:
- 今週マージされたPRのリスト(GitHubから)
- 各PRに対応するJiraチケットの状態(データベースから)
- 開発者のコードレビュー統計
- Slackの#weekly-reportチャンネルにレポートを送信
従来の方法:AIがGitHub API、DBクエリ、Slack APIを別々に呼び出す。各ステップで1回のツール呼び出し。途中でエラーが発生したり、中間結果でコンテキストが埋まったりしやすい。
MCPの選択: jx-codes/codemode-mcp(中央プロキシ、GitHub + PostgreSQL + Slackを連携)⚠️ メンテナンス終了、pctxへ移行推薦
プロンプト例:
execute_codeを使って今週の開発進捗レポートを生成してください:
1. GitHub APIからyelban/main-projectの今週マージされたPRを取得
2. PostgreSQLのjira_ticketsテーブルで各PRに対応するチケットの状態を比較
3. 各開発者のPR数とレビュー数を集計
4. レポートをフォーマットしてSlack #weekly-reportに送信
AIが生成するコード例:
import os
import json
import requests
from datetime import datetime, timedelta
import psycopg2
# === 1. GitHub:今週マージされたPRを取得 ===
GITHUB_TOKEN = os.environ["GITHUB_TOKEN"]
headers = {"Authorization": f"token {GITHUB_TOKEN}"}
one_week_ago = (datetime.now() - timedelta(days=7)).isoformat()
url = "https://api.github.com/repos/yelban/main-project/pulls"
params = {"state": "closed", "sort": "updated", "direction": "desc", "per_page": 100}
resp = requests.get(url, headers=headers, params=params)
all_prs = resp.json()
# 今週マージされたもののみ保持
merged_prs = [
pr for pr in all_prs
if pr.get("merged_at") and pr["merged_at"] >= one_week_ago
]
# === 2. PostgreSQL:JiraチケットStatus比較 ===
conn = psycopg2.connect(os.environ["DATABASE_URL"])
cur = conn.cursor()
pr_tickets = []
for pr in merged_prs:
# PRタイトルまたはブランチからチケットIDを抽出(例:PROJ-123)
import re
match = re.search(r"(PROJ-\d+)", pr["title"] + " " + (pr["head"]["ref"] or ""))
ticket_id = match.group(1) if match else None
ticket_status = None
if ticket_id:
cur.execute("SELECT status FROM jira_tickets WHERE ticket_id = %s", (ticket_id,))
row = cur.fetchone()
ticket_status = row[0] if row else "NOT_FOUND"
pr_tickets.append({
"pr_number": pr["number"],
"title": pr["title"],
"author": pr["user"]["login"],
"merged_at": pr["merged_at"],
"ticket_id": ticket_id,
"ticket_status": ticket_status,
})
cur.close()
conn.close()
# === 3. 各開発者を集計 ===
dev_stats = {}
for pr in pr_tickets:
author = pr["author"]
if author not in dev_stats:
dev_stats[author] = {"prs_merged": 0, "tickets": []}
dev_stats[author]["prs_merged"] += 1
if pr["ticket_id"]:
dev_stats[author]["tickets"].append(pr["ticket_id"])
# === 4. Slackレポートを組み立てて送信 ===
report_lines = [f"📊 *今週の開発進捗レポート* ({one_week_ago[:10]} ~ {datetime.now().strftime('%Y-%m-%d')})\n"]
report_lines.append(f"*マージされたPR数:{len(merged_prs)}*\n")
report_lines.append("*各開発者の統計:*")
for dev, stats in sorted(dev_stats.items(), key=lambda x: -x[1]["prs_merged"]):
report_lines.append(f" • {dev}: {stats['prs_merged']} PRs, tickets: {', '.join(stats['tickets']) or 'N/A'}")
report_lines.append("\n*PR詳細リスト:*")
for pr in pr_tickets:
status_emoji = "✅" if pr["ticket_status"] == "Done" else "🔄" if pr["ticket_status"] else "❓"
report_lines.append(
f" {status_emoji} #{pr['pr_number']} {pr['title']} (@{pr['author']}) [{pr['ticket_id'] or 'no ticket'}]"
)
slack_payload = {
"channel": "#weekly-report",
"text": "\n".join(report_lines),
}
slack_resp = requests.post(
os.environ["SLACK_WEBHOOK_URL"],
json=slack_payload,
timeout=10,
)
print(json.dumps({
"prs_merged": len(merged_prs),
"developers": len(dev_stats),
"slack_sent": slack_resp.ok,
"report_preview": "\n".join(report_lines[:10]) + "\n..."
}, ensure_ascii=False, indent=2))
期待される出力:
{
"prs_merged": 12,
"developers": 4,
"slack_sent": true,
"report_preview": "📊 *今週の開発進捗レポート* (2026-02-14 ~ 2026-02-21)\n\n*マージされたPR数:12*\n\n*各開発者の統計:*\n • alice: 5 PRs, tickets: PROJ-234, PROJ-238, PROJ-241\n • bob: 4 PRs, tickets: PROJ-235, PROJ-239\n • charlie: 2 PRs, tickets: PROJ-237\n • diana: 1 PRs, tickets: PROJ-240\n..."
}
トークン消費: スクリプト作成~800トークン + 結果~400トークン = 約1,200トークンで3システムをまたぐ自動化を完了。従来の方法では20+ターンの対話、30,000+トークンが必要だった。
5.8 ユースケース8:クロスシステム統合(API + ローカルファイル + 外部サービスを一括完了)
問題背景:
完全なデプロイ前チェックフローを完成させる必要がある:
- ローカルの
package.jsonを読んでバージョン番号を確認 - GitHubにマージされていないPRがないか確認
- ローカルのテストスイートを実行
- すべて通過したら、CloudflareのDNSを新しいデプロイIPに向ける
- 結果通知を送信
MCPの選択: elusznik/mcp-server-code-execution-mode(ローカル実行、ファイルシステム + ネットワークへのアクセス可)
プロンプト例:
execute_codeを使ってデプロイ前チェックスクリプトを書いてください:
1. ローカルの/project/package.jsonからバージョン番号を読み取る
2. GitHub APIを呼び出してmainブランチにpending PRがないか確認
3. npm testを実行して結果をキャプチャ
4. すべて通過したら、Cloudflare APIを使ってapp.example.comのAレコードを203.0.113.50に更新
5. 完全なチェックレポートを出力
AIが生成するコード例:
import json
import subprocess
import os
import requests
report = {"checks": [], "passed": True, "version": None}
# === 1. package.jsonを読み取る ===
try:
with open("/project/package.json", "r") as f:
pkg = json.load(f)
report["version"] = pkg["version"]
report["checks"].append({"name": "バージョン番号の読み取り", "status": "PASS", "detail": f"v{pkg['version']}"})
except Exception as e:
report["checks"].append({"name": "バージョン番号の読み取り", "status": "FAIL", "detail": str(e)})
report["passed"] = False
# === 2. GitHub pending PRを確認 ===
try:
gh_headers = {"Authorization": f"token {os.environ['GITHUB_TOKEN']}"}
resp = requests.get(
"https://api.github.com/repos/yelban/project/pulls",
headers=gh_headers,
params={"state": "open", "base": "main"},
)
open_prs = resp.json()
if len(open_prs) > 0:
pr_list = [f"#{pr['number']}: {pr['title']}" for pr in open_prs[:5]]
report["checks"].append({
"name": "Pending PR確認",
"status": "WARN",
"detail": f"{len(open_prs)}件のマージされていないPR: {', '.join(pr_list)}"
})
else:
report["checks"].append({"name": "Pending PR確認", "status": "PASS", "detail": "pending PRなし"})
except Exception as e:
report["checks"].append({"name": "Pending PR確認", "status": "FAIL", "detail": str(e)})
# === 3. テストを実行 ===
try:
result = subprocess.run(
["npm", "test", "--", "--reporter=json"],
cwd="/project",
capture_output=True,
text=True,
timeout=300,
)
if result.returncode == 0:
report["checks"].append({"name": "テストスイート", "status": "PASS", "detail": "すべてのテストが通過"})
else:
report["checks"].append({"name": "テストスイート", "status": "FAIL", "detail": result.stderr[:500]})
report["passed"] = False
except Exception as e:
report["checks"].append({"name": "テストスイート", "status": "FAIL", "detail": str(e)})
report["passed"] = False
# === 4. Cloudflare DNSを更新(すべて通過した場合のみ) ===
if report["passed"]:
try:
cf_headers = {
"Authorization": f"Bearer {os.environ['CF_API_TOKEN']}",
"Content-Type": "application/json",
}
# zoneを見つける
zones_resp = requests.get(
"https://api.cloudflare.com/client/v4/zones",
headers=cf_headers,
params={"name": "example.com"},
)
zone_id = zones_resp.json()["result"][0]["id"]
# DNSレコードを見つける
dns_resp = requests.get(
f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records",
headers=cf_headers,
params={"name": "app.example.com", "type": "A"},
)
record_id = dns_resp.json()["result"][0]["id"]
# 更新
update_resp = requests.put(
f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records/{record_id}",
headers=cf_headers,
json={"type": "A", "name": "app.example.com", "content": "203.0.113.50", "ttl": 300},
)
report["checks"].append({
"name": "DNS更新",
"status": "PASS" if update_resp.json()["success"] else "FAIL",
"detail": "app.example.com → 203.0.113.50"
})
except Exception as e:
report["checks"].append({"name": "DNS更新", "status": "FAIL", "detail": str(e)})
else:
report["checks"].append({"name": "DNS更新", "status": "SKIP", "detail": "前のチェックが失敗したためスキップ"})
# === 5. レポートを出力 ===
print(json.dumps(report, ensure_ascii=False, indent=2))
期待される出力:
{
"checks": [
{ "name": "バージョン番号の読み取り", "status": "PASS", "detail": "v2.3.1" },
{ "name": "Pending PR確認", "status": "PASS", "detail": "pending PRなし" },
{ "name": "テストスイート", "status": "PASS", "detail": "すべてのテストが通過" },
{ "name": "DNS更新", "status": "PASS", "detail": "app.example.com → 203.0.113.50" }
],
"passed": true,
"version": "2.3.1"
}
6. 推薦オープンソース Code Mode サーバー選定ガイド
6.1 選定デシジョンツリー(要件に合わせて素早く選択)
flowchart TD
Q{"Code Modeで<br/>何をしたい?"}
Q -->|Cloudflareを操作| CF["cloudflare/mcp<br/>(公式、設定ゼロ)"]
Q -->|Replicateモデルを操作| RP["replicate/<br/>replicate-mcp-code-mode"]
Q -->|ローカル開発| LOCAL{"どの言語が必要?"}
Q -->|ウェブスクレイピング| CRAWL{"ページの種類は?"}
Q -->|複数MCP統合| MULTI{"好みは?"}
Q -->|カスタムMCPをCode Modeに変換| ZB["zbowling/mcpcodeserver<br/>⚠️ 非アクティブ"]
LOCAL -->|Pythonエコシステム| EL["elusznik/<br/>mcp-server-code-execution-mode<br/>⭐ 推薦"]
LOCAL -->|JS / TS| OV["dmmulroy/overseer"]
MULTI -->|"オープンソース model-agnostic"| PCTX["portofcontext/pctx<br/>🆕 推薦"]
MULTI -->|"Legacy"| JX["jx-codes/codemode-mcp<br/>⚠️ メンテナンス終了"]
CRAWL -->|静的ページ| EL2["elusznik(ネットワーク有効化)"]
CRAWL -->|JSレンダリングページ| EL3["elusznik + Playwright"]
style Q fill:#e94560,stroke:#fff,color:#fff
style LOCAL fill:#0f3460,stroke:#5dade2,color:#fff
style CRAWL fill:#0f3460,stroke:#5dade2,color:#fff
style MULTI fill:#0f3460,stroke:#5dade2,color:#fff
style EL fill:#1a5c2a,stroke:#2ecc71,color:#fff
style PCTX fill:#1a5c2a,stroke:#2ecc71,color:#fff
6.2 各サーバーの詳細比較表(インストールコマンド、ユースケース、セキュリティ、難易度評価含む)
| 項目 | cloudflare/mcp | elusznik | pctx 🆕 | overseer 🆕 | codemode-mcp | zbowling | replicate |
|---|
| 状態 | ✅ 活発(3.4K⭐) | ⚠️ 低速メンテナンス(307⭐) | ✅ 活発(201⭐) | ✅ 活発(199⭐) | ❌ メンテナンス終了(107⭐) | ❌ 非アクティブ(12⭐) | ❌ 非アクティブ(3⭐) |
| 言語 | TypeScript | Python | Rust + Python SDK | TypeScript | JS/Deno | TypeScript | JS |
| 実行環境 | Cloudflare Workers (V8) | Docker/Podmanコンテナ | Denoサンドボックス(10秒タイムアウト) | Node.js | Denoサンドボックス | Node.js | Node.js |
| セキュリティ隔離 | V8 Isolate + OAuth 2.1 | Rootlessコンテナ(Podman推薦) | Denoサンドボックス + ネットワークをMCPホストに限定 | — | 30秒タイムアウト + ネットワーク制限 | TS変換隔離 | SDKレベル |
| トークン節約率 | 99.9% | ~99% | 高 | 高 | 90%+ | 60-90% | 高 |
| ローカルファイルへのアクセス | 不可 | 可(volumeのマウント) | 設定次第 | 可 | 制限あり | 制限あり | 不可 |
| ネットワーク許可 | CloudflareのAPIのみ | 設定可 | 設定可 | 設定可 | デフォルト無効 | 設定次第 | ReplicateのAPIのみ |
| 特色 | 公式、設定ゼロ | セキュリティ最高、macOS対応 | Model-agnostic、複数MCP統合、Python SDK | Agentタスク管理 | Legacy、lootboxへ移行 | MCPコンバーター | Replicate専用 |
| インストール難易度 | ⭐ 低 | ⭐⭐ 中 | ⭐⭐ 中 | ⭐ 低 | ⭐ 低 | ⭐ 低 | ⭐⭐ 中 |
インストールコマンド早見表:
# cloudflare/mcp(公式)
claude mcp add --transport http cloudflare https://mcp.cloudflare.com/mcp
# elusznik/mcp-server-code-execution-mode(⚠️ PyPI未公開、uvxを使用)
# 前提:brew install podman && podman machine init && podman machine start
uvx --from git+https://github.com/elusznik/mcp-server-code-execution-mode mcp-server-code-execution-mode run
# portofcontext/pctx 🆕
brew install portofcontext/tap/pctx
pctx mcp init && pctx mcp add stripe https://mcp.stripe.com
claude mcp add pctx --scope user -- pctx mcp start --stdio
# Python SDK: pip install pctx-client
# jx-codes/codemode-mcp(⚠️ メンテナンス終了 → lootbox)
npm install -g @jx-codes/codemode-mcp
claude mcp add "codemode" -- npx @jx-codes/codemode-mcp --config ./codemode.json
# zbowling/mcpcodeserver
claude mcp add "codeserver" -- npx mcpcodeserver
# replicate/replicate-mcp-code-mode
claude mcp add "replicate-code-mode" -- npx -y replicate-mcp@alpha --tools=code
6.3 複数MCP連携アーキテクチャ図
シングルMCPモード(最もシンプル):
flowchart TD
IDE["🖥️ Claude Code / Cursor"] --> MCP["📡 Code Mode MCP Server<br/>(cloudflare/mcp)"]
MCP --> API["☁️ 対象サービスAPI<br/>(Cloudflare)"]
style IDE fill:#16213e,stroke:#5dade2,color:#e0e0e0
style MCP fill:#0f3460,stroke:#5dade2,color:#e0e0e0
style API fill:#1a5c2a,stroke:#2ecc71,color:#e0e0e0
プロキシモード(複数サービスを統合):
flowchart TD
IDE["🖥️ Claude Code / Cursor"] --> PROXY["🔀 Code Mode Proxy<br/>(pctx / codemode-mcp)"]
PROXY --> FS["📁 Upstream 1<br/>filesystem(ローカルファイル)"]
PROXY --> GH["🐙 Upstream 2<br/>GitHub(コード管理)"]
PROXY --> PG["🗄️ Upstream 3<br/>PostgreSQL(データベース)"]
PROXY --> SL["💬 Upstream 4<br/>Slack(通知)"]
style IDE fill:#16213e,stroke:#5dade2,color:#e0e0e0
style PROXY fill:#e94560,stroke:#fff,color:#fff
AIはexecute_codeツール1つだけを見るが、プロキシを通じてすべての下層MCPサーバーを操作できる。プロキシが担うのは:
- コードを正しいupstreamにルーティング
- 権限とセキュリティ隔離を管理
- 結果を集約して返す
ハイブリッドモード(ローカル + クラウド):
flowchart TD
IDE["🖥️ Claude Code / Cursor"] --> CF["☁️ cloudflare/mcp<br/>(クラウドAPI、直接接続)"]
IDE --> EL["🔒 elusznik<br/>(ローカルサンドボックス)"]
EL --> FS["📁 ローカルファイルシステム"]
EL --> GIT["🔀 ローカルGit"]
EL --> TEST["🧪 ローカルテストスイート"]
style IDE fill:#16213e,stroke:#5dade2,color:#e0e0e0
style CF fill:#1a5c2a,stroke:#2ecc71,color:#e0e0e0
style EL fill:#0f3460,stroke:#5dade2,color:#e0e0e0
複数のCode Mode MCPを同時に登録でき、AIはタスクに応じて自分で選択する。
参考資料
| ソース | リンク |
|---|
| Cloudflare公式ブログ:Code Mode | https://blog.cloudflare.com/code-mode-mcp/ |
| Cloudflare MCP Serverソースコード | https://github.com/cloudflare/mcp |
@cloudflare/codemode SDKドキュメント | https://developers.cloudflare.com/agents/api-reference/codemode/ |
| Anthropicエンジニアリングブログ:Code execution with MCP | https://www.anthropic.com/engineering/code-execution-with-mcp |
| portofcontext/pctx(オープンソース Code Modeフレームワーク)🆕 | https://github.com/portofcontext/pctx |
| dmmulroy/overseer(Agentタスク管理)🆕 | https://github.com/dmmulroy/overseer |
| elusznik/mcp-server-code-execution-mode | https://github.com/elusznik/mcp-server-code-execution-mode |
| jx-codes/codemode-mcp(⚠️ メンテナンス終了 → lootbox) | https://github.com/jx-codes/codemode-mcp |
| jx-codes/lootbox(codemode-mcpの後継) | https://github.com/jx-codes/lootbox |
| Claude Code MCPドキュメント | https://code.claude.com/docs/en/mcp |
| Awesome MCP Serversリスト | https://github.com/wong2/awesome-mcp-servers |
全6章:原理、4プラットフォームの設定、8つの実践ユースケース、5つのオープンソースサーバー選定。