MCP(Model Context Protocol)は、AIエージェントが外部ツールや社内システムにつながるための“共通のつなぎ方”みたいなものです。ローカルで試すだけなら、python server.py の一発で動くこともあります。でも、企業で本番運用するとなると話は別。元記事は、そのギャップをかなり実務的に埋めにいく内容でした。
正直、こういう記事は地味に見えて、あとで効いてくる話が多いです。認証が甘いと危ないし、止まったら困るし、アップデートで既存接続を切るのもまずい。AIまわりの話は派手なデモが目立ちますが、現場ではむしろこの“つまらないけど重要な部分”が本体だと思います。
restart、internal: true、resource limits の3点セットが効くMAJOR.MINOR.PATCH で考えるのが基本元記事が最初に挙げているのは、ローカルと本番の“3つの穴”です。
1つ目は認証です。ローカルの stdio モードは、雑に言えば「このプロセスに話しかける」形なので、誰が接続したかを厳密に見る仕組みがありません。本番ではそれだと危ない。社内の別サービスなのか、別部署の人なのか、外部の誰かなのかを区別しないといけません。
2つ目はプロセス管理です。Pythonのサーバーは、落ちても自分では起き上がりません。しかも、落ちたことを誰かに知らせるとは限らない。これは本当に現場泣かせです。デモでは気にならないのに、本番では「静かに死んでいた」が一番やっかいなんですよね。
3つ目はアップグレードです。MCP Serverには複数のAgentセッションが同時につながることがあります。ここでバージョンを上げるたびに接続が切れると、利用者からすると“ちょっと更新しただけなのに使えなくなった”になる。これはかなり印象が悪いです。
この記事で面白いのは、認証を一律に強化しろ、とは言っていないことです。むしろ用途で分けています。ここはかなり実務っぽい判断だと思います。
社内の閉じたネットワーク内で、サービス同士がやり取りするだけなら API Key がいちばんシンプルです。環境変数 MCP_API_KEY にキーを入れておき、HTTPの middleware で X-API-Key や Authorization: Bearer ... を見て照合する。これなら導入も運用も軽い。
ただし、API Key は“誰かが持っていれば通る”ので、個人ごとの権限管理には向きません。ユーザーごとに「この人はJiraのAプロジェクトだけ」「この人はBも見てよい」と分けたいなら OAuth 2.0 の出番です。OAuth は、ざっくり言うと「本人確認済みのログインを通じて、必要な権限だけ渡す仕組み」です。元記事では、Host 側(Claude Desktop や Claude Code のようなもの)がログイン時に token を取得し、それを MCP Server へ渡す流れに触れています。
さらに厳しい要件、たとえば金融・医療・政府系では mTLS が挙げられています。mTLS は mutual TLS の略で、サーバーだけでなくクライアント側も証明書で本人確認する方式です。これは面倒です。設定も運用も重い。でも、その“面倒さ”自体が安全性の裏返しでもあります。規制が厳しい現場なら、ここをケチるわけにはいかない。
個人的には、ここで「全部OAuthで統一」とならず、API Key・OAuth・mTLS を使い分けているのがいいなと思いました。世の中、何でも一番強い方式を選べばよいわけではなくて、コストとリスクの釣り合いで決めるのが本当の設計です。
元記事では、MCP Server を Docker で動かす例も出ています。これがまた実用的です。
まず Dockerfile では、依存関係を先にコピーして pip install し、その後にアプリ本体をコピーしています。これはキャッシュを効かせるための定石です。変更がなければ依存関係のインストールを毎回やり直さずに済みます。
それから、コンテナを root で動かさない。これも大事です。useradd で専用ユーザーを作り、そのユーザーで実行しています。こういうのは地味ですが、事故ったときの被害を小さくします。
さらに HEALTHCHECK を入れて、ちゃんと生きているか見ています。MCP Server は「起動している」だけでは足りません。応答できる状態でなければ意味がないからです。
docker-compose.prod.yml のほうでは、restart: unless-stopped が入っています。これは、落ちたら自動で再起動し、ただし人間が止めたなら止めっぱなしにする設定です。なかなか賢い。
internal: true のネットワーク設定も重要です。これで、そのDockerネットワークの外に通信を出さないようにできます。つまり、サーバーが勝手に外へつながりにくくなる。MCP Server が社内の閉域で使われる前提なら、かなり安心感があります。
あわせて CPU とメモリの上限も決めています。AI周辺のサービスは、意外とリソースを食いがちです。バグったときにホストマシン全体を巻き込むのは最悪なので、上限を切っておくのは合理的です。
Dockerを使わない場合は systemd で守る方法も紹介されています。Restart=always で落ちたら再起動し、journalctl でログを見る。これも典型的な運用の形です。クラウドでもオンプレでも、結局は「死んだら誰が起こすのか」を決めないといけないんですよね。

この部分はかなり面白いです。MCP Server をアップデートするとき、既存の Agent セッションを落とさずに切り替える方法が説明されています。
やり方はシンプルで、旧バージョンと新バージョンを並べて動かします。たとえば jira-mcp-stable に 1.2.0、jira-mcp-canary に 1.3.0 を置く。新しい方をまずテストし、問題がなさそうなら本番の参照先を切り替える。要するに、いきなり全部入れ替えない。これです。
この考え方はかなり大事です。とくに Agent は、裏で何を持ったまま会話しているか分かりにくいことがあるので、途中で接続を切ると妙な不具合になりがちです。だからこそ、旧版を残したまま新版を受ける構成が効く。
そして、バージョン番号のルールもきちんと整理されています。MAJOR.MINOR.PATCH の考え方です。

MAJOR は破壊的変更。たとえばツール名を変える、必須入力を変える、ツールを削る、といったものです。これは既存のAgentコードに影響するので、同時に直してもらう必要があります。
MINOR は後方互換の追加。新しいツールを増やす、任意のパラメータを追加する、返す情報を増やす、など。既存利用は壊さず、新機能を足すイメージです。
PATCH はバグ修正やログ改善など、挙動を壊さない修正です。これなら透明にアップグレードできます。

元記事では、Server の version="1.3.0" のように明示して、Client へも返す形を示していました。こういう“どの版と会話しているかを見える化する”のは、地味ですが本当に効きます。
もうひとつ印象に残ったのが、deprecated なツールの扱いです。たとえば search_jira という古いツール名を残しつつ、新しい search_issues に内部でつなぐ。ログには「このツールは古い。新しい名前を使って。v2.0.0で削除する」と警告を出す。
これ、すごく実践的です。理想を言えば古いものはすぐ消したい。でも現場では、誰かの古いスクリプトやAgent設定がまだ残っています。そこでいきなり切ると壊れる。だから一定期間は両方動かし、使われ方をログで見てから消す。90日くらいの猶予を置く、というのも現実的です。

こういう設計は、単に優しいだけではなく、移行コストをコントロールする意味でも重要です。システム変更のコストって、コードを書く時間より、周辺の人たちが追従する時間のほうが大きいことが多いので。
元記事全体を通して感じるのは、「MCPを本番で使うなら、デモの延長ではだめ」というかなりまっとうなメッセージです。認証をどうするか、落ちたらどうするか、更新時にどう守るか。この3つを雑にすると、せっかくのAI連携もすぐ不安定になります。

個人的には、MCPそのものの機能より、こうした運用設計のほうがずっと価値があると思います。AIツール連携は“つながれば勝ち”に見えますが、実際には“つなぎ続けられるか”のほうが難しい。そこにちゃんと踏み込んでいるのが、この記事のいいところでした。
参考: MCP Series (07): Enterprise Deployment — Security, Authentication, and Version Management