GMO Flatt Security Blog

GMO Flatt Security株式会社の公式ブログです。プロダクト開発やプロダクトセキュリティに関する技術的な知見・トレンドを伝える記事を発信しています。

GMO Flatt Security株式会社の公式ブログです。
プロダクト開発やプロダクトセキュリティに関する技術的な知見・トレンドを伝える記事を発信しています。

MCPにおけるセキュリティ考慮事項と実装における観点(後編)

MCP logo ©︎ 2024–2025 Anthropic, PBC and contributors | MIT license

はじめに

こんにちは、GMO Flatt Security株式会社 セキュリティエンジニアのAzaraです。普段は、クラウドセキュリティや Web アプリケーションのセキュリティを専門領域にしています。

本稿は MCP のセキュリティを前後編で解説するものの後編です。前編では MCP のセキュリティを、利用者の視点から考察しました。

後編となる本稿では、攻撃者視点から脅威や攻撃手法を整理します。そのうえで、日々増えていく MCP Server の提供者が、これらの脅威やセキュリティ課題をどのように考慮し対策を講じるべきかを解説します。

また、GMO Flatt Securityは日本初のセキュリティ診断AIエージェント「Takumi」や、LLMを活用したアプリケーションに対する脆弱性診断・ペネトレーションテストを提供しています。ご興味のある方はリンクよりサービス詳細をご覧ください。

免責事項

本記事の内容はセキュリティに関する知見を広く共有する目的で執筆されており、脆弱性の悪用などの攻撃行為を推奨するものではありません。許可なくプロダクトに攻撃を加えると犯罪になる可能性があります。当社が記載する情報を参照・模倣して行われた行為に関して当社は一切責任を負いません。

また、本記事の内容は執筆時点での情報に基づいており、今後の技術や脅威の進化に伴い、内容が古くなる可能性があります。最新の情報を確認し、適切な対策を講じることをお勧めします。1

MCP の特性から見た攻撃者の関心領域

MCP は設計や利用用途上、実行環境内でのファイル操作やコマンド実行、外部サービスとの通信など、多様な機能を担うことができます。その結果、MCP を取り巻く実行環境には比較的広範な権限が与えられがちです。

MCPの概略

こうした背景から、攻撃者は MCP の構成要素をターゲットとし、以下のような目的を持って攻撃を仕掛ける可能性があります:

  • 機微情報(例:顧客データ、API キーなど)の窃取
  • クラウドリソースへの不正アクセス
  • 実行環境の乗っ取りによる継続的な侵害
  • 外部への情報漏洩やマルウェア拡散の踏み台化

これらのリスクをより具体的に理解するために、以降のセクションでは、MCP を構成する各コンポーネントごとに想定される脅威と、攻撃者がどのようなアプローチを取るのかを解説していきます。

実行環境の特性と脅威

まずは、MCP Server がどのような環境で動作するのかを振り返ってみましょう。 「前編の MCP Server での脅威と注意点」でも触れたように、多くの場合、開発者が用意したスクリプトを利用者が実行することで、MCP Server がその端末上で起します。

起動した MCP Server は stdio 方式で動作し、呼び出し元のソフトウェアの子プロセスとして実行されます。このとき、MCP Server はその呼び出し元ソフトウェア2と同じ権限で実行されます。また、外部リソースにアクセスする際には、認証情報3を取得して通信を行います。

次に、攻撃者がこのような実行環境をどのように捉えるかを考えてみましょう。 MCP Server の特性を踏まえると、攻撃者は悪意のある MCP Server を作成し、それを利用者に実行させることで、実行環境への攻撃を試みる可能性があります。

この悪意のある MCP Server を通じて、攻撃者は呼び出し元のソフトウェアが持つ権限を利用し、実行環境内で任意のコマンド実行、ファイル操作、外部通信が可能となるため、攻撃者は情報収集や悪意のある操作を実行でき、深刻な被害につながる可能性があります。

MCP Host および MCP Client の特性と脅威

次に、MCP Host と MCP Client が直面する脅威について見ていきましょう。

MCP Host と MCP Client の特徴

MCP Host は生成 AI を活用するアプリケーションであり、MCP Client を通じて MCP Server にリクエストを送信し、取得したデータを処理します。MCP Client は、MCP Server とのやりとりを担うインターフェースであり、レスポンスを MCP Host に橋渡しする役割を果たします。MCP Host や MCP Client は多くの場合、一体化された生成 AI アプリケーションとして提供され、利用者が MCP Server を明示的に登録することで、その Server が提供する Tools や Prompts を生成 AI に読み込ませ、自律的な活用が可能になります。

利用者はこの生成 AI アプリケーションにプロンプトやファイルを入力し、それが生成 AI に渡されます。生成 AI からの応答を受け取った後、アプリケーションは MCP Server を呼び出し、結果をユーザーに返す、または必要な処理を実行します。

以下に、MCP Server の Tool 実装例と、その通信内容、さらに MCP Client の実装例を示します。

MCPサーバーの実装例 [クリックして開いてください]

ここで紹介する例は単純化した例です。実際のアプリケーションでは、これらよりもさらに複雑な構成や実装が採用されることが一般的です。

/**
 * MCPサーバーの実装例
 * @param unknown - ツールの実行リクエスト
 * @example request
 */
import { type CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { type ToolRequestSchema } from "./index.js";

const requestSchema: ToolRequestSchema = {
    name: "current_time",
    description: "現在の時刻を取得する",
    inputSchema: {},
};

const handler = (_: unknown): CallToolResult => {
    return {
        content: [
            {
                type: "text",
                text: new Date().toLocaleString("ja-JP", {
                    timeZone: "Asia/Tokyo",
                }),
            },
        ],
    };
};

export default {
    requestSchema,
    handler,
};
{
    "role": "assistant",
    "content": [
        {
            "type": "text",
            "text": "今の東京の時間を調べるために、current_time ツールを使います。"
        },
        {
            "type": "tool_use",
            "id": "toolu_xxxxx",
            "name": "current_time",
            "input": {}
        },
        {
            "type": "text",
            "text": "現在の東京の時間は {placeholder_toolu_current_time} です。"
        }
    ]
}
/*
 * MCP Clientの実装例
 * Anthropic の モデルを用いてメッセージを送り、その結果を受け取る。
 * その後に、ツールを呼び出す。
 */
const response = await anthropic.messages.create({
    model,
    max_tokens,
    messages,
    tools,
});

const finalText: string[] = [];
const toolUseResult: { [x: string]: unknown }[] = [];
for (const content of response.content) {
    if (content.type === "text") {
        if (content.text.includes("{placeholder_toolu_current_time}")) {
            finalText.push(
                content.text.replace(
                    "{placeholder_toolu_current_time}",
                    toolUseResult.current_time
                )
            );
        } else {
            finalText.push(content.text);
        }
    } else if (content.type === "tool_use") {
        const toolName = content.name;
        const toolArgs = content.input as { [x: string]: unknown } | undefined;

        const result = (await mcp.callTool({
            name: toolName,
            arguments: toolArgs,
        })) as { content: { type: string; data: string }[] };

        for (const resultContent of result.content) {
            if (resultContent.type === "text") {
                toolUseResult.push({
                    [toolName]: resultContent.text,
                });
            }
        }
    }
}
return finalText.join("\n");

MCP Host と MCP Client への脅威

攻撃者は、MCP Host や MCP Client に潜む実装上の不備を突き、生成 AI や MCP Server の出力を悪用して、最終的に生成 AI アプリケーションを攻撃者が意図したように制御しようとします。

代表的な攻撃手法として、「Name Collision Attack4」や「Tool Poisoning Attack 5」などが挙げられます。いずれも利用者の端末に悪意のある MCP Server を登録させ、その MCP Server が提供するプロンプトや情報を生成 AI アプリケーションに取り込ませて意図しない動作を引き起こすことを目的としています。

さらに、PDF や画像などのファイルに不可視文字列や特殊な命令を埋め込み、生成 AI に意図しない命令を読み込ませることで、正規のフローを通じた攻撃を成立させることも可能になります。

こうした攻撃者の行動や、MCP Host・MCP Client の特性を踏まえると、攻撃者が狙いやすいポイントは以下のように整理できます。

  • 実装の不備によるプロンプトの操作とその悪用
  • ツールの管理や呼び出しに起因する実装不備とその悪用
  • 入力された値を用いた生成 AI の自律的な MCP の機能利用とその悪用

MCP Server の特性と脅威

ここでは、MCP Server の特性とそれに伴う脅威について整理していきます。

MCP Server の特徴

MCP Server は、生成 AI アプリケーションの機能を拡張する「外部処理モジュール」として、リクエストに応じた処理を行い、結果を返す役割を果たします。 実行環境の特性と脅威でも触れたように、MCP Server はコマンドの実行、リソースの提供、外部サービスとの通信といった処理の入口となる「ゲートウェイ」として機能します。

MCP Server の実装は、通常の Web アプリケーションと大きく異なるわけではありません。しかし、利用されるユースケースや実行方法によっては、若干の特殊性があります。 MCP の仕様の最新版である 2025-03-26 版では、MCP Server の実行方法として、「stdio」と「Streamable HTTP」の 2 種類が定義されています。これらの実行方法は、MCP Server の実装において、MCP Server がどのように動作するかを決定します。

前述の通り stdio 方式は、MCP Server が標準入力と標準出力を介して通信を行う方式であり、MCP Server は呼び出し元のソフトウェアの子プロセスとして実行されます。この方式では、MCP Server は呼び出し元ソフトウェアの権限で実行されるため、その権限が攻撃者に悪用されるリスクがあります。

Streamable HTTP 方式は、MCP Server が HTTP サーバーとして実行され、HTTP リクエストを介して通信を行う方式です。この方式では MCP Server は独立したプロセスとして実行されるため、MCP Server を用いるソフトウェアとは異なる権限で実行されます。また、Streamable HTTP 方式では、stdio 方式と異なり、HTTP(S)の通信を介して MCP Server にアクセスを行うため、ローカルで用いる場合はネットワーク上のインターフェースの秘匿やリモート上で公開する場合は、通信経路の保護、認証・認可の実装も必要とします。

MCP Server への脅威

攻撃者は、まず MCP Server へのアクセス手段を調査しようとするでしょう。例えば、生成 AI アプリケーションと同一の実行環境(ローカルホスト)で実行される MCP Server において、0.0.0.0を用いて実行されている場合、意図せずネットワーク上に公開されてしまうことで、プライベートネットワーク内に攻撃者が侵入している場合、攻撃者は利用者の端末で起動されている MCP Server にアクセスすることが可能になります。

これ以外にも、HTTP(S) の通信を介して通信が可能なことから、設定や実装次第で DNS Rebinding AttackXSS などを用いて、インターネット上のリソースに利用者をアクセスさせ、ブラウザを経由して攻撃者が MCP Server にアクセスすることが可能性があります。

先に挙げた手法を用いて、MCP Server へのアクセス経路が確保できたら、次の目標として、MCP Server の脆弱性を探ることになります。この際、攻撃者の行う手法に関しては、MCP 特有の攻撃手法があるわけではなく、一般的な Web アプリケーションと同様の手法が想定されます。例えば、OWASP Top 10に記載される脆弱性や、OWASP ASVSに記載されるセキュリティ要件に基づいた攻撃が考えられます。

では、これらの攻撃者の行動や MCP Server の特性を考慮して、攻撃者が狙うポイントを整理してみましょう。

通信経路の確保

  • プライベートネットワークへの誤公開
    例:0.0.0.0 で MCP Server を待ち受ける設定にしたまま、LAN 内で誤って公開されてしまう。
  • ブラウザ経由の攻撃
    例:DNS Rebinding や XSS を利用して、ローカルの MCP Server にブラウザ経由で不正アクセス。
  • 認証・認可の不備
    例:Streamable HTTP におけるトークンチェックの未実装や、セッション識別子の不適切な取り扱い。

実装の不備に対する調査と悪用

  • 典型的な Web 脆弱性の利用
    例:コマンドインジェクション、パストラバーサル、入力値の検証不足など。
  • サードパーティライブラリの脆弱性
    例: MCP Server に組み込まれた外部依存パッケージの脆弱性を調査・悪用。

攻撃手法の分類と攻撃経路について

実際に攻撃者はどのような手法を用いて攻撃を行うのでしょうか?また、どのような経路で攻撃が実行されるのでしょうか?本章では、MCP Server に対する代表的な攻撃手法と、それらがどのような経路で攻撃されるかについて整理します。

攻撃経路は大きく次の 5 つに分類できます。

  • ユーザーによる悪意ある MCP Server 実行
    ユーザーに悪意ある MCP Server を意図せず実行させる攻撃
  • 外部リソース汚染によるプロンプト改変
    MCP Server が連携する外部のリソースを攻撃・汚染することで被害を与える手法
  • ユーザー入力操作による意図しない機能実行
    ユーザー入力に細工を加えることで、想定外の MCP Server やツールを実行させる攻撃
  • ブラウザを経由したローカル/リモート攻撃
    HTTP(S) 通信を利用する MCP に対して、ブラウザやウェブページ経由で攻撃する方法
  • 認可設定不備を突いた MCP Server 直接攻撃
    認可制御などが施されていない Remort MCP Server に対して、直接ネットワーク経由でアクセスをする攻撃

なお、これらの分類は執筆時点で特に注目すべき経路に基づいたものであり、今後の MCP 利用の進展に伴って新たな攻撃手法が登場することも想定されます。本記事では、執筆時点で実装者が特に留意すべき攻撃経路に焦点を当てて解説します。

攻撃経路に関しては以下の図(サンプル)のように示します。また、該当の攻撃経路がどの領域を対象にしているかを示すために、右上に合わせて「MCP Server」「MCP Host と MCP Client」「Host machine」の表記をしています。

攻撃経路の例

攻撃経路 1:ユーザーによる悪意ある MCP Server の実行

この攻撃は、広義にはサプライチェーン攻撃に該当します。ユーザーに対して意図的に作成された悪意ある MCP Server を実行させることで、被害を引き起こします。

攻撃経路-悪意のあるMCP Server

攻撃経路 悪意のあるMCP Serverの説明 [クリックして開いてください]

図の説明

図内番号 説明
1 攻撃者が何らかの手法を用いて Host machine に悪意のある MCP Server を実行させる
2 利用者が生成 AI アプリケーションを起動する
3,4 MCP Host が MCP Client を通じて MCP Server の情報を取得する
5 MCP Server が MCP Client に対して悪意のある情報を返す
6 MCP Client が受け取った情報を、MCP Host が受け取り必要に応じて処理を行う
7 MCP Host はこの悪意のある情報を含んだプロンプトを生成 AI に渡す
8 生成 AI がこのプロンプトを元に生成した結果を、MCP Host が受け取る (プロンプトインジェクションの成立)

この図は、Tool Poisoning Attack と呼ばれる攻撃手法を示しています。生成 AI アプリケーションの設計によっては、意図しないツールの呼び出しや不正な引数が指定されるリスクがあります。

起点となる 1 で実施される主な攻撃手法は以下のようなものがあります。

  • Rug Pull
    初めから悪意のある MCP Server を公開し、ユーザーを欺いて使わせる
  • Typosquatting(タイポスクワッティング)
    正規サーバーと似た名前をつけて、誤認を誘う
  • インストーラーの偽装
    一見正しく見えるが、実際には悪意ある MCP Server と接続するよう構成されたインストーラーの配布する

MCP Client 側での完全な防御を施すことは困難であるため、緩和策や多層防御的な対策が必要です。

例えば、MCP Host と MCP Client への脅威の章で紹介した、ツール名の衝突(name collision)と言われる実装不備については、ツール名とサーバー名を組み合わせるなどの工夫である程度の対応が可能です。ただし、この対策はサーバー名が一意であることが前提になります。

また、アプリケーションそのものへの攻撃以外に、実行された権限を悪用し実行環境上で悪意のあるコードが実行されることも考えられます。これに対しては、MCP Server を動作させる環境を端末から分離し、サンドボックス化することで、実行環境の保護と分離を図ることができます。

緩和策の例をまとめると、次の通りです。

  • MCP Client 側での識別強化
    ツール名とサーバー名の組み合わせなどを用いて、ツール衝突を防ぐ
  • MCP Server の信頼性向上
    ベンダーが提供する信頼性の高い MCP Server を利用する
    自社で開発した MCP Server をプライベートリポジトリで管理
    MCP Server のバージョンを固定することで Rug Pull によるリスクを軽減
  • 実行環境の分離と保護
    MCP Server をサンドボックス環境で動作させることで、被害を端末全体に波及させない

本記事や前編において見ておきたい関連項目

攻撃経路 2: 外部リソース汚染によるプロンプト改変

MCP Server はローカルだけでなく、外部の API やデータリソースとも連携することができます。こうした外部リソースが攻撃者により侵害されることで、MCP Server を通じた被害を引き起こします

攻撃経路 外部リソースの汚染

攻撃経路 外部リソースの汚染 [クリックして開いてください]

図の説明

図内番号 説明
1 攻撃者は何らかの手法を用いて、リソースの汚染を行う。例えば、利用するデータベース内のデータに悪意のある情報を埋め込むなど。
2 利用者が生成 AI アプリケーションを起動する
3,4 MCP Host が MCP Client を通じて MCP Server の情報を取得する
5 MCP Server が MCP Client に対して悪意のある情報を返す
6 MCP Client が受け取った情報を、MCP Host が受け取り必要に応じて処理を行う
7 MCP Host はこの悪意のある情報を含んだプロンプトを生成 AI に渡す
8 生成 AI がこのプロンプトを元に生成した結果を、MCP Host が受け取る (プロンプトインジェクションの成立)

この攻撃経路も、先に紹介した「悪意のある MCP Server を実行させる」ケースと同様に、プロンプトインジェクションを引き起こし、意図しない動作を誘発する点に特徴があります。一方でこの攻撃では、MCP の起動や悪意ある MCP Server を動作させる必要はなく、MCP Server からリソースを利用する際に、攻撃者がそのリソースを汚染することで、意図しないプロンプトを生成 AI に渡すことが可能になります。

そのため生成 AI アプリケーションは、MCP Server から取得したデータを元に、生成 AI に渡すプロンプトの生成を行う場合に特に注意が必要です。

特に、ユーザーが Web サービスから任意に入力可能な値を扱う際は、ユーザーの入力をそのままプロンプトに組み込んでいないかなどの注意が必要になります。

これらを前提に、MCP Server が取得するリソースの汚染を行う攻撃の手法は多岐にわたります。合わせて対策についても記載します。

  • サーバー乗っ取り
    サーバーの堅牢化を除けば、根本的な対策は難しいのが現状
  • データポイズニング
    データソースでの入力値検証を徹底
  • DNS ポイズニング
    mTLS による通信相互認証や、デジタル署名の導入
    ※この対策は実装や運用の負担が大きくなるため、実際に導入する場合は十分な検討が必要
  • 脆弱性を突いた外部通信のリダイレクト
    OWASP Top 10 や ASVS に基づいたセキュアコーディングの実践

攻撃経路 3:ユーザー入力操作による意図しない機能実行

この攻撃は、ユーザーの入力を意図的に操作して、悪意のある MCP ツールやサーバーの実行を引き起こすものです。

この攻撃経路内では前述の「MCP Host・Client の特性と脅威」のセクションで紹介したように不可視文字列を埋め込んだファイル6などを利用することで、プロンプトインジェクションを発生させ利用者の意図しない動作を起こせます。

攻撃経路 ユーザーの入力を制御する

攻撃経路 ユーザーの入力を制御する [クリックして開いてください]

図の説明

図内番号 説明
1 攻撃者が何らかの手段で悪意のあるプロンプトを含んだファイルを作成
2 利用者が 1 で用意したファイルを取得
3 2 で取得したファイルを利用者が生成 AI アプリケーションに入力
4 生成 AI アプリケーションがファイルを読み込み、生成 AI に渡し、その回答を受け取る
5 生成 AI は 1 で作成された悪意のあるプロンプトを解釈し、意図しないツールの利用を MCP Host に指示
6 MCP Host はこのプロンプトを元に、MCP Server に対してツールの実行を指示
7 MCP Server はツールを実行

この攻撃経路をはじめ、複数の箇所で登場したプロンプトインジェクションですが、この攻撃を入力のバリデーションなどで完全に防ぐのは困難です。そのため、MCP Host および MCP Client におけるツールの自動呼び出しを無効にし、利用者の明示的な確認を求めるといった対策を行うことが有効です。

cursorのチャットにおけるプロンプトインジェクション対策の例

本記事や前編において見ておきたい関連項目

関連研究:

攻撃経路 4:ブラウザを経由した攻撃

MCP Server は仕様の更新により、Streamable HTTP 形式で実行できるようになりました。これは、従来の SSE 型 MCP よりもステートレスでの運用が可能となり、MCP Server を HTTP(S) サーバーとして実行できるようになったことを意味します。

また、この方式により、従来の stdio や SSE 型 MCP よりもスケーラブルな運用が可能となりました。一方で、HTTP(S) 接続を介して通信を行うため、従来に比べて攻撃経路が広がるというリスクがあります。例えば攻撃者は、ブラウザや HTTP クライアントを利用して MCP Server にアクセスすることが可能です。

攻撃経路 ブラウザを経由した攻撃

攻撃経路 ブラウザを経由した攻撃 [クリックして開いてください]

図の説明

図内番号 説明
1 攻撃者がなんらかの攻撃用サーバーを用意
(例)DNS Rebinding 攻撃を行うための DNS と通信を行うブラウザアプリケーションのホスト
2 攻撃者がなんらかの手段で利用者を攻撃用サーバーに誘導
3 誘導されたページへアクセスし攻撃を実施
(例)DNS Rebinding 攻撃でドメインの名前解決を操作して MCP サーバーへアクセス
4 MCP サーバーへ直接アクセスを行い、ツールやリソースを実行
5 ツールなどの処理を実行し、悪意のある処理を行う
(例)MCP サーバーから AWS の API を実行

主な攻撃手法としては、以下のようなものが考えられます。

  • DNS Rebinding による Same-Origin Policy の回避
  • CORS 設定の不備 によるクロスサイトアクセス

これらの手法は、攻撃者が用意した悪意のあるウェブページ上で JavaScript を実行させ、ユーザーのローカル MCP Server やリモート MCP Server にアクセスするために使われます。

詳しくは別の章で説明しているので、以下の項目を参照してください。

攻撃経路 5:認可設定の不備を突いた MCP Server 直接攻撃

MCP Server は主にローカル環境での実行を想定していますが、社内外との連携を目的にリモートで公開されるケースも増えてきています。

攻撃経路 MCP Server への直接アクセス

攻撃経路 MCP Server への直接アクセス [クリックして開いてください]

図の説明

図内番号 説明
1 Remote に公開された MCP サーバーに攻撃者がアクセスする
この際、MCP Server に認証・認可が適切に設定されていない場合、ツールやリソースが認証なしで実行されてしまう状態にある
2 MCP サーバーに対して、ツールやリソースを実行する

攻撃の内容としては、認可が設定されていない MCP Server に対し、攻撃者が直接アクセスして任意の操作を行う攻撃です。
ToolsResources を通じて機密情報の取得や外部サービスの操作が可能なため、認可制御の欠如は深刻なリスクとなります。

対策については、外部に公開する場合は、MCP における Authorization に従い、MCP Server に適切な認可機構を導入することが重要です。また、加えて、ネットワークレベルでの制御(mutual TLS や IP アドレス制限など)も有効な対策です。

MCP の実装における基本的なセキュリティ対策

この章では MCP Client や MCP Server の実装において、どのようなセキュリティ対策が必要かを考えていきます。

施すべきセキュリティ対策としては、以下の 3 つがあると考えます。

  • Web アプリケーションに共通するセキュリティ対策
    OWASP Top 10 に代表される脆弱性や OWASP ASVS などのセキュリティ要件や検証について
  • MCP 固有の特性を踏まえた対策
    生成 AI に意図しないプロンプトを流し込まない、流し込まれた際の多層的対策について
  • ネットワークに起因する攻撃への対策
    新たに追加された実行方式(HTTP(S))に起因する攻撃への対策や、MCP Server の実装について

この章では、先の章で述べた攻撃者の狙うポイントを踏まえながら、MCP の仕様やユースケースなどをもとに、基本となるセキュリティ対策を解説します。

基礎となる脆弱性対策

MCP はネットワーク領域からの攻撃が発生する可能性があると先の章で述べました。それを前提に基礎的な脆弱性への向き合い方について考えていきましょう。

まず、MCP や生成 AI を利用したアプリケーションそのものというより、Web 技術やそれに近いアプリケーションにおいて基本的な脆弱性対策として「OWASP Top 10」に記載される脆弱性への対策や、「OWASP ASVS」に記載されるセキュリティ要件のようなものを考慮する必要があります。

MCP Server では、多くの外部リソースと通信や処理を行うためのインターフェースとしてToolsやファイルやデータの取得をするためのResourcesを提供します。これらのインターフェースの処理を安全に行うためには、各種脆弱性への対策が必要です。

例として「URI の取り扱い」と「外部通信時の取り扱い」、「コマンド実行」についてこの項では解説します。

URI の取り扱い

MCP では、Tools や Resources のインターフェースを通じて、ファイルの操作や取得をするといったユースケースが多くあり、URI を用いることでリソースの取得や操作を行います。

この際、URI の取り扱いが適切に行われない場合、OWASP Top 10 の A01:2021 – アクセス制御の不備に該当する Path Traversal 攻撃が発生する可能性があります。

例えば、file:///../../../../etc/passwdのような URI を指定することで、意図しないファイルの読み込みや書き込みを行うことが可能になります。これにより、機密情報の漏洩や意図しないファイルの読み込みが行われる可能性があります。

まず初めに、言語に依存せずに対策対策する例を見ていきます。

ファイルの読み書きや通信を行う際に用いられる URI ですが、Path Traversal が発生する実装が二つ存在します。

1 つ目がファイルを取得する際に、ユーザーによって入力された URI やパスを正規化せずに用いてしまうことによる、パス解釈時の Path Traversal です。以下のようなコードが存在する際に、userInputURI../../../../etc/passwdのような入力があったとします。readFileSyncがファイルを読み込む際に、/hoge/fuga/../../../../etc/passwdのパスを解釈する際に、Path Traversal が発生し/etc/passwdを読み込んでしまいます。

const prefix = “/hoge/fuga”;
fs.readFileSync(`${prefix}/${userInputURI}`);

2 つ目がファイル取得を行う関数へ値を渡す前の URI やパスの正規化時に誤った正規化を行ってしまうことによる Path Traversal です。以下のようなコードが存在する際に、userInputURI に 1 つ目同様の入力があったとします。new URLを用いる際に、常に組み立てられた URI を入力することで、パスを正規化する際に、Path Traversal が発生し/etc/passwdを読み込んでしまいます。

const prefix = “/hoge/fuga”;
fs.readFileSync(new URL(`${prefix}/${userInputURI}`));

言語に依存しない対策の指針としては、ユーザーが入力した値は必ず正規化をしてからベースとなるパスと結合するというのが重要です。

これらを前提に本稿では、さらに詳しく実装を見ていくため、TypeScript の@modelcontextprotocol/sdkを用いて、MCP Server を実装することを前提に、ToolsResourcesでのファイルの読み書きに関する解説します。

また、本稿では TypeScript での実装について解説しますが、他の言語やフレームワークでも同様の考慮が必要です。その際は本記事とともに、各言語におけるセキュアコーディングガイドやライブラリのセキュリティ考慮事項などを参考に実装してください。

URI を取り扱う場合の Tool の実装例

まず初めに、Tool 実装時に考慮すべきセキュリティ対策を見ていきましょう。

Tools インターフェースでは、URI が Params 経由で渡されます。
これらの URI は正規化・検証・無害化を前提としておらず、実装側での明示的な対処が必要です。

以下の実装例のように TypeScript では、new URL(uri) を使って URI を正規化し、安全な形式に変換したうえで処理することを推奨します。

TypeScript SDK における Tool の実装例 [クリックして開いてください]

/**
 * MCPサーバーの実装例
 * ファイルの書き込みを行うツールの実装
 * @param args - ツールの実行リクエスト
 * @example request
 * {
 *    "jsonrpc": "2.0",
 *    "id": 1,
 *    "method": "tools/call",
 *    "params": {
 *        "name": "file_write",
 *        "arguments": {
 *            "uri": "file:///test.txt",
 *            "contentBase64": "aGVsbG8="
 *        }
 *    }
 *}
 */

// ~~ Snip ~~

const handler = async (
args: ZodRawShape,
extra: RequestHandlerExtra<ServerRequest, ServerNotification>
): Promise<CallToolResult> => {
const validatedArgs = varidation(args);
// unsafe code
/\*
const uri = validatedArgs.uri;
const content = validatedArgs.content;
const sessionDir = `${process.cwd()}/sessions/${extra.sessionId}`;
const filename = uri.pathname.split("/").pop();
const dirname = uri.pathname.split("/").slice(0, -1).join("/");

    if (!fs.existsSync(`${sessionDir}/${dirname}`)) {
        fs.mkdirSync(`${sessionDir}/${dirname}`, { recursive: true });
    }

    fs.writeFileSync(`${sessionDir}/${dirname}/${filename}`, content);
    */

    // 入力されたURIを `new URL` などを用いて正規化することで、`fs.writeFileSync`などの操作を行う際に発生するPath Traversal攻撃を防ぐことができます。
    const uri = new URL(validatedArgs.uri);
    const content = validatedArgs.content;

    const sessionDir = `${process.cwd()}/sessions/${extra.sessionId}`;
    const filename = uri.pathname.split("/").pop();
    const dirname = uri.pathname.split("/").slice(0, -1).join("/");

    if (!fs.existsSync(`${sessionDir}/${dirname}`)) {
        fs.mkdirSync(`${sessionDir}/${dirname}`, { recursive: true });
    }

    fs.writeFileSync(`${sessionDir}/${dirname}/${filename}`, content);

    return {
        content: [
            {
                type: "text",
                text: `ファイルを書き込みました!`,
            },
        ],
    };

};

URI を取り扱う場合の Resource の実装例

次に Resource を実装する場合を見ていきます。Resource を用いて、ファイルなどを取得する場合、まずはuriという引数に入力が渡されます。その後 uri はコールバック関数に urivariablesの 2 つのパラメーターとして渡されます。

この渡された uri は、new URL(uri)を用いて、ユーザーから入力された値を正規化した状態でコールバック関数に渡すため、実装者が URL Decoding など加工を行わない限り、再度の正規化は必要ありません。

@modelcontextprotocol/sdkの内部実装については、以下のような実装になっており、class McpServer内部でsetRequestHandlerを実行する際に、request.params.urinew URLを用いて正規化した状態で渡しています。

TypeScript SDK における MCP Server の実装例 [クリックして開いてください]

対象のコード: https://github.com/modelcontextprotocol/typescript-sdk/blob/bced33d8bc57419c6d498ca9a26a284f3ccf6016/src/server/mcp.ts#L364-L398

/**
 * TypeScript SDK における実装
 * */
export class McpServer {
  // ~~ Snip ~~
    this.server.setRequestHandler(
      ReadResourceRequestSchema,
      async (request, extra) => {
        /**
         * Flatt Security Blog コメント:
         * この new URLを用いることで、ユーザーから入力されたURIを正規化し、 `file:///../../../../etc/passwd`のようなPath Traversal攻撃を防ぐことができます。
         */
        const uri = new URL(request.params.uri);

        // First check for exact resource match
        const resource = this._registeredResources[uri.toString()];
        if (resource) {
          if (!resource.enabled) {
            throw new McpError(
              ErrorCode.InvalidParams,
              `Resource ${uri} disabled`,
            );
          }
          return resource.readCallback(uri, extra);
        }

        // Then check templates
        for (const template of Object.values(
          this._registeredResourceTemplates,
        )) {
          /**
           * Flatt Security Blog コメント:
           * リソースを取得する実装をTypeScript SDKで実装する場合、以下のように、URIを正規化し、URIのテンプレートを用いることで、File PathのみをValiableにすることができます。
           * 例えば、以下のように、URIのテンプレートを用いることで、 `filePath` に指定されたファイル名を指定することが可能です。
           * ```typescript
           * new ResourceTemplate("file:///{filePath}", {
           *     list: listCallback,
           * }),
           * ```
           */
          const variables = template.resourceTemplate.uriTemplate.match(
            uri.toString(),
          );
          if (variables) {
            return template.readCallback(uri, variables, extra);
          }
        }

        throw new McpError(
          ErrorCode.InvalidParams,
          `Resource ${uri} not found`,
        );
      },
    );
  // ~~ Snip ~~
}

このように、@modelcontextprotocol/sdk内部で URI の正規化を行なっている関係上、MCP Server 側の実装においては、以下のように特別な正規化や追加検証を行わずとも、安全に利用できます。

/**
 * ファイルの読み込みを行うリソースの実装
 * @param uri - リソースの URI
 * @param variables - リソースの変数
 * @param extra - リクエストの追加情報
 * @example request
 * {
 *    "jsonrpc": "2.0",
 *    "id": 2,
 *    "method": "resources/read",
 *    "params": {
 *        "uri": "file:///main.ts"
 *    }
 *}
 */

const callback: ReadResourceTemplateCallback = async (
    uri: URL,
    variables: Variables,
    extra: RequestHandlerExtra<ServerRequest, ServerNotification>
) => {
    if (variables.filePath === undefined) {
        throw new Error("filePath is required");
    }

    if (typeof variables.filePath !== "string") {
        throw new Error("filePath must be a string");
    }

    const filePath = variables.filePath;
    const sessionId = extra.sessionId;
    const sessionDir = `${process.cwd()}/sessions/${sessionId}`;
    console.log("sessionDir", sessionDir);
    if (!fs.existsSync(`${sessionDir}/${filePath}`)) {
        console.log("file not found");
        throw new Error("file not found");
    }

    const content = fs.readFileSync(`${sessionDir}/${filePath}`, "utf-8");

    return {
        contents: [
            {
                uri: filePath,
                text: content,
                mimeType:
                    (await fileTypeFromBuffer(Buffer.from(content)))?.mime ??
                    "application/octet-stream",
            },
        ],
    };
};

外部通信時の取り扱い

前述のように MCP Server は Tools を通じて、他のソフトウェアの操作やクラウドサービスとの通信を行うことが可能です。 この際に、ユーザーから渡された引数や URI をそのまま外部サービスへの通信に利用した場合、MCP Server から意図しないリクエストを発行する可能性があります。

このような事象が発生する脆弱性として、OWASP Top 10 の A10:2021 に該当する SSRF(Server-Side Request Forgery) 攻撃があります。

この攻撃は提供者の意図しないサーバーに対して、リクエストを発行させることで、情報の持ち出しや意図しないデータの読み込みを行うことが可能になるというものです。

例えば、パスとして @evil.test/ のような文字列を与えると、URL 解釈の仕様により http://evil.test/ へのアクセスとなってしまいます。以下のコードは、そうした入力を防げない不適切な実装例です。

const handler = async (
    args: ZodRawShape,
    extra: RequestHandlerExtra<ServerRequest, ServerNotification>
): Promise<CallToolResult> => {
    const path = args.path as unknown as string;
    const result = await fetch(`http://example.test${path}`);
    return {
        content: [
            {
                type: "text",
                text: `fetch http://example.test${path}`,
            },
            {
                type: "text",
                text: result.toString(),
            },
        ],
    };
};

このような攻撃を防ぐために、ユーザーから渡された引数をそのまま文字列に結合するのではなく、引数を検証したり、エスケープしたりすることが推奨されます。

今回のような実装の場合、http://example.testのようなベース URL を定義し、ユーザーから渡された引数をそのまま文字列に結合するのではなく、new URL(path, baseUrl)を用いて、URL を生成することで、意図しないリクエストを発行することを防ぐことができます。

const handler = async (
    args: ZodRawShape,
    extra: RequestHandlerExtra<ServerRequest, ServerNotification>
): Promise<CallToolResult> => {
    const path = args.path as unknown as string;

    const baseUrl = "http://example.test";
    const url = new URL(path, baseUrl);
    if (url.origin !== new URL(baseUrl).origin) {
        throw new Error("不正なパスです");
    }
    const result = await fetch(url.toString());
    return {
        content: [
            {
                type: "text",
                text: `fetch ${url.toString()}`,
            },
            {
                type: "text",
                text: result.toString(),
            },
        ],
    };
};

詳しくは、弊社ブログの以下の記事をご覧ください。

blog.flatt.tech

コマンド実行

MCP Server では、コマンドなどをはじめとした他のソフトウェアの操作を行い、その結果を返すなどのユースケースがあります。固定のコマンドを実行する場合には大きな問題は発生しませんが、ユーザーから渡された引数をそのままコマンドに渡す場合、OWASP Top 10 の A03:2021 – インジェクションに該当するコマンドインジェクション攻撃を用いて、意図しないコマンドの実行がなされる可能性があります。

例えば、git show {commit_id}のようなコマンドを実行するとします。ユーザーからHEAD; whoami のような値が渡された場合、引数にそのまま渡すと、git show HEAD; whoamiのようなコマンドが実行されてしまう可能性があります。

安全ではないコードの例を以下に示します。

const commit_id = args.commit_id as unknown as string;
// 安全ではないコードの例
const result = await exec(`git show ${commit_id}`);

このようなコマンドインジェクション攻撃を防ぐためには、ユーザーから渡された引数をそのままコマンドに渡すのではなく引数の検証やサニタイズ(無害化)を行うことが推奨されます。

実際の実装では、child_process.execFilechild_process.execFileSyncを用いてコマンドを実行することで、引数をエスケープすることができます。

安全なコードの例を以下に示します。

/**
 * MCPサーバーの実装例
 * コマンドの実行を行うツールの実装
 * @param args - ツールの実行リクエスト
 * @example request
 * {
 *    "jsonrpc": "2.0",
 *    "id": 1,
 *    "method": "tools/call",
 *    "params": {
 *        "name": "git_show",
 *        "arguments": {
 *            "commit_id": "HEAD"
 *        }
 *    }
 * }
 */

// ~~ Snip ~~

const handler = async (
    args: ZodRawShape,
    extra: RequestHandlerExtra<ServerRequest, ServerNotification>
): Promise<CallToolResult> => {
    if (!Object.keys(args).includes("commit_id")) {
        throw new Error("arguments is required");
    }
    const commit_id = args.commit_id as unknown as string;

    // 安全なコードの例
    const result = execFileSync("git", ["show", commit_id]);

    return {
        content: [
            {
                type: "text",
                text: `git show ${commit_id}`,
            },
            {
                type: "text",
                text: result.toString(),
            },
        ],
    };
};

他の言語においても、類似の方法を用いることで、コマンドインジェクション攻撃を防ぐことができます。 詳しくは、弊社のブログ記事をご覧ください。

blog.flatt.tech

意図しないプロンプトに起因した機能の実行を防ぐ

MCP では複数のインターフェースにおいて、プロンプトに組み込まれる可能性のある属性やメタ情報が存在します。例えば、Tools には説明文を記載する description があり、Tool の説明などをプロンプトとして読み込ませることができます。また、Prompts と呼ばれるプロンプト提供用のインターフェースもあり、これを通じて MCP Server は生成 AI にプロンプトを提供できます。

こうしたインターフェースから取得した情報をそのまま生成 AI のプロンプトに埋め込むことは、プロンプトインジェクションのリスクを高める要因となります。

例えば、以下のように悪意のあるサーバーが登録されていた場合、意図しないプロンプトが生成されてしまうことがあります。対策としては、プロンプトにそのまま文字列を埋め込むのではなく、メッセージ生成のタイミングで tools として渡すことで安全性を高めることができます。

/**
 * MCP Serverからツール情報を取得し、プロンプトを生成するサンプルコード。
 */

const tools = await mcp.getTools();

// 取得したツール情報をそのままLLMのプロンプトに埋め込む
const prompt = `
あなたはMCPクライアントのアシスタントです。
以下のツールを使ってユーザーの要望に応えてください。

${tools
    .map((tool) => `ツール名: ${tool.name}\n説明: ${tool.description}`)
    .join("\n\n")}
`;

const response = await anthropic.messages.create({
    model: "claude-3-opus-20240229",
    max_tokens: 1024,
    messages: [{ role: "user", content: prompt }],
    tools,
});

このように、ツール情報などをそのままプロンプトに埋め込むことで発生するプロンプトインジェクションについては、すでに先行研究が存在しており、「Tool Poisoning Attacks」として知られています。

invariantlabs.ai

では、このようなプロンプトインジェクションを防ぐためには、どのような対策が必要でしょうか。 前提として、執筆時点でプロンプトインジェクションを完全に防ぐことは困難です。例えば、入力値のプログラム上でのフィルタリングは可能ですが、自然言語の曖昧さや多義性ゆえに完全なフィルタは難しく、またフィルタリングによって本来意図した意味が損なわれる可能性もあります。Guardrails AI などの LLM ガードレールを用いても、確実に防ぐのは難しいとされています。

そのため、MCP を用いる生成 AI アプリケーションでは多層的な対策を推奨します。

例えば、生成 AI アプリケーションが MCP Server の呼び出しを暗黙的に許可している場合、利用者はこれを認知できず、制御もできない状況が発生します。暗黙的な許可によって処理は迅速になりますが、場合によっては機微な情報が第三者に送信され、利用者が把握できないままになることもあります。

このような状況を避けるためには、MCP Client が MCP Server の Tool を実行する際、利用者に明示的な許可を求めることが重要です。

/**
 * ツール実行前に確認を求めるサンプルコード。
 */
import * as readline from "readline";
import { Anthropic } from "@anthropic-ai/sdk"; // 仮のAnthropic SDK

// ツール実行前に確認を求める関数
async function confirmToolExecution(toolName: string, toolArgs: any) {
    return new Promise<boolean>((resolve) => {
        console.log("=== ツール実行の確認 ===");
        console.log(`ツール名: ${toolName}`);
        console.log("引数:");
        console.log(JSON.stringify(toolArgs, null, 2));
        console.log("このツールを実行しますか? [y]es / [n]o");

        const rl = readline.createInterface({
            input: process.stdin,
            output: process.stdout,
        });

        rl.question("> ", (answer) => {
            rl.close();
            if (answer.toLowerCase().startsWith("y")) {
                resolve(true);
            } else {
                resolve(false);
            }
        });
    });
}

async function main() {
    const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY! });
    const response = await anthropic.messages.create({
        model: "claude-3-opus-20240229",
        max_tokens: 1024,
        messages: [
            {
                role: "user",
                content: `天気情報を取得してください: ${JSON.stringify(
                    toolArgs
                )}`,
            },
        ],
        // Dummy tools
        tools: [
            {
                name: "weather_tool",
                description: "指定した都市の天気を取得します",
                parameters: { city: "string" },
            },
        ],
    });
    const tool_responses = [];
    for (const content of response.content) {
        if (content.type === "tool_use") {
            const toolName = content.name;
            const toolArgs = content.input;
            const allowed = await confirmToolExecution(toolName, toolArgs);
            if (!allowed) {
                console.log("ツールの実行は拒否されました。");
                return;
            }
            console.log(`ツール「${toolName}」を実行します...`);
            const tool_response = mcp.callTool({
                name: toolName,
                arguments: toolArgs,
            });
            tool_responses.push(tool_response.content);
            console.log("ツールの実行結果:", tool_response.content);
        } else if (content.type === "text") {
            console.log(content.text);
        }
    }
}

main();

このように、MCP Server の Tool 実行時に利用者へ明示的な確認を求めることで、意図しないプロンプトの実行を抑制する効果があります。

また、プロンプトインジェクションの発生メカニズムや防止策については、弊社ブログの以下の記事でも詳しく解説していますので、ぜひご覧ください。

blog.flatt.tech

ネットワークレベルでのセキュリティ

MCP は Streamable HTTP 形式で動作するようになり、ネットワークレベルでのアクセスが可能になりました。この変化は利用や運用におけるシーンの幅を増やした一方で、攻撃者によるアクセスもより容易になりました。

本項目では、Streamable HTTP 形式で動作するようになった MCP において、どのようなセキュリティ対策を講じるべきかについて、MCP の仕様や実装をもとに解説します。

ネットワークインターフェースへの誤った公開

ネットワークに接するようになり、最も発生する実装のミスとして挙げられるのが、MCP Server のネットワークインターフェースへの誤った公開です。 現状のユースケースとして、MCP Client からの接続は多くの場合、localhostなどの端末内部での通信が主な通信経路です。その中で、MCP Server の Host 名をすべてのネットワークインターフェースにバインドしてしまうことで、端末の外部からのアクセスを許可してしまうことが考えられます。

例えば、Express などのフレームワークを用いて、MCP Server を実装する場合、以下のように Host 名を指定することができます。

const app = express();
const hostName = "localhost";
const port = 3000;
const server = app.listen(port, hostName, () => {
    console.log(`MCP Server is running on http://${hostName}:${port}`);
});

この場合、localhostにバインドされているため、端末の外部からはアクセスできません。 一方で、以下のように Host 名に0.0.0.0を指定した場合、どうなるでしょうか?

const app = express();
const hostName = "0.0.0.0";
const port = 3000;
const server = app.listen(port, hostName, () => {
    console.log(`MCP Server is running on http://${hostName}:${port}`);
});

この場合、端末のすべてのネットワークインターフェースにバインドされてしまうため、端末の外部からもアクセスできるようになってしまいます。

MCP Server がネットワークインターフェースにバインディングされた場合、MCP Server の特性と脅威で述べたように、MCP Server はプライベートネットワーク上からアクセス可能になってしまうため、攻撃者が利用者の端末へアクセスをする足掛かりを与えてしまうことになります。

対策としては、MCP の仕様における Security Warning7に記載されているように、端末内で利用する用途の場合は、ネットワークインターフェース(0.0.0.0)へのバインドではなく、localhost(127.0.0.1)のみにバインドすることを推奨します。

DNS Rebinding Attack 対策

DNS Rebinding Attack は、攻撃者がドメイン名の名前解決を操作することで、ブラウザの同一オリジンポリシー(SOP)を回避し、悪意のある Web サイトから被害者のプライベートネットワーク内リソースへアクセスする手法です。

攻撃の流れは以下の通りです。

  1. 攻撃者は https://evil.flatt.test という自身が所有するドメインを、攻撃用のインターネット上のサーバーに向けて DNS 設定します。TTL(キャッシュ時間)は極端に短く設定します。
  2. 被害者が https://evil.flatt.test にアクセスすると、攻撃者が用意した悪意のある Web ページが表示され、同ドメインへのリクエストを行う JavaScript が実行されます。
  3. ページの表示後、攻撃者は evil.flatt.test の DNS レコードを、被害者のプライベートネットワーク内のアドレス(例:192.168.x.x127.0.0.1)に書き換えます。
    これにより、ブラウザは evil.flatt.test をプライベートネットワーク内のリソースとして解決します。
  4. ブラウザは引き続き https://evil.flatt.test にアクセスしようとしますが、名前解決の結果、プライベートネットワーク内のリソースにリクエストが送られます。
    SOP(Same-Origin Policy)の原則上、ドメインが一致しているため、アクセスはブロックされません。
  5. この結果、攻撃者は被害者の localhost 上で動作している MCP Server にアクセスし、任意のコマンド実行やファイルの読み取りが可能となります。

このような攻撃を防ぐため、MCP Server では Origin ヘッダを用いた接続元の検証が推奨されています。

具体的な対策としては:

  • MCP Client は、MCP Server にリクエストを送信する際に、Origin ヘッダを付与する
  • MCP Server はリクエストの Origin ヘッダを確認し、信頼できる送信元からのアクセスのみを許可する
  • MCP Server は不正なオリジンからのアクセスは拒否する

これらの対策により、DNS Rebinding Attack を効果的に防ぐことができます。

// ~~ Snip ~~
/**
 * MCPサーバーの実装例
 * Origin チェックにより、MCP Client からの正規のリクエストのみを許可する(DNS Rebinding 対策)
 */
app.post("/mcp", async (req, res) => {
    const origin = req.headers.origin as string | undefined;
    // Originの値はMCP ClientとMCP Serverが理解可能な任意の値で良いため、ここではdesktopapp://localhostを許可する
    // ここでOriginをチェックし、不正なオリジンからのリクエストを拒否することで、DNS Rebinding Attackを防ぐ
    if (!origin || origin !== "desktopapp://localhost") {
        res.status(403).json({
            jsonrpc: "2.0",
            error: { code: -32000, message: "Forbidden" },
        });
        return;
    }
    // ~~ Snip ~~
});
//~~ Snip ~~

CORS の設定不備と XSS

執筆時点における MCP の主な利用用途は、生成 AI アプリケーション、主にデスクトップアプリなどに限定されています。 そのような用途の場合、CORS(Cross-Origin Resource Sharing)のようなブラウザからのリクエストを制限する仕組みは必要ありません。

しかし、MCP Server を Streamable HTTP 形式で実装する場合、FastAPI や Express などのフレームワークを用いることから、CORS の設定が可能となってしまい、MCP Server の作成時に社内のテンプレートを参考にして実行した際に、誤った CORS 設定を行ってしまう可能性があります。これによりブラウザからのアクセスの可能性や不正なオリジンからの XSS 攻撃のリスクが生じます。

例えば、TypeScript や JavaScript で実装された MCP Server では、Express や Fastify といったフレームワークがよく使われます。その際、Access-Control-Allow-Origin ヘッダを誤って設定すると、ローカルホスト上で動作している MCP Server に対し、別オリジンからのアクセスを許可してしまう可能性があります。

特に、Access-Control-Allow-Origin: *のようにワイルドカードを指定してしまうと、万が一ブラウザで XSS が発生した場合、悪意のある Web ページからローカルホスト上の MCP Server へ不正アクセスされるリスクがあります。

対策としては、以下が挙げられます:

  1. CORS が必要な場合は、Access-Control-Allow-Origin ヘッダで信頼できるオリジンのみを明示的に指定する。 例:Access-Control-Allow-Origin: https://example.com ※ ワイルドカード(*)は使用しない。
  2. そもそも現在の MCP の利用用途では CORS 設定が不要であるため、不要な CORS を用いない/実装しない

いずれかの方針が守られていることを確認し、不要な CORS 設定によるリスクを回避することが重要です。

リモート公開をする際のセキュリティ対策

今後のユースケースとして、MCP Server を社内や SaaS の利用者に向けて提供し、そのホストを行うことが考えられます。 その際、従来の MCP Server とは異なるリモートでの公開を行うことになり、セキュリティ対策が必要になります。

本章では、そのようなリモート公開を行う際のセキュリティ対策について解説します。

HTTPS 化

まず初めに考えるべきことは、MCP Server と MCP Client 間の通信の暗号化です。

今まで、ローカルでの運用を前提にしていたことは先に述べたとおりですが、この時点で HTTPS での通信を行なっていた MCP Server は少ないでしょう。 そのため、そのままリモートで公開してしまうと、MCP Server と MCP Client 間の通信は平文で行われることになり、機微情報や Token などが平文で流出してしまうことになります。 そのため、第一に考慮すべきことは、MCP Server と MCP Client 間の通信を HTTPS で行うことです。

HTTPS 通信に関しては、近年のクラウドサービスの普及・活用により、迅速に導入できるようになってきたので、AWS における API Gateway や CloudFront などのサービスを利用することで、HTTPS 通信を簡単に導入することが可能です。

ネットワークレベルでの制御

次に考慮すべきことは、MCP Server へのアクセスをネットワークレベルで制御することです。 この項目は必須の内容ではありませんが、社内システムで、かつ IP ベースでアクセスが制御できる環境の場合、 MCP Server を無闇にインターネットに公開する必要はありません。 可能であれば IP 制限などのネットワークレベルでのアクセス制御を導入することを検討してみてください。

上記の IP 制限以外にも、機微情報や特定の利用者のみのアクセス想定の場合、クライアント証明書などを用いた mutual TLS 認証を導入することで、よりセキュアな通信を実現することが可能です。

MCP における Authorization(認可)の導入

執筆時点での MCP の仕様において、認可の実装に関しては任意とされていますが、実装を行う場合は、 OAuth 2.1 に準拠した認可を実装することが必須とされています。ただ、仕様に書かれていない観点として MCP Server がリモートで公開されることが考慮されていません。この場合、扱うリソースや機能の特性を鑑みるとリモートに公開されている場合は、認可の導入が必須の要件になると考えています。

また、上記の要件以外にも、 Dynamic Client Registration Protocol8 (DCRP) に準拠したクライアント登録の仕組みや認可サーバーメタデータ9 (GET /.well-known/oauth-authorization-server)も選択的に実装することができます。

では、実際に OAuth 2.1 に準拠した認可を MCP で用いるにはどのようなシーケンスで行うべきでしょうか。MCP の仕様では、OAuth Grant Types に関しては OAuth2.1 に準拠したものであれば利用制約はありません。その中で、仕様の例示として、人間を対象とした認可の例として、認可コードフロー (Authorization Code Flow)を、AI Agent などの人間ではない対象に認可を行う場合の例として、Client Credentials フロー (Client Credentials Flow) を挙げています。本稿においては、この例示における認可コードフローをもとに、MCP における認可の解説を行います。

MCP における認可の例

この項目では、認可コードフロー (Authorization Code Flow)を例に、MCP における認可について解説します。

MCP の仕様では、OAuth 2.1 に準拠した認可コードフローを用いる場合、PKCE (Proof Key for Code Exchange) を利用することが必須されています。これにより、悪意のある MCP Client による認可コードの盗聴や再利用を防ぐことができます。実際に仕様に基づいて認可の実装を行う場合、以下のシーケンス図のようになります。また MCP Server には認可サーバーとリソースサーバーの 2 つの機能が必要になります。

sequenceDiagram
    participant UA as UserAgent<br>(ブラウザなど)
    participant C as MCP Client
    box "MCP Server"
        participant M as Resource Server<br>(純粋なMCP Serverとしての機能)
        participant A as Authorization Server<br>(認可機能)
    end

    C->>M: MCP Request<br>(Toolの呼び出し、またはInitialization)
    M->>M: アクセストークンの検証
    M-->>C: HTTP 401 Unauthorized
    note over C: PKCEを用いるため、<br>Code VerifierとCode Challengeを生成
    C->>UA: Code Challengeを付与したURLで認可画面を開かせる
    UA->>A: POST /authorize<br>Code ChallengeとCode Challenge Methodを含む
    A-->>UA: Auth Codeを含むCallback URLへリダイレクト
    UA-->>C: Callback URLへリダイレクト<br>Auth Codeを保持
    C->>A: POST /token<br>Auth CodeとCode Verifierを含む
    A->>A: Auth Codeと<br>Code Verifierの検証
    A-->>C: アクセストークンを発行
    C->>M: Tokenを含むMCP Request<br>(Toolの呼び出し、またはInitialization)
    M->>M: アクセストークンの検証
    M-->>C: Toolの実行結果を返す

仕様ではこのような実装を例にしていますが、現実的にこのような実装は小規模な Local で動作する MCP Server、もしくは社内システム的に動作するものが限界となるでしょう。

そこで、MCP Server を自社プロダクトの機能として提供する場合、どのような形での運用になるのかについても、仕様外の話になりますが、解説します。

結論から言うと、Authorization Server を別途実装せず、既存のものを利用することで、MCP Server の認可を実装することができます。 その場合、MCP Server は Resource Server として機能し、Authorization Server から発行される Access Token を用いてアクセス制御を行います。

sequenceDiagram
    participant UA as UserAgent<br>(ブラウザなど)
    participant C as MCP Client
    box "自社プロダクトの範囲"
        participant M as Resource Serverとしての<br>MCP Server
        participant A as Authorization Server<br>(自社の認可サーバー)
    end
    C->>M: MCP Request<br>(Toolの呼び出し、またはInitialization)
    M->>M: アクセストークンの検証
    M-->>C: HTTP 401 Unauthorized
    note over C: PKCEを用いるため、<br>Code VerifierとCode Challengeを生成
    C->>UA: Code Challengeを付与したURLで認可画面を開かせる
    UA->>A: POST /authorize<br>Code ChallengeとCode Challenge Methodを含む
    A-->>UA: Auth Codeを含むCallback URLへリダイレクト
    UA-->>C: Callback URLへリダイレクト<br>Auth Codeを保持
    C->>A: POST /token<br>Auth CodeとCode Verifierを含む
    A->>A: Auth Codeと<br>Code Verifierの検証
    A-->>C: アクセストークンを発行
    C->>M: Tokenを含むMCP Request<br>(Toolの呼び出し、またはInitialization)
    M->>M: アクセストークンの検証
    M-->>C: Toolの実行結果を返す

この MCP Server のアクセス制御について少し詳しく解説します。

どちらの利用用途においても、MCP Server は Resource Server として機能し、アクセス制御は Authorization Server から発行される Access Token に基づいて行います。具体的には、MCP Server の Resources や Tools などの各インターフェースに対し、Access Token のスコープに応じたアクセス制御を実装する必要があります。また、MCP Server は Access Token を検証し、必要な権限があるかを確認してください。

以下にスコープの例を示します。スコープはRFC 6749に準拠した文字列で、リソースへのアクセス権限を表します。MCP Server はこのスコープをもとにアクセス制御を行います。

スコープの例は mcp.{interface}/{interfaceName}.{action} という形式で定義します。その上で、以下のようなルールに従っています。

  • mcp
    MCP Server を示すプレフィックス
  • {interface}
    インターフェース種別(例:resources、tools)
  • {interfaceName}
    インターフェースの具体名(例:file、wether)
  • {action}
    許可される操作(例:read、execute)

Scope の例:

mcp.resources/file.read
mcp.tools/wether.execute

スコープを用いることで、ユーザーごとに異なるアクセス権限を設定することが可能になり、意図しないリソースへのアクセスを防ぐことができます。

ここまで MCP における認可の基礎的な実装について解説しました。ただ、MCP の利用用途において、これだけではセキュリティ的に不十分な場合があります。詳細については次の項目で解説しますが、外部のクラウドサービスを用いる場合、必要に応じて MCP Server へのユーザーからの認可委譲を行うことが必要となります

認可委譲と Session Binding

「認可委譲(Authorization Delegation)」は、ユーザーなどの認可主体が、自身の持つ権限をアプリケーションなどに一時的に委譲し、リソースへのアクセスを許可する仕組みを指します。この認可委譲を行う仕組みとして OAuth2 系統や OIDC などが用いられます。

MCP においても仕様として、Third-Party Authorization Flowの章に定義されています。

本稿では仕様の内容を補足する形で、もう少し具体性を持って説明を行っていきます。

認可委譲を行うケースとして、Slack や Google Drive などの外部サービスを利用する場面を想定していきましょう。MCP Server は機能を提供するために Slack や Google Drive のリソースサーバーから必要なデータの取得や機能の操作をおこなう必要があります。この際に、MCP Server は外部サービスへのアクセスを行うべきでしょうか?

前提として、ユーザーが MCP Server に認可委譲する際の登場人物について整理します。

  • UserAgent
    • ブラウザやアプリケーションなど、ユーザーが操作するエージェント
  • MCP Client
    • MCP のやり取りにおける OAuth Client に相当する
  • MCP Server
    • MCP のやり取りにおける OAuth Resource Server および OAuth Authorization Server に相当する
    • 外部サービスとの連携における OAuth Client に相当する
  • 外部 IdP
    • 外部の認可サーバー(例:Google、Slack など)
    • 外部サービスとの連携における OAuth Authorization Server に相当する
  • 外部の Resource Server
    • 外部サービスのリソースサーバー(例:Google Drive、Slack など)
    • 外部サービスとの連携における OAuth Resource Server に相当する

このような外部サービスとの連携を行う場合、連携先のサービスにおいては、特段認可プロトコルの指定はされておらず、OAuth2.1 や OAuth2.0 の仕様に準拠した認可を行うとともにユーザーは MCP Server に認可委譲を行います。これら実装に関しては、以下のサービスドキュメントを参考にしながら実装を行うことができます。

docs.github.com

api.slack.com

developers.google.com

では、実際に認可委譲を行う場合は、以下のシーケンス図に示すような流れで認可を行います。また、このシーケンスは外部の Authorization Server が PKCE をサポートしていることを前提としています。

この際考えるべきこととして、MCP Server のアクセス制御は MCP Access Token を用いて MCP Server 側で実装をし、外部サービスのアクセス制御は、外部サービスの Access Token を用いて外部サービス側で実施することになります。

sequenceDiagram
    participant U as UserAgent<br>(ブラウザなど)
    participant C as MCP Client
    box "MCP Server"
        participant MR as MCP Serverとしての機能
        participant MA as 認可関連機能<br>Session Bindingも含む
    end
    box "外部サービス (Google DriveやSlackなど)"
        participant TA as Authorization Server
        participant TR as Resource Server
    end
    U->>MA: Initial OAuth Request
    note over MA: 権限委譲で用いる<br>Code VerifierとCode Challengeを生成
    MA-->>U: 外部サービスの認可画面へリダイレクト<br>Code Challengeを付与したURL
    U->>TA: 認可リクエスト
    note over TA: 認証済みのユーザーが許可をする<br>(例:Google アカウントでログイン)
    TA-->>U: 認可コードを含むCallback URLへリダイレクト
    U->>MA: Callback URLへリダイレクト<br>Auth Codeを保持
    MA->>TA: Auth CodeとCode Verifierを含むToken Request
    TA->>TA: Auth CodeとCode Verifierの検証
    TA-->>MA: 外部サービスのAccess Tokenを発行
    note over MA: 外部Access Tokenを保持し、<br>MCP Access Tokenに紐づける
    MA->>U: MCP ClientへのCallback URLへリダイレクト
    U-->>C: Callback URLへリダイレクト<br>Auth Codeを保持
    C->>MA: POST /token<br>Auth CodeとCode Verifierを含む
    MA->>MA: Auth Codeと<br>Code Verifierの検証
    MA-->>C: MCP Access Tokenを発行
    C->>MR: Tokenを含むMCP Request<br>(Toolの呼び出し、またはInitialization)
    MR->>MR: アクセストークンの検証
    note over MR,MA: MCP Access Tokenを検証し、<br>外部サービスのAccess Tokenを取得
    MR->>TR: 外部サービスのAccess Tokenを用いて<br>Resource Serverへリクエスト
    TR-->>MR: 外部サービスのリソースを返す
    MR-->>C: Toolの実行結果を返す

認可委譲の実装を行う際に肝になるのが、Session Bindingです。Session Binding とは、MCP Server が外部サービスの Access Token を MCP Access Token に紐づけることを指します。この Session Binding によって、MCP Client は MCP Access Token をひとつ持つだけで、複数の外部サービスへのアクセスを行うことが可能になります。また MCP Client の実装を簡素化することができます。

一方で、このような認可委譲を行う場合、MCP Server は外部サービスの Access Token を保持することになり、サービスの侵害を受けた場合、MCP Server を用いるユーザーが連携している外部サービスの情報の漏洩や不正利用のリスクが高まります。そのため、MCP Server は以下のようなセキュリティ対策を講じることが推奨されます。

  • 外部サービスの Access Token の有効期限を短く設定する
    万が一 MCP Server が侵害された場合でも、被害を最小限に抑えることができます。
  • 外部サービスの Access Token のスコープを最小限に設定する
    MCP Server が外部サービスのリソースにアクセスできる範囲を制限し、被害を最小限に抑えることができます。
  • MCP Access Token の有効期限を短く設定する
    万が一 MCP Server が侵害された場合でも、被害を最小限に抑えることができます。

Authorization Server Metadata と Dynamic Client Registration Protocol (DCRP)

MCP の仕様においては、OAuth2.1 への準拠以外に、Authorization Server Metadata と Dynamic Client Registration Protocol (DCRP)の準拠が選択的に求められています。これらは、MCP の利用や運用に際して、各種効率化やセキュリティの向上を図るための仕組みです。

Authorization Server Metadata は、MCP Client に対して認可サーバーのメタデータを提供するための仕組みです。これにより、MCP Client は認可サーバーのエンドポイントやサポートされている認証フローなどの情報を取得することができ、MCP Client の実装を簡素化することができます。

DCRP は、OAuth 2.0 のクライアント登録を動的に行うためのプロトコルであり、MCP Server が OAuth 2.1 に準拠した認可制御を実装する際に利用することが可能な、クライアント登録の仕組みです。

DCRP を使うことによって今までの手動でのクライアント登録を自動化し、MCP Server のクライアント資格を動的に管理することが可能になります。これにより、管理者はクライアント資格の発行処理が自動化され、利用者は MCP Client の設定を簡単に行うことができます。

また、MCP Client に MCP Server 固有の処理を実装することなく、DCRP に準拠した認可を実装することで、複数の MCP Server に対しても同じ MCP Client を利用することが可能になります。

その上で、DCRP を利用する場合、仕様においていくつかのセキュリティ対策10を行うことを推奨しています。例えば Client Registration Endpoint(MCP の仕様では、POST /registerが該当) に対して意図しないクライアントの追加や DoS 攻撃を防ぐために Initial Access Token(IAT) または、Software Statement11 を用いてリクエストを行うことが推奨されています。

この IAT はシステム管理者(テナントの管理者)、または個人が発行する必要があります。IAT はクライアント資格を取得するためのものであるため、MCP Server そのものへのアクセス権限は含まれません。また、有効期限を短期間に設定することが推奨されます。

IAT の取得から DCRP を用いたクライアント資格の取得までの流れの例を以下のシーケンス図に示します。 この例では、IAT の取得は手動で行い、MCP Client に設定することを想定しています。

sequenceDiagram
    participant U as User
    participant UA as UserAgent<br>(ブラウザなど)
    participant C as MCP Client
    participant M as MCP Server<br>および認証認可機能

    UA->>M: 認証および IAT の取得
    M-->>UA: IAT の発行
    UA->>U: IATの取得
    U->>C: ITAをMCP Clientに設定
    C->>M: MCP Request<br>(Toolの呼び出し、またはInitialization)
    M->>M: アクセストークンの検証
    M-->>C: HTTP 401 Unauthorized
    C->>M: POST /register<br>クライアント資格の取得<br>(IATを含む)
    M-->>C: クライアント資格の発行
    C->>M: POST /authorize<br>認可リクエスト(PKCE)
    M-->>UA: 認可<br>認証画面の表示
    C->>UA: ユーザー認証<br>認可の許可を求める
    U->>UA: 認可の許可
    UA-->>C: コードを保持したリダイレクトURLへリダイレクト
    C->>M: POST /token<br>アクセストークンの取得<br>(PKCEを含む)
    M-->>C: アクセストークンの発行
    C->>M: MCP Request<br>(Toolの呼び出し)<br>アクセストークンを含む
    M->>M: アクセストークンの検証
    alt アクセストークンが有効な場合
        M-->>C: Toolの実行結果
    else アクセストークンが無効な場合
        M-->>C: HTTP 401 Unauthorized
    end

まとめ

本記事では、MCP を取り巻く脅威と具体的なセキュリティ対策を俯瞰し、実装者が直面しやすい論点を整理しました。

  • 特性と脅威の整理 実行環境/MCP Host・Client/MCP Server の 3 層それぞれに対し、攻撃者の狙いどころを体系的に解説
  • 攻撃経路の分類 悪意ある MCP Server、外部リソース汚染、ユーザー入力操作、ブラウザ経由、直接アクセス――5 つの経路を提示
  • 基本的な脆弱性対策 URI 正規化、SSRF/Path Traversal/コマンドインジェクション防止など、Web と共通する守りを再確認
  • プロンプトインジェクション対策 Tool 情報を直接プロンプトに埋め込まない、多層の確認フローで自動実行を抑制
  • ネットワーク防御 Streamable HTTP 化に伴う誤公開防止、DNS Rebinding・CORS 設定の適正化を推奨
  • 認可とリモート公開 HTTPS 化、IP 制限、mutual TLS、OAuth2 系プロトコルの導入による保護を推奨
  • 実装者チェックリスト 末尾に汎用チェックリストを添付し、実装・レビュー時の即時参照を可能に(この後に記載があります)

MCP の利活用や提供は多くの企業で進んでいくと考えられます。その際に、本記事とともに前編を参照し、MCP のセキュリティを考慮した実装や運用を行うことが重要です。

また、MCP のセキュリティは日々進化しています。新たな脅威や攻撃手法が登場する中で、実装者は常に最新の情報をキャッチアップし、適切な対策を講じる必要があります。

今後も MCP や生成 AI を取り巻くセキュリティの最新動向を発信していきます。ぜひ引き続きご注目ください。

お知らせ

GMO Flatt Securityは2025年3月から日本初のセキュリティ診断AIエージェント「Takumi」を開発・提供しています。Takumiを導入することで、高度なセキュリティレビューや巨大なコードベース内調査を月額7万円(税別)でAIに任せることができます。

また、セキュリティエンジニアによる脆弱性診断・ペネトレーションテストとして「LLMアプリケーション診断」を正式リリースしました。LLMを活用するアプリケーションの実装のセキュリティリスクをソースコード解析により網羅的に検出します。

今後ともGMO Flatt SecurityはAIエージェントを開発している組織だからこその専門的な深い知見も活かしながら、AIを活用するソフトウェアプロダクトにとって最適なサービスを提供していきます。公式Xをフォローして最新情報をご確認ください!

付録: 実装者向けセキュリティチェックリスト

以下は、MCP Server や Client を実装・運用する際に確認すべきセキュリティ観点のチェックリストです。

# MCP Server / Client 実装者・運用者向けセキュリティチェックリスト

## ✅ 実行環境と権限管理

-   [ ] MCP Server はサンドボックスや隔離環境で動作しているか
-   [ ] 最小権限で動作するように設定されているか
-   [ ] 外部サービス用のトークンや認証情報は安全に保護されているか

## ✅ 入力値の取り扱い

-   [ ] URI やファイルパスは正規化 (`new URL()` など) されているか
        ↳ [MCP SDK における URI 正規化の実装](https://github.com/modelcontextprotocol/typescript-sdk/blob/bced33d8bc57419c6d498ca9a26a284f3ccf6016/src/server/mcp.ts#L364-L398)
-   [ ] ユーザー入力の検証・バリデーションは適切に行っているか
-   [ ] Path Traversal や SSRF を防ぐ制限が設けられているか
        ↳ [GMO Flatt Security Tech Blog - LLM の外部通信・連携におけるセキュリティ観点](https://blog.flatt.tech/entry/llm_ext_collab_security)

## ✅ 外部通信とコマンド実行

-   [ ] 外部通信先はホワイトリストや baseURL 制限などを設けているか
-   [ ] fetch などの API 呼び出しは安全に構築されているか
-   [ ] コマンド実行には `execFile` などの安全な API を使用しているか
        ↳ [GMO Flatt Security Tech Blog - プロンプトインジェクション対策: 様々な攻撃パターンから学ぶセキュリティのリスク](https://blog.flatt.tech/entry/how_to_deal_with_injection_vulnerabilities)

## ✅ プロンプトと Tool の設計

-   [ ] tool の `description` や prompt を LLM 入力に直接埋め込んでいないか
-   [ ] `tools` パラメータを活用し、LLM に構造化情報として渡しているか
-   [ ] Tool 実行にはユーザー確認などの制御が導入されているか
        ↳ [GMO Flatt Security Tech Blog - プロンプトインジェクション対策: 様々な攻撃パターンから学ぶセキュリティのリスク](https://blog.flatt.tech/entry/prompt_injection)
        ↳ [Invariant Labs - Tool Poisoning Attacks](https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks)

## ✅ MCP Server の公開と通信制御

-   [ ] MCP Server は `localhost` バインドになっているか(`0.0.0.0` にしていないか)
        ↳ [MCP Spec - Security Warning](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#security-warning)
-   [ ] Origin ヘッダを用いて DNS Rebinding 対策がされているか
-   [ ] CORS 設定にワイルドカード (`*`) を使っていないか

## ✅ 認可とリモート利用

-   [ ] 公開 MCP Server には OAuth2.1 ベースの認可が導入されているか
        ↳ [MCP Spec - Authorization](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization)
-   [ ] 認可スコープに応じたアクセス制御を設計しているか
-   [ ] 外部 IdP との連携時、トークンの検証や失効チェックが行われているか
        ↳ [GMO Flatt Security Tech Blog - AI 時代の認可制御入門:「AI でつくる人」「AI をつくる人」のための実践ガイド](https://blog.flatt.tech/entry/ai_authz)

  1. 執筆時における最新の仕様は 2025/03/26 に策定されたバージョンのものです。 https://modelcontextprotocol.io/specification/2025-03-26
  2. ここで想定するソフトウェアは VSCode や Cursor、Cloaude といった生成 AI アプリケーションを想定しています。これらソフトウェアは比較的ローカルで動作するソフトウェアの中では「ファイルの閲覧や操作」「ツール間の連携」「コマンドの実行」といった比較的高い権限を付与されるため、攻撃者にとっては狙いやすいターゲットとなります。
  3. 例えば Amazon Web Services (以後 AWS と呼称する) の S3 Bucket にアクセスする場合、AWS のアクセスキーなどの認証情報を取得して通信を行います。
  4. 同一名のツールを別の MCP Server 上に定義することで、意図せず悪意のあるツールが選択されてしまう脆弱性。主に Model に渡した際や、tool_use時のツール取得時にプログラム上の実装不備が原因で問題が発生する。
  5. Tool の説明や出力に悪意あるプロンプトを仕込み、生成 AI の挙動を意図的に変化させる手法。Invariant Labs により命名された。詳細は https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks を参照。
  6. PDF 内部に利用者の意図しない文字列を埋め込むことで生成 AI による課題の解答生成を誤ったものにするという例も存在しており、利用者の意図しない入力を引き起こすことは現実可能です。 https://news.yahoo.co.jp/articles/27903ca46d6c399109c3d520a05938282591a734
  7. MCP の仕様においては各所にセキュリティに関する警告項目を設けており、これらを実直に実装することにより一定のセキュリテイ対策を行うことができます。 https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#security-warning
  8. Dynamic Client Registration Protocol は、OAuth 2.0 のクライアント登録を動的に行うためのプロトコルであり、MCP Server が OAuth 2.1 に準拠した認可制御を実装する際に利用されます。 https://datatracker.ietf.org/doc/html/rfc7591 / https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12#section-1.7-3.2.1
  9. OAuth 2.0 Authorization Server Metadata は、OAuth 2.0 認可サーバーのメタデータを提供するためのプロトコルであり、MCP Server が OAuth 2.1 に準拠した認可制御を実装する際に利用されます。 https://datatracker.ietf.org/doc/html/rfc8414 / https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12#section-1.7-3.1.1
  10. Dynamic Client Registration Protocol を用いて Client を追加する場合、DoS や意図しない追加を防ぐために、ITA を用いてクライアント資格を取得することができます。https://openid.net/specs/openid-connect-registration-1_0.html
  11. Software Statement は、クライアントの資格情報を事前に登録するための仕組みであり、IAT の代わりに利用することができます。https://openid.net/specs/openid-connect-registration-1_0.html