このMCPサーバーは安全?導入前にできる第三者製MCPサーバーの見極め方と12のサイン【MCP Security 2026】
第三者製MCPサーバーを導入前に見極める方法。公式MCP Registryが確認していること・いないこと、15分でできる8ステップ、怪しいサーバーの12のサイン、バージョン固定で本当に固定されるもの(検証:依存12個中4個、81個中5個にしかprovenanceなし)、設定ファイルの点検スクリプト、チームの承認フローまで。
最終更新:2026年10月22日 / 対象:MCP仕様 2026-07-28版(Security Best Practices)、MCP公式ドキュメント「Local Server Security」(2026-07-28版)、公式MCP Registry(プレビュー版)、SEP-1024、npm provenance、OWASP MCP04:2025
結論(30秒で読める要約)
MCPサーバーの見極め(vetting)とは、そのサーバーを一度も動かす前に「公開者・パッケージそのもの・依存関係を信頼してよいか」を判断し、判断が外れたときのために渡す権限をどこまで絞るかを決めることです。第三者製MCPサーバーに対するMCP Securityの「導入前」の部分にあたります。導入後の部分は、サンドボックス化とツール定義の固定が担います。
「このMCPサーバーは安全か?」という問いに、検査で「安全だ」と証明する方法はありません。MCP公式ドキュメント自身が「サーバーが何をするかを証明できるチェックは存在しない」と書いています。そのうえで、15分ほどでできることは次の5つです。
- レジストリに載っていることを「審査済み」と読まない。公式MCP Registryが確認するのは、名前空間とパッケージの持ち主だけです。モデレーションポリシーには「モデレーションはほぼ無いものと考えるべき」とあり、脆弱性のあるサーバーも削除対象外です(3章)。
- 3つの名前を突き合わせる。レジストリの名前空間、ソースリポジトリ、パッケージ名が同じ公開者を指しているか確認します。初めて見つかった悪意あるMCPサーバー
postmark-mcpは、本物のベンダーと同じ名前を名乗っていました(2章)。 - 思っているより深く固定する。今回の検証では、バージョンを指定して
npm installしてもpackage.jsonには^付きの範囲で保存されました。npm provenanceが付いていたのは、公式ファイルシステムサーバーの依存ツリー12個中4個、mcp-remoteは81個中5個だけでした(6章)。 - パッケージだけでなく設定ファイルも点検する。短いスクリプトで10件のサンプル設定を調べたところ、6件で問題が見つかりました。バージョン未固定、トークンの直書き、Dockerソケットのマウント、シェル経由の実行、平文HTTPです(7章)。
- 動かし方は導入前に決める。リモートのAPIを包むだけのサーバーなら、そもそも手元のPCで動かす必要はありません。
目次
- MCPサーバーを見極めるとは
- なぜ見極めが必要か:第三者製MCPサーバーが触れられる範囲
- レジストリや一覧サイトが確認していること・していないこと
- 15分でできる見極め手順(8ステップ)
- 怪しいMCPサーバーの12のサイン
- バージョン固定で実際に固定されるもの(検証)
- 検証:MCPクライアントの設定ファイルを点検する
- リモートMCPサーバーの見極め(パッケージではなくURLの場合)
- スキャナーとツール:何が見つかり、何が見つからないか
- チームでの承認フロー
- チェックリスト(15項目)
- よくあるハマりどころ(症状→原因→対処)
- NodeFlareならこう解決できる
- FAQ
1. MCPサーバーを見極めるとは
MCPサーバーを見極めるとは、出どころ(誰が、どのソースから公開したか)、正体(インストールするパッケージが、ドキュメントの指すものと同一か)、依存関係、求められる権限を確認し、「承認」「条件付き承認」「却下」のいずれかを記録することです。
このブログで扱ってきた他の対策との位置関係は次のとおりです。
| 段階 | 問い | 対策 | 関連記事 |
|---|---|---|---|
| 導入前 | そもそも信頼してよいか | 見極め(この記事) | — |
| 実行時(毎セッション) | ツール定義が変わっていないか、指示が隠れていないか | ツール定義の固定、説明文の確認 | MCPのtool poisoning対策ガイド |
| 信頼が外れたとき | どこまで届いてしまうか | サンドボックス、Egress許可リスト、スコープを絞ったトークン | MCPサーバーのサンドボックス化ガイド |
MCP公式ドキュメントは、この関係を一文でまとめています。「見極めは誤った信頼判断の確率を下げ、封じ込めは誤った判断の代償を決める」。
2. なぜ見極めが必要か:第三者製MCPサーバーが触れられる範囲
ローカルのMCPサーバーは、ネットからダウンロードして自分のユーザー権限で動かす普通のソフトウェアです。2026-07-28版の「Local Server Security」ガイドは、ローカルサーバーが環境変数を引き継ぎ、アカウントが読めるものは何でも読め、どこへでも外向き通信を開けると書いています。さらに、設定したサーバーはすべてLLMのコンテキストを共有するため、「1つ追加するたびに、他のすべてのサーバーがさらされる攻撃面が広がる」とも指摘しています。
サプライチェーンの経路ごとに、すでに公開事例があります。
| 経路 | 公開事例 | 何が起きたか(出典の記述どおり) | 導入前に効いたはずの確認 |
|---|---|---|---|
| なりすましパッケージ | npmの postmark-mcp(2025年9月) |
Postmark公式ライブラリと同じ名前を名乗り、バージョン1.0.16で送信メールすべてを公開者宛てにBCCする1行が追加された。Koi Securityが発見した時点で1,643ダウンロード。Postmarkは自社の開発・許可を否定 | ベンダー自身のリポジトリやドキュメントとパッケージを突き合わせる |
| 依存パッケージの侵害 | npmワーム「Shai-Hulud」(2025年9月) | CISAによれば500以上のパッケージが侵害された。GitHubトークンやクラウドの鍵を収集し、乗っ取ったメンテナーのアカウントで自己増殖した | ロックファイルやイメージのダイジェストで依存ツリーごと固定する。外向き通信は既定で拒否する |
| 悪意ある設定 | OX SecurityによるSTDIOの開示(2026年4月) | CSAのリサーチノートによると、公式SDKのstdio起動経路で設定値がOSのシェルに渡るため、MCPの設定を書き換えられる人はコマンドを実行できる。下流のツールで少なくとも14件のCVE。Anthropicはこの挙動を「想定どおり」とした | command と args はコードとして扱い、設定の変更はすべてレビューする |
| 脆弱なブリッジ | CVE-2025-6514(mcp-remote 0.0.5〜0.1.16未満) |
信頼できないサーバーへの接続時に、細工された authorization_endpoint からOSコマンドインジェクション(CVSS 3.1:9.6) |
勧告とバージョンを照合する。知らないサーバーにブリッジを向けない |
| 便利そうに見える悪意あるサーバー | Kasperskyの検証用PoC(2025年9月) | 開発者向けの機能が本当に動くサーバーで、検知できたのはネットワークセンサーが不審な外向き通信を捉えたときだけだった | 新しいサーバーはEgressを絞って動かし、接続先を見る |
OWASPはこのリスクを、MCP Top 10の中で MCP04:2025「Software Supply Chain Attacks & Dependency Tampering」として挙げています。
3. レジストリや一覧サイトが確認していること・していないこと
公式MCP Registry(registry.modelcontextprotocol.io、現在プレビュー版)が確認しているのは持ち主であって、安全性ではありません。各チェックが何を証明するかを表にまとめます。
| チェック | 仕組み(レジストリのドキュメントより) | 証明できること | 証明できないこと |
|---|---|---|---|
GitHub名前空間 io.github.<user>/* |
公開者が mcp-publisher からGitHubのOAuthでログイン |
そのGitHubアカウントや組織を公開者が管理している | そのアカウントが、想定しているベンダー本人であること |
ドメイン名前空間 com.example/* |
DNSのTXTレコード、または /.well-known/mcp-registry-auth にEd25519かECDSA P-384の公開鍵を置く |
そのドメインを公開者が管理している | コードについては何も |
| npmパッケージ | package.json の mcpName がサーバー名と一致すること(MUST) |
レジストリの登録とnpmパッケージの持ち主が同じ | パッケージや依存関係が安全であること |
| PyPI・NuGet・Cargo | READMEに mcp-name: <サーバー名> の文字列 |
同上 | 同上 |
| OCIイメージ | io.modelcontextprotocol.server.name アノテーション |
同上 | 同上。タグは後から付け替えられる |
| MCPBバンドル | server.json の fileSha256。レジストリはこのハッシュを「検証しない」、検証するのはクライアント |
ダウンロードしたファイルが登録されたファイルと同一 | 誰が書いたか、何をするか |
| リモートサーバー | remotes[].url は公開アクセス可能であること(MUST) |
URLが応答する | 公開手順のページには、URLのドメインと名前空間を結びつける確認の記述がない |
| モデレーション | 違法コンテンツ、マルウェア、スパム、動かないサーバーを削除 | 既知の悪質なものの一部は消える | 「モデレーションはほぼ無いものと考えるべき」。脆弱性のあるサーバーは削除しない |
ここから言えることは3つです。
- 名前空間がいちばん頼れる身元の手がかりです。
io.github.github/...やcom.stripe/...は偽装しにくい一方、io.github.randomuser/stripe-mcpは、READMEがどれだけ立派でもStripeではありません。 - 削除されても消えてはいません。削除されたサーバーは
status: "deleted"になりますが、メタデータはAPIから読めるままです。社内カタログに同期している場合は、_meta["io.modelcontextprotocol.registry/official"].statusを確認してください。 - 踏み込んだモデレーションは上流が担います。レジストリ自身が、npm、PyPI、Docker、下流のサブレジストリに頼っていると書いています。MCP公式ドキュメントも、厳選型のカタログですら自らの審査を「ベストエフォート」と説明していると指摘しています。比較的強い手がかりとしては、Dockerのカタログがあります。ドキュメントによると、
mcp/配下のイメージはDockerがビルドと署名を行い、SBOMを同梱しています。
4. 15分でできる見極め手順(8ステップ)
上から順に進め、失敗したステップで止めます。
- ローカルで動かす必要があるか考える。MCP公式ドキュメントは、リモートのAPIを包むだけのサーバーは「PCで動かしても何も得をしない」と書いています。ベンダーのリモートサーバーを使うか、自分で手元のPC以外にホストします。
- 公開者を特定する。パッケージをソースリポジトリと実在のメンテナーや組織に結びつけます。リポジトリに最近のもっともらしい更新があるか、ベンダー自身のドキュメントがそのリポジトリを案内しているかを確認します。
- 3つの名前を突き合わせる。レジストリの名前空間、リポジトリの持ち主、パッケージ名が一致するかを1文字ずつ比べます。MCP公式ドキュメントの言葉では、タイポスクワッティングは「最も安上がりな攻撃」です。
- 要所のコードを読む。全部を監査する必要はありません。外向き通信、環境変数やホームディレクトリの読み取り、子プロセスやシェルの実行、インストール時スクリプトをソースから検索し、どれもサーバーの役割で説明がつくかを見ます。
- provenanceを確認する。npmなら
npm view <pkg>@<version> dist.attestationsで証明書(attestation)の有無がわかり、npm audit signatures(npm 9.5.0以降)でインストール済みパッケージの署名と証明書を検証できます。provenanceが示すのは、どのリポジトリ・コミット・ワークフローでビルドされたかです。コードが安全かどうかは示しません。 - 確認したバージョンで固定する。パッケージは厳密なバージョン、コンテナイメージはダイジェストで固定します(6章)。
- LLMに見せる前にツール一覧を読む。MCP Inspectorで接続し、ツール名・説明文・入力スキーマをすべて読みます。説明文にツールの役割と無関係な指示があれば、そのサーバーは外します。
- 動かし方を決めて記録する。固定したバージョン、渡すトークン(サーバーごとに1つ、最小のスコープ)、見せるディレクトリ、通信してよいホスト、承認者を書き残します。
ステップ2・5・6をnpmで行うコマンド例です。
# 誰が、どこから公開し、最後にいつ変わったか
npm view @modelcontextprotocol/server-filesystem@2.0.0 repository.url maintainers time.modified
# このバージョンにprovenanceの証明書があるか
npm view @modelcontextprotocol/server-filesystem@2.0.0 dist.attestations.provenance.predicateType
# そのバージョンを厳密に、インストール時スクリプトを実行せずに入れてから検証
npm install --save-exact --ignore-scripts @modelcontextprotocol/server-filesystem@2.0.0
npm audit signatures
5. 怪しいMCPサーバーの12のサイン
1つでも当てはまれば慎重に。2つ以上なら別のサーバーを探すことをおすすめします。
| サイン | なぜ問題か | 対処 |
|---|---|---|
| 有名ベンダーに似た名前なのに、公開者が違う | postmark-mcp と同じパターン |
ベンダー自身のドキュメントが示すものだけを入れる |
名前空間がベンダーと一致しない(例:io.github.someone/<vendor>-mcp) |
名前空間はレジストリが行う唯一の身元確認 | ベンダーのドメイン名前空間のものを優先する |
| リモートのAPIを呼ぶだけなのに、ローカルのstdio版しかない | ローカルに入れると、得るものなしにPCへの権限だけが増える | リモート版を使うか、PC以外でホストする |
導入手順が npx -y <pkg> や @latest |
起動のたびに最新版が実行される | 厳密なバージョンで固定する |
狭い用途なのに ~ や / などの広いルートを求める |
過剰収集。設定上の許可リストは「協力的な境界」にすぎない | プロジェクトのディレクトリ1つを読み取り専用で渡す |
| アカウント全体に効くトークンを求める | 1回の漏えいで、そのトークンが届く範囲すべてが漏れる | サーバー専用でタスクに絞ったトークンを発行する |
インストール時スクリプト(preinstall、postinstall)が通信する |
ツールを目にする前にコードが動く | --ignore-scripts で入れ、スクリプトを読む |
| ソースリポジトリが無い、アーカイブ済み、非公開、パッケージと無関係 | 動かすものを確認できない。npmでもリポジトリが削除・非公開になるとprovenanceを「確認できなくなる」 | 却下するか、自分で管理するフォークからビルドする |
| 最近持ち主が変わった、長く止まっていたのに急に更新された | 放置プロジェクトの乗っ取りはMCP公式ドキュメントが挙げる脅威 | 前回信頼した版との差分を読む |
| ツールの説明文に、他のツールについての指示や、操作を隠す指示がある | tool poisoningやshadowing | そのサーバーを外す |
設定が bash -c を経由する、ダウンロードしたものをシェルに流し込む |
設定そのものが攻撃の本体になる | 固定のバイナリと引数に置き換える |
| 認証なしでローカルのHTTPを待ち受ける | MCP公式ドキュメントいわく、127.0.0.1へのバインドは「認証の境界ではない」 | stdioにするか、トークンを必須にする |
6. バージョン固定で実際に固定されるもの(検証)
固定できるのは、指定した層だけです。MCP公式ドキュメントは、npx や uvx でのバージョン指定は「最上位のパッケージだけを固定する」もので、推移的な依存関係はインストールのたびに解決され、「そこがまさに侵害された依存パッケージが入り込む場所だ」と注意しています。
| 固定の方法 | 固定されるもの | 固定されないもの |
|---|---|---|
npx -y pkg |
何も | すべて |
npx -y pkg@2.0.0 |
最上位のパッケージ | 依存関係(範囲内で変わる) |
uvx pkg==2026.10.19 |
最上位のパッケージ | 推移的な依存関係 |
ロックファイルをコミットしたプロジェクトで npm ci |
npmの依存ツリー全体 | ランタイム自体、ネイティブのダウンロード |
コンテナイメージをタグで指定(:1.2.3) |
保証されない。タグは付け替えられる | すべて |
コンテナイメージをダイジェストで指定(@sha256:...) |
依存関係を含むファイルシステム全体 | イメージの中では何も残らない |
2026年10月22日に、npm 10.9.4とNode.js 22で、よく使われる3つのパッケージを空のプロジェクトへ --ignore-scripts 付きで入れて確かめました。
| パッケージ(入れたバージョン) | 依存ツリーのパッケージ数 | npm provenanceあり | 直接の依存関係の指定 |
|---|---|---|---|
@modelcontextprotocol/server-filesystem@2.0.0 |
12 | 4 | すべて ^ の範囲(例:diff ^8.0.3、glob ^13.0.6) |
@playwright/mcp@0.0.83 |
3 | 3 | 厳密なバージョン |
mcp-remote@0.15.2 |
81 | 5 | すべて ^ の範囲(例:express ^4.21.2、undici ^7.12.0) |
わかったこと:
- 「2.0.0を入れた」は固定ではありません。
npm install pkg@2.0.0を普通に実行すると、package.jsonには"^2.0.0"と書かれました。--save-exactを付け、ロックファイルをコミットし、npm ciで入れてください。 - 最上位のprovenanceは、ツリー全体についてほとんど何も語りません。3つとも最上位にはSLSAのprovenanceがありましたが、
mcp-remote配下の81個の大半にはありませんでした。今のnpmでは珍しいことではなく、だからこそ個々の証明書よりロックファイルやダイジェストが効きます。 - 依存関係を厳密に固定しているのは良いサインです。
@playwright/mcpは2つの依存を厳密なバージョンで指定しており、インストールのたびにツリーが変わることがありません。 - 固定には更新の習慣が要ります。MCP公式ドキュメントが言うとおり、勧告が出たときは「固定こそが脆弱なままにする原因」になります。固定したサーバーごとに勧告を追ってください。
計測について2点補足します。証明書の数はレジストリのメタデータから npm view で数えました。npm audit signatures は、検証環境のネットワーク制限でSigstoreのTUFエンドポイントに届かず完了できませんでした。数値はこの日時点のもので、メンテナーの対応が進めば変わります。
7. 検証:MCPクライアントの設定ファイルを点検する
設定ファイルもサプライチェーンの一部です。どのパッケージを、どの引数・トークン・マウントで動かすかを決めているからです。次の読み取り専用スクリプトは、mcpServers 形式のJSON(Claude DesktopやCursorなどが使う形式)から、よくある危険なパターンを洗い出します。2026年10月22日にPython 3で動作を確認しました。
#!/usr/bin/env python3
"""Flag risky entries in an MCP client config (mcpServers JSON). Read-only."""
import json, re, sys
SECRET = re.compile(r"(ghp_|github_pat_|sk-|xox[bp]-|AKIA|AIza)[A-Za-z0-9_\-]{8,}")
SHELLS = {"sh", "bash", "zsh", "cmd", "powershell", "pwsh"}
def pkg_arg(args):
return next((a for a in args if not a.startswith("-") and a != "run"), "")
def unpinned(spec, launcher):
if launcher == "npx":
name = spec[1:] if spec.startswith("@") else spec
return "@" not in name or spec.endswith("@latest")
if launcher in ("uvx", "pipx"):
return ("==" not in spec and "@" not in spec) or spec.endswith("@latest")
return False
def audit(cfg):
out, cmd, args = [], cfg.get("command", ""), [str(a) for a in cfg.get("args", [])]
exe = cmd.rsplit("/", 1)[-1]
if exe in ("npx", "uvx", "pipx") and unpinned(pkg_arg(args), exe):
out.append("HIGH unpinned package")
if exe in SHELLS or "-c" in args:
out.append("HIGH runs through a shell")
if exe == "docker":
if "@sha256:" not in " ".join(args):
out.append("MED image not pinned by digest")
if any("docker.sock" in a for a in args):
out.append("HIGH Docker socket mounted")
mounts = [b.split(":")[0] for a, b in zip(args, args[1:]) if a in ("-v", "--volume")]
if any(m in ("~", "/", "$HOME") for m in mounts):
out.append("HIGH home or root directory mounted")
if "--network" not in " ".join(args):
out.append("LOW no --network restriction")
if SECRET.search(json.dumps(cfg)):
out.append("HIGH literal secret in config")
url = cfg.get("url", "")
if url.startswith("http://") and not re.match(r"http://(127\.0\.0\.1|localhost)", url):
out.append("HIGH remote server over plain HTTP")
return out
if __name__ == "__main__":
for name, cfg in json.load(open(sys.argv[1])).get("mcpServers", {}).items():
print(f"{name}: " + ("; ".join(audit(cfg)) or "OK"))
危険な設定5件と、それぞれを堅くした設定5件、計10件のサンプルで実行した結果です。
| エントリ | 内容 | 検出結果 |
|---|---|---|
filesystem |
npx -y @modelcontextprotocol/server-filesystem |
HIGH バージョン未固定 |
filesystem-pinned |
同じものを @2.0.0 で指定 |
OK |
github |
some-github-mcp@latest、env に ghp_... のトークン |
HIGH バージョン未固定、HIGH 秘密情報の直書き |
fetch |
uvx mcp-server-fetch |
HIGH バージョン未固定 |
fetch-pinned |
uvx mcp-server-fetch==2026.10.19 |
OK |
db |
Dockerの :latest、-v /var/run/docker.sock:...、-v ~:/data |
MED ダイジェスト未固定、HIGH Dockerソケット、HIGH ホームをマウント、LOW ネットワーク制限なし |
db-hardened |
ダイジェスト指定、--network none、--read-only |
OK |
helper |
bash -c でスクリプトをダウンロードして sh に流し、サーバーを起動 |
HIGH シェル経由で実行 |
crm |
http://crm.example.com/mcp |
HIGH 平文HTTP |
crm-tls |
HTTPS、トークンは ${CRM_TOKEN} から参照 |
OK |
10件中6件で問題を検出し、堅くした4件はすべて通過しました。限界もあります。ここでの「OK」は、上のパターンが見つからなかったという意味にすぎません。バージョンを固定した uvx でも推移的な依存関係は毎回解決されますし(6章)、パッケージそのものの良し悪しは判断できません。共有している設定ファイルにはCIで、端末管理ツールで集めた設定ファイルには定期的に実行するのがおすすめです。
8. リモートMCPサーバーの見極め(パッケージではなくURLの場合)
リモートMCPサーバーは手元でコードを動かさないので、問いが「このコードは何に触れるか」から「このエンドポイントを誰が運用し、自分は何を渡すのか」に変わります。
| 確認すること | 理由 | 確かめ方 |
|---|---|---|
| ドメインはベンダーのものか | レジストリの公開手順ページには、リモートURLと名前空間を結びつける確認の記述がない | 一覧サイトだけでなく、ベンダー自身のドキュメントでURLを確認する |
| HTTPSで、認証があるか | トークンもツールの結果もネットワークを通る | 平文HTTPや、社内データに触れるのに認証のないものは却下する |
| 標準のMCP認可に対応しているか | OAuthなら、長期トークンをローカルの設定ファイルに置かずに済む | Protected Resource Metadata(RFC 9728)の有無と、要求スコープの狭さを見る |
| 同意画面でどんなスコープや権限を求めるか | 広すぎる付与は、1回の誤った呼び出しを大きな漏えいにする | タスクに不要な書き込み・管理スコープは断る |
| ツールの引数や結果にどんなデータが載るか | 引数に顧客データや秘密情報が入りうる | ベンダーのデータの扱いと保存期間の規約を読む |
| コミュニティ製なら、誰が運用しているか | 第三者のホストはすべてのリクエストを見られる | ベンダー公式を選ぶか、自分でデプロイする |
コミュニティ製のstdioパッケージで、APIを包んでいるだけの場合は中間の選択肢もあります。一度レビューしたうえで、自分で管理する基盤で動かし、コードを開発者のPCに一切置かない方法です。HTTPブリッジの比較はstdioのMCPサーバーをリモートで動かすチュートリアルにまとめています。
9. スキャナーとツール:何が見つかり、何が見つからないか
スキャナーは役に立ちますが、それぞれ1つの層しか見ていません。
| ツール | 確認するもの | 注意点 |
|---|---|---|
| MCP Inspector | サーバーが公開するツール名・説明文・スキーマをLLMを介さずに一覧表示 | MCP公式ドキュメントがステップ7で推奨。Inspector自体も更新を(CVE-2025-49596は0.14.1未満が対象) |
| Snyk Agent Scan(旧Invariantのmcp-scan) | エージェントの設定を自動で見つけ、MCPサーバーやスキルのプロンプトインジェクション、機密データの扱い、マルウェアを検査 | uvx snyk-agent-scan@latest で実行。SNYK_TOKEN が必要。検査のため構成要素の情報を解析APIへ送る(秘密情報は送信前に伏せると説明) |
npm audit signatures |
インストール済みnpmパッケージのレジストリ署名とprovenance | 出どころを検証するもので、振る舞いは見ない |
| SBOM生成ツール(Syft、Trivy) | 成果物の中身。MCP SDKのバージョンも含む | MCP公式ドキュメントは、公開されたSBOMを信じるより自分で生成することを勧めている |
| 設定ファイルの点検(7章) | バージョン未固定、秘密情報、マウント、シェル、平文HTTP | CIで安く回せる |
スキャナーが何も報告しないのは、「知っているパターンが見つからなかった」というだけです。サンドボックス化の記事で紹介した封じ込めは、いずれにしても外さないでください。
10. チームでの承認フロー
個人の見極めは、会社全体にはそのまま広げられません。MCP公式ドキュメントの組織向けの指針は、次の5つに集約できます。
- 承認済みサーバーの許可リストを公開する。固定バージョンと、受け入れ基準(公開者が特定できる、ソースが読める、provenanceのメタデータがある、SBOMがある)をセットにします。
- 承認された経路をいちばん楽な経路にする。利用者は、エディタの拡張機能と同じ感覚で、断りなくサーバーを入れるものだと考えておきます。
- 既定の動かし方を決める。たとえば「第三者製サーバーはホームディレクトリをマウントしないコンテナで動かす」。
- ローカルの権限が不要なものは集中してデプロイする。リモートの1インスタンスなら、パッチも監査も数百台ではなく1か所で済みます。
- 全社規模のインシデントに備える。設定の棚卸しから該当インスタンスをすべて見つけ、Egressを遮断し、渡していた認証情報をすべてローテーションし、修正済みの固定バージョンを配布します。
サーバーごとの承認記録は、1ページで十分です。
| 項目 | 記入例 |
|---|---|
| サーバーと固定バージョン | @modelcontextprotocol/server-filesystem@2.0.0 |
| 公開者の根拠 | 名前空間、リポジトリURL、provenanceあり |
| 動かす場所 | コンテナ、プロジェクトディレクトリを読み取り専用、--network none |
| 認証情報 | 不要 |
| 承認したツール | read_text_file、list_directory |
| 担当と日付 | プラットフォームチーム、2026-10-22 |
| 再審査のきっかけ | 新バージョン、持ち主の変更、勧告 |
11. チェックリスト(15項目)
導入前
- [ ] ローカルの権限が本当に必要か確認した。不要ならリモート版を使う
- [ ] 公開者を特定し、ベンダーのドキュメントがそのリポジトリを案内している
- [ ] 名前空間・リポジトリの持ち主・パッケージ名が一致している
- [ ] 外向き通信、環境変数やホームディレクトリの読み取り、シェル実行、インストール時スクリプトをソースで確認した
- [ ] provenanceや署名があり、対応しているエコシステムでは検証した
- [ ] MCP Inspectorでツール名と説明文を読んだ
固定
- [ ] 厳密なバージョンで保存(
--save-exact)しロックファイルをコミットした、またはイメージをダイジェストで固定した - [ ] どの設定にもバージョンなしの
npx -yや@latestがない - [ ] 固定したサーバーごとに勧告を追っている
動かし方
- [ ] 第三者製サーバーは隔離して動かし、素のプロセスでは動かさない
- [ ] サーバーごとに絞ったトークンを1つ、サーバー単位で渡している。個人の広いトークンは使い回さない
- [ ] 見せるのはプロジェクトディレクトリ1つ、できれば読み取り専用。
~やDockerソケットは渡さない - [ ] 外向き通信は既定で拒否し、想定する接続先を列挙している
組織
- [ ] 受け入れ基準つきの承認済みサーバー許可リストがある
- [ ] 設定ファイルの棚卸しと、試験済みの緊急停止手順(Egress遮断、認証情報のローテーション)がある
12. よくあるハマりどころ(症状→原因→対処)
| 症状 | 原因 | 対処 |
|---|---|---|
| 「公式レジストリに載っているから安全」と判断した | レジストリが確認するのは持ち主でコードではない。ポリシー上もモデレーションは最小限 | 他のパッケージと同じく公開者とコードを確認する |
| 固定したはずのサーバーが、入れ直したら挙動が変わった | 固定していたのは最上位のパッケージだけ | ロックファイルと npm ci、またはコンテナのダイジェスト |
「固定」したのに package.json が ^2.0.0 |
npm install pkg@2.0.0 は既定で範囲を保存する |
--save-exact を使う |
| 不要なはずの鍵をサーバーが読んでいた | シェルのプロファイルでexportした秘密情報を引き継いだ | 秘密情報はサーバーごとの設定で渡す |
| 承認済みのサーバーが知らないホストに通信し始めた | 悪い更新、依存パッケージの侵害、またはインジェクション | Egress許可リストと、新しい接続先へのアラート |
| チームの設定ファイルに本物のトークンが入っている | env やヘッダーに直接貼った |
シークレットストアや環境変数から参照する |
| 脆弱なサーバーがどのPCで動いているかわからない | 棚卸しがない | 端末管理ツールでクライアントの設定を収集する |
| スキャナーは通ったのにインシデントが起きた | スキャナーは既知のパターンを見るだけで、意図は判断できない | 隔離とEgress制限は外さない |
13. NodeFlareならこう解決できる
NodeFlareはリモートMCPサーバーのホスティングサービスです。GitHubリポジトリからデプロイすると、各サーバーは専用のFirecracker microVMで動き、手前のプロキシがすべてのリクエストを認証・認可・記録します。ただし、パッケージの見極めを代わりに行うものではありません。依存関係のスキャン、署名の検証、コミットの固定はドキュメントに記載がないため、4章のステップ1〜7はご自身で行う必要があります。変わるのは「動かし方」です。承認したサーバーを開発者のPCから離し、一般的なローカル導入より厳しい制限の中で動かせます。この記事で挙げたリスクと、ドキュメントに記載された機能の対応は次のとおりです。
| この記事のリスク | NodeFlareの機能 | 内容 |
|---|---|---|
| 第三者製サーバーが開発者のファイルや鍵を読む(2章) | サーバーごとのFirecracker microVM | サーバーはPCではなく専用のmicroVMで動くため、~/.ssh やブラウザのプロファイルがそもそも存在しない |
| レビューしていないコードが動く | 自分で選んだGitHubリポジトリからデプロイ | レビューしたリポジトリ(自分のフォークなど)を指定できる。entry_command と build_command を明示すれば自動検出より優先され、不足しているビルドツールは許可リスト(git、unzip、build-essential など)からのみ入る |
| 悪い更新や依存パッケージが外部に送信する(2章・6章) | Egress制御 | モードは off(既定)、observe、enforce。登録は最大100件(完全一致のホスト名、先頭1つのワイルドカード *.example.com、IP)。ホスト側でDNSとnftablesにより適用。Logs > Egress で観測された接続先を確認し、許可してから enforce に切り替える |
| 設定ファイルやイメージにトークンが残る(5章・7章) | 暗号化されたシークレット | 環境変数は保存時に暗号化され、VMの起動時にだけ注入される。ビルド引数、イメージのレイヤー、ログには入らず、ビルドログでは既知のトークン形式が伏せられる |
| タスクに不要なツールまで公開される | ツール単位のスコープと絞り込まれたツール一覧 | tools:call:<ツール名>(例:tools:call:read_text_file)などのスコープをプロキシが確認し、拒否した呼び出しはJSON-RPCエラーを返してサーバーに届かない。tool_list_filter_by_scope で、呼び出し元ごとに使えるツールだけを見せる |
| 認証のない、または知らない呼び出し元が届く | 既定で非公開、ハッシュ化されたキー、ロックアウト、IP許可リスト | サーバーは共有・公開を選ばない限り非公開。mcp_* キーはハッシュ化して保存。同じIPから誤ったキーが繰り返されると、そのIPを10分間ロック。restricted のネットワークポリシーはIPv4/IPv6のCIDRで指定し、認証より前に確認される(ネットワークアクセス制限はPro・Teamプラン) |
| 承認したサーバーが何をしたかわからない(10章) | リクエストログ | リクエストごとに mcp_method、tool_name、arg_keys(名前のみ)、http_status、outcome(scope_denied など)、caller_kind、client_ip を記録。保存期間はFreeで7日、Pro・Teamで30日 |
NodeFlareでできないこと:パッケージが安全かの判定、provenanceの検証、依存関係の固定、ツール説明文に仕込まれた毒の検知、LLM内部でのプロンプトインジェクションの防止はできません。Egress制御はオンにするまで無効で、チームがローカルで動かし続けるサーバーには効きません。
最小の始め方:
- 4章の手順で一度レビューし、承認したリポジトリをフォークしてそのフォークをデプロイします。APIトークンは暗号化された環境変数として登録します。
- 呼び出し元ごとに
mcp_*キーを1つ発行し、承認したtools:call:<ツール名>のスコープだけを付けます。 - Egress制御を1週間
observeで動かし、観測した接続先を登録してenforceに切り替えます。
1サーバーまでは無料で試せます。NodeFlareで始める
14. FAQ
MCPサーバーが安全かどうかはどうやって判断しますか?
事前に安全だと証明することはできません。MCP公式ドキュメントも、サーバーが何をするかを証明するチェックは無いと明言しています。できるのはリスクを下げることです。公開者を確認し、名前空間・リポジトリ・パッケージ名を突き合わせ、通信・環境変数・シェルに触れるコードを読み、確認したバージョンで固定し、Egressを絞って隔離して動かします。
公式MCP Registryはセキュリティの審査をしていますか?
していません。確認しているのは名前空間とパッケージの持ち主です。モデレーションポリシーには「モデレーションはほぼ無いものと考えるべき」とあり、削除されるのは違法コンテンツ、マルウェア、スパム、動かないサーバーだけです。脆弱性のあるサーバーは削除されません。
MCP Registryの名前空間は何を証明しますか?
公開者がそのGitHubアカウント(io.github.<user>/*)またはドメイン(com.example/*。DNSのTXTレコードか /.well-known/mcp-registry-auth で確認)を管理していることです。誰が公開したかはわかりますが、コードが安全かどうかはわかりません。
npx -y でMCPサーバーを動かしても大丈夫ですか?
バージョンを指定しないなら避けてください。npx -y pkg は起動のたびに最新の公開版を実行します。最低でも厳密なバージョンを付け、できればプロジェクトに --save-exact で入れてロックファイルをコミットし npm ci で入れるか、ダイジェストで固定したコンテナイメージを使います。
MCPのサプライチェーンセキュリティとは何ですか?
MCP Securityのうち、サーバーのコードの出どころを扱う領域です。パッケージ、依存関係、コンテナイメージ、設定ファイルが対象になります。OWASPは MCP04:2025「Software Supply Chain Attacks & Dependency Tampering」として挙げています。対策は公開者の確認、バージョン固定、provenanceの確認、隔離、Egress制限です。
最初に見つかった悪意あるMCPサーバーは何ですか?
Koi Securityが「実環境で初めての悪意あるMCPサーバー」とした、2025年9月にnpmで見つかった postmark-mcp です。Postmark公式ライブラリと同じ名前を名乗り、バージョン1.0.16で送信メールすべてを公開者にBCCする1行が追加されました。削除までに1,643ダウンロードされています。
npm provenanceがあればMCPサーバーは安全ですか?
いいえ。provenanceが示すのは、どのリポジトリ・コミット・ビルドワークフローで作られ、権限のあるアカウントが公開したかです。本物のリポジトリからビルドされた悪意あるコードでも、provenanceは有効になります。今回の検証では、mcp-remote の依存関係の大半にはprovenance自体がありませんでした。
AIクライアントにつなぐ前に、MCPサーバーのツールを確認するには?
MCP Inspectorで接続すると、LLMを介さずにすべてのツール名・説明文・入力スキーマを一覧できます。説明文にツールの役割と無関係な指示があればサーバーを外し、ツール定義が変わったときに再確認を求めるクライアントを選んでください。
ローカルではなくリモートのMCPサーバーを使うべきですか?
リモートのAPIを包むだけのサーバーなら、リモートをおすすめします。MCP公式ドキュメントは、そうしたサーバーをPCで動かしても得るものはないとしています。リモートなら手元でコードが動かず、設定ファイルにトークンを置く代わりに標準のOAuthを使えます。ファイル、ローカルのツール、ハードウェアが必要なサーバーだけをローカルに残してください。
MCPのセキュリティスキャナーだけで十分ですか?
十分ではありません。Snyk Agent Scanなどのスキャナーは、説明文の中のプロンプトインジェクションやマルウェアといった既知のパターンを調べます。意図の判断や、侵害されたすべての依存パッケージの発見はできません。バージョン固定、隔離、Egress制限と組み合わせてください。
会社のMCPサーバー許可リストには何を載せればよいですか?
承認したサーバーごとに、固定バージョン、公開者の根拠、動かす場所と方法、承認した認証情報とツール、担当者、再審査のきっかけを載せます。MCP公式ドキュメントは、受け入れ基準(公開者が特定できる、ソースが読める、provenanceのメタデータがある、SBOMがある)を公開することを勧めています。
まとめ
MCPサーバーの見極めは、サーバーを動かす前に下す信頼の判断です。MCP公式ドキュメントのとおり、確率を下げることはできても、安全を証明することはできません。公式MCP Registryが教えてくれるのは「誰が公開したか」であって「安全か」ではないので、名前空間・リポジトリ・パッケージ名は自分で突き合わせ、通信・環境変数・シェルに触れるコードを読み、provenanceがあれば確認します。そのうえで、最上位のパッケージより深く固定してください。今回の検証では、バージョン指定の npm install でも ^ 付きで保存され、依存関係の大半にはprovenanceがありませんでした。設定ファイルもサプライチェーンの一部として点検し、ローカルの権限が要らないサーバーはリモートか集中管理の基盤で動かし、信頼していたサーバーが悪くなる日に備えて隔離とEgress制限を外さないことが大切です。導入後の対策は、MCPサーバーのサンドボックス化ガイドに続きます。
参考資料(一次情報)
- MCP docs(2026-07-28):Local Server Security
- MCP docs(2026-07-28):Security Best Practices
- SEP-1024:MCP Client Security Requirements for Local Server Installation
- MCP Registry:Moderation Policy
- MCP Registry:Authentication(名前空間)
- MCP Registry:Supported Package Types(持ち主の確認)
- MCP Registry:Publishing Remote Servers
- MCP Registry:FAQ(悪意あるサーバーの報告)
- npm Docs:Viewing package provenance
- CISA:Widespread Supply Chain Compromise Impacting npm Ecosystem
- The Hacker News:First malicious MCP server found(postmark-mcp)
- Cloud Security Alliance:MCPのSTDIO設計上の脆弱性に関するリサーチノート
- Kaspersky Securelist:サプライチェーン攻撃に悪用される悪意あるMCPサーバー
- Snyk Agent Scan(GitHub)
- Docker MCP Toolkit ドキュメント
- NodeFlare Docs
