このテックブログの記事は、AI の Claude から直接、下書きを作ったり更新したりできるようになっています。そのために使っているのが MCP(Model Context Protocol)です。
この記事では、エンジニア向けに、MCP の仕組みと、このブログで実際に作った MCP サーバーの中身を紹介します。読み終えたときに、自分たちのサービスに MCP サーバーを作るべきか、作るなら何が必要かを判断できることを目指します。内容は 2026 年 11 月 8 日時点で、modelcontextprotocol.io の仕様書を確認したものです。
MCP とは:AI とシステムをつなぐ共通の規格
MCP は、AI アプリケーションと外部のシステムを接続するための、オープンな通信の規格です。AI に「社内のデータを読ませたい」「このサービスを操作させたい」と思ったとき、これまでは AI アプリごとに、つなぎ込みの仕組みを個別に作る必要がありました。MCP は、その接続の方法を 1 つに揃えます。一度 MCP サーバーを作れば、Claude Code、Claude デスクトップ、VS Code など、MCP に対応したどのアプリからも同じように使えます。
API と比べると、違いがわかりやすくなります。
| 普通の Web API | MCP | |
|---|---|---|
| 主な利用者 | 人が書いたプログラム | AI(モデルが自分で判断して呼ぶ) |
| 何ができるかの伝え方 | 人が読むドキュメント | サーバーが、ツールの名前・説明・入力の形を機械が読める形で返す |
| 形式 | サービスごとに自由(REST など) | JSON-RPC 2.0 に統一 |
| 呼び出しの決定 | プログラムに書いた順に呼ぶ | AI が会話の内容から、どのツールをいつ呼ぶか決める |
大事なのは、MCP は API の代わりではなく、API の「AI 向けの包み紙」に近いという点です。このブログの MCP サーバーも、中では管理画面と同じ記事の保存処理を呼んでいるだけです。すでに API や管理機能を持っているサービスなら、その上に薄い層を足すだけで MCP に対応できます。
仕組み:host・client・server と、ツールが呼ばれるまで
MCP には 3 つの登場人物がいます。
- host:利用者が使う AI アプリ。Claude Code や Claude デスクトップなど
- client:host の中にあり、MCP サーバー 1 つと接続を受け持つ部品。サーバーを 2 つつなげば、client も 2 つ作られる
- server:AI に機能やデータを提供するプログラム。この記事で作るもの
サーバーが提供できるものは、主に 3 種類あります。AI が呼び出して実行する tools(ツール)、AI に読ませる文脈データの resources、決まった手順の雛形の prompts です。実際によく使われるのは tools で、このブログのサーバーも tools だけを提供しています。
通信は 2 層に分かれています。内側のデータ層は JSON-RPC 2.0 で書かれたメッセージの決まりです。外側のトランスポート層は、メッセージの運び方を決めます。運び方は 2 つあり、同じパソコンの中でプロセスを起動して標準入出力でやりとりする stdio と、ネットワーク越しに HTTP の POST で送る Streamable HTTP です。Web サービスとして公開するなら Streamable HTTP を使います。
ツールが呼ばれるまでの流れは、次のとおりです。
ポイントは、AI がツールの一覧と説明を読んで、どのツールをどう呼ぶかを自分で決めることです。そのため、サーバー側が書くツールの説明文は、人が読む API のドキュメントと同じくらい重要になります。
実装例:このブログの MCP サーバー(Laravel)
このブログの MCP サーバーは、Laravel で書いた 1 本のエンドポイントです。公式の SDK は使わず、JSON-RPC のメッセージを自分で処理しています。仕組みを理解するには、このくらい小さい実装がちょうどよい教材になります。
入口:POST を 1 本だけ受ける
Route::middleware(['throttle:240,1', 'admin.token'])->group(function () {
Route::post('/mcp', [McpController::class, 'handle'])->name('mcp');
});
admin.token は、管理画面で発行したトークンを Authorization: Bearer ヘッダーで受け取り、どの管理者からの要求かを確かめる自作のミドルウェアです。回数制限(1 分に 240 回)を先に置いて、無効なトークンでの総当たりにも制限がかかるようにしています。
メッセージの振り分け
届いた JSON-RPC のメッセージは、method の値で処理を振り分けます。
return match ($message['method']) {
'tools/list' => $this->result($id, ['tools' => $this->toolDefinitions()]),
'tools/call' => $this->callTool($id, $params),
default => $this->error($id, -32601, "Method not found: {$message['method']}"),
};
ツール 1 つ = クラス 1 つ
ツールは、名前・説明・入力の形(JSON Schema)・処理をまとめたクラスにしました。tools/list では前の 3 つを返し、tools/call で handle を実行します。
class DeleteArticle extends ArticleTool
{
public function name(): string
{
return 'delete_article';
}
public function description(): string
{
return '記事を削除する(元に戻せない)。ユーザーが削除を明示したときだけ使う。'
. '間違い防止のため confirm_title に記事のタイトルをそのまま渡す。';
}
protected function properties(): array
{
return [
'id' => ['type' => 'integer', 'description' => '記事 ID'],
'confirm_title' => ['type' => 'string', 'description' => '削除する記事のタイトル'],
];
}
public function handle(array $arguments, Admin $admin): array
{
// タイトルが一致しなければ削除しない(省略)
}
}
説明文に「ユーザーが削除を明示したときだけ使う」と書いているのは、AI がこの文を読んで呼ぶかどうかを判断するからです。
ツールの分け方も、AI が使いやすいかどうかで決めました。このブログのサーバーが提供しているのは、一覧(list_articles)、1 件の取得(get_article)、作成(create_article)、更新(update_article)、削除(delete_article)、トピックの一覧(list_topics)、画像のアップロード(upload_image)、記法の説明(get_markdown_guide)の 8 つです。最後の get_markdown_guide は、このブログで使える Markdown の書き方を返すだけのツールです。サーバーの使い方の説明(instructions)で「書く前にこれを読む」よう伝えているので、AI はこのブログで使える記法に合わせて書けます。データを操作するツールだけでなく、「AI が正しく使うための説明を返すツール」を用意するのも、MCP ならではの工夫です。
ツールが失敗したときは、JSON-RPC のエラーではなく、isError: true の結果として返します。仕様の決まりで、AI が失敗の理由を読み、入力を直して呼び直せるようにするためです。
呼び出してみる
最新の仕様の形で tools/call を送ると、次のようになります。最新版では、各リクエストの _meta で、どの版の仕様で話しているかを毎回伝えます。
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "list_articles",
"arguments": { "status": "draft" },
"_meta": { "io.modelcontextprotocol/protocolVersion": "2026-07-28" }
}
}
Claude Code への登録は、コマンド 1 行です。
claude mcp add --transport http --scope user goezo-tech-blog \
https://goezo.jp/api/mcp --header "Authorization: Bearer <発行したトークン>"
最新の仕様で変わったこと
MCP の仕様は日付で版を管理していて、2026 年 11 月時点の最新は 2026-07-28 版、ひとつ前が 2025-11-25 版です。最新版では、仕組みの考え方に大きな変更がありました。サーバーが接続ごとの状態を持たない「ステートレス」な形になったのです。
- 接続の最初に行っていた
initializeのやりとりと、pingが廃止された。代わりに、各リクエストの_metaで、仕様の版やクライアントの機能を毎回伝える - サーバーは、対応する版や機能を 1 回で返す
server/discoverを必ず実装する - Streamable HTTP のセッション(
Mcp-Session-Idヘッダー)が廃止された - すべての結果に、処理が完了したかを表す
resultTypeが必須になった。tools/listの結果には、キャッシュの期間を表すttlMsと範囲を表すcacheScopeも必要 - Streamable HTTP の POST に、
MCP-Protocol-Version・Mcp-Method・Mcp-Nameなどのヘッダーが必要になった
作るべきか:判断の基準
MCP サーバーは、どのサービスにも必要なわけではありません。次の 3 つにあてはまるほど、作る価値が高くなります。
| 判断の軸 | 作る価値が高い | 急がなくてよい |
|---|---|---|
| 操作の中身 | 文章の作成・データの整理など、AI が手伝うと速くなる作業 | 決まった処理を決まった順に動かすだけ |
| 使う人 | 社内で Claude などの AI アプリを日常的に使っている | AI アプリを使う人がいない |
| 土台 | 管理機能や API がすでにあり、その処理を呼ぶだけで済む | 一から機能を作る必要がある |
このブログは 3 つともあてはまりました。記事を書く作業は AI が大いに手伝えます。社内では Claude Code を毎日使っています。そして、管理画面の保存処理がすでにありました。結果として、MCP のために追加したコードは、ツール 8 個を含めて約 900 行で済んでいます。
逆に、AI に任せてよい操作かどうかは慎重に決めましょう。このブログでは、削除と公開を「人が確認してから」行う作りにしています。
公開するときのセキュリティ
MCP サーバーは、AI を通じて自社のシステムを操作できる入口です。仕様書には、守るべき点が MUST(必須)や SHOULD(推奨)として書かれています。特に大事なものを挙げます。
- 認証を必ず付ける:仕様は、すべての接続を認証することを推奨しています。このブログでは、管理者ごとに発行した、期限付きのトークンで認証しています
- Origin ヘッダーを確かめる:Streamable HTTP のサーバーは、DNS リバインディング攻撃(悪意のあるサイトを開いたブラウザ経由で、なりすましの要求を送る手口)を防ぐため、Origin を確かめることが必須です。不正な Origin には 403 を返します
- 受け取ったトークンを他へ渡さない:MCP サーバーは、自分に向けて発行されたもの以外のトークンを受け付けてはいけません
- 入力の検証・アクセス制御・回数制限・出力の無害化:いずれも、仕様がサーバーに求めている項目です
- 人が止められるようにする:ツールの呼び出しは、人が拒否できる状態にしておくことが推奨されています
あわせて、AI が調べ物の途中で読んだ Web ページに悪意のある指示が書かれていて、それに従ってしまう「プロンプトインジェクション」にも備えます。このブログでは、本文に HTML やスクリプトが入っても無害な文字として表示します。新しい記事は必ず下書きで保存し、削除には記事のタイトルの完全一致を求めています。AI がだまされても、被害が小さく済む作りにしておくことが大切です。
まとめ
- MCP は、AI とシステムをつなぐ共通の規格です。既存の API や管理機能の上に、薄い層を足すだけで作れます
- サーバーが返すツールの説明文を、AI が読んで使い方を決めます。説明文は、AI 向けのドキュメントとして丁寧に書きます
- 最新の 2026-07-28 版では、仕組みがステートレスに変わりました。作るときは、必ず最新の仕様を確認します