概要
MCP(Model Context Protocol)は、AIクライアントが外部のツールやデータを呼び出すための共通プロトコルです。社内の業務APIやデータベース、設備をMCPサーバーとして用意すると、チャット画面でもエディタ内のAIエージェントでも、同じツールを同じ手順で呼べるようになります。
ただ、個人の検証から全社利用に広げる段階では、プロトコルの仕様だけでは決まらない運用上の論点が出てきます。誰が呼んでいるのか(認証)、どのツールを誰に見せるのか(公開範囲)、書き込みを誰が止めるのか(承認)、後から何を確認できるのか(ログ)の4つです。
本記事では、社内のツールを外部のAIクライアントへ公開する向きと、社内のAI基盤から外部のMCPサーバーへつなぐ向きの両方について、この4つの設計の考え方を整理します。
MCPを社内で使い始めると起きること
MCPサーバーは、tools/list で使えるツールの一覧と引数のスキーマを返し、tools/call で実際の処理を実行します。仕組みが単純なため、開発者が自分で書いたMCPサーバーを自分のAIクライアントに登録する、という使い方はすぐに広がります。
一方で、この広がり方をそのまま全社に持ち込むと、次のような状態になりがちです。
- 社内APIの認証情報が、個人のPCや設定ファイルに散らばる
- 参照だけのつもりで公開したサーバーに、更新系のツールが含まれている
- AIが何を呼んだのかが、各クライアントの手元にしか残らない
- 退職や異動のあとも、登録したMCPサーバーが動き続ける
これを解消するには、MCPサーバーを個人の持ち物から、権限と記録を持つ社内の共有部品として扱い直す必要があります。最初に、どちらの向きの接続を設計しているのかをはっきりさせます。
| 向き | 典型的な構成 | 主な論点 |
|---|---|---|
| 社内基盤がMCPサーバーになる | 外部のAIクライアントが、社内基盤の /mcp に接続する | クライアントの認証、ツールの公開範囲、承認者がいない経路の扱い |
| 社内基盤がMCPクライアントになる | 社内のチャットやワークフローが、別のMCPサーバーを呼ぶ | 接続先の確認、ツール名の衝突、申告された権限の扱い |
同じ基盤が両方の役割を持つ場合でも、守り方は向きによって異なります。
認証:誰が呼んでいるかを決める
MCPの呼び出しは、最終的に「どの利用者の権限で実行されたか」に結び付けます。結び付けられないと、データの閲覧権限もログの追跡も成り立たないためです。
閉域網の中では、接続ごとに発行するAPIキーをBearerトークンとして送る方式が扱いやすいです。クライアント側の設定は、多くの場合次のような形になります。
{ "mcpServers": { "internal-tools": { "type": "http", "url": "https://ai-gateway.example.com/mcp", "headers": { "Authorization": "Bearer <発行したAPIキー>" } } } }
クラウド上のAIサービスから接続したい場合や、社員のIDで統一したい場合は、社内のIDプロバイダー(Entra IDなど)が発行するOAuthのアクセストークンで認証する方法もあります。このとき大切なのは、トークンの持ち主を既存の利用者に対応付け、見つからなければ拒否することです。トークンの検証が通ったからといって利用者を自動で作ると、誰がその利用者を管理するのかが曖昧になります。
APIキーについても、次の項目をキー単位で持たせると運用で困りません。
- 有効期限と、無効化した後も利用量の集計には残す扱い
- 接続元IPの許可リスト
- 1分あたりのリクエスト数と、月あたりのトークン数・リクエスト数の上限
公開範囲:誰にどのツールを見せるか
提示と実行の2段階で絞る
ツールの公開範囲は、一覧に出す段階と実行する段階の2か所で絞ります。
tools/listでは、そのキーに許可した範囲のツールだけを返すtools/callでは、一覧に出していないツール名の呼び出しを拒否する- 引数は、スキーマの必須項目と型をサーバー側で検査してから処理に渡す
一覧に出さないだけでは、ツール名を知っているクライアントが直接呼び出せてしまいます。逆に実行時の検査だけでは、AIが使えないツールを何度も試すことになります。両方で絞るのが基本です。
権限区分はサーバー側で決める
ツールは「読み取り」「書き込み」「実行」のように、副作用の大きさで区分しておきます。MCPには、ツールの性質を示す annotations という仕組みがあります。
| annotations | 意味 | 割り当てる区分 |
|---|---|---|
readOnlyHint: true | 環境を変更しない | 読み取り |
destructiveHint: false | 変更はするが破壊的ではない | 書き込み |
| 宣言なし | 不明 | 実行(最も厳しい区分) |
宣言がないツールを最も厳しい区分に倒しておけば、書き忘れが権限の抜けにつながりません。なお、区分はAIモデルの申告ではなく、ツール名と引数からサーバーが決めることが重要です。SQLを受け取るツールであれば、文の中身を見てSELECTなら読み取り、更新文なら書き込み以上として扱います。
MCPサーバーを書く側は、ツールごとに性質を宣言しておきます。以下はPythonのMCPライブラリでの一般的な書き方の例です。
from fastmcp import FastMCP mcp = FastMCP("inventory") @mcp.tool(annotations={"readOnlyHint": True}) def get_stock(item_code: str) -> dict: """在庫数を返す(参照のみ)""" ... @mcp.tool(annotations={"destructiveHint": False}) def reserve_stock(item_code: str, quantity: int) -> dict: """在庫を引き当てる(更新あり)""" ...
業務単位の設定に束ねる
公開範囲をキーごとに個別設定すると、管理が追いつかなくなります。「品質保証部向けの問い合わせ用」「生産技術の装置データ参照用」のように、業務単位の設定として範囲を定義し、キーをそれに紐付けるのが現実的です。
DigitalBaseでは、APIキーにアシスタント設定(モデル、使えるデータやツールの範囲、許可する最大の権限区分)を紐付け、そこから tools/list の結果を組み立てる仕組みにしています。範囲はアシスタント設定、キーの制限、クライアントの要求の順に狭まるだけで、途中で広げる経路は持たせていません。
書き込みの承認:人がいる経路と、いない経路
人がいる経路では、実行前に止める
社内のチャット画面のように操作している本人がその場にいる経路では、書き込み以上のツールを実行する前に確認を求めます。DigitalBaseでは、承認モードを次の段階に分けています。
| モード | ツールの扱い |
|---|---|
| ツールなし | ツールを使わず、会話だけ |
| 計画 | 読み取りだけを自動で通す |
| 都度承認 | 読み取りは自動、変更・実行は1回ごとに承認を求める |
| 全自動 | すべて承認なしで通す |
承認画面には、ツール名だけでなく対象と値(どのテーブルの何件か、どの宛先に何を送るか)を表示します。また、承認待ちには上限時間を設け、時間切れは拒否として扱います。放置された承認待ちが、会話や処理を残し続けるのを防ぐためです。「許可」「拒否」「以後この会話では許可」といった応答そのものも記録に残します。
人がいない経路では、範囲で守る
外部のAIクライアントやバッチからMCPで呼ばれる経路には、その場で承認する人がいません。この経路で書き込みを止める手段は、最初から見せないことです。外部のクライアントに渡すキーは、許可する最大の区分を「読み取り」か「書き込み」までに設定しておきます。上限を指定しないと、シェル実行やファイル削除のような強い権限のツールまで一覧に出てしまいます。
承認が必要な操作は、承認者がいる画面からだけ実行できるようにする。これが、両方の経路を持つ基盤での基本方針です。
外部のMCPサーバーにつなぐ側の設計
社内基盤がクライアントとして他のMCPサーバーを呼ぶ場合も、公開する側と同じ考え方で守ります。
- ツール名を名前空間で区切る:複数のサーバーが同じ
searchというツールを持つことはよくあります。サーバー名を接頭辞にしたツール名に変換し、説明文にも「どのサーバーのツールか」を付けておくと、衝突を避けられ、AIも出どころを区別できます - 接続先を確かめる:URLのスキームを限定し、リンクローカルアドレス(クラウドのメタデータサービスなど)への接続は拒否します
- 待ち時間に上限を設ける:ツール一覧の取得とツールの実行に、それぞれタイムアウトを設けます。応答しないサーバーが会話全体を止めないようにするためです
- 申告された区分を過信しない:annotationsはサーバーの作者が書いたものです。宣言がなければ最も厳しい区分として扱い、承認や上限の対象にします
社内の業務APIや装置をMCP化する場合は、開発者が個別に立てたサーバーを登録するより、基盤側でサーバーを動かす方が統制しやすくなります。DigitalBaseでは、利用者が画面で書いたMCPサーバーのコードを基盤が別プロセスとして起動・監視し、ツール一覧の取得で稼働を確認する仕組みにしています。コードの更新に失敗した場合は直前のバージョンが動き続けます。共有先の部署はツールを選んで使えますが、コードやログ、エラーの詳細を見られるのは作成者だけです。
ログ:何を残すか
MCPのツール呼び出しは、1回ごとに1行の監査ログを残します。最低限、次の項目があれば後から追跡できます。
| 項目 | 用途 |
|---|---|
| 利用者・APIキー | 誰の権限で実行されたか |
| 経路(チャット・MCP・ワークフローなど) | どこから呼ばれたか |
| サーバー名・元のツール名 | 何が呼ばれたか |
| 引数の要約 | 何に対して実行されたか |
| 成否・所要時間 | 失敗や遅延の切り分け |
| 承認の応答 | 誰が許可または拒否したか |
引数をそのまま保存すると、パスワードやトークンが紛れ込むことがあります。記録前に秘密情報らしい値を伏せ、長さに上限を設けて切り詰めます。
{ "action": "tool_call", "user": "user-1234", "channel": "mcp", "server": "inventory", "tool": "reserve_stock", "arguments": "{\"item_code\": \"A-100\", \"quantity\": 5}", "ok": true, "latency_ms": 182 }
ツールの実行結果の全文までは残さず、利用量の集計とは別の監査ログとして持つと、保存量と見られる範囲を分けて管理できます。
運用チェックリスト
社内でMCPを運用する前に、次の項目を確認しておきます。
- すべての呼び出しが、既存の利用者またはキーに結び付いているか
- 外部クライアントに渡すキーに、権限区分の上限を設定したか
- annotationsのないツールが、最も厳しい区分として扱われるか
- 一覧に出していないツールの呼び出しを、実行時にも拒否しているか
- 承認待ちに上限時間があり、承認の応答も記録されるか
- 監査ログの引数から、秘密情報が伏せられているか
- 外部MCPサーバーの接続先とタイムアウトを確認しているか
まとめ
MCPの運用設計では、プロトコルが自由な分、権限と記録を基盤側で決めることが要点です。
- 認証:呼び出しを既存の利用者に結び付け、対応しない主体は拒否する
- 公開範囲:一覧と実行の2段階で絞り、区分はサーバー側で決める
- 承認:人がいる経路では実行前に確認し、人がいない経路では範囲で守る
- ログ:1呼び出し1行で、誰が・どこから・何を・どうなったかを残す
公開する向きとつなぐ向きのどちらでも、同じ4つの観点で設計しておくと、ツールが増えても管理の仕方を変えずに済みます。