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 ?

Gérez vos clusters Skycloak (Keycloak managé), vos realms et votre SSO depuis n'importe quel client MCP.

  • Examen des mises à niveau de cluster — Demandez quels clusters sont en retard sur les mises à niveau Keycloak et obtenez le chemin de mise à niveau via list_cluster_upgrades et get_cluster_upgrade_path.
  • Provisionnement de realm — Créez un realm avec connexion Google et GitHub à l'aide de create_realm et create_identity_provider.
  • Transfert SIEM — Configurez une destination SIEM qui transmet les événements administrateurs à un webhook Datadog via create_siem_destination.
  • Configuration de domaine personnalisé — Ajoutez un domaine personnalisé, obtenez les enregistrements DNS et vérifiez-les avec 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 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 comme 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 autorisent, 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 comme 403 de l'API.
  • Stdio local. Exécutez skycloak-mcp init et approuvez dans votre navigateur (flux d'autorisation d'appareil OAuth 2.0). Cela 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 fonctionne avec capacités d'écriture, et ce que vous pouvez réellement modifier est limité par les portées de votre clé et votre rôle d'espace de travail : un membre en lecture seule ne peut rien modifier, quelle que soit la liste d'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 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

129 outils : 58 en lecture seule et 71 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, 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_contentset_theme_assignment, set_client_theme_assignment, update_theme, 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
Exportations 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) exigent confirm=true. 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 thème intégré par défaut). 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 du 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 une exportation existante (source_export_id) ou depuis une archive téléversée (create_realm_import_upload_url, PUT, puis upload_s3_key) ; l'importation crée un realm et refuse une collision de nom plutôt que d'écraser, et nécessite confirm=true car elle apporte utilisateurs et identifiants avec elle.

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 d'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, axé sur les paramètres de connexion et de sécurité
provision_environmentCréer un cluster, ajouter un realm et connecter un fournisseur d'identité, en confirmant chaque étape
set_up_custom_domainAjouter un domaine personnalisé, fournir 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 le rayon d'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 brouillon SEP-2640 Skills : 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-triageTrier « les utilisateurs ne peuvent pas se connecter » : séparer 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 courtier, test de connexion et vérification contre les événements de connexion réels
keycloak-migration-doctorPré-vérifier une exportation, importation ou migration Keycloak contre les blocages que le support voit réellement (politiques de script, chemin hérité /auth, attentes d'exportation partielle), et diagnostiquer un travail échoué en lisant son vrai error_message au lieu de l'avis générique du tableau de bord
keycloak-upgrade-readinessÉvaluer la dérive de version, déterminer ce que la nouvelle version Keycloak casse (extensions, thèmes), et séquencer le déploiement entre environnements avec une exportation comme plan de restauration

Les compétences suivent le même contrôle que les outils qu'elles nomment : les trois flux construits autour d'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 vivent dans internal/tools/skills/, un répertoire par compétence, au format standard Agent Skills, donc elles fonctionnent aussi copiées directement dans un répertoire de compétences local.

Connexion

Pour HTTP hébergé, la voie la plus simple est OAuth, qui ne nécessite aucun identifiant :

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

Le premier appel ouvre votre navigateur, vous approuvez sur 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 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 un usage headless / CI (sans navigateur), ignorez init et transmettez plutôt la clé : 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 si vous avez l'intention d'apporter 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 n'exposer que 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 est par défaut false, mais les outils d'écriture ne sont enregistrés que si le serveur a été démarré avec --allow-writes.

Ajoutez ?workspace=<uuid> pour choisir l'espace de travail sur lequel une session OAuth agit. Cela n'est nécessaire que si vous appartenez à plusieurs espaces de travail ; 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 n'a besoin d'aucune information d'identification propre : les appelants fournissent les leurs à chaque 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 une panne en amont ne peut pas faire échouer la sonde de toutes les réplicas à la fois. Le serveur ne conserve aucun état de session, donc les réplicas n'ont besoin d'aucune affinité de session et peuvent être mises à l'échelle ou redéployées librement. SIGTERM arrête les nouvelles connexions et vide les appels en cours.

Le chemin OAuth est actif dès 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 requête elle-même via Host et le schéma, donc un déploiement mono-hôte derrière un ingress 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, car la terminaison TLS se fait 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 ingress 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 jeton fait appeler par le 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 d'être porté vers un échange qui ne peut pas réussir, donc un client détenant encore une autorisation antérieure 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. S'il n'est pas défini, la route n'est pas enregistrée et le chemin renvoie une 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, etc.) ; 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 d'appareil 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 l'ingress réécrit Host)
OPENAI_APPS_CHALLENGE_TOKENSert le jeton de vérification du répertoire de plugins d'OpenAI à /.well-known/openai-apps-challenge. S'il n'est pas défini, ce chemin renvoie une 404.

Commandes : init (connexion par 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-writesfalseactive les outils de mutation pour stdio et permet 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 tenant compte de Retry-After.

Distribution

Publié sous forme de binaires GitHub et d'une image conteneur ghcr.io/sky-cloak/skycloak-mcp à chaque tag, et publié dans le registre MCP 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é lors de son ouverture, 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 afin que le client puisse être généré et vérifié. Voir NOTICE.