脱・MCP幻想:なぜトップ開発者はCLIとコード実行に回帰するのか?2つのツールの使い分けとは
はじめに:MCPの「違和感」とCLI、スクリプトへの回帰
2024年の終わり頃、AIエージェント開発の世界に彗星の如く現れた「MCP(Model Context Protocol)」。このオープンスタンダードは、Anthropic社によって提唱され、「AIエージェントと外部ツールを接続する銀の弾丸」として、技術コミュニティから大きな期待を寄せられました。
「APIごとのカスタム統合が不要になる」「MCPサーバーを立てれば、どんなツールも容易に接続できる」といった期待感は、自律型エージェントの実現が目前に迫っているかのような熱狂を生み出しました。
しかし、それから約一年。実際にプロダクション環境でMCPと向き合ってきた開発者たちの間から、少しずつ、しかし確実に、ある種の「違和感」が表明されるようになりました。
- 「想定以上にトークンを消費するのではないか?」
- 「単純なタスクにもかかわらず、応答が遅い場合がある」
- 「より複雑な処理を実行させたいが、ツール定義の制約が逆に不自由さを生んでいる」
Hacker Newsのスレッドや開発者ブログでは、こうした声が散見されるようになりました。そして、その流れを決定づけたのが、2025年11月にAnthropic自身が発表した「Code execution with MCP」という画期的な記事でした。
この記事が提示したのは、「MCPに比べてコード実行は98.7%も効率的である」 という、これまでの常識を覆す事実です。それは、多くの開発者が抱いていた「違和感」の正体を、明確に言語化するものでした。
本記事は、単なる技術トレンドの解説に留まりません。
開発者の皆様が「明日からの開発」や「同僚との技術的な議論」において、自信を持ってMCPとCLI、スクリプトについて語れるようになるための、実践的なガイドとなることを目指します!
なぜ開発者たちはMCPの限界に直面し、そして今、古き良きCLIとスクリプトの世界に回帰しようとしているのか。その本質に迫っていきます。
目次
第1章:MCPの光と影 – 人々の熱狂と課題への直面
まず、誤解のないように強調しておきたいのは、MCPの思想そのものが誤っていたわけではないということです。
乱立するAPIの仕様を統一し、エージェントによるツールの発見と利用を容易にするという功績は非常に大きいものでした。
しかし、理想と現実は異なります。特に、プロダクションレベルの複雑なタスクを処理しようとした際、MCPの「隠れたコスト」が顕在化し始めました。
隠れたコスト①:トークンの大量消費とコストの問題
これが最大の課題でした。MCPの基本的な仕組みは、エージェントが利用可能な「すべてのツール定義」を、プロンプトの一部としてコンテキストウィンドウに含めるというものです。これが、非効率性を生む根本的な原因となりました。
開発者のマリオ・ゼクナー氏による調査では、驚くべき事実が報告されています。
- Playwright MCPサーバー: 21個のツール定義だけで 13,700トークン
- Chrome DevTools MCPサーバー: 26個のツール定義で 18,000トークン
これは、単一のMCPサーバーを接続するだけで、Claudeの標準コンテキストウィンドウ(200K)の約9%が消費されることを意味します。
複数のサーバー(例: Google Drive, Salesforce, Slack)を接続した場合、コンテキストはツール定義によって急速に圧迫され、エージェントがタスクを遂行するために本当に必要な思考領域が奪われてしまいます。
さらに深刻なのが、中間結果のコンテキスト通過です。
Anthropicが例として挙げた「Google Driveから文字起こしを取得し、Salesforceに要約を添付する」ワークフローを考えてみましょう。
- エージェントが
gdrive.getDocument()を呼び出します。 - 数万トークン にも及ぶ文字起こしの全文が、コンテキストウィンドウに返されます。
- エージェントがその全文を読み込み、要約を生成します。
- エージェントが
salesforce.updateRecord()を呼び出し、要約を引数として渡します。
このプロセスでは、巨大なデータがツール呼び出しのたびにコンテキストウィンドウを往復することになります。Anthropicの記事によれば、このようなワークフローでは 150,000トークン を消費する可能性があると指摘されています。
また、Anthropicの発表を受けて自身のワークフローで検証を行った開発者(Bhavyansh氏)は、コストが $12.47 に達したケースを報告しています。
隠れたコスト②:柔軟性の喪失とエージェントの硬直化
トークンの問題に加え、MCPはエージェントの「自律性」という本来の目的を阻害する可能性も指摘されました。
MCPのツールは、厳密に事前定義されたインターフェースです。エージェントは、その定義に記述された操作しか実行できません。
- 「APIドキュメントにはないが、実際には追加のパラメータを受け付ける」
- 「このツールの出力を、JSONではなくCSV形式で取得したい」
- 「Aツールの出力とBツールの出力を加工して、Cツールに渡したい」
人間であれば柔軟に対応できるこのような状況も、MCPに制約されたエージェントには困難です。
「指示されたツールを、定義通りに呼び出す」ことしかできず、自律的な問題解決能力が制限されてしまうのです。
結論:MCPの適用範囲
もちろん、これはMCPが「失敗」であったことを意味するものではありません。
小規模で、タスクが限定的な環境であれば、MCPは依然として有効なソリューションです。
しかし、エンタープライズレベルの複雑なワークフローを真に自律的に解決しようとした時、MCPの設計思想そのものが制約となることが明らかになったのです。
開発現場が求めていたのは、より自由度が高く、より強力で、開発者のワークフローに親和性の高いアプローチでした。
そしてその答えは、非常に身近な「CLI」と「コード」の世界に見出されました。
次の章では、Anthropic自身が提示した「コード実行」という解決策が、いかにしてこの状況を打開したのか、その核心に迫ります。
第2章:解決策としてのコード実行 – Anthropicが示した「98.7%コスト削減」のインパクト
MCPのトークン効率の問題に直面していた開発コミュニティに対し、一つの光明が差し込みました。
それは、MCPの提唱者であるAnthropic自身が提示した「Code execution with MCP(MCPによるコード実行)」というアプローチです。
その効果は劇的でした。前章で触れた 150,000トークン のワークフローが、このアプローチの採用により、わずか 2,000トークン にまで削減されたのです。これは実に 98.7% ものトークン削減に相当します。
前述のBhavyansh氏の検証によれば、コスト面でも $12.47から$0.16 への削減が確認されています。
この劇的な改善を可能にしたアイデアは、驚くほどシンプルでした。
「LLMにツールを直接呼び出させるのではなく、ツールを呼び出すためのコードを生成させる」
この発想の転換が、すべてを劇的に変えたのです。
発想の転換:ツール呼び出しから「コード生成」へ
従来のMCPアプローチでは、エージェント(LLM)はオーケストレーターの役割を担っていました。ツール定義という楽譜を渡され、どのツールをどの順番で呼び出すかを決定し、その結果はすべてコンテキストウィンドウを経由します。
一方、コード実行アプローチでは、エージェントは作曲家となります。与えられたタスクを解決するための短いプログラム(スクリプト)を生成し、そのプログラムはエージェントの外部にある「実行環境(Sandbox)」で実行されます。エージェントは、実行のすべての詳細を把握する必要はなく、最終的な結果のレポートを受け取るだけで済みます。
Anthropicが示した実装は、利用可能なツールをファイルツリーとして表現するものでした。
servers/
├── google-drive/
│ ├── getDocument.ts
│ └── ...
└── salesforce/
├── updateRecord.ts
└── ...
そして、先のワークフローは、エージェントが生成する以下の短いTypeScriptコードに置き換わります。
// Google Driveから文字起こしを読み込み、Salesforceのリードに追加する
import * as gdrive from './servers/google-drive';
import * as salesforce from './servers/salesforce';
// 1. 巨大な文字起こしデータを取得。このデータはコンテキストには渡されない
const transcript = (await gdrive.getDocument({ documentId: 'abc123' })).content;
// 2. 必要なデータを使ってSalesforceを更新
await salesforce.updateRecord({
objectType: 'SalesMeeting',
recordId: '00Q5f000001abcXYZ',
data: { Notes: transcript }
});
console.log("Salesforceの更新が完了しました。");
このアプローチが劇的な改善をもたらした理由は、MCPが抱えていた問題を的確に解決する、いくつかの重要な利点にあります。
利点①:プログレッシブ・ディスクロージャー(段階的開示)
これがトークン削減の最大の鍵です。エージェントは、すべてのツール定義を事前に読み込む必要がなくなります。
ファイルシステムを探索し(lsコマンドなど)、その時点で必要なツール(.tsファイル)だけを読み込んでインポートします。
これにより、コンテキストにロードされるツール定義のトークン量は、数万から数百へと、桁違いに減少します。
利点②:実行環境内でのデータ処理
これも革命的な点です。
上記のコード例で、transcript変数に格納された数万トークンのデータは、LLMのコンテキストウィンドウを一切通過しません。
データはサンドボックス化された実行環境のメモリ上にのみ存在します。
LLMは、巨大なデータそのものではなく、「transcriptという変数にデータが格納されている」という事実だけを認識し、その変数を次の関数の引数として渡すコードを生成するだけで済みます。
例えば、10,000行のスプレッドシートから特定の条件に合う5行だけが必要な場合、エージェントは以下のようなコードを生成します。
const allRows = await gdrive.getSheet({ sheetId: 'abc123' });
const pendingOrders = allRows.filter(row => row["Status"] === 'pending');
// モデルが受け取るのは、この簡潔なログ出力のみ
console.log(`保留中の注文が ${pendingOrders.length} 件見つかりました。`);
console.log(pendingOrders.slice(0, 5)); // 確認のために最初の5件だけ表示
10,000行のデータがコンテキストを汚染する代わりに、モデルはわずか数行のログを確認するだけでタスクを続行できます。
利点③:強力な制御フローと状態の永続化
プログラミング言語の利用は、if文、forループ、try-catchといった強力な制御フローの活用を可能にします。
- 「デプロイが完了するまで5秒ごとにステータスをチェックする」
- 「API呼び出しが失敗した場合、3回までリトライする」
このような複雑なロジックも、MCPツールを何度も往復させることなく、短いコードで表現できます。
さらに、実行環境のファイルシステム(fsモジュール)を利用すれば、中間結果をファイルに保存し、状態を永続化することも可能です。
const leads = await salesforce.query({ query: 'SELECT Id, Email FROM Lead' });
// 中間結果をCSVとして保存
await fs.writeFile('./workspace/leads.csv', convertToCsv(leads));
これにより、エージェントは長時間のタスクを中断・再開したり、過去の作業結果を再利用したりと、より高度な振る舞いが可能になります。
まとめ:LLMの真の力を解放する
結局のところ、コード実行アプローチが目指すのは、「LLMが最も得意なこと、すなわちコードの生成に集中させる」 という原点回帰です。
LLMは、JSON形式のツール定義を解釈するよりも、膨大な学習データで習得したプログラミング言語を用いて、問題解決の手順を記述する方が遥かに高い能力と表現力を発揮します。
このアプローチは、MCPを完全に否定するものではありません。むしろ、MCPサーバーを「コードから呼び出されるAPI」として再定義することで、MCPのエコシステムを活かしつつ、その最大の欠点であったトークン効率の問題を克服する、洗練された解決策と言えるでしょう。
しかし、議論はここで終わりません。一部の先進的な開発者たちは、さらに一歩先へと進み始めています。「そもそも、MCPという抽象化レイヤー自体が不要なのではないか?」と。次の章では、CLIという、より直接的でパワフルなアプローチの世界を探求します。
第3章:CLIの優位性 – 開発現場のリアルとV字モデルによるツール選択術
Anthropicの「コード実行」アプローチは、MCPが抱える多くの問題を解決しました。
しかし、多くの開発者はこう考えるかもしれません。
「LLMがコードを生成できるのであれば、なにもTypeScriptのファイルツリーに固執する必要はない。よりシンプルで、よりパワフルで、我々が日常的に使用しているツールがあるではないか」と。
それが、CLI(コマンドラインインターフェース)です。
ls, grep, curl, git, docker, kubectl…。これらは、開発を支える、伝統的かつ今なお強力なツール群です。
もしAIエージェントが、これらを人間と同様に使いこなせたらどうなるでしょうか。
この章では、その可能性を探るため、ソフトウェア開発のV字モデルをフレームワークとして用い、MCPとCLI/スクリプトのアプローチが、開発の各フェーズでどのように活用できるかを実践的に比較します。
このパートは、皆様の明日の開発に直接役立つ情報となるでしょう。
MCPという抽象化レイヤーを介さず、開発環境そのものを直接操作できたなら、その可能性は無限に広がります。
V字モデルによるフェーズ別・実践ツール選択術
V字モデルは、左側に要件定義から実装までの「開発プロセス」、右側に対応する「テストプロセス」を配置したフレームワークです。
この流れに沿って、各フェーズにおける最適なツールアプローチを探っていきます。
要件定義フェーズ:情報収集の「広さ」と「深さ」
このフェーズの目的は、市場、競合、ユーザーニーズを広く深く理解することであり、情報収集が主要なタスクとなります。
| アプローチ | 強み | 弱み | 実践的な活用例 |
| MCP | ・Web検索やニュースAPIのような構造化ツールを容易に呼び出せる。 ・思考プロセスがシンプル。 | ・ツール定義にない柔軟な情報収集が困難。 ・大量の検索結果がコンテキストを圧迫する可能性がある。 | web_search.search(query="競合製品Aの最新レビュー") のようなMCPツールを呼び出し、結果の要約を依頼する。 |
| CLI / スクリプト | ・curlとpup(HTMLパーサー)等で、Webサイトから自由に情報を抽出できる。・取得した生データをファイルに保存し、必要な部分だけをLLMに渡すことでトークンを劇的に節約できる。 | ・スクリプトの作成・実行・デバッグに手間がかかる。 ・対象サイトのHTML構造変更に弱い。 | curl "https://foobar.example" |
【現場の視点】
このフェーズでは、ハイブリッドアプローチが最も効果的だと思っています。
初期のブレーンストーミング段階では、MCPの検索ツールで広範な情報を迅速に収集するのが効率的です。
しかし、「特定のフォーラムの特定のスレッドの評判を詳細に分析したい」といった深掘りフェーズでは、CLIの柔軟性が不可欠となります。curlでHTMLを取得し、grepでキーワードを絞り込み、その結果をLLMに分析させる、といった使い分けが現実的です。
設計フェーズ:アーキテクチャの分析と構築
アーキテクチャの設計や既存コードの分析など、深い思考が求められるフェーズです。
| アプローチ | 強み | 弱み | 実践的な活用例 |
| MCP | ・作図ツール(Mermaidなど)のMCPサーバーがあれば、自然言語から設計図を生成できる。 | ・複雑な依存関係やコードの歴史的経緯といった文脈を読むのは困難。 ・ツールが返す情報が固定的で、深掘りできない。 | diagram_tool.generate_sequence_diagram(description="ユーザーログイン処理") のようなツールでシーケンス図のドラフトを作成させる。 |
| CLI / スクリプト | ・ctagsやls -R、grepを駆使して、ソースコードの構造を直接分析できる。・LLMに「このリポジトリの全Pythonファイルのimport文を解析し、依存関係をMermaid形式で出力するスクリプトを書いて」と指示できる。 | ・分析対象の環境構築が必要な場合がある。 ・大規模なコードベースの完全な分析は、LLMのコンテキストサイズの制約から依然として難しい。 | find . -name "*.js" -print0 |
【現場の視点】
設計フェーズにおいて、MCPの活用シーンは限定的です。
設計プロセスは、より試行錯誤を伴うものです。
CLIで既存コードを調査し、git logで変更履歴を追い、grepで技術的負債を洗い出す。
そうして得た生の情報をもとにLLMと対話しながら設計を練り上げるプロセスの方が、質の高いアウトプットにつながります。
特に、既存システムの解析にはCLIが不可欠と言えるでしょう。
実装&テストフェーズ:開発ライフサイクルの核心
コーディング、リファクタリング、そしてテスト。開発ライフサイクルの核心部分です。
| アプローチ | 強み | 弱み | 実践的な活用例 |
| MCP | ・自己完結した単純な関数生成程度は可能。 | ・ファイル間の依存関係を考慮した編集が極めて困難。 ・リファクタリングは事実上不可能。 ・テスト実行はできても、失敗時の詳細なデバッグ情報がコンテキストを非効率に消費する。 | (実用的な例は限定的) |
| CLI / スクリプト | ・このフェーズにおける主役。 ・LLMにファイル操作(読み書き、新規作成)を含むスクリプトを生成させ、開発環境を直接操作。 ・ git CLIでブランチ作成からプルリクエスト作成まで自動化。・ pytestやjestを直接実行し、結果をJUnit XML形式で出力。LLMにそのXMLを解析させ、失敗したテストの修正コードを生成させる。 | ・サンドボックス環境のセキュリティ担保が絶対条件。rm -rf / のような破壊的コマンドのリスク。・LLMが生成したコードやコマンドは、実行前に人間によるレビューが必須。 | 実装: 「ApiServiceクラスにfetchDataメソッドを追加してください。ファイルはsrc/services/api.jsにあります」という指示から、ファイルの読み込み、編集、書き込みまでを行うスクリプトを生成・実行。テスト: pytest --junitxml=results.xml; を実行後、LLMに「results.xmlを読み込み、失敗したテスト(<failure>タグ)の原因を特定し、修正案を提示してください」と指示する。 |
【現場の視点】
実装とテストのフェーズにおいて、MCPにできることは限られています。
Hacker Newsのあるコメントがこの状況を的確に表現しています。
「Claudeにトポロジカルソートを“最善を尽くして”実行させるより、トポロジカルソートを実装したPythonスクリプトを生成させる方が100倍効率的だ」と。1
まさにその通りです。開発者が求めるのは、非決定論的なLLMの「推論」そのものではなく、決定論的で、検証可能で、手元で実行できる「コード」なのです。
結論:プロトコルは「手段」であり「目的」ではない
V字モデルを通して見えてくるのは、開発ライフサイクルの核心部分(設計、実装、テスト)において、CLI/スクリプトアプローチが圧倒的な優位性を持つという事実です。
開発者のマリオ・ゼクナー氏は、自身のベンチマーク記事で「プロトコル(MCPかCLIか)は単なる“配管”に過ぎず、本当に重要なのはツールの設計品質だ」と結論づけています。2
彼の実験では、トークン効率を極限まで高めたMCPサーバーが、CLI版よりも高速であったという結果さえ報告されています。これは、MCPが本質的に劣っているのではなく、多くの公開MCPサーバーの「設計が非効率である」可能性を示唆しています。
しかし、開発者にとって、既存の非効率なMCPサーバーを改良するよりも、手元にある強力なCLIツール群をAIに活用させる方が、遥かに実践的かつ効率的ではないでしょうか。
最終章では、これまでの議論を踏まえ、我々が明日から取るべき現実的な戦略を考察します。MCPを完全に捨てるべきか、あるいは共存の道はあるのか。その答えを探ります。
実践編:今日から始めるCLIエージェント開発 – ステップバイステップガイド
ここからは、実際に手を動かし、CLIベースのAIエージェントを構築するプロセスを紹介します。
このセクションでは、具体的なコード例とともに、明日の開発に直接活用できる実践的なテクニックを解説します。
ステップ1:環境構築とツールディレクトリの作成
まず、エージェントが使用するツール群を格納するディレクトリを作成します。
# ホームディレクトリにツール用のフォルダを作成
mkdir -p ~/agent-tools/browser
mkdir -p ~/agent-tools/git-helpers
mkdir -p ~/agent-tools/data-analysis
# 各ディレクトリにREADMEを作成
touch ~/agent-tools/browser/README.md
touch ~/agent-tools/git-helpers/README.md
touch ~/agent-tools/data-analysis/README.md
このディレクトリ構造は、エージェントが「ツールを発見」するための基盤となります。
各ディレクトリのREADMEには、そこに含まれるツールの簡潔な説明を記述し、エージェントにとっての「ツールカタログ」とします。
ステップ2:ブラウザ操作ツールの実装
マリオ・ゼクナー氏のアプローチを参考に、シンプルなブラウザ操作ツールを作成します。3
まず、Puppeteer Coreをインストールします。
cd ~/agent-tools/browser
npm init -y
npm install puppeteer-core
次に、基本的なツールスクリプトを作成します。
start.js – ブラウザを起動
#!/usr/bin/env node
const puppeteer = require('puppeteer-core');
(async () => {
const browser = await puppeteer.launch({
executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', // ご自身の環境に合わせて変更してください
headless: false,
args: ['--remote-debugging-port=9222']
});
console.log('ブラウザが起動しました。ポート9222でリモートデバッグが有効です。');
})();
nav.js – URLにナビゲート
#!/usr/bin/env node
const puppeteer = require('puppeteer-core');
const url = process.argv[2];
if (!url) {
console.error('使用法: node nav.js <URL>');
process.exit(1);
}
(async () => {
const browser = await puppeteer.connect({ browserURL: 'http://localhost:9222' });
const pages = await browser.pages();
const page = pages[0] || await browser.newPage();
await page.goto(url, { waitUntil: 'networkidle2' });
console.log(`${url} にナビゲートしました。`);
await browser.disconnect();
})();
eval.js – JavaScriptを実行
#!/usr/bin/env node
const puppeteer = require('puppeteer-core');
const code = process.argv[2];
if (!code) {
console.error('使用法: node eval.js "<JavaScriptコード>"');
process.exit(1);
}
(async () => {
const browser = await puppeteer.connect({ browserURL: 'http://localhost:9222' });
const pages = await browser.pages();
const page = pages[pages.length - 1];
const result = await page.evaluate(code);
console.log(JSON.stringify(result, null, 2));
await browser.disconnect();
})();
screenshot.js – スクリーンショットを撮る
#!/usr/bin/env node
const puppeteer = require('puppeteer-core');
const fs = require('fs');
const path = require('path');
(async () => {
const browser = await puppeteer.connect({ browserURL: 'http://localhost:9222' });
const pages = await browser.pages();
const page = pages[pages.length - 1];
const timestamp = Date.now();
const filename = `/tmp/screenshot_${timestamp}.png`;
await page.screenshot({ path: filename, fullPage: false });
console.log(filename);
await browser.disconnect();
})();
これらのスクリプトに実行権限を付与します。
chmod +x ~/agent-tools/browser/*.js
ステップ3:Git操作ヘルパーの作成
開発現場では、Gitの操作が頻繁に発生します。よく使うGitコマンドをラップしたヘルパースクリプトを作成します。
git-helpers/create-feature-branch.sh
#!/bin/bash
# 使用法: create-feature-branch.sh <ブランチ名>
if [ -z "$1" ]; then
echo "エラー: ブランチ名を指定してください。"
echo "使用法: create-feature-branch.sh <ブランチ名>"
exit 1
fi
BRANCH_NAME="feature/$1"
# mainブランチから最新を取得
git checkout main
git pull origin main
# 新しいfeatureブランチを作成
git checkout -b "$BRANCH_NAME"
echo "ブランチ '$BRANCH_NAME' を作成し、チェックアウトしました。"
git-helpers/commit-and-push.sh
#!/bin/bash
# 使用法: commit-and-push.sh "<コミットメッセージ>"
if [ -z "$1" ]; then
echo "エラー: コミットメッセージを指定してください。"
echo "使用法: commit-and-push.sh \"<コミットメッセージ>\""
exit 1
fi
COMMIT_MESSAGE="$1"
CURRENT_BRANCH=$(git branch --show-current)
# 変更をステージング
git add -A
# コミット
git commit -m "$COMMIT_MESSAGE"
# プッシュ
git push origin "$CURRENT_BRANCH"
echo "変更をコミットし、ブランチ '$CURRENT_BRANCH' にプッシュしました。"
実行権限を付与します。
chmod +x ~/agent-tools/git-helpers/*.sh
ステップ4:データ分析ツールの作成
ログファイルやCSVデータの分析も頻繁に行います。Pythonスクリプトで簡単な分析ツールを作成します。
data-analysis/analyze-csv.py
#!/usr/bin/env python3
import sys
import csv
from collections import Counter
if len(sys.argv) < 2:
print("使用法: analyze-csv.py <CSVファイルパス> [カラム名]")
sys.exit(1)
csv_file = sys.argv[1]
column_name = sys.argv[2] if len(sys.argv) > 2 else None
try:
with open(csv_file, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
rows = list(reader)
print(f"総行数: {len(rows)}")
print(f"カラム: {', '.join(rows[0].keys())}")
if column_name and column_name in rows[0]:
values = [row[column_name] for row in rows if row.get(column_name)]
counter = Counter(values)
print(f"\n'{column_name}' カラムの値の分布:")
for value, count in counter.most_common(10):
print(f" {value}: {count}回")
except FileNotFoundError:
print(f"エラー: ファイル '{csv_file}' が見つかりません。")
sys.exit(1)
except Exception as e:
print(f"エラー: {e}")
sys.exit(1)
実行権限を付与します。
chmod +x ~/agent-tools/data-analysis/*.py
ステップ5:ツールカタログ(README)の作成
各ディレクトリのREADMEに、ツールの使い方を簡潔に記述します。これが、エージェントにとっての「マニュアル」となります。
browser/README.md
# ブラウザ操作ツール
Puppeteer Coreを使用したシンプルなブラウザ自動化ツール群。
## ツール一覧
- `start.js`: Chromeをリモートデバッグモードで起動(ポート9222)
- `nav.js <URL>`: 指定したURLにナビゲート
- `eval.js "<code>"`: アクティブなページでJavaScriptを実行
- `screenshot.js`: 現在のビューポートのスクリーンショットを撮影し、ファイルパスを出力
## 使用例
```bash
# ブラウザを起動
node ~/agent-tools/browser/start.js
# Hacker Newsにアクセス
node ~/agent-tools/browser/nav.js "https://news.ycombinator.com"
# ページタイトルを取得
node ~/agent-tools/browser/eval.js "document.title"
# スクリーンショットを撮る
node ~/agent-tools/browser/screenshot.js
# ブラウザ操作ツール
Puppeteer Coreを使用したシンプルなブラウザ自動化ツール群。
## ツール一覧
- `start.js`: Chromeをリモートデバッグモードで起動(ポート9222)
- `nav.js <URL>`: 指定したURLにナビゲート
- `eval.js "<code>"`: アクティブなページでJavaScriptを実行
- `screenshot.js`: 現在のビューポートのスクリーンショットを撮影し、ファイルパスを出力
## 使用例
```bash
# ブラウザを起動
node ~/agent-tools/browser/start.js
# Hacker Newsにアクセス
node ~/agent-tools/browser/nav.js "https://news.ycombinator.com"
# ページタイトルを取得
node ~/agent-tools/browser/eval.js "document.title"
# スクリーンショットを撮る
node ~/agent-tools/browser/screenshot.js
トークン消費
このREADME全体: 約250トークン(MCPサーバーの13,000トークンと比較)
**`git-helpers/README.md`**
```markdown
# Git操作ヘルパー
よく使うGit操作をラップしたシェルスクリプト群。
## ツール一覧
- `create-feature-branch.sh <ブランチ名>`: mainから最新を取得し、新しいfeatureブランチを作成
- `commit-and-push.sh "<メッセージ>"`: 変更をステージング、コミット、プッシュ
## 使用例
```bash
# 新しいfeatureブランチを作成
~/agent-tools/git-helpers/create-feature-branch.sh add-login-page
# 変更をコミット&プッシュ
~/agent-tools/git-helpers/commit-and-push.sh "feat: ログインページのUIを実装"
**`data-analysis/README.md`**
```markdown
# データ分析ツール
CSVやログファイルを分析するPythonスクリプト群。
## ツール一覧
- `analyze-csv.py <CSVファイル> [カラム名]`: CSVファイルの基本統計と、指定カラムの値の分布を出力
## 使用例
```bash
# CSVファイルの概要を表示
~/agent-tools/data-analysis/analyze-csv.py ./data/users.csv
# 特定カラムの分布を分析
~/agent-tools/data-analysis/analyze-csv.py ./data/users.csv "country"
### ステップ6:エイリアスの設定とエージェントの起動
最後に、エージェントがこれらのツールにアクセスできるよう、パスを設定します。
`.bashrc`または`.zshrc`に以下を追加します。
```bash
# AIエージェント用のツールパス
export AGENT_TOOLS_PATH="$HOME/agent-tools/browser:$HOME/agent-tools/git-helpers:$HOME/agent-tools/data-analysis"
# エージェント起動用のエイリアス
alias my-agent="PATH=\$PATH:\$AGENT_TOOLS_PATH && claude --dangerously-skip-permissions"
設定を反映させます。
source ~/.bashrc # または source ~/.zshrc
これで、my-agentコマンドで起動したClaudeは、作成したすべてのツールにアクセスできるようになります。
ステップ7:実際に使用する
エージェントを起動し、実際にタスクを依頼してみましょう。
my-agent
Claudeが起動したら、以下のように指示します。
「
~/agent-toolsディレクトリを探索して、利用可能なツールをリストアップしてください。その後、Hacker Newsのトップページにアクセスし、現在のトップ記事のタイトルを取得してください。」
Claudeは、以下のようなコマンドを生成・実行するはずです。
# ツールのリストアップ
ls -R ~/agent-tools
# ブラウザを起動
node ~/agent-tools/browser/start.js
# Hacker Newsにアクセス
node ~/agent-tools/browser/nav.js "https://news.ycombinator.com"
# トップ記事のタイトルを取得
node ~/agent-tools/browser/eval.js "document.querySelector('.titleline > a').textContent"
そして、取得した結果を報告します。これが、CLIベースのエージェントの力です。
ステップ8:ツールセットの拡張
ここからが本当のスタートです。日々の開発で頻繁に使用するコマンドやスクリプトを、~/agent-toolsに追加していきましょう。
- Docker操作ヘルパー:
docker psやdocker logsをラップしたスクリプト - API呼び出しラッパー: 社内APIを叩くための
curlコマンドをまとめたスクリプト - テスト実行ヘルパー:
pytestやjestを実行し、結果を整形して出力するスクリプト
そして、それぞれのツールにREADMEを記述します。このプロセスを繰り返すことで、エージェントは開発スタイルに最適化され、より強力なアシスタントへと成長していきます。
これこそが、MCPでは実現が難しかった「カスタマイズ性」と「拡張性」の真髄です。
トークン効率の実測:MCPとの比較
ここで、実際のトークン消費を比較してみましょう。
| アプローチ | ツール定義のトークン数 | 中間結果のトークン数 | 合計 |
| MCP(Chrome DevTools Server) | 18,000 | 50,000(文字起こし全文) | 68,000 |
| CLI(上記のブラウザツール) | 250(READMEのみ) | 50(ログ出力のみ) | 300 |
削減率: 99.6%
この数値が、アプローチの違いがもたらすインパクトを物語っています。
深掘り:MCPとCLIの技術的な違いを完全理解する
ここでは、さらに技術的な観点から両アプローチの違いを深掘りします。「なぜMCPはトークンを大量に消費するのか?」「CLIアプローチの本質的な優位性は何か?」をアーキテクチャレベルで理解することで、より深い知見が得られるでしょう。
MCPのアーキテクチャとトークン消費のメカニズム
MCPの基本的なアーキテクチャでは、すべてのツール定義がタスク開始時にコンテキストにロードされ、ツールが返す結果もすべてコンテキストウィンドウを通過します。これが、トークン消費が爆発的に増加する根本的な原因です。
CLIアプローチのアーキテクチャと効率性の源泉
一方、CLIアプローチ(コード実行)では、ツール定義は必要に応じて読み込まれ(プログレッシブ・ディスクロージャー)、中間データは実行環境のメモリやファイルシステムに保持されます。LLMは簡潔なログのみを受け取るため、コンテキストウィンドウはクリーンに保たれ、本来の目的である「タスクの理解と推論」にリソースを集中できます。
表現力の違い
MCPのツール定義はJSON Schemaで記述され、明確である一方、柔軟性に欠けます。対照的に、CLIアプローチでは、LLMはプログラミング言語の全機能(条件分岐、ループ、並行処理、エラーハンドリングなど)を活用でき、複雑なタスクに対して遥かに高い表現力を発揮します。
セキュリティに関する考察:CLIアプローチの「危険性」
LLMに任意のコードを実行させるCLIアプローチには、MCPにはないセキュリティリスクが伴います。破壊的なコマンドの実行、情報漏洩、リソースを枯渇させる無限ループなどが考えられます。
したがって、CLIアプローチを採用する際には、以下の対策が不可欠です。
- サンドボックス化: Docker、Firecracker、gVisorなどの技術を用いて、エージェントの実行環境を厳密に隔離する。
- ホワイトリスト方式: 実行可能なコマンドやアクセス可能なファイルを、事前にホワイトリストで定義する。
- 人間によるレビュー: 重要な操作(デプロイ、データベース変更など)の前に、生成されたコードを人間がレビューするプロセスを挟む。
- 監視とロギング: すべてのコマンド実行をログに記録し、異常な動作を検知できる体制を整える。
Anthropicの実装でも、コード実行は「信頼されたサンドボックス環境」内で行われることが前提とされています。
このセキュリティコストは、CLIアプローチの唯一の「弱点」と言えるかもしれませんが、適切な対策を講じることでリスクは管理可能であり、その対価として得られるパワーと柔軟性は、コストを上回る価値をもたらします。
FAQ:想定質問
Q1: MCPは完全に時代遅れになったのでしょうか?
A: いいえ、そうではありません。MCPは「時代遅れ」になったのではなく、「適用範囲がより明確になった」と捉えるべきです。
天気予報の取得のようなシンプルで自己完結したタスクや、非技術者向けの安全性を最優先するツールにおいては、依然として有効な選択肢です。
しかし、複雑なワークフローや開発タスクには、CLI/スクリプトアプローチが遥かに適しています。
Q2: Anthropicの「Code execution with MCP」は、MCPとCLIのどちらに分類されますか?
A: これは、両者のハイブリッドアプローチです。ツールの実体はMCPサーバーですが、その呼び出しをLLMが生成したTypeScriptコードによって行います。MCPのエコシステムを活かしつつ、呼び出し方法をコードによる間接的なものに変えることで、トークン効率を劇的に改善した、非常に賢い解決策と言えます。
Q3: 独自のツールを開発する場合、MCPサーバーとCLIツールのどちらを選ぶべきですか?
A: ツールの目的によります。他の開発者にも広く使ってもらいたい汎用ツールであれば、MCPサーバーとして公開する価値はあります。その際は、ツール定義をコンパクトにし、返す結果も簡潔にすることが重要です。一方、自身のワークフローに最適化された専用ツールであれば、CLIスクリプトの方が迅速かつ柔軟に開発できます。
Q4: V字モデルは現代の開発プロセスに適していますか?
A: V字モデルはウォーターフォール型の開発プロセスで用いられることが多いですが、本記事では「開発の各フェーズを整理するためのフレームワーク」として活用しました。アジャイル開発のスプリント内でも「設計→実装→テスト」というサイクルは存在し、その各フェーズでどのツールアプローチが有効かを考える上で、V字モデルは有用な思考の地図となります。
Q5: トークン効率は、なぜそれほど重要なのでしょうか?
A: トークン効率は、単なる「コスト」の問題ではありません。LLMの応答速度、コンテキストの質(本当に重要な情報に割けるスペース)、そしてスケーラビリティ(同じ予算で処理できるタスク量)に直結します。トークン効率は、AIエージェントの「パフォーマンス」そのものなのです。
Q6: この記事の要点は何ですか?
A: 要点は以下の通りです。
「MCPはAIとツールの連携に大きな可能性を示したが、現実の複雑なタスクに対してはトークン効率と柔軟性の面で課題があった。その解決策として、LLMにコードを生成させ、CLIとファイルシステムを直接操作させるアプローチが台頭している。この未来は、すでに我々開発者の手の中にある。」
最終章:結論と今後の展望
本記事では、MCPの登場からその課題の顕在化、そして解決策としてのコード実行とCLIアプローチへの回帰という一連の流れを、具体的な技術情報とともに解説してきました。
結論として、我々が取るべき戦略は「適材適所のハイブリッド戦略」です。
- 外部のシンプルな情報取得にはMCPを活用する: 標準化されたシンプルなAPI呼び出しには、MCPの手軽さが活きます。
- 開発のコアプロセスではCLI/スクリプトを徹底活用する: 設計、実装、テスト、デバッグといった、開発の核心部分では、AIエージェントにCLIとファイルシステムへのフルアクセスを与えることで、その能力を最大限に引き出します。
この対立は、単なる技術選択の問題ではなく、我々がAIエージェントとどう向き合うかという哲学の表れでもあります。
- MCPの世界観: AIを、安全な箱庭の中で、定義されたツールのみを使わせる、受動的な存在と捉える。
- CLI/コード実行の世界観: AIを、我々と同じ開発環境に置き、同じツールを与えて問題を解決させる、能動的な創造者と捉える。
現在の潮流は、明らかに後者へと向かっています。
我々はAIを、単なる便利なAPI呼び出し機としてではなく、自律的に思考し、コードを書き、我々と同じ土俵で問題を解決してくれる「同僚」として迎え入れようとしているのです。
もちろん、そのためにはセキュリティ、監視、コードレビューといった新たな課題を克服する必要があります。
しかし、それらの課題の先には、AIと人間が真に協調し、これまでにないスピードと創造性でソフトウェアを開発する未来が待っています。
MCPが示した「AIとツールの連携」という夢は一度、トークンという壁に直面しました。
しかし今、我々はCLIとコード実行という、より堅牢でパワフルな翼を手に入れ、再びその夢に向かって飛び立とうとしています。
皆様も、この新しい冒険に参加してみてはいかがでしょうか。まずは、ご自身のターミナルでmkdir ~/agent-toolsと打ち込むところから、すべては始まります。
- Hacker News Discussion. (2025, November). What if you don’t need MCP at all? https://news.ycombinator.com/item?id=45947444 ↩︎
- Zechner, M. (2025, August 15). MCP vs. CLI: A Benchmark. https://mariozechner.at/posts/2025-08-15-mcp-vs-cli/ ↩︎
- Zechner, M. (2025, November 2). What if you don’t need MCP at all? https://mariozechner.at/posts/2025-11-02-what-if-you-dont-need-mcp/ ↩︎
