MCPサーバーのセキュリティ
このページは、AIエージェントをDocsbookに接続することを承認する必要がある方を対象にしています。ここでは、MCPサーバーが現在実際に行っていること、つまりクライアントの認証方法、各スコープでアクセスできる範囲、記録される内容、ネットワーク外に出るものを説明し、そのうえで、DocsbookがModel Context Protocolの仕様を満たしていない点と、現時点で存在しないコンプライアンス関連の成果物を、それぞれ別の2つのセクションで示します。
ここに書かれている内容は、将来的な目標ではありません。制御が欠けている場合は、欠けているものとして記載しています。
得られるもの#
接続されたクライアントは、1つのDocsbookアカウントに紐づいた、2つあるスコープのいずれかを持つ1つの不透明なベアラートークンを保持します。スコープはクライアントが要求するのではなく、同意画面で人間が選択します。プロジェクトに対して動作するすべてのツールは、所有者によってそのプロジェクトを解決するため、他人に属するワークスペースIDを指定したトークンは、そのワークスペースではなく、何も返しません。これがテナント間の境界であり、すべてのツールで維持されます。
読み取りと書き込みの境界は、2つのスコープ名が示唆するほど単純ではありません。以下のセクションでは、どのツールがこの境界を強制し、どのツールが強制しないのかを正確に説明します。読み取り専用トークンを封じ込めの手段として扱う前に、そこを読んでください。
計測対象となるすべての呼び出しでは、プロジェクト固有の呼び出しログに1行が書き込まれます。そこには、どのツールか、何が入力されたか、何が返されたか、どれだけ時間がかかったか、どれだけ消費したかが記録されます。引数と結果は保存前にキー単位で秘匿化されるため、ツールに渡されたAPIキーが記録されることはありません。
得られないもの:トークンの有効期限、リフレッシュトークン、レート制限、アカウント内のロール、監査レポート。
認証の仕組み#
認可フロー#
Docsbookは独自の認可サーバーであり、独自のリソースサーバーでもあります。自らのために不透明トークンを発行し、他者が発行したトークンを受け入れたり、転送したり、再利用したりすることはありません。
| ステップ | 処理内容 |
|---|---|
| ディスカバリー | サーバーエンドポイントへの未認証リクエストは、401 と WWW-Authenticate: Bearer resource_metadata="…/.well-known/oauth-protected-resource" を返します。このドキュメントにはリソースとその認可サーバーが記載され、/.well-known/oauth-authorization-server にはRFC 8414形式のエンドポイントが含まれます。 |
| クライアント登録 | 登録エンドポイントへの POST は、RFC 7591形式の新しい client_id を返します。クライアントは永続化されません — IDはステートレスに生成され、認可エンドポイントは任意の client_id を受け入れます。 |
| 認可 | クライアントは response_type=code、redirect_uri、8文字以上の state、通常はPKCEの code_challenge を送信します。パラメーターは state に関連付けて保存され、ブラウザーは同意ページへ移動します。この行は10分後に期限切れになります。 |
| 同意 | 同意ページでは、Docsbookアカウントへのサインインと明示的なクリックが必要です。ページにはチェックボックスが1つ — ドキュメントの編集を許可 — あり、これによってスコープが決まります。「このクライアントを記憶する」Cookieも、サイレントな再承認の経路もありません。認可のたびにこの画面が表示されます。 |
| トークン交換 | コードはトークンエンドポイントでBearerトークンと交換されます。クライアントがメソッド S256 のPKCEチャレンジを指定した場合、ベリファイアが検証され、不一致の場合は拒否されます。コードは1回限り使用できます。最初の交換が成功すると消去されます。 |
公開されたメタデータでは、パブリッククライアントモデル — code_challenge_methods_supported: ["S256"]、token_endpoint_auth_methods_supported: ["none"]、grant_types_supported: ["authorization_code"] — が宣言されています。クライアントシークレットも、クライアントクレデンシャルグラントもありません。
トークンとは#
トークンはプラットフォームの CSPRNG から取得した48バイトで、96個の16進文字として表現されます。クレームは含まれておらず、アカウント、スコープ、失効タイムスタンプを保持する行を検索するためのキーです。
- 有効期限はありません。
expires_inは返されず、リフレッシュトークンも発行されません。トークンは失効されるまで有効です。 - 失効は即時に反映されます。 パネルから失効させると行に記録され、その後のすべての呼び出しで検索に失敗します。前段にキャッシュはありません。
- ハッシュ化されず、発行されたまま保存されます。 Docsbook MCP トークンはパスワードと同じように扱ってください。トークンを保持するマシンが侵害された場合は、トークンの有効期限切れを期待するのではなく、失効させてください。(保存時に暗号化されるものについては、ワークスペースから外部に出るものに記載されています。)
- 最終使用日時はすべての呼び出しで記録されるため、未使用のトークンもパネルのトークン一覧で確認できます。
各スコープでできること#
スコープは完全一致で比較される単一の文字列です。書き込みスコープでないものはすべて読み取り専用として扱われ、認識されない値は安全側に倒して拒否されます。
| 呼び出し元 | 返される内容 |
|---|---|
| トークンなし、スコープなしのエンドポイント | 何もありません。ディスカバリーヘッダー付きの 401。 |
トークンなし、リポジトリスコープのエンドポイント(/{owner}/{repo}/api/mcp/server) |
5つのツール、つまり get_info、find_skill、find_widget、list_content_widgets、search を、その1つの公開済みサイトに対して利用できます。メーター計測も請求も行われず、誰にも課金されません。 |
| 読み取り専用トークン | すべてのレポート、検索、アウトライン、分析ツールに加え、監査モードで実行される run_docs_analyze — そして現時点では、以下に記載する設定書き込みツールも含まれます |
| 読み書きトークン | アカウントで実行できるすべての操作 |
現在、スコープチェックはすべての書き込みツールを対象としているわけではないため、その前提で計画してください。 このチェックが適用されるのは、正確には8つのツールです。write_docs、create_issue、connect_source、configure_source、enable_agent、および書き込みを行う3つの run_docs_* 実行です。これらは何も実行する前に、読み取り専用トークンを拒否します。
その他の状態変更ツール — update_* および set_* の設定書き込みツール、update_access、Webhook の登録と削除、目標とファネルの作成、翻訳のアップロード、承認、削除、create_workspace — は、スコープではなくプロジェクトの所有権だけによって制限されます。したがって、読み取り専用トークンでも、そのアカウントが所有するプロジェクトの設定を変更したり、Webhook を有効化したり、翻訳を削除したりできます。それでも、ページをコミットしたり、課題を登録したり、ソースを接続したり、エージェントを有効化したりすることはできません。
読み取り専用スコープは「公開したり新しい機能を接続したりできない」と捉え、「何も変更できない」とは考えないでください。それ以上の封じ込めが必要な場合は、公開してもよいプロジェクトだけを所有する別の Docsbook アカウントを使用してください。これは設計ではなく、制限事項で改めて記載している不具合です。
チェックを適用するツールは、読み取り専用トークンに対して、ツール名と再認証の方法を示す構造化された READ_ONLY_TOKEN エラーを返します。単なる 403 でも、何も通知しない無操作でもありません。同じ形式は、プロジェクトの残高が空の場合(プロジェクト名、価格、残額を示す INSUFFICIENT_BALANCE)や、プランにその機能が含まれていない場合(ティアを示す PLAN_RESTRICTION)にも適用されます。
匿名の search は、トークンなしでプロジェクトを読み取る唯一のツールです。ただし、3つのケースで拒否されます。プロジェクトに固定されていないエンドポイントである場合、公開設定が非公開のプロジェクトである場合(期限切れのプランもこれに含まれます)、そしてクエリの埋め込みに必要な料金を支払う残高がプロジェクトに残っていない場合です。プロジェクト引数を受け取らないため、固定先のサイトだけを読み取ることができます。
1つのトークンでは到達できないもの#
すべてのツールは、明示的な workspace_id、repo 引数、またはエンドポイント自身のピンから対象ワークスペースを解決します。いずれの場合も、検索対象はトークンのアカウントでフィルタリングされます。アカウントが所有していないワークスペースは何も解決されず、ツールは「ワークスペースが見つかりません」と応答します。請求情報のリゾルバーにも同じフィルターが適用されるため、他人のプロジェクト ID を指定しても、他人の残高から引き落とすことはできません。
意外に思われるため、さらに2つの境界についても明記しておきます。
write_docsは、Docsbook 自身の GitHub 認証情報を使用して、Docsbook がホストするリポジトリにコミットします。 自分の GitHub アカウント内のリポジトリから提供されるサイトは、コミットされるのではなく、NO_GITHUB_ACCESSとともに拒否されます。したがって、MCP トークンは GitHub 組織にプッシュする手段ではありません。- 監査モードで実行されているスキルは変更を加えられません。
auditモードのスキルがアクティブな間は、明示的な writer のリストに加え、名前がupdate_、set_、register_webhook_、enable_またはdisable_で始まるすべてのツールが、実行前に拒否されます。run_docs_analyzeは実行全体に対してそのモードを設定するため、読み取り専用トークンでも安全です。
記録される内容#
すべての MCP 呼び出し(メータリング対象かどうか、成功したかどうかを問わず)は、プロジェクトの呼び出し台帳に 1 行を書き込み、プロジェクトの所有者はフィードパネルでそれを読むことができます。
| 記録される内容 | 記録されない内容 |
|---|---|
| ツール名、課金クラス、価格、実際に差し引かれたセント数、実行時間、成功フラグ、バックグラウンド実行 ID、呼び出し元(エージェント、パネル、スケジュール、イベント) | 呼び出し元の IP アドレス |
| 呼び出しの引数と結果(シリアライズ、秘匿化、切り詰め済み) | 生のペイロード — 秘匿化され、切り詰められた表示のみが保存されます |
| 呼び出しを行ったアカウントと、呼び出しの対象となったプロジェクト | apikey、api_key、authorization、credential、password、passwd、secret、token、private_key、privatekey、session または cookie を含むキーの下にある値 |
レビューにあたっては、秘匿化に関する 2 つの点が重要です。秘匿化は値の形状ではなく、キーに対して、大文字と小文字を区別せず、部分文字列として一致します。そのため、秘密情報がどのような形をしているかを推測する方法では見逃しが生じます。また、秘匿化は入力時だけでなく出力時にも実行されるため、入力をそのまま返すツールであっても、結果を通じてキーが漏洩することはありません。各側は 8,000 文字で切り詰められ、削除された文字数を示すマーカーが付加されます。
閲覧者レベルの分析情報が MCP クライアントに個人を特定できる情報を渡すことはありません。訪問者は仮名化された識別子 sha256(salt | repository | ip) です。これは 16 桁の 16 進文字に切り詰められ、ソルトはサーバー側で保持されます。get_top_visitors、get_page_journeys、get_visitor_activity は、その仮名化識別子、国、ページレベルのイベントを返します。どのツールも IP アドレス、名前、メールアドレスを返しません。仮名化識別子は 1 つのリポジトリにスコープされるため、2 つのサイトを訪れた同じ閲覧者は、互いに関係のない 2 つの ID として扱われます。
ワークスペースから外部に出るもの#
| データ | 送信先 | 保存時の暗号化 |
|---|---|---|
| ページ本文、見出し、タイトル | 全文検索用にDocsbookのPostgresへコピーされ、セマンティック検索用のベクトルとして埋め込まれます | いいえ — コンテンツとして保存 |
| 埋め込み、チャット、エージェント処理のために送信されるページ本文 | OpenRouter、Docsbookのキーを使用するモデルプロバイダー、または自分でキーを設定した場合はそのキーのプロバイダー | 該当なし — 転送中のみ |
| 読者イベント | 生のIPアドレスを含むDocsbookの分析ストア。このIPアドレスを返すAPIはありません | 該当なし |
| プライベートドキュメント用のOIDCクライアントシークレット | DocsbookのPostgres | はい — AES-GCM、プラットフォームシークレットから導出されたキー |
| プライベートリポジトリのソースとして接続するGitHubトークン | DocsbookのPostgres | はい — 同じ方式。APIが返すのはトークンの有無のみ |
| 自分のモデルAPIキー(BYOK) | DocsbookのPostgres、およびそのキーで行うすべての呼び出しにおけるプロバイダー | いいえ — 指定されたまま保存され、APIが返すすべてのワークスペースペイロードから除外 |
| MCP Bearerトークン | DocsbookのPostgres | いいえ — 上記を参照 |
fetch_url、read_source、およびクローラーが取得したページ |
指定したアドレスへ | 該当なし |
ドキュメントベンダーのセキュリティページで通常謳われる2つの主張を訂正します。
- 「コンテンツがリポジトリから外部に出ることはありません」は、ここでは正しくありません。 Docsbookは、ページ本文の検索可能なコピーとそのベクトル埋め込みを保存し、それらの埋め込みの作成やチャットおよびエージェント呼び出しへの回答のために、ページ本文をモデルプロバイダーへ送信します。正しいのは、GitHubが信頼できる唯一の情報源であり続けるため、支払いを停止すれば、Markdownを削除せずに従量制の処理を停止できるという点です。
- 外部への取得は、単に信頼されているのではなく、保護されています。 取得の前にスキームが確認され、ホスト名が解決され、解決されたアドレスがプライベートまたは予約済みの範囲にある場合は拒否されます。さらにこの確認はリダイレクトの各ホップで再実行されるため、公開URLから内部URLへ転送することはできません。
robots.txtは遵守され、レスポンスには上限が設定されます。スキルフェッチャーはさらに制限が厳しく、カタログ独自のホストとパスプレフィックスからのみ取得するため、任意のURLプロキシとして利用することはできません。
Webhookとチャットフックは同じものではありません#
送信Webhookの配信には署名が付けられます。署名は、X-Docsbook-Signature-256: sha256=<hex>内で、X-Docsbook-Eventとともに送信される正確なバイト列に対するHMAC-SHA256です。DiscordまたはSlackの受信Webhook URLは、署名を行う前に各プラットフォーム用に整形されるため、署名は常にエンドポイントが実際に受信する内容を対象とします。シークレットは登録時に設定され、16文字以上であり、その後プレーンテキストで返されることはありません。配信試行は15秒でタイムアウトし、レスポンスは切り詰められて保存されます。
チャットフックには署名がありません。ドキュメントアシスタントのpre、post、ストリーミングフックは、5秒のタイムアウトが設定されたプレーンなJSON POSTsであり、HMACヘッダーはありません。そこではWebhookの検証コードを再利用して、何かが検証済みだと想定しないでください。preフックはinject_contextを返すこともでき、そのテキストはアシスタントのプロンプトに入ります。つまり、チャットフックの送信先に指定したエンドポイントはアシスタントの発言内容に影響を与えられるため、信頼できるインフラストラクチャとして扱い、別の手段で認証し、自分が管理していないURLを指定しないでください。
これが正しい方法である理由(根拠)#
| Docsbookが従うルール | それを利用する側にとって重要な理由 | 出典 |
|---|---|---|
| 独自の不透明なトークンを発行し、他所で発行されたトークンは決して受け入れたり転送したりしない | 「MCPサーバーは、MCPサーバー向けに明示的に発行されたものではないトークンを受け入れてはならない」 | MCPセキュリティのベストプラクティス、トークン・パススルー |
認証されていない呼び出しには、保護リソースメタデータを示すWWW-Authenticateを返す |
「MCPサーバーはOAuth 2.0保護リソースメタデータ(RFC9728)を実装しなければならない」 | MCP認可 |
トークンエンドポイントでPKCEのS256検証子を検証し、code_challenge_methods_supportedを公開する |
「code_challenge_methods_supportedが存在しない場合、認可サーバーはPKCEをサポートしておらず、MCPクライアントは処理を続行することを拒否しなければならない」 |
認可に関するセキュリティ上の考慮事項 |
| クライアントを記憶しておくのではなく、認可のたびに同意画面を表示する | 混乱した代理人攻撃は、スキップされた同意画面を経由して成立する:「Cookieが存在するため、同意をスキップ」 | MCPセキュリティのベストプラクティス、混乱した代理人 |
| クライアントが要求するスコープの一覧ではなく、人が選択した2つのスコープに限定する | 不適切なスコープ設計は、「攻撃範囲の拡大:広範なトークンを盗まれると、無関係なツールやリソースへのアクセスが可能になる」ことを意味する | MCPセキュリティのベストプラクティス、スコープの最小化 |
| 解決されたプライベートIPアドレスまたは予約済みIPアドレスを拒否し、リダイレクトのたびに再確認する | クライアントとサーバーは「リンクローカル:169.254.0.0/16(クラウドメタデータエンドポイントを含む)」をブロックすべきである |
MCPセキュリティのベストプラクティス、SSRF |
| 各ツールの対象を、呼び出し元が指定したIDではなく、呼び出し元の所有権に関連付ける | サーバーは「状態ハンドルを所持していることを認証として扱ってはならず」、検証済みのプリンシパルに状態を関連付けるべきである | MCPセキュリティのベストプラクティス、状態ハンドルの乗っ取り |
| エージェントが読み込むスキルを、私たちのものも含めて精査する | 「外部URLからデータを取得するスキルには特にリスクがある。取得したコンテンツに悪意のある指示が含まれている可能性があるためである」 | Anthropic、Agent Skills |
もう1つ、私たちではなく皆さんのクライアントに関係する点があります。MCP仕様では、クライアントに対して「ツールのアノテーションが信頼できるサーバーから提供されたものでない限り、信頼できないものとして扱う」こと、そして「ツール呼び出しを拒否できる人間をループ内に置く」ことを推奨しています(MCPツール)。読み書き可能なDocsbookトークンは、まさにその人間による確認が必要なケースです。
現在、DocsbookがMCP仕様を満たしていない点#
これらは 2026-07-28 リビジョンを基準に評価したものです。いずれも仕様への異議ではなく、Docsbookにおける不足です。
| 要件 | Docsbookの動作 | レビュー担当者にとっての重大度 |
|---|---|---|
| 「認可サーバーは、事前登録された値に対して正確なリダイレクトURIを必ず検証しなければならない」 | redirect_uri のスキームを許可リスト(HTTPS、ループバック、およびエディターのディープリンク用に固定されたスキーム一覧)に照らして検証しますが、クライアントが永続化されないため、交換時に登録済みの値との比較は行いません |
最初に指摘すべき点です。リダイレクト先を表示しない同意画面と組み合わせると、細工されたリンクをクリックしたユーザーが、別の場所に到達する認可を承認してしまう可能性があります。画面では毎回、意図的なクリックが必要であり、スキップすることはできません。 |
| 「認可サーバーは短期間有効なアクセストークンを発行すべき」であり、パブリッククライアントのリフレッシュトークンをローテーションする | 有効期限もリフレッシュトークンもないトークンを発行します | 漏洩したトークンは、誰かが失効させるまで有効です |
| サーバーはツール呼び出しをレート制限しなければならない | レート制限を行いません。プロジェクトの残高が唯一の制限であり、メータリングされないディスカバリー呼び出しには制限がまったくありません | リスクはリクエスト数ではなく、金額で見積もってください |
| 認可コードでのPKCE | クライアントがメソッド S256 のチャレンジを提供した場合に検証されます。何も提供しないクライアントでもフローを完了できます |
主要なMCPクライアントはすべてPKCEを送信しますが、サーバーは現在それを必須としていません |
| プロトコルリビジョン | サーバーは、ステートレスHTTPトランスポート上で、現在のSDKがサポートする初期化ベースのリビジョン(最新は 2025-11-25)を使用します |
2026-07-28 のみをサポートするクライアントは接続できません |
チャレンジ内の scope とメタデータ内の scopes_supported |
どちらも公開されず、スコープは同意画面で選択されます | クライアントは2つのスコープをプログラムから検出できません |
Docsbookにまだないもの#
レビューで第3週ではなく1時間でDocsbookを候補から外せるよう、一覧にしています。
| 機能 | ステータス |
|---|---|
| SOC 2 Type II | 提供なし — 共有できるレポートはありません |
| データ処理契約 | 提供なし — 現時点で双方が署名したDPAはありません |
| 契約上のSLA | 提供なし |
| Docsbookへのサインイン用SAML SSO | 提供なし — アカウントへのサインインにはGitHub OAuthを使用します |
| チームアカウント、ロール、RBAC | 提供なし — アクセスはアカウント単位であり、アカウントにサインインできる人は誰でも、そのアカウントで可能なことをすべて実行できます |
| アカウントイベントの監査ログ | 提供なし — サインイン、トークンの発行、プランの変更はイベントログとして公開されません。MCPツールの呼び出しはプロジェクトごとに完全に記録され、コンテンツのコミットは変更履歴から確認できます |
| 侵入テストレポート | 提供なし |
2番目と4番目の行の内容と混同されることが多い機能が1つあります。プライベートワークスペースは、すべてのプランで、パスワードまたは update_access を介した独自のOIDCプロバイダーによってアクセス制限できます。これはドキュメントサイトの閲覧者向けのシングルサインオンです。Docsbookアカウントのメンバー向けのシングルサインオンではなく、MCPアクセスも許可しません。
組織に特定の成果物 — GDPR DPA、BAA、記入済みの質問票など — が必要な場合は、support@docsbook.io に連絡して何が用意されているか尋ねてください。現時点では、存在しないという回答になる可能性も十分にあります。
制限事項と未解決の問題#
- ホスティングリージョンは未確認です。 このページでは、データベースや分析ストアのリージョンを意図的に記載していません。どちらもマネージドサービスであり、リージョンはDocsbookの動作から読者が確認できるものではなく、デプロイ設定です。また、このページの以前のバージョンでは、出典のないリージョンが記載されていました。データレジデンシーが審査の一部である場合は、サポートに書面で現在の回答を問い合わせてください。
- 仮名化された訪問者IDは、匿名化ではなく仮名です。 これは64ビットに切り詰めたIPアドレスのソルト付きハッシュです。ソルトと生のイベントストアの両方を持つ人は、そこから再導出できます。保証されているのは、ソルトがデータに含まれておらず、どのAPIもIPアドレスを返さないことです。それで規制当局の要件を満たすかどうかは、規制当局に確認してください。
- 読み書きトークンは完全な管理者資格情報です。「ページの編集は許可するが設定の変更は許可しない」、または「分析の読み取りは許可するがチャットのトランスクリプトは許可しない」といった権限を付与する方法はありません。スコープの段階は2つだけです。
- 読み取り専用スコープの適用は不完全です。 8つのツールはこれをチェックしますが、設定、Webhook、目標、翻訳の書き込みツールはチェックしません。また、それらのツールの一部には、実際には何もチェックしていないにもかかわらず、読み書きトークンが必要だと説明されています。これが解消されるまでは、信頼できる境界はスコープではなくアカウント所有権です。したがって、アカウント単位で分離し、ツールの説明ではなく、上記の適用済みリストを確認してください。
- ここに記載されている事項は、第三者による独立した保証を受けていません。 上記のすべての記述は、Docsbookの動作で確認できます。たとえば、読み取り専用トークンを発行して書き込みツールが拒否することを確認したり、所有していないプロジェクトを接続して解決されないことを確認したりできます。しかし、第三者による監査は行われていません。このページは認証書ではなく、テスト可能な仕様として扱ってください。
- 利用可能性と価格については料金ページをご覧ください。 ここでは価格を記載していません。ドキュメントに転載した価格は、気付かないうちに古くなるためです。