Skip to main content
Glama
shigechika

keycloak-mcp

by shigechika

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
KEYCLOAK_URLYesBase URL of the Keycloak server, e.g. https://keycloak.example.com
KEYCLOAK_REALMNoRealm namemaster
KEYCLOAK_CLIENT_IDYesService Account client ID
KEYCLOAK_SITES_ININoPath to INI file for IP-to-site labeling
KEYCLOAK_CLIENT_SECRETYesClient secret
KEYCLOAK_DEFAULT_DATE_FROM_HOURSNoDefault look-back window for event tools when date_from is omitted24

Capabilities

Features and capabilities supported by this server

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
health_checkA

Report server version and KeyCloak backend connectivity / authentication.

Call this at session start (or after a tool-call timeout) to confirm the MCP is up, see which version is running, and verify the KeyCloak Admin API is reachable and the service account can authenticate. Lightweight: it acquires an admin access token via the Client Credentials Grant (reusing the cached client) and does NOT enumerate users, events, or sessions.

Always returns the same keys: status (healthy / degraded / error), service, version, keycloak_url (configured base URL, empty if unset), realm (configured realm), keycloak_version (None — not exposed by a cheap call), and auth (ok / error / missing-env). On a degraded or error result, detail carries the reason.

count_usersA

Get total user count in the realm.

search_usersA

Search users by username, email, first name, or last name.

Args: query: Search string (partial match). max_results: Maximum results to return (default 20).

get_userA

Get detailed user information by exact username (email).

Args: username: Exact username (e.g., user@example.com).

reset_passwordB

Reset a user's password.

Args: username: Exact username (email). password: New password to set. temporary: If True, user must change password on next login.

reset_passwords_batchA

Reset passwords for multiple users from CSV text.

Each line should be: username,password If password column is empty, a random 12-char password is generated and included in the response (the caller cannot recover it otherwise). Caller-supplied passwords are never echoed back.

Args: csv_text: CSV text with username,password per line (header optional). temporary: If True, users must change password on next login.

get_user_sessionsC

Get active sessions for a user.

Args: username: Exact username (email).

logout_userA

Force logout a user by removing all their active sessions.

Args: username: Exact username (email).

get_user_credentialsA

List the credential types configured for one user (password, otp, webauthn, …).

Use this to check a single user's MFA status: an otp credential means TOTP/HOTP is configured. Reads /users/{id}/credentials (read-only; does not create a session).

Args: username: Exact username (email).

get_totp_usersA

Report how many users have TOTP (OTP) configured across the realm.

Enumerates users and inspects each one's credentials for an otp entry. KeyCloak has no bulk credential endpoint, so this makes one credential request per user (N+1) — expect it to be slow on large realms; bound it with max_users (which also short-circuits the user enumeration). Users whose credential lookup fails are counted separately and skipped, so a single transient error does not abort the whole scan.

Args: enabled_only: Only scan enabled users (default True). list_users: Include the list of usernames with TOTP (default True). max_users: Cap the number of users scanned (0 = all). When the cap is hit the percentage covers only the sample, not the realm.

get_brute_force_statusA

Check if a user is temporarily locked due to brute force detection.

Args: username: Exact username (email).

list_user_groupsB

List groups a user belongs to.

Args: username: Exact username (email).

list_users_by_groupB

List all users in a group.

Args: group_name: Group name (partial match). max_results: Maximum results (default 100).

get_eventsB

Get KeyCloak events with optional filters.

Args: event_type: Event type filter (e.g., LOGIN, LOGIN_ERROR, UPDATE_PASSWORD). username: Filter by exact username (email). Resolved to user ID internally. client_id: Filter by client ID (SP name). ip_address: Filter events by source IP (client-side filter). date_from: Start date (YYYY-MM-DD). Defaults to last 24h when omitted (KEYCLOAK_DEFAULT_DATE_FROM_HOURS). date_to: End date (YYYY-MM-DD). max_results: Maximum results (default 50).

get_login_statsA

Get login success/failure statistics with full pagination.

Args: date_from: Start date (YYYY-MM-DD). Defaults to last 24h when omitted (KEYCLOAK_DEFAULT_DATE_FROM_HOURS). date_to: End date (YYYY-MM-DD). Empty for all.

get_login_stats_by_hourA

Get login statistics broken down by hour (local time).

Args: date_from: Start date (YYYY-MM-DD). Defaults to last 24h when omitted (KEYCLOAK_DEFAULT_DATE_FROM_HOURS). date_to: End date (YYYY-MM-DD). Empty for all.

get_login_failures_by_ipB

Get login failure statistics broken down by source IP.

Args: date_from: Start date (YYYY-MM-DD). Defaults to last 24h when omitted (KEYCLOAK_DEFAULT_DATE_FROM_HOURS). date_to: End date (YYYY-MM-DD). Empty for all. top: Number of top IPs to show (default 20).

get_ip_activityA

Exhaustive investigation of all activity from one source IP address.

Unlike get_events(ip_address=...), which filters a single page and can miss activity outside the most recent max_results events, this tool fully paginates every requested event type (via get_events_all) before filtering by IP, so the result is exhaustive over the requested date range. Use this for brute-force / credential-stuffing / shared-workstation investigations where get_login_failures_by_ip told you which IP to look at and you now need the full picture for that one IP.

Returns a fixed-shape dict (JSON), not formatted text — every key below is always present, even when zero events match.

Returns: error: None on success. Set to a descriptive message if event_types resolved to no event types (e.g. empty or all-whitespace/commas); every other key is still present, with an empty/zero result in that case (no data was fetched). ip_address: Echoes the input. site: Site name from KEYCLOAK_SITES_INI, or null if unmatched or unconfigured (see sites_configured to tell those apart). sites_configured: True if KEYCLOAK_SITES_INI was loaded at all. date_from / date_to: The resolved date range actually scanned. event_types: The event types scanned (echoes the input, split). summary: total_events, login_success, login_failure, unique_users, unique_clients, first_seen/last_seen (ISO 8601, null if no match). login_success/login_failure classify EVERY scanned event type by whether its type ends in "_ERROR" (matching the users/clients breakdown below), not just literal LOGIN/LOGIN_ERROR — so widening event_types always keeps these numbers reconciled with the per-user/per-client totals. Always computed over the FULL matched set, unaffected by max_timeline truncation. users: Per-user breakdown (success/failure counts, distinct error codes), sorted by total activity descending. Note: successful LOGIN events often carry only a userId (UUID) while LOGIN_ERROR carries details.username — this tool keys on username-or-userId-or-"unknown", so the same human can legitimately appear under two different keys across success vs. failure events. clients: Per-client (SP) breakdown, same shape, sorted descending. timeline: Chronological event list, capped at max_timeline (most recent kept on overflow — see truncated). max_timeline<=0 returns an empty timeline. truncated: True if timeline was capped; summary/users/clients are never affected by this cap.

Args: ip_address: Source IP to investigate. Compared against KeyCloak's recorded ipAddress field after normalizing both sides through Python's ipaddress module (so equivalent IPv6 notations like "::1" and "0:0:0:0:0:0:0:1" match); falls back to a raw string compare if either side doesn't parse as an IP. event_types: Comma-separated KeyCloak event types to scan (default "LOGIN,LOGIN_ERROR"). Widen with e.g. "LOGIN,LOGIN_ERROR,LOGOUT,UPDATE_PASSWORD,CLIENT_LOGIN,CLIENT_LOGIN_ERROR" for a broader sweep. Must resolve to at least one type. date_from: Start date (YYYY-MM-DD). Defaults to last 24h when omitted (KEYCLOAK_DEFAULT_DATE_FROM_HOURS). Widening the window means fully paginating every event type over that window before filtering — expect it to be slower on large realms. date_to: End date (YYYY-MM-DD). Empty for open-ended. max_timeline: Cap on the number of most-recent timeline entries returned (default 200; <=0 means no timeline entries). Does not affect summary/users/clients.

get_login_stats_by_clientC

Get login statistics broken down by client (SP).

Args: date_from: Start date (YYYY-MM-DD). Defaults to last 24h when omitted (KEYCLOAK_DEFAULT_DATE_FROM_HOURS). date_to: End date (YYYY-MM-DD). Empty for all.

detect_login_loopsA

Detect users with rapid repeated logins (possible redirect loops).

Scans all LOGIN events and finds users who logged in more than threshold times within window_seconds.

Args: date_from: Start date (YYYY-MM-DD). Defaults to last 24h when omitted (KEYCLOAK_DEFAULT_DATE_FROM_HOURS). date_to: End date (YYYY-MM-DD). Empty for all. threshold: Minimum logins within the window to flag (default 10). window_seconds: Time window in seconds (default 60). top: Number of top users to show (default 20). Use 0 for all.

get_password_update_eventsA

Get password update events.

Args: date_from: Start date (YYYY-MM-DD). Defaults to last 24h when omitted (KEYCLOAK_DEFAULT_DATE_FROM_HOURS). date_to: End date (YYYY-MM-DD). max_results: Maximum results (default 100).

get_admin_eventsA

Get KeyCloak admin events (changes performed via the Admin REST API).

Admin events record operations performed by service accounts or admin users — e.g. custom user attribute updates (temp_password), role / group assignments, client configuration changes. These are distinct from user events (login / password change). Use this when UPDATE_PROFILE in get_events is empty but an attribute is known to have changed.

Args: operation_types: Comma-separated list of CREATE, UPDATE, DELETE, ACTION. resource_types: Comma-separated list of USER, CLIENT, ROLE, GROUP, REALM_ROLE, etc. resource_path: Filter by resource path (e.g. "users/{userId}"). date_from: Start date (YYYY-MM-DD). Defaults to last 24h when omitted (KEYCLOAK_DEFAULT_DATE_FROM_HOURS). date_to: End date (YYYY-MM-DD). max_results: Maximum results (default 50). max_repr: Max chars of the representation field. 0 = omit, -1 = full.

get_user_attribute_historyA

Get admin-side attribute change history for a single user.

Queries admin events scoped to users/{userId} with UPDATE / ACTION operations. Intended for tracking custom attribute changes such as temp_password which are written by admin API and do not surface in get_events (which only shows user-driven events like LOGIN / UPDATE_PASSWORD).

Args: username: Exact username (email). date_from: Start date (YYYY-MM-DD). Defaults to last 24h when omitted (KEYCLOAK_DEFAULT_DATE_FROM_HOURS). date_to: End date (YYYY-MM-DD). max_results: Maximum results (default 100). max_repr: Max chars of the representation field. 0 = omit, -1 = full.

get_session_statsA

Get active session count per client.

get_client_sessionsA

Get active sessions for a specific client (SP).

Args: client_id: Client ID (e.g., 'xflow', 'shadowserver'). max_results: Maximum results (default 100).

list_clientsA

List all SAML/OIDC clients in the realm.

get_realm_rolesA

List all realm-level roles.

get_realm_security_defensesA

Show the realm's security-defense settings (read-only).

Reports the realm-level security configuration that the admin console groups under "Security defenses":

  • Brute force detection: whether it is enabled, the lockout strategy, and the thresholds (max login failures, wait increments, reset window).

  • Password policy.

  • Browser security headers.

Use this to verify that brute-force protection is actually turned on and how aggressively it locks accounts — the per-user get_brute_force_status only reflects runtime state, not whether the policy itself is configured.

daily_briefA

Run a morning Keycloak health check.

Checks (all scoped to the last since_hours hours):

  • Login statistics (success / failure totals, top failing IPs)

  • Active sessions by client

  • Password update events

  • Admin events (CREATE/UPDATE/DELETE on USER/CLIENT resources)

A single IP with login failures >= ip_failure_threshold is flagged as WARNING (possible brute-force).

since_hours defaults to 18 (≈ previous 15:00 for a 09:00 morning run).

Output tiers:

  • CRITICAL — API connection failure

  • WARNING — anomalies detected

  • OK — clean

Args: since_hours: Look-back window in hours (default 18). ip_failure_threshold: Login failures from a single IP that triggers a WARNING (default 50).

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/shigechika/keycloak-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server