mcp-keycloak
A Model Context Protocol server that lets
AI agents administer a Keycloak identity server:
realms, clients, users, groups and realm roles.
Built with the official Go MCP SDK
over gocloak and the Keycloak Admin REST
API. Speaks MCP over stdio. MIT licensed.
Before connecting an account, review Security for credential,
HTTPS, and transcript handling requirements.
Benefits
- An AI agent can create realms, users, clients, and roles on request.
- You do not need the Keycloak admin console or the CLI for routine tasks.
- Keycloak API failures return as tool errors, so the agent can see and
correct them.
Contents
Quickstart
- Install the binary. See Installation.
- Create a dedicated Keycloak administrator account. See
Getting started.
- Connect your MCP client. See Client setup.
- Ask the client to list the Keycloak realms. The first read-only call must
be
realm_list.
- If the call fails, follow the
troubleshooting steps.
| Group |
Tools |
| Realms |
realm_list, realm_get, realm_create, realm_update, realm_delete |
| Clients |
client_list, client_get, client_create, client_update, client_secret_get, client_delete |
| Client scopes |
client_scope_list, client_scope_get, client_scope_create, client_scope_delete, client_scope_assign, client_scope_unassign |
| Audit events |
event_admin_list, event_login_list |
| Identity providers |
identity_provider_list, identity_provider_get, identity_provider_create, identity_provider_update, identity_provider_delete |
| Users |
user_list, user_get, user_sessions_list, user_groups_list, user_roles_list, user_create, user_update, user_set_password, user_delete, user_add_realm_role, user_remove_realm_role, user_add_to_group, user_remove_from_group, user_logout_all, user_session_logout |
| Groups |
group_list, group_members_list, group_roles_list, group_get, group_children_list, group_create, group_child_create, group_update, group_delete |
| Realm roles |
realm_role_list, realm_role_create, realm_role_delete |
Notes for agents calling the tools:
- Realms are addressed by name. Clients are addressed by their
clientId,
which the tools resolve internally. Users and groups are addressed by their
internal UUID. Every create and list tool returns this UUID. Role
assignment matches realm roles by name. group_get also accepts a group
path such as parent/child.
user_create accepts an optional initial password. The password is
temporary by default, so the user must change it at first login.
- Created clients are confidential unless you pass
public: true. A
confidential client gets an auto-generated secret. Fetch it with
client_secret_get.
client_secret_get omits the secret by default. Set includeSecret: true
only when you need the value. The tool then returns the value in structured
output. The MCP client's transcript or model context may retain it.
- List tools return at most 100 results by default. Use a smaller
max to
limit disclosure.
user_roles_list and group_roles_list return two lists: direct
assignments and effective roles after composite expansion.
user_remove_realm_role removes only direct assignments.
- For
event_admin_list, enable Admin Events in the realm. For
event_login_list, enable user events. The tools support filters for event
type, admin operation, and resource.
- See event filters, date formats, and troubleshooting for
audit queries.
- Identity-provider tools configure realm login brokering, not MCP
authentication. OIDC provider client secrets are redacted from every tool
response. Provider changes can affect realm-wide login.
- Failures surface as MCP tool errors with the Keycloak API status and
message, so the model can see and correct them.
Security
Use HTTPS for remote Keycloak connections. HTTP is accepted only for
localhost (case-insensitive) or literal loopback IPs, such as
http://127.0.0.1:8080 and http://[::1]:8080. Private LAN addresses,
container hostnames, and DNS aliases that resolve to loopback do not qualify.
URLs must not contain embedded credentials, query strings, or fragments.
For a private CA, set KEYCLOAK_CA_CERT_FILE to a PEM bundle. TLS
certificate verification remains enabled.
- Administrator credentials: use a dedicated, least-privileged account or
service account. Configure exactly one authentication mode. Keep passwords
and
KEYCLOAK_ADMIN_CLIENT_SECRET in the process environment or in a
protected, gitignored .env. Never put them in prompts, commits, or shared
client configuration. The server acts with the configured account's
Keycloak permissions.
- Client secrets:
client_secret_get omits the value unless
includeSecret: true. If you opt in, the secret enters structured tool
output. The MCP client and model may retain it. Do not request the value
for routine inspection. Do not copy it into tickets or chat.
- OIDC provider secrets: provider tools redact sensitive configuration
keys in responses, including
clientSecret. Secrets supplied to
create/update tools still enter tool arguments. Transcripts may retain
them.
- Event data: audit representations and login details can contain user
identifiers, IP addresses, email addresses, resource paths, and
configuration data. Sensitive keys containing
secret, password,
token, or credential are redacted case-insensitively. Admin JSON
representations are sanitized recursively. Invalid JSON is replaced with
[REDACTED]. This is key-based redaction, not comprehensive anonymization.
Personal data, free text, URLs, and values under other keys may remain
sensitive.
- Client/model transcripts: tool inputs and outputs may be logged,
shared, or retained by the client or model provider. Check those retention
settings. Restrict access to transcripts. Review and redact diagnostics
before you share them. Rotate any credential that was exposed by accident.
Set KEYCLOAK_READ_ONLY=true to omit mutating tools at startup. This does
not reduce the Keycloak account's permissions or prevent data disclosure:
client_secret_get remains available, including its explicit secret opt-in.
Combine read-only mode with scoped Keycloak permissions and narrow queries.
See event filters and safe read-only examples.
Configuration
| Variable |
Required |
Description |
KEYCLOAK_URL |
yes |
Base URL of the Keycloak server |
KEYCLOAK_ADMIN_USERNAME |
conditional |
Administrator account username |
KEYCLOAK_ADMIN_PASSWORD |
conditional |
Administrator account password |
KEYCLOAK_ADMIN_CLIENT_ID |
conditional |
Confidential service-account client ID |
KEYCLOAK_ADMIN_CLIENT_SECRET |
conditional |
Confidential service-account client secret |
KEYCLOAK_ADMIN_REALM |
no |
Realm holding the admin account (default master) |
KEYCLOAK_TIMEOUT |
no |
Per-request HTTP timeout (default 30s) |
KEYCLOAK_CA_CERT_FILE |
no |
PEM CA bundle for private Keycloak TLS certificates |
KEYCLOAK_READ_ONLY |
no |
Advertise only non-mutating tools (default false) |
KEYCLOAK_URL must use HTTPS for remote Keycloak servers. HTTP is accepted
only for localhost or loopback development environments.
Configure exactly one authentication mode: administrator username/password or
a confidential client ID/secret with a service account. Service accounts are
the better choice for automation because their realm-management roles can be
scoped explicitly. Never grant more roles than the tools require.
KEYCLOAK_TIMEOUT uses Go duration syntax such as 30s or 2m. The
optional CA bundle extends the system trust store. Certificate verification
is never disabled. Set KEYCLOAK_READ_ONLY=true to omit all mutating tools
from MCP discovery. Read-only mode is enforced before tools are advertised.
Variables can live in the process environment. When the server starts from a
working directory that contains .env, it loads that file as a local
development convenience. See .env.example. Existing environment variables
always win. MCP clients must pass the variables explicitly in their server
configuration.
The server uses the permissions granted to its configured account. Start
with a dedicated account and, where possible, a non-production realm.
Install
Install the binary from a release archive, with Go, or from source. See
Installation for the platform matrix, checksum
verification, and the build steps.
Development
Install the same pinned vulnerability scanner used by CI, and ensure
$(go env GOPATH)/bin (or your custom GOBIN) is on PATH:
go install golang.org/x/vuln/cmd/govulncheck@v1.7.0
gofmt -l . # format check
golangci-lint run # lint (config: .golangci.yml)
go vet ./...
go test ./... # unit tests (no Docker needed)
go test -tags integration ./... # integration tests (needs Docker)
govulncheck ./... # known vulnerabilities (needs network)
go test ./internal/mcpserver/ -run TestRealmCreate # single test
CI runs the vulnerability scan in the existing test job on pull requests
and pushes to main. Findings and scanner errors fail the check. The scan
is not advisory. Require the test check in branch protection to block
merging failing pull requests.
Integration tests start a disposable Keycloak 26.7 container through
testcontainers. The image is pinned in internal/mcpserver/integration_test.go.
The tests drive the full tool surface over an in-memory MCP transport.
golangci-lint must be built with a Go toolchain at least as new as the one
building the project. Release binaries can lag. If golangci-lint run fails
with a Go-version complaint, install from source:
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.8.0
GitHub Actions are pinned to immutable commits. Maintainers review updates
monthly and promptly for security advisories using the
action update process. Maintainers publish releases
from annotated tags. See the release process.
Layout
cmd/mcp-keycloak — stdio entrypoint
internal/config — environment configuration
internal/keycloak — gocloak wrapper with admin-token caching
internal/mcpserver — MCP server, tool definitions and tests