第1回: そもそもMCPサーバってなんだ
MCPという言葉を見かける機会が増えてきました。
業務の中でも「MCPサーバを使って〜」というように、積極的にMCPサーバを扱うことが増えてきました。
なんとなくは理解しているつもりなのですが、改めてMCPサーバについて理解を深めたい、整理したいと思ったので自作のMCPサーバを実装しつつ整理を進めていきます。
AIエージェントのSKILLも活用し、『自作MCPサーバ✖️PRレビュースキル』という開発を進めていきます。
いくつかの記事に分けて、段階的にこの開発を進めていきます。
最終的には、PRレビュースキルから自作MCPサーバを通してBacklogの課題内容を確認しつつレビューを実施し、GitHubのPRにレビュー結果を出力するところを目指します。
第1回目の本記事では、「そもそもMCPサーバとは何か」を整理します。
今回作ろうとしているもの
今回の題材は、Backlog課題の内容を加味したPRレビューSKILLです。
コードレビューは、あくまでもコードをレビューするものです。仕様についての確認は、実装者自身がきちんとおこなうのが本来は正しいのかなと私は考えています。
もちろんコードレビューの中でも仕様がきちんと反映できているのか、という観点でレビューをしてもいいと思ってますが、やはり時間はかかると思います。
なんとかしてうまい具合にAIにも仕様通りかのレビューをさせたいなと。。。
そうした仕様は、Backlogのようなツールでテキストベースに整理することがあると思います。
せっかくテキストベースで整理された仕様があるのであれば、それを使わない手はないですよね。
なので今回作成するPRレビュースキルでは、Backlog上に仕様が整理されている前提で、Backlogから仕様を取得し、PRレビューの際に活用する流れを作ります。
下記のような構成を作ります。
Backlog APIをPRレビュースキルから直接呼ぶのではなく、Backlogの取得処理だけを自作MCPサーバに任せます。
MCPサーバ: Backlogから情報を安全に取得する
PRレビュースキル: 取得した情報をどう読んで、どうレビューするかを決める
ではMCPは何をするものなのか
そもそもMCPサーバとはなんなのか??
MCPはModel Context Protocolの略です。
OpenAI Developersのドキュメントでは、MCPはAIクライアントを外部ツールやデータへ接続するためのオープンな仕様として説明されています。プラグインがライブ情報を読んだり、外部サービスと連携したり、制御された操作を行ったりする必要がある場合に、MCPサーバを含めることができます。
参考: MCP server - OpenAI Developers
つまりざっくり言うと、MCPは「AIが外部の機能やデータを使うための共通インターフェース」です。私のイメージとしては「翻訳レイヤー」みたいなものかなと。
AIモデル単体は、手元のBacklog APIへ勝手にアクセスできません。GitHubのPR差分を取得することも、社内の課題管理ツールを読むことも、ローカルのDockerコンテナを起動することも、モデルだけではできません。
そこで、AIを動かしているアプリケーション側が、外部サービスへ接続するための道具を用意します。その道具を、AIが見つけ、入力を組み立て、結果を受け取れるようにするための仕組みがMCPです。
host、client、serverの関係
MCPを理解するときに、まず出てくるのがhost、client、serverです。
この3つは、次のように考えると分かりやすいです。
| 名前 | 役割 | 今回の例 |
|---|---|---|
| MCP host | AIを動かしているアプリケーション | Codex |
| MCP client | hostの中でMCPサーバと通信する部分 | CodexがMCPサーバへ接続する部分 |
| MCP server | 外部機能やデータを公開する接続先 | Backlog課題を読む自作サーバ |
図にすると、こうなります。
ユーザーが「このPRをレビューして」と依頼します。
CodexはPRレビューに必要な情報を集めるために、使えるツールを確認します。Backlog課題URLがPR本文に含まれていれば、自作MCPサーバの get_issue_context というtoolを呼び出します。
MCPサーバは、そのURLが許可されたBacklogスペースのURLかどうかを検証し、Backlog APIから課題本文やコメントを取得し、構造化された結果を返します。
Codexはその結果を使って、レビューを続けます。
ここで重要なのは、MCPサーバはBacklog情報を取得して返すだけということです。
レビューとして何を問題にするか、どの観点で見るか、どの形式で出力するかはPRレビュースキル側で扱います。
MCPサーバが公開できるもの
MCPサーバは、外部機能やデータをいくつかの形で公開できます。
OpenAI Developersのドキュメントでは、MCPサーバが公開できるものとして、tools、resources、prompts、instructionsが挙げられています。
参考: MCP server - What an MCP server provides
この連載で主に扱うのはtoolです。
| 種類 | ざっくりした説明 | 今回使うか |
|---|---|---|
| tool | モデルが構造化された入力で呼び出せる関数 | 使う |
| resource | クライアントが読めるデータやコンテンツ | 今回は中心ではない |
| prompt | 再利用可能なプロンプトテンプレート | 今回は中心ではない |
| instruction | サーバ全体の利用ガイダンス | 補助的に使う |
今回作るMCPサーバでは、get_issue_context というtoolを公開します。
toolは、AIエージェントが呼び出せる関数のようなもの、と捉えると分かりやすいです。もう少し正確に言うと、呼び出せる機能そのものと、その説明やschemaのセットです。
どんな機能なのか、引数には何を渡せばいいのか、どんな形式で結果が返ってくるのか。エージェントはその情報を見て、引数を渡してtoolを呼び出し、結果を受け取って後続処理へ進んでいきます。
今回のtoolとしては下記のような設定になります。
入力はBacklog課題URLです。
{
"backlog_url": "https://your-space.backlog.jp/view/PROJECT-123"
}
出力は、PRレビューで使いやすいように正規化した課題コンテキストです。
{
"issue": {},
"comments": [],
"change_logs": [],
"relationships": {},
"retrieval": {}
}
このように、toolには名前、説明、入力、出力があります。エージェントはtoolの説明やschemaを見て、「この場面ではこのtoolを呼べばよさそうだ」と判断します。
tool呼び出しは何が起きているのか
MCPのtool呼び出しは、概念としては次の流れです。
- hostがMCPサーバに接続する
- clientがMCPサーバのtool一覧を取得する
- モデルがユーザー依頼に合うtoolを選ぶ
- モデルがtoolのinput schemaに合う引数を作る
- MCPサーバが引数を検証し、外部APIなどを呼ぶ
- MCPサーバが結果を返す
- モデルが結果を使って回答や次の作業を続ける
OpenAI DevelopersのMCP serverドキュメントでも、clientによるtool discovery、モデルによるtool選択、サーバによる検証と処理、モデルによる結果利用という流れが説明されています。
今回のBacklog MCPサーバなら、流れはこうです。
ユーザー:
このPRをレビューして
Codex:
PR本文にBacklog URLがある
get_issue_contextを使えそう
Codex -> MCPサーバ:
get_issue_context({
"backlog_url": "https://your-space.backlog.jp/view/PROJECT-123"
})
MCPサーバ:
URLのscheme、host、port、pathを検証する
/view/<issue-key> から課題キーを抽出する
Backlog APIから課題本文、コメント、変更履歴を取得する
structured responseとして返す
Codex:
返ってきた課題情報をPRレビューの要求整理に使う
この時点で、MCPサーバは「レビューとして正しいかどうか」を判断していません。MCPサーバが担当しているのは、あくまでBacklog情報の取得と正規化です。
REST APIと何が違うのか
ここで疑問になるのが、「それなら普通にREST APIを呼べばいいのでは」という点です。エージェントは利用できるAPIがあれば直接それを呼ぶことだって可能なはずです。
実際、MCPサーバの中ではBacklog REST APIを呼びます。外部サービスがREST APIを提供しているなら、MCPサーバはそのAPI clientを内部に持つことになります。
では、REST APIとMCPは何が違うのでしょうか。
REST APIは、アプリケーション同士がHTTPでやり取りするためのインターフェースです。たとえばBacklog APIなら、課題詳細を取得するendpoint、コメントを取得するendpoint、添付ファイルを取得するendpointなどが用意されています。
一方でMCPは、AI clientが外部ツールを発見し、呼び出し、結果を利用するためのインターフェースです。
つまり、同じ「外部データを取る」でも、見ている相手が違います。
| 観点 | REST API | MCP |
|---|---|---|
| 主な利用者 | 通常のアプリケーションコード | AI client / agent |
| 関心 | HTTP endpoint、method、status code、認証 | toolの発見、input schema、出力、モデルが使いやすい説明 |
| 粒度 | 外部サービスのAPI設計に従う | AIの作業単位に合わせて設計できる |
| 今回の例 | Backlog APIの課題詳細・コメント取得 | get_issue_context(backlog_url) |
今回のPRレビューでは、Backlog APIのendpointをそのままAIに見せたいわけではありません。
レビューに必要なのは、「このBacklog URLの課題について、本文、コメント、変更履歴、関連情報をまとめたコンテキスト」です。
そのため、MCPサーバ側でBacklog APIの細かい呼び出しを隠し、PRレビュースキルが扱いやすい1つのtoolにまとめることができます。
Backlog REST API:
GET /api/v2/issues/:issueIdOrKey
GET /api/v2/issues/:issueIdOrKey/comments
...
MCP tool:
get_issue_context(backlog_url)
REST APIは外部サービスの都合で設計されます。MCP toolはAIの作業単位に合わせて設計できます。
もちろんMCPサーバ内でAPIの呼び出しをしないこともあります。
MCPサーバは、エージェントへ見せるラッパーのようなものです。内部ではAPIなどを呼び出し、その結果を整形してエージェントに渡します。今回の文脈では「AIのための翻訳レイヤー」に近い立ち位置です。
なぜBacklog URLをそのまま渡すのか
今回のtoolでは、課題キーではなくBacklog URLを受け取る設計にします。
{
"backlog_url": "https://your-space.backlog.jp/view/PROJECT-123"
}
理由は、実際のレビュー依頼では、PR本文やGitHub Issue本文にBacklogのURLが貼られていることが多いと考えたためです。
ただし、PR本文に含まれるURLをそのまま外部接続に使うのは危険です。
たとえば、PR本文に任意のURLが書かれていたとして、そのURLへMCPサーバが無条件にアクセスしてしまうと、意図しないhostへの通信が発生します。レビュー対象のPR本文は、あくまで外部入力です。そこに書かれたURLを信用しすぎてはいけません。
そのため、MCPサーバ側で次のように検証します。
- 許可されたBacklog base URLとscheme、host、portが一致する
- user infoを含むURLは拒否する
- pathは
/view/<issue-key>だけを受け付ける - issue keyの形式を検証する
- Backlog API clientへはURLではなく、検証済みの課題キーだけを渡す
この設計にしておくと、PRレビュースキルはPR本文から見つけたBacklog URLをそのままMCPサーバへ渡せます。一方で、MCPサーバが許可されていないURLへの接続を防ぎます。
transportとは何か
MCPでは、hostとserverが通信するためのtransportも重要です。
transportは、ざっくり言うと通信路です。
MCPサーバとの通信には、ローカルプロセスの標準入出力を使うstdio transportや、HTTPを使うtransportがあります。OpenAI DevelopersのMCP serverドキュメントでは、本番のMCPサーバは安定したHTTPS endpointへdeployし、streamable HTTP transportを使うことが説明されています。
今回の連載では、開発しやすさを優先してstdio transportを使います。
Codex
↓ stdio
Docker Composeで起動したBacklog MCPサーバ
↓ HTTPS
Backlog API
stdio transportでは、MCPサーバの標準入力と標準出力を使ってJSON-RPCメッセージをやり取りします。
そのため、MCPサーバのstdoutへ通常のログを雑に出してはいけません。stdoutはMCPの通信路として使われるため、余計な文字列を出すとclientがJSON-RPCとして解釈できなくなります。
MCPサーバはAIモデルではない
MCPを理解するときに、自分が最初に混乱しやすいと思った点があります。
それは、MCPサーバが何か賢い判断をする存在に見えてしまうことです。
しかし、MCPサーバはAIモデルではありません。
今回作るBacklog MCPサーバも、PRレビューの良し悪しを判断しません。コードの問題点も探しません。要求に対して実装が足りているかも判定しません。
MCPサーバがやることは、もっと限定的です。
- Backlog URLを検証する
- Backlog APIを呼ぶ
- 課題本文を取得する
- コメントを取得する
- 変更履歴を取り出す
- 関連情報を正規化する
- 取得できなかった範囲を
partialやwarningsで示す
レビュー判断はPRレビュースキルの責務です。
PRレビュースキルでは、次のような判断手順を定義します。
- PR本文、GitHub Issue、Backlog課題から要求を整理する
- 要求に
R-001のようなIDを付ける - 実装、テスト、設定、ドキュメントと突き合わせる
- 固定15観点で確認する
- 指摘に
F-01のようなIDを付ける -
must、question、suggestion、nitpickに分類する - GitHub PRコメントとして読みやすい形に整える
ここを分けておくと、MCPサーバは小さく保てます。Backlog以外のサービスへ広げるときも、外部データ取得とレビュー判断を混ぜずに拡張できます。
あくまでもAIエージェントと外部サービスをつなぐための「翻訳レイヤー」という立ち位置にいるのが、MCPサーバです。
今回の連載におけるMCPサーバの役割
この連載で作るMCPサーバは、Backlog読み取り専用です。
公開するtoolは、まずは get_issue_context だけにします。
get_issue_context(backlog_url)
このtoolは、許可されたBacklogスペースの課題URLだけを受け取り、レビューに必要な情報を1つのstructured responseへまとめて返します。
{
"issue": {
"key": "PROJECT-123",
"summary": "...",
"description": "..."
},
"comments": [],
"change_logs": [],
"relationships": {
"parent": null,
"children": [],
"related": []
},
"retrieval": {
"source_url": "https://your-space.backlog.jp/view/PROJECT-123",
"comment_count": 0,
"comments_truncated": false,
"partial": false,
"warnings": []
}
}
retrieval を含めるのは、取得結果を盲信しないためです。
たとえば、課題本文は取れたけれどコメント取得に失敗した場合、レビュー側は「Backlog確認済み」と言い切るべきではありません。コメントに追加要求が書かれている可能性があるからです。
そのため、MCPサーバは一部取得失敗を partial: true として返し、どの範囲が未確認なのかを warnings に入れます。
この情報を受け取ったPRレビュースキルは、レビュー結果の未確認事項に「Backlogコメントが未取得のため、追加要求の有無は未確認」と書けます。
MCPサーバがただデータを返すだけでなく、取得範囲や失敗範囲も構造化して返す。これが、レビュー用途ではかなり重要になります。
今回のまとめ
今回は、MCPサーバが何をするものなのかを整理しました。
要点は次のとおりです。
- MCPは、AI clientを外部ツールやデータへ接続するための仕様
- MCPサーバは、tool、resource、prompt、instructionを公開できる
- MCPサーバはAIモデルではない。AIエージェントと外部サービスをつなぐ翻訳レイヤー
- toolは、モデルが構造化された入力で呼び出せる関数として扱える
- Backlog MCPサーバは外部データ取得を担当する
- PRレビュースキルは、取得した情報をどう解釈してレビューするかを担当する
第2回では、Pythonで実際にMCPサーバを作ります。まずは get_issue_context というtoolを実装していきます。その後、Backlog URLの検証とBacklog APIからの課題取得まで進めます。