Skycloak

officiel

Serveur Model Context Protocol pour Skycloak Keycloak géré. Gérez les clusters, les domaines, les applications, le SSO et les utilisateurs depuis n'importe quel client MCP.

Que pouvez-vous faire avec Skycloak MCP ?

  • Examen de mise à niveau du cluster — Demandez quels clusters Keycloak sont en retard sur les mises à niveau et obtenez le chemin recommandé via list_cluster_upgrades et get_cluster_upgrade_path.

  • Provisionnement de realm — Créez un realm de staging sur un cluster spécifique avec des fournisseurs d'identité configurés, en utilisant create_realm et create_identity_provider.

  • Audit d'activité des utilisateurs — Trouvez qui a été ajouté à un realm récemment et examinez les modifications administratives, en exploitant list_realm_users et query_events.

  • Configuration de l'intégration SIEM — Configurez une destination qui transmet les événements administratifs à un webhook externe, en utilisant create_siem_destination et test_siem_destination.

  • Remplacement du contenu du thème — Mettez à jour l'archive d'un thème personnalisé en place sans perdre ses affectations, via update_theme_content avec confirmation.

  • Routage de domaine personnalisé — Ajoutez un domaine personnalisé, récupérez les enregistrements DNS à créer, vérifiez-les et routez le trafic vers un realm en utilisant create_domain et verify_domain.

Documentation

skycloak-mcp

Smithery

Serveur officiel Model Context Protocol pour Skycloak (Keycloak géré) : gérez vos clusters, realms, applications et SSO depuis n'importe quel client MCP (Claude Desktop, Claude Code, Cursor).

Statut : version précoce. La couverture des outils s'étoffe ; consultez le journal des modifications pour voir ce qui est disponible.

Démarrage rapide

claude mcp add --transport http skycloak https://mcp.skycloak.io

Pas de clé API, pas d'identifiant client, aucune configuration. Votre navigateur s'ouvre, vous vous connectez à Skycloak, et les outils apparaissent. Tout client MCP qui parle HTTP streamable fonctionne de la même manière : donnez-lui l'URL et rien d'autre.

Puis demandez quelque chose :

  • « Quels sont mes clusters Keycloak en retard sur les mises à niveau ? »
  • « Crée un realm de staging sur le cluster UE avec la connexion Google et GitHub. »
  • « Qui a été ajouté au realm de production la semaine dernière ? »
  • « Configure une destination SIEM qui transmet les événements admin à notre webhook Datadog. »

Authentification et sécurité

  • HTTP hébergé, avec OAuth (aucun identifiant à configurer). Pointez votre client vers https://mcp.skycloak.io sans en-tête. Le serveur répond 401 avec un pointeur vers ses métadonnées RFC 9728 à /.well-known/oauth-protected-resource, le client exécute le flux de code d'autorisation navigateur contre le realm de connexion Skycloak, et le jeton d'accès obtenu est échangé contre une clé API de courte durée, limitée à l'espace de travail, sur laquelle la session s'exécute. La clé dure une heure et est renouvelée automatiquement. Rien n'est stocké dans la configuration de votre client.
  • HTTP hébergé, avec une clé API. Créez une clé dans le tableau de bord Skycloak et envoyez-la comme Authorization: Bearer <key> (ou API-Key: <key>). Chaque requête porte son propre identifiant et agit uniquement en tant qu'espace de travail de cet identifiant. Le serveur ne conserve aucun état de session, donc une requête n'hérite jamais d'un autre appelant. Les clés ne sont pas vérifiées avant utilisation : l'API Skycloak fait autorité, donc une clé invalide se manifeste par un 401 au premier appel d'outil plutôt qu'à la connexion.
  • Les outils correspondent à votre rôle. En OAuth, la liste des outils est réduite à ce que les portées de la session permettent, donc un membre d'espace de travail en lecture seule ne voit pas les outils d'écriture qui répondraient 403. Avec une clé API, toute la surface est enregistrée, car les portées d'une clé ne sont pas visibles par le serveur, et un appel non autorisé se manifeste par un 403 de l'API.
  • Stdio local. Exécutez skycloak-mcp init et approuvez dans votre navigateur (flux d'autorisation d'appareil OAuth 2.0). Il génère une clé API limitée à l'espace de travail, la stocke dans le trousseau de votre système d'exploitation et détecte automatiquement votre espace de travail par défaut (passez --workspace <id> pour en choisir un autre). skycloak-mcp logout supprime la clé stockée.
  • Sans interface / CI. Définissez la variable d'environnement SKYCLOAK_API_KEY (créez une clé dans le tableau de bord Skycloak) pour ignorer complètement le navigateur. Elle a toujours priorité sur le trousseau.
  • Les écritures sont contrôlées par votre identifiant, pas par un drapeau. Le serveur hébergé à https://mcp.skycloak.io est capable d'écrire, et ce que vous pouvez réellement modifier est limité par les portées de votre clé et votre rôle dans l'espace de travail : un membre en lecture seule ne peut rien modifier, quelle que soit la liste des outils. Ajoutez ?readonly=true à l'URL pour forcer une surface d'outils en lecture seule pour une session. Le binaire local est à l'inverse et n'enregistre aucun outil d'écriture sauf s'il est démarré avec --allow-writes.
  • Les identifiants de cluster sont facultatifs. get_cluster_credentials renvoie les identifiants admin Keycloak d'un cluster, qu'un assistant détenant la clé verrait ensuite, donc init ne demande pas cette portée par défaut. Utilisez une clé qui la porte : créez-en une dans le tableau de bord, ou en stdio connectez-vous avec skycloak-mcp init --allow-credentials. Sans elle, l'outil renvoie un 403 qui explique les deux voies.
  • Les outils destructeurs exigent une confirmation : supprimer un realm, par exemple, nécessite un argument explicite confirm=true.
  • Les requêtes sont limitées en débit selon votre plan Skycloak ; sur une réponse 429, le serveur expose Retry-After.

Outils

137 outils : 60 en lecture seule et 77 en écriture. Les outils en lecture seule sont toujours disponibles. Sur le serveur hébergé, les outils d'écriture sont également enregistrés et contrôlés par les portées de votre identifiant ; le binaire local ne les enregistre que lorsqu'il est démarré avec --allow-writes.

Les noms d'outils portent un préfixe skycloak_ que le tableau ci-dessous omet, donc list_clusters est skycloak_list_clusters dans votre client.

DomaineLecture seuleÉcriture (--allow-writes)
Clusterslist_clusters, get_cluster, list_cluster_locations, list_cluster_types, list_cluster_features, list_cluster_versions, list_cluster_upgrades, get_cluster_upgrade_path, get_cluster_credentials, get_cluster_insights, get_cluster_maintenance_windowcreate_cluster, update_cluster, delete_cluster, cancel_cluster_upgrade, restart_cluster_instances, set_cluster_maintenance_window, delete_cluster_maintenance_window
Sécurité périphériqueget_cluster_security, list_cluster_captcha_domainsupdate_cluster_security, add_cluster_captcha_domain, remove_cluster_captcha_domain
Realmslist_realms, get_realmcreate_realm, update_realm, delete_realm
Applicationslist_applications, get_application, list_application_roles, list_application_sessionscreate_application, update_application, delete_application, assign_application_role, remove_application_role, rotate_application_secret
Fournisseurs d'identitélist_identity_providers, get_identity_provider, list_identity_provider_templates, discover_oidccreate_identity_provider (OIDC), update_identity_provider, delete_identity_provider, test_identity_provider
Utilisateurs, rôles et groupeslist_realm_users, get_realm_user, list_realm_roles, get_realm_role, list_realm_groups, get_realm_group, list_realm_group_members, list_user_roles, list_user_groupscreate_realm_user, update_realm_user, delete_realm_user, create_realm_role, update_realm_role, delete_realm_role, create_realm_group, update_realm_group, delete_realm_group, assign_realm_user_role, remove_realm_user_role, add_realm_user_to_group, remove_realm_user_from_group
Domaines personnaliséslist_domains, get_domain, list_domain_routes, get_domain_routecreate_domain, verify_domain, delete_domain, create_domain_route, update_domain_route, delete_domain_route
Marque et thèmeslist_themes, get_theme, get_theme_assignment, get_client_theme_assignment, get_login_branding, get_email_branding, download_theme_content, get_theme_settingsset_theme_assignment, set_client_theme_assignment, update_theme, update_theme_content, update_theme_settings, delete_theme, upsert_login_branding, delete_login_branding, upsert_email_branding, delete_email_branding
Extensionslist_extensions, list_cluster_extensionsinstall_extension, upgrade_extension, update_extension, uninstall_extension, delete_extension
SMTPget_smtpupsert_smtp, delete_smtp, test_smtp
Exports et journauxlist_exports, get_export, get_logs, get_security_logs, query_eventscreate_export, delete_export, export_cluster_events
Import et export de realmget_realm_export, get_realm_importcreate_realm_export, create_realm_import, create_realm_import_upload_url
SIEMlist_siem_destinations, get_siem_destinationcreate_siem_destination, update_siem_destination, delete_siem_destination, test_siem_destination
Webhookslist_webhook_event_types, list_webhook_subscriptions, get_webhook_subscriptioncreate_webhook_subscription, update_webhook_subscription, delete_webhook_subscription, test_webhook_subscription

Conventions : les outils destructeurs (delete_*, uninstall_extension, cancel_cluster_upgrade, update_theme_content, update_theme_settings, restart_cluster_instances) exigent confirm=true. update_theme_settings active ou désactive exact_theme_names pour l'espace de travail ; la clé API de l'appelant doit avoir été générée pour un propriétaire ou un administrateur d'espace de travail, sinon elle reçoit 403 même avec themes:write. L'activer déplace les thèmes existants vers leurs noms servis exacts en arrière-plan ; un thème dont le contenu a été remplacé sous son nom exact signale restart_required: true depuis get_theme/list_themes/update_theme_content jusqu'à ce que restart_cluster_instances redémarre les instances Keycloak de ce cluster. Un redémarrage peut être différé à la fenêtre de maintenance du cluster au lieu d'être appliqué immédiatement, signalé comme deferred: true et, lorsqu'il est connu, next_window. create_cluster est asynchrone : interrogez get_cluster jusqu'à ce que le cluster soit available. create_domain renvoie les enregistrements DNS que le client doit créer ; verify_domain déclenche une vérification DNS. set_theme_assignment active un thème personnalisé par type de thème Keycloak (chaîne vide réinitialise au défaut intégré). update_theme_content remplace l'archive d'un thème en place (ZIP base64 ou JAR Keycloakify dans content_base64), en conservant l'ID, le nom et les affectations de realm et d'application du thème, donc modifier un thème ne signifie plus le supprimer et le re-téléverser ; cela nécessite confirm=true car l'archive qu'il écrase n'est pas récupérable, et update_theme ne modifie toujours que le nom, la description et la version. Voir docs/theme-content-update.md pour savoir comment cet appel est effectué. update_cluster_security laisse les paramètres CAPTCHA intacts. L'import/export de realm déplace la configuration d'un seul realm et est distinct de create_export, qui vide la base de données d'un cluster entier : les deux sont asynchrones, et l'archive de realm est toujours chiffrée, donc le mot de passe utilisé pour l'exporter est nécessaire pour l'importer à nouveau. Un realm peut être importé directement depuis un export existant (source_export_id) ou depuis une archive téléversée (create_realm_import_upload_url, PUT, puis upload_s3_key) ; l'import crée un realm et refuse une collision de nom plutôt que d'écraser, et nécessite confirm=true car il apporte des utilisateurs et des identifiants avec lui.

Invites

Huit invites vous donnent un point de départ dans cette surface d'outils. Les clients les présentent comme des commandes slash ou des actions suggérées ; chacune prend des arguments (realm, cluster, fenêtre temporelle) et guide le modèle à travers les bons outils dans le bon ordre.

InviteCe qu'elle fait
audit_self_registrationTrouver chaque realm qui autorise encore l'auto-inscription, sur un cluster ou tous
review_upgradesRepérer les clusters en retard sur leur version Keycloak et tracer le chemin de mise à niveau
triage_failed_loginsExtraire les échecs de connexion récents pour un realm et les regrouper par IP source
review_identity_providersLister les connexions SSO d'un realm et vérifier si une connexion spécifique est activée
review_admin_changesMontrer qui a modifié quoi dans un realm récemment, en se concentrant sur les paramètres de connexion et de sécurité
provision_environmentCréer un cluster, ajouter un realm et configurer un fournisseur d'identité, en confirmant chaque étape
set_up_custom_domainAjouter un domaine personnalisé, renvoyer les enregistrements DNS exacts, vérifier et le router vers un realm
rotate_client_secretRégénérer le secret client d'une application avec l'impact expliqué d'abord

Les invites sont contrôlées de la même manière que les outils qu'elles nomment : les trois qui modifient ne sont proposées qu'aux sessions qui pourraient appeler les outils d'écriture qu'elles référencent, et leurs instructions disent au modèle de confirmer avec vous avant de changer quoi que ce soit. L'exigence confirm=true sur les outils destructeurs s'applique toujours en plus.

Compétences

Là où une invite est un point de départ, une compétence est un manuel opérationnel complet que le modèle charge à la demande. Le serveur en fournit quatre, servies via l'extension de compétences SEP-2640 en avant-première : il déclare io.modelcontextprotocol/skills dans ses capacités, répond à skills/list et skills/get, et sert chaque SKILL.md comme une ressource ordinaire à skill://<name>/SKILL.md avec un digest sha256 dans son entrée de liste. Le répertoire de plugins d'OpenAI importe les compétences exactement sous cette forme.

CompétenceCe qu'elle encode
auth-incident-triageTriage des « utilisateurs incapables de se connecter » : distinguer les pannes de plateforme des attaques et des changements de configuration, en utilisant les événements, les journaux WAF et la santé du cluster. Lecture seule
enterprise-sso-rolloutConnecter un IdP d'entreprise à un realm de bout en bout : validation de l'émetteur, enregistrement de l'application en amont, configuration du broker, test de connexion et vérification par rapport aux événements de connexion réels
keycloak-migration-doctorPré-vérifier une exportation, importation ou migration Keycloak par rapport aux blocages que le support rencontre réellement (politiques de script, chemin /auth hérité, attentes d'exportation partielle), et diagnostiquer un travail échoué en lisant son error_message réel au lieu de l'avis générique du tableau de bord
keycloak-upgrade-readinessÉvaluer l'écart de version, déterminer ce que la nouvelle version de Keycloak casse (extensions, thèmes), et séquencer le déploiement entre les environnements avec une exportation comme plan de restauration

Les compétences suivent le même contrôle d'accès que les outils qu'elles nomment : les trois flux de travail construits autour des outils d'écriture sont retirés des sessions en lecture seule, et une session limitée ne se voit proposer qu'une compétence dont elle possède réellement les outils. Les sources se trouvent dans internal/tools/skills/, un répertoire par compétence, au format standard Agent Skills, elles fonctionnent donc aussi copiées directement dans un répertoire de compétences local.

Connexion

Pour le HTTP hébergé, le plus simple est OAuth, qui ne nécessite aucune information d'identification :

claude mcp add --transport http skycloak https://mcp.skycloak.io

Le premier appel ouvre votre navigateur, vous approuvez dans la page de connexion Skycloak, et les outils apparaissent. Si vous appartenez à plusieurs espaces de travail, nommez celui que vous voulez :

claude mcp add --transport http skycloak "https://mcp.skycloak.io?workspace=<workspace-id>"

Sinon, créez une clé API dans le tableau de bord Skycloak et configurez votre client MCP pour l'envoyer comme jeton porteur :

claude mcp add --transport http skycloak https://mcp.skycloak.io --header "Authorization: Bearer sk_sc_XXX"

Cela ajoute ce qui suit à .claude.json :

{
  "mcpServers": {
    "skycloak": {
      "type": "http",
      "url": "https://mcp.skycloak.io",
      "headers": {
        "Authorization": "Bearer sk_sc_XXX"
      }
    }
  }
}

Pour le stdio local, connectez-vous une fois, puis pointez votre client vers skycloak-mcp run :

skycloak-mcp init        # one-time browser sign-in; stores a key in your keychain

Claude Desktop / Cursor (local, stdio) :

{
  "mcpServers": {
    "skycloak": {
      "command": "skycloak-mcp",
      "args": ["run", "--transport", "stdio"]
    }
  }
}

Claude Code :

claude mcp add skycloak -- skycloak-mcp run --transport stdio

Pour headless / CI (sans navigateur), ignorez init et passez la clé à la place : ajoutez "env": { "SKYCLOAK_API_KEY": "sk_sc_..." } à la configuration, ou claude mcp add skycloak --env SKYCLOAK_API_KEY=sk_sc_... -- skycloak-mcp run --transport stdio.

Ajoutez --allow-writes uniquement lorsque vous avez l'intention de faire des modifications (connectez-vous avec skycloak-mcp init --allow-writes, ou utilisez une clé à portée d'écriture).

Ajoutez ?readonly=true à une URL HTTP hébergée pour exposer uniquement les outils en lecture seule pour cette session HTTP, ou ?readonly=false pour demander la surface d'outils avec capacité d'écriture. Le paramètre de requête par défaut est false, mais les outils d'écriture ne sont enregistrés que lorsque le serveur a été démarré avec --allow-writes.

Ajoutez ?workspace=<uuid> pour choisir sur quel espace de travail une session OAuth agit. Cela n'est nécessaire que lorsque vous appartenez à plusieurs espaces ; avec un seul espace de travail, le serveur le choisit pour vous, et si vous appartenez à plusieurs et n'en nommez aucun, la connexion échoue avec un message les listant.

Exécution du transport HTTP

skycloak-mcp run --transport http --http-addr :8080

Il ne nécessite aucune information d'identification propre : les appelants fournissent les leurs par requête, donc rien n'est injecté au moment du déploiement. GET /healthz et GET /readyz ne sont pas authentifiés et signalent uniquement que le processus est actif ; ils ne sondent délibérément pas l'API Skycloak, donc un incident en amont ne peut pas faire échouer la sonde de chaque réplica à la fois. Le serveur ne conserve aucun état de session, donc les réplicas n'ont pas besoin d'affinité de session et peuvent être mis à l'échelle ou redéployés librement. SIGTERM arrête les nouvelles connexions et draine les appels en cours.

Le chemin OAuth est actif chaque fois que SKYCLOAK_ISSUER et SKYCLOAK_DASHBOARD_URL sont définis, ce qui est le cas par défaut. GET /.well-known/oauth-protected-resource est alors servi sans authentification, nommant le realm comme serveur d'autorisation. Sa valeur resource est tirée de SKYCLOAK_PUBLIC_URL lorsqu'elle est définie, et sinon de la propre Host et du schéma de la requête, donc un déploiement à hôte unique derrière une passerelle d'entrée ne nécessite aucune configuration supplémentaire. Le schéma provient de X-Forwarded-Proto lorsqu'il est présent, et sinon par défaut de https pour tout sauf un hôte de bouclage, puisque TLS se termine en amont et publier un identifiant http:// ne correspondrait pas à l'URL sur laquelle le client s'est connecté. Définissez SKYCLOAK_PUBLIC_URL si votre passerelle d'entrée réécrit Host. Le document liste également openid profile email comme son scopes_supported, et le défi WWW-Authenticate les répète comme paramètre scope, donc un client lisant l'un ou l'autre demande au realm de les fournir : openid est requis, car l'échange de jetons fait appeler au tableau de bord le point de terminaison userinfo de Keycloak et Keycloak refuse un jeton accordé sans lui. Un jeton qui arrive sans lui est refusé à la vérification avec un 401 et le défi, plutôt que porté vers un échange qui ne peut pas réussir, donc un client détenant encore une autorisation d'avant cesse de réessayer et se reconnecte. Vider l'une ou l'autre des variables d'émetteur ou de tableau de bord désactive complètement OAuth, et le serveur revient à demander une clé API et rien d'autre.

OPENAI_APPS_CHALLENGE_TOKEN sert le jeton de vérification du domaine du répertoire de plugins d'OpenAI à /.well-known/openai-apps-challenge, en texte brut et rien d'autre. Non défini, la route n'est pas enregistrée et le chemin renvoie 404.

Le démarrage journalise une ligne avec le câblage résolu (oauth=, issuer=, dashboard=, public_url=, endpoint=, allow_writes=), donc un déploiement mal configuré peut être repéré sans redéploiement. Chaque requête refusée sur le chemin OAuth journalise une ligne nommant l'étape qui a échoué (verify, exchange ou scopes), le statut reçu par l'appelant et l'erreur sous-jacente. Un échec de vérification ajoute le contrôle qui a rejeté le jeton (expired, wrong_issuer, bad_signature, unknown_key_id, wrong_token_type, no_openid_scope, et ainsi de suite) ; un échec d'échange ajoute le statut du tableau de bord et l'hôte appelé. L'appelant apparaît comme le sujet du jeton une fois vérifié, et jamais comme une information d'identification : le jeton d'accès, l'en-tête Authorization et la clé API frappée ne sont jamais journalisés.

Configuration

Variable d'environnementDéfaut
SKYCLOAK_API_KEYaucun (facultatif pour stdio ; les clients HTTP fournissent des en-têtes API-Key à la place)
SKYCLOAK_ENDPOINThttps://api.skycloak.io
SKYCLOAK_API_VERSIONversion actuelle de l'API
SKYCLOAK_ISSUERhttps://login.app.skycloak.io/realms/skycloak (connexion CLI, et le serveur d'autorisation contre lequel le transport HTTP vérifie les jetons)
SKYCLOAK_CLIENT_IDskycloak-mcp (flux de dispositif CLI uniquement)
SKYCLOAK_DASHBOARD_URLhttps://app.skycloak.io (frappe les clés CLI et les clés de session HTTP)
SKYCLOAK_PUBLIC_URLaucun (dérivé de chaque requête ; définissez-le lorsque la passerelle d'entrée réécrit Host)
OPENAI_APPS_CHALLENGE_TOKENSert le jeton de vérification du répertoire de plugins d'OpenAI à /.well-known/openai-apps-challenge. Non défini, ce chemin renvoie 404.

Commandes : init (connexion navigateur), run (servir), logout (supprimer la clé stockée). init accepte --workspace <id>, --allow-writes, --allow-credentials et --ttl-days (défaut 90).

DrapeauDéfautDescription
--transportstdiostdio ou http
--http-addr:8080adresse d'écoute pour le transport HTTP
--allow-writesfalseactiver les outils de mutation pour stdio et permettre aux sessions HTTP avec readonly=false d'enregistrer des outils d'écriture

Développement

make build      # build the server binary
make test       # unit tests
make run        # run on stdio for local testing
make inspector  # MCP Inspector against the local binary
make lint       # golangci-lint
make generate   # regenerate the API client from the OpenAPI spec

Le client API sous internal/apiclient est généré à partir de la spécification OpenAPI de Skycloak avec oapi-codegen.

Rester synchronisé avec l'API

Le client dans internal/apiclient est généré à partir de internal/apiclient/openapi.yaml avec oapi-codegen ; exécutez make generate pour le rafraîchir. CI échoue si le code généré validé s'écarte de la spécification. Les requêtes sont réessayées sur 429/5xx avec un backoff sensible à Retry-After.

Distribution

Publié sous forme de binaires GitHub et d'une image de conteneur ghcr.io/sky-cloak/skycloak-mcp sur chaque tag, et publié dans le MCP Registry sous le nom io.skycloak/skycloak-mcp. La plupart des gens n'ont besoin d'aucun des deux : le serveur hébergé ne nécessite aucune installation.

Sécurité

Veuillez signaler les vulnérabilités en privé. Voir SECURITY.md.

Contributeurs

Construit chez Skycloak par Guilliano Molaire, Neville Omangi et Aphilas. L'historique du dépôt a été compressé lorsqu'il a été ouvert, donc le journal des commits ne reflète pas qui a écrit quoi.

Licence

Apache-2.0. La description OpenAPI dans internal/apiclient/openapi.yaml est générée à partir de l'API de la plateforme Skycloak et est (c) Skycloak ; elle est incluse ici pour que le client puisse être généré et vérifié. Voir NOTICE.