mcpField
Q
Qdrant RBAC

Qdrant RBAC

ローカル
fidonis.deデータベース03 週間前に更新

Qdrant RBAC について

Qdrant RBACは、OIDC認証とロールに応じたアクセス制御を備え、Qdrantのコレクションを公開するFastMCPサーバーです。権限付与情報をQdrantに保存し、コレクション単位の権限に加えてドキュメント単位のポリシーも適用できます。

主な機能

  1. 01OIDCトークンの検証と範囲限定Qdrant JWTの生成
  2. 02MCPツールによるロール権限の管理
  3. 03コレクションごとの読み取り・書き込み・管理権限
  4. 04ペイロードポリシーによるドキュメントアクセスの絞り込み
  5. 05Qdrantポイントの検索・閲覧・挿入・削除

活用シーン

  1. 01チームのアクセスを特定のQdrantコレクションに限定
  2. 02タグやフィールドで閲覧可能なドキュメントを制限
  3. 03実行時にロール権限を付与または取り消し
  4. 04MCPクライアントに認証付きベクトル検索を提供

MCP 対応

ストリーミングHTTPのMCPサーバーは、Qdrantのコレクションとポイントを操作するツール、およびロール権限の管理ツールを提供します。クライアントのOIDCトークンを検証し、各リクエストに対応する範囲の権限を適用します。

設定

ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。

mcp.json · 共通設定
{
"mcpServers": {
"de-fidonis-qdrant-mcp-rbac": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"OIDC_ISSUER_URL",
"-e",
"OIDC_AUDIENCE",
"-e",
"QDRANT_URL",
"-e",
"QDRANT_JWT_SECRET",
"ghcr.io/fidonis/qdrant-mcp-rbac:0.4.0"
],
"env": {
"OIDC_ISSUER_URL": "<OIDC_ISSUER_URL>",
"OIDC_AUDIENCE": "<OIDC_AUDIENCE>",
"QDRANT_URL": "<QDRANT_URL>",
"QDRANT_JWT_SECRET": "<QDRANT_JWT_SECRET>"
}
}
}
}
起動コマンドdocker run -i --rm -e OIDC_ISSUER_URL -e OIDC_AUDIENCE -e QDRANT_URL -e QDRANT_JWT_SECRET ghcr.io/fidonis/qdrant-mcp-rbac:0.4.0
設定が必要な環境変数
OIDC_ISSUER_URLOIDC issuer / realm URL, e.g. https://kc.example.com/realms/myrealm
OIDC_AUDIENCEExpected aud claim of incoming access tokens, e.g. mcp-server
QDRANT_URLQdrant HTTP endpoint, e.g. http://qdrant:6333
QDRANT_JWT_SECRETシークレットHS256 signing secret, at least 32 bytes; must equal Qdrant's service.api_key

ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。

パッケージ
ocighcr.io/fidonis/qdrant-mcp-rbac:0.4.0

ツール

ツール一覧はまだ取得されていません

ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。

詳細

qdrant-mcp-rbac

License: MIT Fidonis がメンテナンスしています · 商標に関する通知は TRADEMARK.md をご覧ください。

同じ MCP ツール呼び出しでも、2 つの ID では結果セットが異なります — サーバー側で強制されます。

ストリーミング可能な HTTP と OIDC ベースの認証(Keycloak 互換)を使用し、 ロールベースのアクセス制御を Qdrant ネイティブの JWT アクセスルールに マッピングして、Qdrant ベクトルデータベースを公開する FastMCP サーバーです。

ロールの権限付与は設定ファイルではなく、専用の Qdrant コレクション内にデータとして 保存されます。管理者は MCP ツールを使って、実行時に管理できます。

┌──────────┐   OIDC Bearer   ┌─────────────────┐   Qdrant JWT    ┌──────────┐
│ MCP host │ ──────────────▶ │ qdrant-mcp-rbac │ ──────────────▶ │  Qdrant  │
│ (client) │                 │   (FastMCP)     │                 │          │
└──────────┘                 └─────────────────┘                 │  ┌─────┐ │
                                     │                           │  │_rbac│ │
                                     ▼                           │  │_acl │ │
                                 Keycloak                        │  └─────┘ │
                                 (JWKS, OIDC discovery)          └──────────┘

クイックスタート(Docker)

docker run --rm -p 8000:8000 \
  -e OIDC_ISSUER_URL=https://kc.example.com/realms/myrealm \
  -e OIDC_AUDIENCE=mcp-server \
  -e QDRANT_URL=http://qdrant:6333 \
  -e QDRANT_JWT_SECRET=<same secret as Qdrant's api-key> \
  ghcr.io/fidonis/qdrant-mcp-rbac:latest

/mcp はストリーミング可能な HTTP エンドポイント、/health は認証不要です。 すべての変数については、docker/.env.example をご覧ください。

仕組み

  1. MCP クライアントは OIDC アクセストークン(Authorization: Bearer …)を付けてリクエストを送信します。
  2. OIDCAuthMiddleware は OIDC プロバイダーの JWKS に照らしてトークンを検証します (署名、有効期限、オーディエンス、発行者については、トークンの検証をご覧ください)。
  3. JWTBuilder はユーザー用の Qdrant JWT を生成します。
    • ユーザーが 緊急用管理者ロール(RBAC_ADMIN_ROLE)に属する場合、 グローバル管理トークンが直接発行されます。
    • それ以外の場合、AclResolver は ACL コレクション(RBAC_ACL_COLLECTION、 デフォルトは _rbac_acl)から構築された、キャッシュ済みの role -> [grants] マッピングを返します。
  4. Qdrant JWT がリクエストスコープに付加されます。
  5. 各 MCP ツールは、対象コレクションに対するユーザーの実効アクセス権を確認し、 生成された JWT を使ってリクエストを Qdrant に転送します。
トークンの検証

トークンは PyJWT を使って、発行者が公開する鍵 ({OIDC_ISSUER_URL}/.well-known/openid-configuration、続いてその jwks_uri)に照らして検証されます。

  • 署名アルゴリズムは署名鍵(その alg、または指定がない RSA / EC 鍵の場合は RS256 / ES256)から取得し、トークンヘッダーからは取得しません。受け入れられるのは RS256、RS384、RS512、ES256、ES384、ES512 のみです。対称鍵 (HS*)および none トークンは拒否されます。
  • 必須クレーム:exp、aud(OIDC_AUDIENCE を含む必要があります)、iss(ディスカバリードキュメント内の発行者と一致する必要があります)、空でない sub。exp または aud がないトークンは拒否されます。nbf が存在する場合は検証されます。
  • iat は検証されません。そのため、このホストと ID プロバイダー間の時刻のずれによって、発行直後のトークンが拒否されることはありません。
  • 鍵のローテーション:鍵は OIDC_JWKS_CACHE_TTL 秒間キャッシュされます。不明な kid を持つトークンがあると、拒否する前に JWKS がちょうど 1 回再取得されます。
  • ロールは realm_access.roles およびすべての resource_access.<client>.roles から読み取られます。
ACL コレクションのスキーマ

各権限付与は _rbac_acl 内の 1 つのポイントです。ポイント ID は決定的な uuid5(role, collection) なので、同じ権限を再付与しても冪等です。ペイロード:

{ "role": "data-scientist", "collection": "embeddings_v2", "access": "rw" }

access は次のいずれかです。

  • r – 読み取り専用
  • rw – 読み取りと書き込み
  • m – 管理(グローバル。collection は参考情報です。慣例として "*" を使用します)

コレクションは、サーバーが自己発行したサービス用トークンを使って、初回読み取り時に自動作成されます。

ドキュメントレベルのアクセス制御(doc_policy)

コレクションレベルのアクセス制御では、ロールがコレクションを読み取れるかどうかを決定します。 権限付与には、さらに任意の doc_policy を設定して、そのコレクション内でロールが参照できる **個々のドキュメント(ポイント)**を制限できます。サーバーはポリシーを Qdrant のペイロードフィルターに変換し、すべての読み取り処理 (search_collection、 search_collection_by_text、scroll_collection、list_documents)に must 句として追加します (ファセット処理も、ロールが参照できるドキュメントだけを対象にします)。呼び出し元が指定した query_filter の値は保持され、ドキュメントフィルターも併せて追加されるため、両方が適用されます。

doc_policy のない権限付与は従来どおり動作し、コレクション内のすべてのドキュメントを参照できます。

スキーマ
{
  "default": "allow" | "deny",
  "conditions": [
    { "field": "<payload field>", "mode": "allow" | "deny", "values": ["<v>", "…"] }
  ]
}
  • default: "allow" — デフォルトですべてのドキュメントが表示され、条件に一致するドキュメントは deny によって非表示になります。
  • default: "deny" — デフォルトではどのドキュメントも表示されず、条件に一致するドキュメントは allow によって表示されます。
  • values: ["*"] — 「すべてのドキュメント」を意味するワイルドカードです。allow 条件(デフォルトが deny)の場合はフィルターが解除され、コレクション全体が表示されます。deny 条件(デフォルトが allow)の場合は、空の結果セットが返されます。
  • allow 条件がない default: "deny" → 空の結果セットになります。

同じモードの条件が複数ある場合は、和集合として扱われます(いずれかの deny 条件に一致するドキュメントは非表示になり、いずれかの allow 条件に一致するドキュメントは表示されます)。

複数ロールのマージ

ユーザーが同じコレクションに対して複数の許可(異なるロール経由)を持つ場合、サーバーは最も許容的なルールを使ってポリシーをマージします。

  • 一致する許可のいずれかに doc_policy がない場合、そのコレクションに対するユーザーのアクセスは制限されません。
  • 一致する許可のいずれかが default: "allow" の場合、マージ後のポリシーは default: "allow" となり、それらの許可の deny 条件が統合されます(デフォルトが deny の許可は無視されます)。
  • それ以外の場合、すべての許可が default: "deny" となり、allow 条件が統合されます。
推奨ペイロードフィールド:acl_tags

アクセス制御が必要なドキュメント用に、新しい任意フィールド acl_tags: list[str] が予約されています。このフィールドは必須ではありません。acl_tags のないドキュメントも引き続き完全に機能します。

  • デフォルトが allow の許可では、タグのないドキュメントが acl_tags に対する deny 条件に一致することはありません → 常に表示されます。
  • デフォルトが deny の許可では、タグのないドキュメントが acl_tags に対する allow 条件を満たすことはありません → 暗黙的に非表示になります。

ブートストラップスクリプト demo/bootstrap/vectorize.py は、各 Markdown ソース(データディレクトリからの相対 POSIX パス)を、そのファイルから取り込まれるすべてのチャンクに適用するタグのリストに対応付ける、任意のサイドカーファイル demo/data/acl_tags.yml を読み込みます。

例

デフォルトを allow にして、機密ドキュメントを deny する場合:

{
  "role": "finance-analyst",
  "collection": "finance",
  "access": "r",
  "doc_policy": {
    "default": "allow",
    "conditions": [
      { "field": "acl_tags", "mode": "deny", "values": ["confidential", "board-only"] }
    ]
  }
}

デフォルトを deny にして、公開ドキュメントのみを allow する場合:

{
  "role": "guest",
  "collection": "finance",
  "access": "r",
  "doc_policy": {
    "default": "deny",
    "conditions": [
      { "field": "acl_tags", "mode": "allow", "values": ["public"] }
    ]
  }
}

source フィールドでフィルタリングする場合(acl_tags は不要):

{
  "role": "junior-analyst",
  "collection": "finance",
  "access": "r",
  "doc_policy": {
    "default": "deny",
    "conditions": [
      { "field": "source", "mode": "allow", "values": ["annual-report.md", "q4-summary.md"] }
    ]
  }
}

grant_access は同じ形式を受け付けます。

{
  "tool": "grant_access",
  "args": {
    "role": "guest",
    "collection": "finance",
    "access": "r",
    "doc_policy": {
      "default": "deny",
      "conditions": [
        { "field": "acl_tags", "mode": "allow", "values": ["public"] }
      ]
    }
  }
}

構成

リポジトリでは、本番用サーバー(src/)とデモ用素材(demo/)を分けています。src/ と demo/ 内の各プロジェクトは、それぞれ独自の pyproject.toml と .venv を持つ独立した uv プロジェクトです。リポジトリのルートには仮想環境がありません。

src/                       # uv project: the FastMCP server
  pyproject.toml
  uv.lock
  .venv/                   # created by `uv sync` (gitignored)
  .env                     # local config (gitignored)
  .env.example             # template for `.env`
  main.py                  # Entry point (uvicorn)
  config.py                # Settings (pydantic-settings, .env)
  auth/
    models.py              # OIDCClaims, CollectionAccess, AclEntry, QdrantToken
    oidc.py                # JWKS-based OIDC token validator (PyJWT)
    acl.py                 # AclResolver: TTL-cached read of the ACL collection
    jwt_builder.py         # Builds Qdrant JWTs from claims + ACL mapping
  qdrant/
    client.py              # AsyncQdrantClient factory (per-request, JWT-scoped)
    collections.py         # Thin async wrappers around Qdrant collection operations
    meta.py                # Read/write helpers for the _collection_meta system collection
  mcp_app/                 # named `mcp_app` to avoid shadowing the installed `mcp` SDK
    server.py              # FastMCP instance + Starlette app wiring
    tools.py               # MCP tools: data tools + ACL admin tools
    middleware.py          # ASGI auth middleware: OIDC → Qdrant JWT

tests/                     # pytest suite, run from src/ (kept out of the Docker image)
  fakes/oidc.py            # In-process OIDC issuer: RSA key, JWKS, token minting
  test_doc_filter.py
  test_facet.py
  test_jwt_builder.py
  test_oidc_validator.py
  test_scroll.py

demo/                      # everything for the end-to-end demo
  README.md                # Demo quickstart (order of operations)
  bootstrap/               # uv project: vectorize Markdown → Qdrant collections
    pyproject.toml
    uv.lock
    .venv/
    vectorize.py
  client/                  # uv project: OIDC + LLM CLI client
    pyproject.toml
    uv.lock
    .venv/
    client.py
    agent.py
    oidc.py
    config.py
  data/                    # demo seed data (Markdown, collection = file stem up to the first "-")
    finance-2025.md
    finance-2026.md
    finance-aquise.md
    it.md
    sales.md

セットアップ

前提条件
  • Python 3.11 以降
  • uv がインストールされていること
  • 接続可能な OIDC プロバイダー(例:Keycloak)
  • JWT RBAC が有効になっている、接続可能な Qdrant インスタンス
インストール
cd src
uv sync

これにより、すべての依存関係を含む src/.venv が作成されます。リポジトリのルートには独自の .venv はありません。

設定

サンプルの環境変数ファイルをコピーし、値を調整します。

cp src/.env.example src/.env

サーバーは config.py を基準に解決した src/.env を読み込むため、実行時の作業ディレクトリにかかわらず、ファイルは src/ 内に置いてください。

主な変数:

変数用途
OIDC_ISSUER_URLKeycloak のレルム URL。例:https://kc.example.com/realms/myrealm
OIDC_AUDIENCE想定される aud クレーム。例:mcp-server
OIDC_JWKS_CACHE_TTLOIDC ディスカバリードキュメントと JWKS のキャッシュ TTL(デフォルトは 3600 秒)
QDRANT_URLQdrant の HTTP エンドポイント
QDRANT_JWT_SECRET署名シークレット — Qdrant の service.api_key と一致させる必要があります。32 バイト以上を使用してください。短い HS256 キーについては PyJWT が警告します(例:openssl rand -hex 32)
QDRANT_JWT_TTLリクエストごとに生成される Qdrant JWT の有効期間(デフォルトは 3600 秒、最小は 60 秒)
MCP_HOST / MCP_PORT / MCP_PATHリッスンするアドレスとパス(デフォルトは 0.0.0.0:8000/mcp)
LOG_LEVELログレベル(デフォルトは INFO)
EMBEDDING_API_URLOpenAI 互換の埋め込み API のベース URL(デフォルトは http://localhost:11434/v1)
EMBEDDING_API_KEY埋め込みエンドポイント用の任意のベアラートークン
EMBEDDING_META_COLLECTIONコレクションごとの埋め込みメタデータを保存するコレクション(デフォルトは _collection_meta)
RBAC_ADMIN_ROLEグローバルな管理権限を付与する OIDC ロール(デフォルトは qdrant-admin)
RBAC_ACL_COLLECTION権限付与情報を保存する Qdrant コレクション(デフォルトは _rbac_acl)
RBAC_ACL_CACHE_TTLメモリ内 ACL キャッシュの TTL(デフォルトは 60 秒)
RBAC_SERVICE_TOKEN_TTLACL の読み取り用にサーバーが発行するサービストークンの TTL(デフォルトは 300 秒)
実行
cd src
uv run python main.py
Docker で実行

ホスト上ではなくコンテナー内でサーバー自体を実行するには、docker/ 内の Compose ファイルを使用します。

cp docker/.env.example docker/.env   # then edit secrets and OIDC_ISSUER_URL
docker compose -f docker/docker-compose.yml up -d

これにより、docker/Dockerfile からイメージをビルドし、Qdrant とともに mcp-server コンテナーを起動します(:8000 で公開し、/health のヘルスチェックを実施します)。Keycloak は含まれていません。docker/.env の OIDC_ISSUER_URL には外部 OIDC プロバイダーを指定してください。各変数の説明は docker/.env.example に記載されています。

アクセスの初期設定

  1. Keycloak で、1 人のユーザーに qdrant-admin レルムロールを割り当てます。
  2. サーバーを起動します。
  3. そのユーザーとして grant_access ツールを呼び出し、他のロールに権限を付与します。
// MCP tool call
{
  "tool": "grant_access",
  "args": { "role": "data-scientist", "collection": "embeddings_v2", "access": "rw" }
}
  1. data-scientist ロールを持つ他のユーザーは、embeddings_v2 にスコープされた rw JWT を取得できるようになります。

ツール

データツール
ツール必要なアクセス権
list_collections(任意)— 呼び出し元が読み取り可能なコレクションのみを返します
get_collection_info対象コレクションに対する r
search_collection対象コレクションに対する r
search_collection_by_text対象コレクションに対する r
scroll_collection対象コレクションに対する r
list_documents対象コレクションに対する r
upsert_points対象コレクションに対する rw
delete_points対象コレクションに対する rw

search_collection_by_text は自然言語のクエリを受け付け、設定された OpenAI 互換エンドポイントを使って初期設定時に記録されたモデルで埋め込みを生成し、そのベクトルで検索を実行します。

scroll_collection は、クエリを使わずに生のポイント(チャンク)を一覧表示します。返された next_offset カーソルを使ってコレクション内をページングします(最後のページでは null)。実際に保存されているポイントを調べる際に使用してください。

list_documents は、「コレクション X に含まれるドキュメントはどれか/いくつか」という質問に答えます。サーバー側で source ペイロードフィールドを使ってポイントを集計し(Qdrant のファセット機能)、ドキュメントごとのチャンク数とともに、重複のないエントリを 1 つずつ返します。1 つのドキュメントが多数のチャンクにまたがるため、一覧を確認する質問では scroll_collection よりこちらを優先してください。ファセット機能には source のキーワードペイロードインデックスが必要です。初期設定時に作成され、見つからない場合はサーバーも初回使用時に作成するため、手動での作業は不要です。

upsert_points と delete_points はシステムコレクション(_rbac_acl、_collection_meta)に対する操作を拒否します。代わりに管理ツールまたは初期設定を使用してください。

ACL 管理ツール(グローバルな管理権限が必要)
ツール効果
list_acl(role?)すべての許可を返します。必要に応じてロールで絞り込めます
grant_access(role, collection, access)1 件の許可を冪等に追加または更新します
revoke_access(role, collection)許可を削除します
refresh_acl()インメモリキャッシュを強制的に再読み込みします

変更を加えるとローカルキャッシュは直ちに無効化されます。ACL コレクションへの範囲外の編集(Qdrant API を直接使用する場合など)は、最長でも RBAC_ACL_CACHE_TTL 秒後に反映されます。

docker-compose でのローカル開発

ローカルでのサーバー開発用に Qdrant のみを起動するには、docker/docker-compose.yml の qdrant サービスを使用します。 Compose が QDRANT_JWT_SECRET を読み込めるように、src/.env を渡します。

docker compose --env-file src/.env -f docker/docker-compose.yml up -d qdrant

これにより、以下が起動します。

  • JWT RBAC が有効で、QDRANT_JWT_SECRET の署名キーを使用する Qdrant(:6333)

レルム、オーディエンスが mcp-server の機密クライアント、qdrant-admin ロール、およびアクセスを許可する予定のチームごとのロールを作成します。 テストユーザーにロールを割り当てます。

Qdrant JWT のセットアップ

qdrant-mcp-rbac は QDRANT_JWT_SECRET を使って JWT に署名します(HS256)。Qdrant が JWT を受け入れ、API キーと同じシークレットを使用するように設定する必要があります。

# qdrant config.yaml
service:
  api_key: <same value as QDRANT_JWT_SECRET>
  jwt_rbac: true

管理者以外のユーザーに対して生成される JWT の構造は次のとおりです。

{
  "exp": 1735689600,
  "access": [
    { "collection": "col_a", "access": "r" },
    { "collection": "col_b", "access": "rw" }
  ]
}

管理者の場合(または access: "m" の許可の場合)は次のとおりです。

{ "exp": 1735689600, "access": "m" }

MCP クライアントからの呼び出し

OIDC アクセストークンを Authorization ヘッダーに渡します。

TOKEN=$(curl -s -X POST \
  -d "client_id=mcp-cli" -d "username=alice" -d "password=…" \
  -d "grant_type=password" \
  https://kc.example.com/realms/myrealm/protocol/openid-connect/token | jq -r .access_token)

curl -H "Authorization: Bearer $TOKEN" \
     -H "Accept: text/event-stream" \
     http://localhost:8000/mcp

Fidonis について

qdrant-mcp-rbac は Fidonis が開発・保守しています。オープンソース、オープンスタンダードを採用し、ベンダーロックインのない AI インフラストラクチャーを、企業がエンドツーエンドで運用できるよう支援しています。このプロジェクトでは、その全体像の一部として、ACL を設定ファイルに埋め込まずに、ベクトルストア内のデータを「誰が読めるか」を制御します。

同様のセルフホスト可能なスタックを構築していて、情報交換をご希望の場合は、fidonis.de にお越しください。

ライセンス

qdrant-mcp-rbac は MIT ライセンスのもとで公開されています — Copyright (c) 2026 Fidonis GmbH (in Gründung) and contributors.

  • 商標に関する通知(「Fidonis」とプロジェクト名 qdrant-mcp-rbac を対象)については、TRADEMARK.md をご覧ください。
  • このプロジェクトに含まれるサードパーティ製 Python 依存関係のライセンスについては、THIRD_PARTY_LICENSES.md をご覧ください。
  • Inbound = Outbound(MIT) ルールと、事前承認なしにコントリビューションへ追加できないライセンスカテゴリの一覧については、CONTRIBUTING.md をご覧ください。

「Qdrant」は Qdrant Solutions GmbH の登録商標です。このプロジェクトでの名称の使用は記述的なものであり、このサーバーが基盤としている上流コンポーネントを示すもので、推奨や支持を意味するものではありません。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。