Qdrant RBAC
概要
作者による説明(英語の原文)
Role-based access to your Qdrant vector store, via MCP. OIDC in, scoped JWTs out.
PopNx MCPの3つの柱
この3つを1つのスコアにまとめることはしません。意見、測定、人気はそれぞれ別のものだからです。
- 利用者の声iレビューはまだありませんレビューは今後のステップで、アカウント機能と一緒に始まります
- 私たちの基本チェックi1項目中1項目に合格公開情報からチェック。コードはまだスキャンしていません
- 利用状況iとても新しい★ –
できること
このサーバーのやさしい解説はまだ書いていません。以下はレジストリから読み取った事実です。
- 接続方法: パソコンで動く
- トランスポート: Streamable HTTP
- カテゴリ: 検索・AIの記憶
- 入力が必要なもの:OIDC_ISSUER_URL, OIDC_AUDIENCE, QDRANT_URL, QDRANT_JWT_SECRET
インストール
使っているAIアプリを選んで、設定をコピーしてください。
インストールの前に
- 基本チェック:1項目中1項目に合格
- あなたのパソコンで、あなたのユーザーと同じ権限(ファイル、ネットワーク、アプリ)で動きます。
- 自分で入力するもの:
OIDC_ISSUER_URL,OIDC_AUDIENCE,QDRANT_URL,QDRANT_JWT_SECRET
「秘密」と表示された値は、あなたのアカウントの鍵です。絶対に人に教えたり、チャットに貼り付けたりしないでください。
必要なもの
- DockerDockerのインストール
どのアプリを使っていますか?
上でアプリを選んでください。選んだアプリを覚えておくので、次からはボタンに「…にインストール」と表示されます。
Claude Desktop → Settings → Developer → Edit Config を開き、claude_desktop_config.json にこれを貼り付けます
{
"mcpServers": {
"qdrant-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.1"
],
"env": {
"OIDC_ISSUER_URL": "your-value",
"OIDC_AUDIENCE": "your-value",
"QDRANT_URL": "your-value",
"QDRANT_JWT_SECRET": "your-value"
}
}
}
}ターミナルでこれを実行します
claude mcp add qdrant-rbac --env OIDC_ISSUER_URL=your-value --env OIDC_AUDIENCE=your-value --env QDRANT_URL=your-value --env QDRANT_JWT_SECRET=your-value -- 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.1動かす前に、空欄の値を入力してください。
または、設定を自分でコピーする
プロジェクトの .cursor/mcp.json、または ~/.cursor/mcp.json に貼り付けます
{
"mcpServers": {
"qdrant-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.1"
],
"env": {
"OIDC_ISSUER_URL": "your-value",
"OIDC_AUDIENCE": "your-value",
"QDRANT_URL": "your-value",
"QDRANT_JWT_SECRET": "your-value"
}
}
}
}ブラウザがアプリを開いてよいか確認し、そのあとアプリが設定を表示して確認を求めます。キーの値は空欄のままなので、自分で入力してください。
または、設定を自分でコピーする
プロジェクトの .vscode/mcp.json に貼り付けます
{
"servers": {
"qdrant-rbac": {
"type": "stdio",
"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.1"
],
"env": {
"OIDC_ISSUER_URL": "your-value",
"OIDC_AUDIENCE": "your-value",
"QDRANT_URL": "your-value",
"QDRANT_JWT_SECRET": "your-value"
}
}
}
}ブラウザがアプリを開いてよいか確認し、そのあとアプリが設定を表示して確認を求めます。キーの値は空欄のままなので、自分で入力してください。
これはパソコンで動くサーバーですが、ChatGPTがつなげるのはインターネット上のサーバーだけです。ほかのアプリを選んでください。
選んだアプリは、この端末のCookieに保存されます。アカウントは不要です。
自分で入力する値
- OIDC issuer / realm URL, e.g. https://kc.example.com/realms/myrealm
- Expected aud claim of incoming access tokens, e.g. mcp-server
- Qdrant HTTP endpoint, e.g. http://qdrant:6333
- HS256 signing secret, at least 32 bytes; must equal Qdrant's service.api_key
この設定は、作者のレジストリ登録情報から作成しています。READMEと違う場合は、READMEに従ってください。
できること
パソコンで動くサーバーです。インストールすると、ツール一覧がAIアプリに表示されます。
基本チェックi
誰でも見られる情報をチェックしており、コードは読んでいません。当てはまらない項目は数に入れていません。 · 2026年11月8日にチェック
- ✓ 合格
作者とリポジトリが一致
レジストリ名はドメイン fidonis.de で確認済みです(レジストリがドメインの所有を確認しています)
- … 未チェック
今もメンテナンスされている
このリポジトリはまだGitHubから読み取っていません
- … 未チェック
ライセンスがある
このリポジトリはまだGitHubから読み取っていません
- – 対象外
エンドポイントが応答する
これはパソコンで動くため、インターネット上のエンドポイントはありません
- – 対象外
OAuthでサインイン
パソコンで動き、代わりにローカルの設定を使います
- … 未チェック
ツールの説明に隠れた指示がない
パソコンで動くサーバーです。ツール一覧を読み取れるのは、インターネット上のエンドポイントがある場合だけです
検索・AIの記憶のほかのサーバーとの比較i
- このカテゴリのほかの5716件のうち0%よりスターが多い
- このカテゴリのほかの5716件のうち97%より最近レジストリに公開
- 基本チェックの結果が、このカテゴリのほかの5716件のうち100%と同じかそれ以上
レジストリでこのカテゴリにある有効なすべてのサーバーと比較しています。スターは、公開者がリポジトリの所有者である場合だけ数えます。
よくある質問
Qdrant RBACは安全ですか?
当てはまる基本チェック1項目のうち1項目に合格しました。コードは読んでいません。キーやトークンを追加する前に、サーバーがどんなアクセスを求めているかを確認し、必要な権限だけを持つキーを使ってください。
どんなキーやコードが必要ですか?
入力が必要なもの:OIDC_ISSUER_URL, OIDC_AUDIENCE, QDRANT_URL, QDRANT_JWT_SECRET
パソコンで動きますか、それともクラウドですか?
あなたのパソコンで動きます。必要なときにAIアプリが起動し、データは作者のサーバーを通りません(サーバー自体がオンラインサービスを呼び出す場合を除きます)。
今もメンテナンスされていますか?
GitHubリポジトリの最終更新は–、最新バージョン(0.4.1)がレジストリに届いたのは昨日です。
どのアプリで使えますか?
Claude Desktop、Claude Code、Cursor、VS CodeなどのMCP対応アプリで使えます。パソコンにDockerも必要です。
代わりに使えるものは?
同じカテゴリには:Context7, Codebase Memory, Exa
代わりの候補
同じカテゴリで、ほかの作者が作ったサーバー。スターの多い順。
カードの見方:↓ 週あたりのダウンロードi★ GitHubスターi3つの柱:レビュー · チェック · 利用状況i更新=最新バージョンをレジストリに公開した日i
Codebase Memory
Codebase knowledge graph for AI agents — 162 languages, sub-ms queries, 99% fewer tokens.
Exa
Connect AI agents to Exa for web search, content fetching, and multi-step research.
作者のREADME
READMEを開く
作者のリポジトリから書かれたとおりにコピーしたものです。PopNx MCPは内容を確認・推奨していません。HTML、画像、スクリプトは取り除いています。リンクはこのサイトの外へ移動します。
qdrant-mcp-rbac
Maintained by Fidonis · See TRADEMARK.md for the trademark notice.
A FastMCP server that exposes a Qdrant vector database over streamable HTTP with OIDC-based authentication (Keycloak-compatible) and role-based access control mapped onto Qdrant's native JWT access rules.
Role grants are stored as data inside a dedicated Qdrant collection, not in configuration files — admins manage them at runtime via MCP tools.
┌──────────┐ OIDC Bearer ┌─────────────────┐ Qdrant JWT ┌──────────┐
│ MCP host │ ──────────────▶ │ qdrant-mcp-rbac │ ──────────────▶ │ Qdrant │ │ (client) │ │ (FastMCP) │ │ │ └──────────┘ └─────────────────┘ │ ┌─────┐ │ │ │ │_rbac│ │ ▼ │ │_acl │ │ Keycloak │ └─────┘ │ (JWKS, OIDC discovery) └──────────┘
Quick start (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= \ ghcr.io/fidonis/qdrant-mcp-rbac:latest
/mcp is the streamable-HTTP endpoint, /health is unauthenticated. See the full docker/.env.example for every variable.
How it works
- The MCP client sends a request with an OIDC access token (
Authorization: Bearer …). - The
OIDCAuthMiddlewarevalidates the token against the OIDC provider's JWKS (signature, expiry, audience, issuer; see Token validation). - The
JWTBuilderderives a Qdrant JWT for the user:
- If the user is in the break-glass admin role (
RBAC_ADMIN_ROLE), a global-manage token is minted directly. - Otherwise, the
AclResolverreturns the cachedrole -> [grants]mapping built from the ACL collection (RBAC_ACL_COLLECTION, default_rbac_acl).
- The Qdrant JWT is attached to the request scope.
- Each MCP tool checks the user's effective access for the targeted collection and forwards the request to Qdrant using the derived JWT.
Token validation
Tokens are validated with PyJWT against the keys published by the issuer ({OIDC_ISSUER_URL}/.well-known/openid-configuration, then its jwks_uri):
- Signature algorithm comes from the signing key (its
alg, orRS256/ES256for an RSA / EC key without one), never from the token header. OnlyRS256,RS384,RS512,ES256,ES384andES512are accepted; symmetric (HS*) andnonetokens are rejected. - Required claims:
exp,aud(must containOIDC_AUDIENCE),iss(must equal the issuer in the discovery document) and a non-emptysub. A token withoutexporaudis rejected.nbfis enforced when present. - `iat` is not checked, so clock skew between this host and the identity provider does not reject freshly issued tokens.
- Key rotation: keys are cached for
OIDC_JWKS_CACHE_TTLseconds. A token with an unknownkidtriggers exactly one JWKS refresh before it is rejected. - Roles are read from
realm_access.rolesand from everyresource_access. .roles.
ACL collection schema
Each grant is one point in _rbac_acl. The point id is a deterministic uuid5(role, collection), so re-granting is idempotent. Payload:
{ "role": "data-scientist", "collection": "embeddings_v2", "access": "rw" }
access is one of:
r– read-onlyrw– read & writem– manage (global;collectionis informational, convention:"*")
The collection is auto-created on first read by the server using a self-minted service token.
Document-level access control (doc_policy)
Collection-level access decides whether a role can read a collection at all. A grant may additionally carry an optional doc_policy that restricts which individual documents (points) inside that collection the role can see. The server translates the policy into a Qdrant payload filter and injects it as a must clause on every read — search_collection, search_collection_by_text, scroll_collection, and list_documents (faceting only over documents the role may see). Caller-supplied query_filter values are preserved; the doc filter is added alongside, so both apply together.
Grants without doc_policy behave exactly as before — every document in the collection is visible.
Schema
{
"default": "allow" | "deny", "conditions": [ { "field": " ", "mode": "allow" | "deny", "values": [" ", "…"] } ] }
default: "allow"— every document is visible by default;denyconditions hide matching ones.default: "deny"— no documents are visible by default;allowconditions expose matching ones.values: ["*"]— wildcard meaning "all documents". On anallowcondition (default-deny) it cancels the filter, exposing the whole collection; on adenycondition (default-allow) it returns an empty result set.default: "deny"with noallowconditions → empty result set.
Multiple conditions of the same mode are unioned (a document is hidden by any deny condition; a document is exposed by any allow condition).
Multi-role merge
When a user holds several grants on the same collection (via different roles), the server merges their policies using the most-permissive rule:
- If any matching grant has no
doc_policy, the user is unrestricted on that collection. - If any matching grant has
default: "allow", the merged policy isdefault: "allow"with the union of those grants' deny conditions (default-deny grants are ignored). - Otherwise all grants are
default: "deny"and their allow conditions are unioned.
Recommended payload field: acl_tags
A new optional acl_tags: list[str] field is reserved for documents that need access control. It is never required — documents without acl_tags remain fully functional:
- In default-allow grants, an untagged document is never matched by a
denycondition onacl_tags→ always visible. - In default-deny grants, an untagged document never satisfies an
allowcondition onacl_tags→ implicitly hidden.
The bootstrap script demo/bootstrap/vectorize.py reads an optional demo/data/acl_tags.yml sidecar mapping each Markdown source (POSIX path relative to the data directory) to a list of tags applied to every chunk ingested from that file.
Examples
Default-allow, deny confidential documents:
{
"role": "finance-analyst", "collection": "finance", "access": "r", "doc_policy": { "default": "allow", "conditions": [ { "field": "acl_tags", "mode": "deny", "values": ["confidential", "board-only"] } ] } }
Default-deny, allow only public documents:
{
"role": "guest", "collection": "finance", "access": "r", "doc_policy": { "default": "deny", "conditions": [ { "field": "acl_tags", "mode": "allow", "values": ["public"] } ] } }
Filtering on the source field (no acl_tags required):
{
"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 accepts the same shape:
{
"tool": "grant_access", "args": { "role": "guest", "collection": "finance", "access": "r", "doc_policy": { "default": "deny", "conditions": [ { "field": "acl_tags", "mode": "allow", "values": ["public"] } ] } } }
Layout
The repo separates the production server (src/) from demo material (demo/). src/ and each project under demo/ is its own uv project with its own pyproject.toml and .venv — there is no virtual environment in the repo root.
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
Setup
Prerequisites
- Python 3.11+
- uv installed
- A reachable OIDC provider (e.g. Keycloak)
- A reachable Qdrant instance with JWT RBAC enabled
Install
cd src
uv sync
This creates src/.venv with all dependencies. The repo root has no .venv of its own.
Configure
Copy the example env file and adjust values:
cp src/.env.example src/.env
The server reads src/.env (resolved relative to config.py), so keep it inside src/ regardless of the working directory you run from.
Important variables:
| Variable | Purpose |
|---|---|
OIDC_ISSUER_URL | Keycloak realm URL, e.g. https://kc.example.com/realms/myrealm |
OIDC_AUDIENCE | Expected aud claim, e.g. mcp-server |
OIDC_JWKS_CACHE_TTL | Cache TTL of the OIDC discovery document and JWKS (default 3600 s) |
QDRANT_URL | Qdrant HTTP endpoint |
QDRANT_JWT_SECRET | Signing secret — must equal Qdrant's `service.api_key`; use at least 32 bytes, PyJWT warns about shorter HS256 keys (e.g. openssl rand -hex 32) |
QDRANT_JWT_TTL | Lifetime of the Qdrant JWTs derived per request (default 3600 s, minimum 60) |
MCP_HOST / MCP_PORT / MCP_PATH | Listen address and path (default 0.0.0.0:8000/mcp) |
LOG_LEVEL | Log level (default INFO) |
EMBEDDING_API_URL | OpenAI-compatible embeddings base URL (default http://localhost:11434/v1) |
| EMBEDDING_API_KEY | Optional bearer token for
冒頭だけを表示しています。続きはリポジトリで読めます