keycloak-mcp
Provides tools for inspecting and modifying Keycloak realm, client, and protocol-mapper configuration across multiple Keycloak hosts, including listing clients, reading client config, managing protocol mappers, and handling client secrets.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@keycloak-mcp list realms on staging host"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
keycloak-mcp
An MCP (Model Context Protocol) server, stdio transport, that lets an AI assistant inspect and — behind explicit guards — modify Keycloak realm, client, and protocol-mapper configuration across multiple Keycloak hosts from a single server process.
Built on the official
@keycloak/keycloak-admin-client
and the @modelcontextprotocol/sdk.
Design derived from the MIT-licensed
Octodet keycloak-mcp — see NOTICE.
Install
git clone https://github.com/Faust-Systems/keycloak-mcp.git
cd keycloak-mcp
npm install
npm run build # tsc → dist/Then create a config file (see Configuration) and register the server with your MCP client (see Registering with Claude).
Related MCP server: k8s-mcp-server
Hosts
Every tool takes a host argument: a string key naming an entry in the
config file's hosts map (or discovered from the KC_<HOST>_* env
fallback — see below). Host keys are entirely arbitrary and user-defined
— there is no fixed list of hosts baked into this server. Point it at
whatever Keycloak instances you like, under whatever names make sense to you
(prod-eu, staging, customer-a, ...).
Each host entry carries its own explicit production flag:
"prod-eu": { "url": "...", "adminUser": "", "adminPassword": "", "production": true }production: truemarks the host as production: writes against it are refused unlessallowProdWriteis alsotruein the config.production: falsemarks it non-production: writes need only the per-callwrite=true.
Fail-closed rule: if a host's production flag is absent, null,
or any non-boolean value, the host is treated as production. Only a
literal boolean false disarms the production write guard. This tool
rotates live client secrets, so a typo or an omission in config must never
silently disable the safety gate — when in doubt, it defaults to the safer
(more restrictive) behaviour.
The server authenticates per host with a password grant against the
admin-cli client on the master realm, and caches the admin client
per host (re-authenticating when the token expires). The target realm is a
per-call argument on every tool.
Safety model
Read-only by default. Mutating tools (
ensure_hardcoded_claim_mapper,delete_protocol_mapper) take awriteboolean that defaults tofalse. Withoutwrite=truethey return a dry-run plan and call no mutating API.Production gate, fail-closed. Even with
write=true, a write against a production host is refused unlessallowProdWriteistruein the config file (or, when using the env fallback,KC_ALLOW_PROD_WRITE=true). A host is production whenever itsproductionflag istrue, absent, or any non-boolean value — only an explicitproduction: falseopts a host out of the gate. See Hosts.No secrets, ever. Admin passwords and tokens are never logged or returned; client secrets and registration access tokens are redacted from
get_clientoutput.Audit trail. Every successful write emits a structured JSON line to stderr: timestamp, host, realm, clientId, action, mapper name.
Idempotent verbs.
ensure_hardcoded_claim_mapperreconciles toward a desired state (already-present / update-with-diff / create) instead of blindly creating; genuine ambiguity (e.g. two mappers already emitting the claim) is reported as a conflict and never auto-resolved.
Client secrets — the file-sink model
dump_client_secret and regenerate_client_secret handle real client secret
values. To keep those values out of the AI model's context entirely, the
server never returns or logs the value:
The secret value is written directly to a local file by the server process (
outPath, mode0600, exact bytes, no trailing newline).The tool returns only metadata —
{ host, realm, clientId, outPath, byteLength }(plusrotated: truefor a regeneration). The value is never in the return object, any log line, the audit line, or any error message.Keycloak admin-API failures are reduced to an HTTP status plus a generic message, so no response body can leak.
The server warns (does not fail) if
outPath's directory is group/world-writable, since a secret file there could be exposed.dump_client_secretis a read (no Keycloak mutation) so it is not write-gated — but it still writes a local file.regenerate_client_secretis a mutation:write=false(default) is a dry run, and rotating a production host requiresallowProdWrite(see the fail-closed rule under Hosts).
Configuration
All configuration — host URLs, admin credentials, and the production-write gate — comes from a single JSON config file. Nothing is hardcoded.
File location & precedence
The config path is resolved in this order:
The environment variable
KEYCLOAK_MCP_CONFIG, if set (explicit override).Otherwise the default
~/.config/keycloak-mcp/config.json.
The file takes precedence. If no file is found at the resolved path, the server falls back to the legacy per-host environment variables (below) so nothing breaks — but when the file is present it is used exclusively and the env vars are ignored.
File shape
See config.example.json. Copy it to ~/.config/keycloak-mcp/config.json
and fill in your own host keys and credentials:
{
"hosts": {
"prod-eu": { "url": "https://keycloak.example.com", "adminUser": "", "adminPassword": "", "production": true },
"staging": { "url": "https://kc-staging.example.com", "adminUser": "", "adminPassword": "", "production": false }
},
"allowProdWrite": false
}Host keys (
"prod-eu","staging"above) are entirely arbitrary — name your hosts however makes sense to you. There is no fixed set of hosts; add or remove entries freely.production(per host) gates writes behindallowProdWrite. Fail-closed rule: ifproductionis absent,null, or any non-boolean value, the host is treated as production. Only a literalproduction: falseopts a host out. See Hosts.allowProdWritemust betrueto permit writes to any host whoseproductionflag resolves to production (per the rule above); a host explicitly markedproduction: falseonly needs the per-callwrite=true.A host with a missing
url,adminUser, oradminPasswordfails only when addressed, with an error naming the missing field names (never values). The other hosts keep working.Calling a tool with a
hostkey that isn't in the config fails with an error naming the requested host and listing the configured host keys (never values).
Protect the file: it holds admin credentials in the clear. Keep it at
chmod 600 — the server prints a one-line warning to stderr (it does not
refuse) if the file is group- or world-readable.
Environment-variable fallback
Used only when no config file exists at the resolved path. See .env.example.
Host keys are discovered by scanning for a KC_<HOST>_URL variable —
there is no fixed list. The host key is the captured part of the variable
name, lowercased, with underscores left as-is: KC_PROD_EU_URL yields the
host key prod_eu. Hyphens in a host key are not expressible via env
vars — use the config file if you need one.
variable | purpose |
| override the config file path (else |
| the host's base URL — presence of this variable is what discovers the host |
| admin credentials for that host |
|
|
|
|
Build
npm install
npm run build # tsc → dist/
npm test # vitest unit testsRegistering with Claude (MCP config)
Because all credentials live in the config file, the MCP registration needs
only command + args — no env block:
{
"mcpServers": {
"keycloak": {
"command": "node",
"args": ["/absolute/path/to/keycloak-mcp/dist/index.js"]
}
}
}The server reads ~/.config/keycloak-mcp/config.json by default. To point it
at a different file, add a single override:
"env": { "KEYCLOAK_MCP_CONFIG": "/absolute/path/to/config.json" }Keep allowProdWrite at false in the file to hold production read-only;
set it to true only when a session must change production.
Tools
tool | arguments | what it does |
| host, realm | clients of a realm: |
| host, realm, clientId | full client representation (secrets redacted) |
| host, realm, clientId | the client's dedicated-scope mappers: id, name, type, config |
| host, realm, clientId, claimName, claimValue, addToAccessToken=true, addToIdToken=false, claimJsonType="String", write=false | idempotently ensure an |
| host, realm, clientId, mapperId, write=false | delete one mapper by UUID |
| host, realm, clientId, outPath | write the client's current secret to a local 0600 file; returns metadata only |
| host, realm, clientId, outPath, write=false | rotate the client secret and write the new value to a local 0600 file; returns metadata only |
Usage example — hardcoded realm claim
Goal: the my-app client in realm acme on the staging host (configured
with "production": false, see Hosts) must emit a hardcoded
realm claim with value acme in access tokens.
Dry run (default — nothing changes):
ensure_hardcoded_claim_mapperwith{ "host": "staging", "realm": "acme", "clientId": "my-app", "claimName": "realm", "claimValue": "acme" }→ returns
status: "dry-run", wouldDo: "create"with the exact mapper it would create — orwouldDo: "update"with a per-key diff if a mapper already exists with different config, orstatus: "already-present"if everything already matches.Apply: same call plus
"write": true.→ creates/updates the mapper and emits an audit line to stderr.
Repeat against a production host (e.g.
prod-eu) once verified — those calls additionally require"allowProdWrite": truein the config file.
Development
src/index.ts— server bootstrap + tool registration (stdio).src/config.ts— config file loader (file → env fallback), perms warning.src/hosts.ts— host registry, config validation, production write gate.src/kc.ts— cached, re-authenticating admin client per host.src/mappers.ts— pure plan/diff logic for the ensure tool (unit-tested).src/secrets.ts— client-secret file-sink tools (value never returned/logged).src/redact.ts— secret redaction.src/audit.ts— stderr audit lines.test/— vitest unit tests for all pure logic.
License
MIT — see LICENSE. Derived from the design of Octodet's keycloak-mcp; see
NOTICE for attribution.
Available Tools
7 toolsdelete_protocol_mapperDelete protocol mapperA
Delete one of a client's protocol mappers by mapper UUID. With write=false (default) it reports which mapper would be deleted; write=true performs the deletion.
Inputs: host (required), realm (required), clientId (required), mapperId (required), +1 more.
dump_client_secretDump client secret to a fileA
Fetch a confidential client's current secret and write ONLY the value to a local file (mode 0600, no trailing newline). The secret value is never returned to the caller or logged — the tool returns only metadata (path, byte length). This is a read against Keycloak (no mutation), so it is not write-gated.
Inputs: host (required), realm (required), outPath (required), clientId (required).
ensure_hardcoded_claim_mapperEnsure hardcoded claim mapperA
Idempotently ensure a client has an oidc-hardcoded-claim-mapper emitting the given claim. Matches existing mappers by claim name: reports 'already-present' when the config matches, a diff + update when it differs, and a create when absent. With write=false (default) it only returns the plan; write=true applies it.
Inputs: host (required), realm (required), clientId (required), claimName (required), +5 more.
get_clientGet clientA
Fetch the full representation of one client by clientId. Secret-bearing fields (client secret, registration access token) are always redacted.
Inputs: host (required), realm (required), clientId (required).
list_clientsList clientsA
List the clients of a realm on a Keycloak host. Returns clientId, internal UUID (id), and name for each client.
Inputs: host (required), realm (required).
list_protocol_mappersList protocol mappersB
List a client's dedicated-scope protocol mappers: id, name, mapper type (protocolMapper), and config.
Inputs: host (required), realm (required), clientId (required).
regenerate_client_secretRegenerate client secret to a fileA
Rotate a confidential client's secret and write ONLY the NEW value to a local file (mode 0600, no trailing newline). The secret value is never returned to the caller or logged — the tool returns only metadata. This mutates Keycloak: with write=false (default) it returns a dry-run plan and rotates nothing; with write=true it rotates. Production hosts (us/za) additionally require allowProdWrite in the config.
Inputs: host (required), realm (required), outPath (required), clientId (required), +1 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 7 tools
Each tool has a clearly distinct purpose: listing clients, getting one client, dumping/regenerating secrets, and managing protocol mappers (list, delete, ensure a specific type). No overlap or ambiguity.
All tools follow a consistent verb_noun pattern in snake_case (e.g., list_clients, get_client, dump_client_secret). No mixing of conventions or unclear naming.
7 tools is well-scoped for the focused domain of Keycloak client secrets and protocol mapper management. Not excessive, and each tool serves a clear purpose.
The tool set covers core operations for client secrets and protocol mappers, including reading, idempotent ensures, and deletions. Minor gaps exist (e.g., no generic protocol mapper creation or client CRUD), but the surface is coherent for its intended scope.
Maintenance
Related MCP Connectors
An MCP server that provides an API to LLMs to manage their JumpCloud resources.
MCP server that lets your AI assistant build and deploy apps, hosting each one at a live URL.
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
MCP server for building and testing AI agents with multi-model experimentation and insights.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceAn MCP server that enables AI assistants to navigate, search, and analyze local Keycloak source code to support developer customizations like SPIs and authenticators. It provides tools for searching classes, generating boilerplate code, detecting breaking changes between versions, and tracing dependencies.8MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that lets AI assistants safely inspect and operate on Kubernetes clusters through natural conversation.MIT
- AlicenseAqualityBmaintenanceAn MCP server for Keycloak Admin REST API, enabling user, group, event, and security management through service account authentication.33152 PyPIMIT
- AlicenseNot gradedqualityDmaintenanceA Model Context Protocol (MCP) server that provides a natural language interface for managing Keycloak identity and access management through its REST API.MIT