「AI 連携なら MCP でしょ」——そんな空気があります。でもこのブログの WordPress 操作は、MCP を使わず WP-CLI直呼びにしています。その判断が正しいのか、最小の MCP サーバを実際に立てて往復時間・依存数・起動コストを測りました。数字で見えた線引きを、正直に書きます。
先に結論:MCP を入れず WP-CLI直呼びにした
結論から言うと、いまの使い方なら直接叩くほうが素直でした。このブログの投稿スキル(koma-publisher)は、記事1本を上げるあいだに wp コマンドを十数回叩きます。回数はその程度で、頻度も1日に数回。ここに MCP という常駐サーバを1枚かませる理由が、測っても見つかりませんでした。
数字を先に置きます。WP-CLI直呼びは1コマンドあたり毎回およそ718ms。対して最小の MCP サーバは、初回の起動に972ms、依存パッケージは93個でした。この差が何を意味するのかを、実装と実測でほどきます。
経路の違い:MCP を1枚かませるか、PHP を直接叩くか
まず絵で見たほうが早いです。MCP(Model Context Protocol)は、AI と外部ツールを標準プロトコルでつなぐ仕組み。Claude Code はサーバへ JSON-RPC を投げ、サーバが WordPress を操作して返します。一方の直呼びは、PHP と WP-CLI をその場で起動して WordPress を触るだけ。終わればプロセスは捨てます。あいだに常駐する層がありません。

ポイントは、MCP を通しても最終的に WordPress を触るのは結局 WP-CLI か PHP だという点。MCP はその手前に通信レイヤーを足すもので、WordPress を速く操作する魔法ではありません。ここを押さえると、次の実測が読みやすくなります。
実測1:WP-CLI直呼びの往復は毎回718ms
まず WP-CLI直呼びから測ります。環境は Windows 11 / PHP 8.2.29(Local by Flywheel)です。呼び出しはこの PowerShell ラッパーを使います。同じ形をそのまま貼れば動きます。
$php = "C:Userskoma0AppDataRoamingLocallightning-servicesphp-8.2.29+0binwin64php.exe"
$phar = "C:Userskoma0AppDataLocalProgramsLocalresourcesextraResourcesbinwp-cliwp-cli.phar"
$ini = "C:Userskoma0AppDataRoamingLocalrunJukMWXMMyconfphp"
function wp { & $php -d display_startup_errors=0 -d error_reporting=0 -c $ini $phar --path="...public" @args 2>&1 }
# 往復を10回測る(副作用のない読み取りコマンド)
$t = @()
for ($i=0; $i -lt 10; $i++) {
$sw = [System.Diagnostics.Stopwatch]::StartNew()
wp option get siteurl | Out-Null
$sw.Stop(); $t += $sw.Elapsed.TotalMilliseconds
}
"median = {0} ms" -f ([math]::Round(($t | Sort-Object)[5],1))
結果はこうなりました(N=10・単位 ms)。副作用のない読み取りを2種類、siteurl 取得と投稿数カウントで測っています。
| コマンド | cold | min | median | max |
|---|---|---|---|---|
| wp option get siteurl | 720.1 | 694.5 | 718.2 | 738.0 |
| wp post list –format=count | 721.2 | 699.5 | 717.9 | 842.1 |
初回(cold)と2回目以降(warm)で時間がほぼ変わらないのが、この方式の性格をよく表しています。永続プロセスを持たないので、リクエストのたびに PHP と WordPress コアをまるごとブートするからです。だから常に700〜720ms。中身は DB へのクエリ1回で、そこは軽いのに、ブートで時間を払っています。
そして地味に効くのが、追加の npm 依存がゼロだという点。Local 同梱の wp-cli.phar と PHP をそのまま使うだけ。プロジェクトの package.json を1行も汚しません。
実測2:最小 MCP サーバを立てて測る
比較のため、最小の MCP サーバを Node で書きました。公開するツールは1個だけ。公式 SDK は @modelcontextprotocol/sdk@1.29.0。ランタイムは Node v24.15.0 です。ping は WordPress を触らず即返します。プロトコルの往復だけを切り出したいからです。
// server-sdk.js — ツール1個だけの最小 MCP サーバ(stdio)
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new McpServer({ name: "mcp-min", version: "1.0.0" });
server.registerTool(
"ping",
{ description: "returns pong (no WordPress access)", inputSchema: {} },
async () => ({ content: [{ type: "text", text: "pong" }] })
);
await server.connect(new StdioServerTransport());
依存93パッケージ・起動972ms
まず入れた時点で数字が出ます。npm install @modelcontextprotocol/sdk を叩くと、こうなりました。
$ npm install @modelcontextprotocol/sdk
added 93 packages, and audited 94 packages in 3s
$ du -sh node_modules
23M node_modules
ツール1個のために、推移的な依存も含めて93パッケージ・23MB を抱えます。次に、クライアントからつないで往復を測るベンチを書きました。
// bench-mcp.mjs(要点)— コールドスタートと往復レイテンシを測る
const t0 = performance.now();
const transport = new StdioClientTransport({ command: process.execPath, args: ["server-sdk.js"] });
const client = new Client({ name: "bench", version: "1.0.0" });
await client.connect(transport); // node起動 + SDK読込 + initialize
const cold = performance.now() - t0;
const rt = [];
for (let i = 0; i < 20; i++) {
const s = performance.now();
await client.callTool({ name: "ping", arguments: {} }); // ハンドシェイク後の1往復
rt.push(performance.now() - s);
}
cold_start_ms : 972.06
roundtrip_ms : { N: 20, min: 0.22, median: 0.41, avg: 0.56, max: 2.65 }
コールドスタートは972ms。ただしこれは一度きりで、常駐させれば以降は無料です。そのうえでハンドシェイク後の往復は中央値0.41ms。桁が3つ違うので、ここだけ見ると MCP の圧勝に見えます。この見え方に落とし穴があるのですが、それは次の節で書きます。
ちなみに972ms の中身も測りました。素の node -e "" がこの環境で約846ms。SDK 読み込みで+約115ms、ハンドシェイクで+約11ms です。つまり大半は Node 本体のプロセス起動でした。Windows だと spawn 自体が重い、という事情も見えます。
実装で並べる比較表
WP-CLI直呼びと最小 MCP を、測れたものと測れない設計判断の両面で1枚に並べます。緑が実測、灰が判断です。

認証情報の置き場も、地味だけど無視できません。直呼びは既存の wp-config.php(gitignore 済み)を単一の出所として使い回します。MCP を採ると、そこに秘匿ファイル .mcp.json がひとつ。うっかりコミットしないよう気を配る対象も、その分だけ増えます。
正直に:ここは実測、ここは設計判断(0.4msの罠)
ここが一番大事なので、はっきり分けます。先ほどの往復0.41msは、あくまで JSON-RPC のトランスポートだけの数字。ping は WordPress を一切触っていません。
もし MCP のツールが本当に WordPress を操作するなら、その中で結局 WP-CLI か PHP を呼びます。すると、あの718msのブートがまるごと往復に戻ってきます。MCP を通したから WordPress 操作が0.4msで返る、という話ではないのです。
MCP 側で本当に0.4msを出したいなら、サーバに PHP や DB の永続接続層を自前で組む必要があります。けれどそれこそ、わたしが避けたかった追加実装そのもの。表面的な損益分岐(972ms 払えば以降ずっと得)は、実際の WordPress 操作では成立しません。だから測れた事実は、こう区別しています。
- 実測できたこと:直呼びの往復718ms、MCP の起動972ms とトランスポート往復0.41ms、依存93個。
- 設計上の判断:実操作では MCP がブートを内包する点、認証ファイルが増える点、常駐プロセスの運用コスト。ここは時間より運用で効いてくる話。
数字を都合よく切り取れば「MCP は0.4msで爆速」と書けてしまいます。でもそれは、測定条件を隠した数字。ここを濁さないのが、この検証でいちばん守りたかった線でした。
それでも MCP が正解になる場面
直呼びを選んだからといって、MCP を否定したいわけではありません。向く場面ははっきりあります。
- つなぎ先が多く、複数クライアント(Claude Desktop・Cursor・VS Code)で操作を共有したいとき。標準化の恩恵がそのまま効きます。
- 1セッションで大量の呼び出しをする対話的な使い方。永続接続層まで作り込めば、往復コストを本当に削れます。
- チームで配布して、接続方法を1つの規約にそろえたいとき。
裏を返すと、つなぎ先が WordPress 1つで呼び出しもたまに数回、という個人運用では、標準化のうまみは薄めです。少数ツールなら直接 API を叩くほうが素直、という整理は他でも語られています。わたしの結論も、実測を経て同じ場所に着きました。
Claude Code の設計判断は、ほかの記事でも同じ姿勢で扱っています。hooks でうっかりを止める話や、逐次 vs 並列を実測した記事も、よかったらどうぞ。
まとめ:ツールが少ないうちは直呼びで十分
- WP-CLI直呼びは毎回718ms(実測)。永続プロセスがなく、追加依存はゼロ。
- 最小 MCP は起動972ms・依存93個(実測)。往復0.41msはトランスポートのみで、実操作ではブートが戻ります。
- 認証は
wp-config.php一本 vs.mcp.json追加。常駐サーバは監視・再起動の運用コストを連れてきます。 - つなぎ先が少なく呼び出しもまばらな個人運用は、直呼びが素直。多クライアント共有や大量呼び出しなら MCP が効きます。
「流行っているから入れる」ではなく、自分のワークフローの回数と頻度で決める——それだけで、抱える依存と運用はずいぶん軽くなります。ほかの設計判断は爆速開発・環境構築のカテゴリにまとめました。こうした「連携をどう実装すると自社にとって軽いか」の設計は、NEORIVA として法人向けにも一緒に組んでいます。