Cette page a été traduite de l'anglais avec l'aide de l'IA. En cas de divergence, la version anglaise fait référence.
mcp
Commande utilisée pour lancer StackQL en tant que serveur Model Context Protocol (MCP), ce qui permet aux agents et assistants IA d'interagir avec l'infrastructure cloud à l'aide des capacités de requête de StackQL.
Le Model Context Protocol (MCP) est un protocole ouvert qui standardise la manière dont les applications d'IA interagissent avec les sources de données et les outils externes. En exécutant StackQL en tant que serveur MCP, vous permettez aux agents IA (Claude, Cursor, Continue, agents personnalisés, etc.) d'interroger et de gérer l'infrastructure cloud de plusieurs providers en langage naturel.
Syntaxe
stackql mcp [flags] pour un serveur MCP autonome.
stackql srv [flags] pour exécuter le serveur MCP aux côtés du serveur de protocole filaire PostgreSQL dans le même processus.
Modes de déploiement
Le serveur MCP de StackQL peut être déployé dans trois configurations différentes pour répondre à diverses exigences d'architecture. Les exemples ci-dessous activent explicitement le service sans authentification avec "allow_unauthenticated": true, ce qui convient au développement local ; pour tout ce qu'un autre processus ou un autre hôte peut atteindre, configurez plutôt un jeton bearer (voir Authentification des clients HTTP).
1. Serveur MCP autonome
Exécutez StackQL en tant que serveur MCP dédié sur un port donné.
stackql mcp \
--mcp.server.type=http \
--mcp.config '{"server": {"transport": "http", "address": "127.0.0.1:9912", "allow_unauthenticated": true}}'
Cas d'utilisation : lorsque vous avez uniquement besoin d'un accès par le protocole MCP et que la compatibilité avec le protocole filaire PostgreSQL n'est pas nécessaire.
2. Serveur MCP + PostgreSQL (en mémoire)
Exécutez simultanément les serveurs MCP et PostgreSQL, avec une communication en mémoire entre eux.
stackql srv \
--mcp.server.type=http \
--mcp.config '{"server": {"transport": "http", "address": "127.0.0.1:9912", "allow_unauthenticated": true}}' \
--pgsrv.port 5665
Cas d'utilisation : lorsque vous avez besoin à la fois d'un accès par le protocole MCP pour les agents IA et du protocole filaire PostgreSQL pour les clients de base de données traditionnels, avec des performances maximales grâce à la communication en mémoire.
3. Serveur MCP + PostgreSQL (proxy inverse)
Exécutez les deux serveurs avec une communication TCP, ce qui prend en charge les déploiements distribués et le chiffrement TLS.
stackql srv \
--mcp.server.type=reverse_proxy \
--mcp.config '{"server": {"transport": "http", "address": "127.0.0.1:9004", "allow_unauthenticated": true}, "backend": {"dsn": "postgres://stackql:stackql@127.0.0.1:5446?default_query_exec_mode=simple_protocol"}}' \
--pgsrv.port 5446
Avec chiffrement TLS :
stackql srv \
--mcp.server.type=reverse_proxy \
--mcp.config '{"server": {"tls_cert_file": "/path/to/server_cert.pem", "tls_key_file": "/path/to/server_key.pem", "transport": "http", "address": "127.0.0.1:9004", "auth_token_env_var": "STACKQL_MCP_TOKEN"}, "backend": {"dsn": "postgres://stackql:stackql@127.0.0.1:5446?default_query_exec_mode=simple_protocol"}}' \
--pgsrv.port 5446
TLS chiffre le transport mais n'authentifie pas le client ; cet exemple exige donc aussi le jeton bearer contenu dans STACKQL_MCP_TOKEN.
Cas d'utilisation : lorsque vous devez séparer les charges de travail MCP et PostgreSQL entre différents processus ou hôtes, ou lorsque vous avez besoin du chiffrement TLS pour le point de terminaison MCP.
Options de configuration
Type de serveur MCP
| Type | Description |
|---|---|
http | Mode serveur HTTP direct - les requêtes MCP sont traitées dans le processus par le moteur StackQL. |
reverse_proxy | Mode proxy inverse - les requêtes MCP sont transmises à un serveur PostgreSQL sous-jacent via le DSN configuré. Utilisé avec stackql srv. |
stdio | Transport par entrée/sortie standard - le serveur lit les requêtes sur stdin et écrit les réponses sur stdout. Utilisé par les clients MCP embarqués dans un éditeur (Claude Desktop, Cursor, etc.). |
Format de journal MCP
L'option --mcp.log.format sélectionne l'encodage du journal d'audit : jsonl (valeur par défaut) ou otel (enregistrements de journal OpenTelemetry OTLP/JSON). Elle prévaut sur server.audit.format dans l'objet de configuration. Consultez Format de journal.
Version du protocole MCP
L'option --mcp.protocol.version définit la révision du protocole la plus récente que le serveur annonce : auto (valeur par défaut, toutes les révisions prises en charge), 2026-07-28 (sans session uniquement) ou une révision plus ancienne telle que 2025-11-25 (cette révision et les précédentes). Elle prévaut sur server.protocol_version dans l'objet de configuration. Consultez Fixer la révision.
Objet de configuration MCP
L'option --mcp.config accepte un objet JSON de la structure suivante.
Configuration du serveur
| Champ | Description | Obligatoire |
|---|---|---|
server.transport | Protocole de transport - http ou stdio. | Oui |
server.address | Adresse et port d'écoute du serveur MCP (par exemple 127.0.0.1:9912). Transport HTTP uniquement. | Pour http |
server.tls_cert_file | Chemin du fichier de certificat TLS pour HTTPS. | Non |
server.tls_key_file | Chemin du fichier de clé privée TLS pour HTTPS. | Non |
server.auth_token_env_var | Nom d'une variable d'environnement contenant un jeton bearer prépartagé. Lorsqu'il est défini, chaque requête HTTP doit porter Authorization: Bearer <token> ; le serveur refuse de démarrer si la variable est absente ou vide. Consultez Authentification des clients HTTP. | Ce champ ou allow_unauthenticated, pour http |
server.allow_unauthenticated | Activation explicite du service du transport HTTP sans authentification des clients. Valeur par défaut : false. | Ce champ ou auth_token_env_var, pour http |
server.mode | Contrat de sécurité qui contrôle les mutations et les opérations de cycle de vie. L'une des valeurs read_only, safe (valeur par défaut), delete_safe, full_access. Consultez Modes du serveur. | Non |
server.read_only | Alias booléen hérité de mode: read_only. Lorsque les deux champs sont définis, mode l'emporte. | Non |
server.stateless | Sert Streamable HTTP sans sessions (pas de Mcp-Session-Id), ce qui est la manière dont la révision du protocole 2026-07-28 est servie en HTTP. Valeur par défaut : false. Ignoré pour stdio. Consultez Prise en charge des révisions du protocole. | Non |
server.protocol_version | Révision du protocole la plus récente annoncée : auto (valeur par défaut), 2026-07-28 ou une révision plus ancienne telle que 2025-11-25. 2026-07-28 implique stateless pour Streamable HTTP. Consultez Fixer la révision. | Non |
server.audit | Configuration du sous-système d'audit, dont audit.format (jsonl ou otel). Consultez Journal d'audit. | Non |
Configuration du backend (mode proxy inverse uniquement)
| Champ | Description | Obligatoire |
|---|---|---|
backend.dsn | Chaîne de connexion PostgreSQL du serveur StackQL backend. | Oui (pour reverse_proxy) |
Le DSN du backend doit inclure le paramètre default_query_exec_mode=simple_protocol pour une compatibilité optimale.
Listes d'autorisation
| Champ | Description |
|---|---|
enabled_tools | Tableau des noms d'outils que le serveur est autorisé à publier. S'il est omis ou vide, tous les outils intégrés sont enregistrés. Sert à exposer un sous-ensemble restreint (par exemple un serveur d'inventaire en lecture seule). |
enabled_prompts | Tableau de noms de prompts. Même sémantique que enabled_tools, mais pour la surface des prompts. |
Exemple - un serveur qui publie uniquement server_info et list_providers :
{
"server": {"transport": "http", "address": "127.0.0.1:9912", "allow_unauthenticated": true},
"enabled_tools": ["server_info", "list_providers"]
}
Prise en charge des révisions du protocole
La révision du protocole 2026-07-28, server.stateless et le format de journal d'audit otel sont disponibles dans les versions de StackQL à partir de v0.11.660. server.protocol_version et l'option --mcp.protocol.version sont disponibles dans les versions de StackQL à partir de v0.12.732.
Le serveur parle toutes les révisions du Model Context Protocol prises en charge par le SDK MCP Go et négocie client par client, de sorte qu'un parc de clients hétérogènes fonctionne avec un seul serveur.
| Révision | Cycle de vie | Demande d'approbation (safe / delete_safe) |
|---|---|---|
2026-07-28 (annoncée) | Pas de handshake : server/discover, puis chaque requête porte io.modelcontextprotocol/protocolVersion et io.modelcontextprotocol/clientCapabilities dans _meta (plus les en-têtes Mcp-Protocol-Version, Mcp-Method et Mcp-Name en HTTP). | Résultat input_required, que le client relance avec inputResponses (SEP-2322). |
2025-11-25, 2025-06-18 | Handshake initialize / notifications/initialized. | Requête elicitation/create à l'initiative du serveur. |
2025-03-26, 2024-11-05 | Comme ci-dessus. | Comme ci-dessus. |
stdio sert toutes les révisions dans un seul processus : la première requête d'un client 2026-07-28 est servie sans handshake et le initialize d'un client plus ancien fonctionne toujours. Rien n'est à configurer pour Claude Desktop, les lanceurs npm / PyPI ou l'image Docker.
Streamable HTTP utilise par défaut le modèle avec état, à une session par client (Mcp-Session-Id), que le SDK sert pour les révisions jusqu'à 2025-11-25. Une requête 2026-07-28 reçoit l'erreur JSON-RPC -32022 (version de protocole non prise en charge ; un simple HTTP 400 dans les versions jusqu'à v0.12.718) dont data.supported liste les révisions à handshake, et server/discover annonce la même chose ; le client négocie donc une révision inférieure et les intégrations HTTP existantes conservent leurs sessions et leurs demandes d'approbation inchangées. Définissez server.stateless (ou fixez la révision à 2026-07-28, ci-dessous) pour servir 2026-07-28 nativement en HTTP :
stackql mcp \
--mcp.server.type=http \
--mcp.config '{"server": {"transport": "http", "address": "127.0.0.1:9912", "allow_unauthenticated": true, "stateless": true}}'
Un serveur sans session n'émet aucun Mcp-Session-Id, répond à GET et DELETE par 405 (il n'y a pas de session à fermer), garde tools/list, prompts/list et resources/list invariants d'une connexion à l'autre, et fait passer l'aller-retour d'approbation par input_required. Il accepte toujours le initialize d'un client plus ancien et lui sert les lectures, mais il ne peut pas conserver la capacité d'élicitation que ce client a déclarée à l'initialisation (chaque requête obtient une session éphémère) ; les clients plus anciens ne peuvent donc pas approuver les écritures soumises à approbation sur un serveur sans session. Choisissez stateless pour les hôtes à la révision actuelle et la valeur par défaut pour un parc qui comprend encore des clients plus anciens.
Le serveur ne conserve aucun état entre les appels : le mode, l'audit et les identifiants des providers relèvent de la configuration au niveau du processus, de sorte que rien n'a besoin d'être déplacé derrière des handles explicites.
Fixer la révision
Par défaut, le serveur annonce toutes les révisions prises en charge et négocie client par client. L'option --mcp.protocol.version, ou server.protocol_version dans l'objet de configuration (l'option l'emporte), définit la révision la plus récente annoncée :
# sessionless only; stateless Streamable HTTP is implied
stackql mcp \
--mcp.server.type=http \
--mcp.protocol.version=2026-07-28 \
--mcp.config '{"server": {"transport": "http", "address": "127.0.0.1:9912", "allow_unauthenticated": true}}'
# handshake lifecycle only
stackql mcp --mcp.server.type=stdio --mcp.protocol.version=2025-11-25
| Valeur | Annoncé | Effet |
|---|---|---|
auto (valeur par défaut) ou absente | Toutes les révisions prises en charge. | Négociation comme ci-dessus : la révision la plus élevée que les deux parties parlent. |
2026-07-28 | 2026-07-28 uniquement. | Sans session uniquement, et stateless est implicite pour Streamable HTTP. Le initialize d'un client plus ancien reçoit la réponse 2025-11-25, signal pour ce client de se déconnecter plutôt que de lire la réponse comme le nouveau cycle de vie. |
2025-11-25 (ou toute révision plus ancienne) | Cette révision et toutes les précédentes. | Cycle de vie à handshake uniquement : une requête 2026-07-28 reçoit l'erreur JSON-RPC -32022 avec data.supported listant les révisions annoncées, afin que le client puisse renégocier. Les clients à handshake plus anciens conservent leur propre révision. |
Toute autre valeur fait échouer la validation de la configuration au démarrage, et l'erreur indique les valeurs autorisées.
Limites de transport
Les corps des requêtes Streamable HTTP sont plafonnés à 4 MiB (HTTP 413 au-delà), un JSON imbriqué sur plus de 1000 niveaux est rejeté avant l'analyse, et une trame stdio est plafonnée à 8 MiB. Aucune de ces limites n'est configurable ; toutes se situent bien au-dessus de toute instruction SQL que le serveur accepte.
(Re)chargement des identifiants (--env.file + reload_credentials)
--env.file et l'outil reload_credentials sont disponibles dans les versions de StackQL postérieures à v0.10.542.
Le bloc d'environnement d'un processus est figé à son lancement. Cela pose deux problèmes pour les serveurs MCP :
- Un serveur MCP
stdiolancé par un client de bureau (Claude Desktop, Cursor, etc.) sans les variables d'environnement d'identifiants ne peut jamais les voir - le client transmet son propre environnement au sous-processus. - Les identifiants de courte durée renouvelés n'atteignent jamais une session de serveur de longue durée.
L'option --env.file comble ces deux lacunes en désignant un fichier de type dotenv qui sert de magasin d'identifiants modifiable :
stackql mcp --mcp.server.type=stdio --env.file /path/to/stackql-credentials.env
Sémantique du chargement
Le fichier est chargé dans l'environnement du processus au démarrage, pour chaque point d'entrée (exec, shell, srv, registry, mcp) :
- Lorsque l'option est vide ou absente, rien ne se passe - les identifiants sont résolus à la demande depuis l'environnement du processus au moment de la requête, exactement comme dans le comportement historique.
- Un fichier absent au chemin indiqué est une opération sans effet tolérée (le fichier peut être créé plus tard).
- Un fichier mal formé ou illisible est une erreur fatale au démarrage.
- Seules les clés dont la valeur n'est pas vide sont définies ; les variables d'environnement existantes du processus sont écrasées (le fichier est la source de vérité) ; rien n'est jamais supprimé.
- L'option est disponible en ligne de commande uniquement - elle n'est pas lue depuis
.stackqlrc.
Le format du fichier est un KEY=VALUE par ligne. Les commentaires #, les lignes vides, un préfixe export facultatif, des guillemets simples ou doubles facultatifs autour de la valeur et les fins de ligne CRLF sont tous tolérés :
# stackql-credentials.env
export OKTA_SECRET_KEY="00abc...xyz"
STACKQL_GITHUB_USERNAME=myuser
STACKQL_GITHUB_PASSWORD='ghp_mytoken'
reload_credentials
L'outil reload_credentials recharge le fichier --env.file dans l'environnement du processus en cours de session, puis indique l'état de résolution des identifiants par provider. Les valeurs des secrets ne sont jamais renvoyées, journalisées ni auditées - uniquement les noms et les états. Sans --env.file configuré, l'outil se réduit à une simple sonde d'état.
Lorsqu'une requête échoue à la résolution des identifiants, l'erreur MCP porte une indication invitant l'agent à appeler reload_credentials puis à réessayer ; les clients agentiques se rétablissent ainsi d'eux-mêmes : écrivez l'identifiant dans le fichier, demandez à l'agent de recharger, et la requête en échec réussit à la nouvelle tentative - aucun redémarrage du serveur n'est nécessaire.
reload_credentials n'est pas pris en charge en mode backend reverse_proxy - les requêtes s'exécutent dans le processus du serveur stackql distant ; l'outil renvoie donc une erreur invitant l'utilisateur à recharger sur le serveur sous-jacent.
Windows et Claude Desktop
setx écrit dans le registre, pas dans les processus en cours d'exécution, et Claude Desktop transmet son propre environnement (périmé) aux sous-processus MCP - les changements d'identifiants nécessitent donc normalement un redémarrage complet de Claude Desktop. Avec --env.file, le fichier d'identifiants peut être créé ou renouvelé à tout moment et reload_credentials le prend en compte sans aucun redémarrage. Consultez Utiliser StackQL avec Claude Desktop pour un exemple de configuration complet.
Authentification des clients HTTP
server.auth_token_env_var et server.allow_unauthenticated sont disponibles dans les versions de StackQL à partir de v0.12.742.
Le transport HTTP exige l'authentification des clients. server.auth_token_env_var nomme une variable d'environnement contenant un jeton bearer prépartagé ; chaque requête doit porter Authorization: Bearer <token>, faute de quoi elle reçoit la réponse 401. Le jeton est lu depuis l'environnement ; il n'apparaît donc jamais dans --mcp.config ni dans les arguments du processus.
export STACKQL_MCP_TOKEN="$(openssl rand -hex 32)"
stackql mcp \
--mcp.server.type=http \
--mcp.config '{"server": {"transport": "http", "address": "127.0.0.1:9912", "auth_token_env_var": "STACKQL_MCP_TOKEN"}}'
Servir sans jeton relève d'une activation explicite : définissez "allow_unauthenticated": true dans server. Sans aucune des deux clés, le serveur s'arrête au démarrage avec un message qui nomme les deux ; il s'arrête aussi si la variable du jeton est absente ou vide. À partir de la version v0.12.742, vous devez ajouter soit auth_token_env_var, soit "allow_unauthenticated": true à server lorsque vous utilisez le transport http.
TLS (tls_cert_file / tls_key_file) chiffre le transport mais n'authentifie pas le client ; associez-le à un jeton pour tout écouteur au-delà de l'interface de bouclage. Les requêtes de navigateur cross-origin (un Origin non concordant, ou un Sec-Fetch-Site cross-site) sont refusées avec 403, quelle que soit l'authentification. Le stackql_mcp_client fourni n'envoie aucun en-tête Authorization ; un serveur qu'il pilote doit donc activer explicitement le service sans authentification.
À partir de v1.0, démarrer le serveur avec --access.config remplace le contrôle par jeton partagé par une authentification par appelant : chaque requête HTTPS est vérifiée avec le schéma configuré (JWT, bearer statique ou TLS mutuel) et autorisée au regard des règles de politique. Le TLS du serveur est alors obligatoire, l'authentification local_os est refusée en HTTP, et une requête sans identifiants ne se rabat jamais sur le jeton d'environnement du serveur. La gestion des accès n'est pas disponible avec le type de serveur reverse_proxy.
Modes du serveur
server.mode choisit l'un des quatre contrats de sécurité. Tous les quatre autorisent SELECT et les lectures de métadonnées ; ils diffèrent dans leur traitement des mutations et des opérations de cycle de vie.
| Mode | SELECT / métadonnées | INSERT / UPDATE / REPLACE | DELETE | EXEC (cycle de vie) |
|---|---|---|---|---|
read_only | autorisé | refusé | refusé | refusé |
safe (valeur par défaut) | autorisé | approbation requise | approbation requise | approbation requise |
delete_safe | autorisé | autorisé | approbation requise | approbation requise |
full_access | autorisé | autorisé | autorisé | autorisé |
Refusé renvoie immédiatement une erreur au client.
Approbation requise utilise le flux d'élicitation MCP, dont la forme dépend de la révision du protocole négociée :
- Si le client a annoncé la capacité d'élicitation (à l'initialisation, ou dans les capacités client de
_metapar requête en2026-07-28), le serveur demande à l'utilisateur d'approuver l'action au moyen d'un court message (nom de l'outil, classe de requête, SQL). En2026-07-28, la demande est renvoyée sous la forme d'un résultatinput_requiredportant une requête d'entréeelicitation/createsous l'identifiantstackql_approval, et le client relance l'appel avec la réponse dansinputResponses; sur les révisions antérieures, le serveur envoie lui-même la requêteelicitation/createen cours d'appel. L'utilisateur accepte, refuse ou annule. - Si le client n'a pas annoncé l'élicitation, l'outil est refusé avec un message qui explique ce manque et oriente l'exploitant vers le mode
full_access.
L'approbation est donnée par le client ; elle protège donc contre un agent qui agit sans son utilisateur, pas contre un appelant non fiable. Associez le transport HTTP à l'authentification des clients lorsque les appelants ne sont pas de confiance.
Le mode est global pour chaque serveur. Il n'existe pas de dérogation par outil.
À partir de v1.0, run_select_query refuse INSERT, UPDATE, REPLACE, DELETE et EXEC dans tous les modes, y compris full_access ; l'erreur nomme run_mutation_query ou run_lifecycle_operation. Chaque outil porte aussi un title et les quatre indications de comportement MCP sous forme de booléens explicites (readOnlyHint, destructiveHint, idempotentHint, openWorldHint), dérivées de la même classification que celle appliquée par le contrôle de politique. openWorldHint vaut true pour list_registry, pull_provider, run_select_query, run_mutation_query et run_lifecycle_operation, qui atteignent les points de terminaison du registre ou des providers, et false pour les outils qui ne lisent que l'état local. Les indications sont consultatives, pour l'expérience utilisateur du client ; l'application reste du ressort du contrôle de politique.
À partir de la version v0.12.742, une charge utile contenant plusieurs instructions est contrôlée par son instruction la plus privilégiée dans tous les modes ; SELECT 1; DELETE ... est donc traité comme un DELETE et l'enregistrement d'audit porte le query_class mutation_delete. validate_select_query accepte exactement une instruction.
Changement de comportement du mode par défaut
Les versions précédentes n'appliquaient la sécurité qu'au moyen d'une seule option read_only: true/false dont la valeur par défaut était "aucune application". La valeur par défaut actuelle (mode: safe) soumet d'emblée les mutations à l'approbation de l'utilisateur. Les exploitants qui utilisent un client compatible avec l'élicitation (Claude Desktop, Cursor, Continue, etc.) verront une demande d'approbation par mutation. Les exploitants qui exécutent des automatisations, ou le stackql_mcp_client fourni (qui n'annonce pas l'élicitation), doivent activer explicitement mode: full_access pour exécuter des mutations et des opérations de cycle de vie.
La clé JSON / YAML héritée read_only: true est toujours acceptée par compatibilité ascendante et est traitée comme équivalente à mode: read_only.
Exemples
# Read-only: SELECTs proceed; mutations and lifecycle refused immediately.
stackql mcp \
--mcp.server.type=http \
--mcp.config '{"server": {"transport": "http", "address": "127.0.0.1:9912", "allow_unauthenticated": true, "mode": "read_only"}}'
# Delete-safe: INSERT/UPDATE proceed; DELETE and EXEC need approval.
stackql mcp \
--mcp.server.type=http \
--mcp.config '{"server": {"transport": "http", "address": "127.0.0.1:9912", "allow_unauthenticated": true, "mode": "delete_safe"}}'
# Full access: everything proceeds without prompting. Use only with trusted
# clients and operators.
stackql mcp \
--mcp.server.type=http \
--mcp.config '{"server": {"transport": "http", "address": "127.0.0.1:9912", "allow_unauthenticated": true, "mode": "full_access"}}'
Journal d'audit
Chaque appel d'outil écrit un enregistrement dans la destination d'audit configurée, en JSONL par défaut ou sous forme d'enregistrements de journal OpenTelemetry (voir Format de journal). L'audit est activé par défaut. L'audit répond à la question "qu'a fait l'agent", pas à "qu'a vu l'agent" - les lignes de résultat des instructions SELECT ne sont volontairement pas enregistrées, quel que soit le format.
Ce qui est enregistré
| Champ | Description |
|---|---|
timestamp | Heure réelle au début de l'appel (RFC3339). |
tool | Nom de l'outil (par exemple run_select_query). |
mode | Mode du serveur en vigueur au moment de l'appel. |
decision | allow / refuse_immediate / needs_approval_accepted / needs_approval_declined / needs_approval_cancelled / needs_approval_unavailable. |
query_class | select / mutation_create / mutation_delete / lifecycle / unknown. Pour une charge utile contenant plusieurs instructions, la classe de la plus privilégiée. |
sql | Chaîne SQL pour les outils de requête (run_select_query, run_mutation_query, run_lifecycle_operation, validate_select_query). |
args | Champs de hiérarchie pour les outils de métadonnées (list_*, describe_method) ; SQL + row_limit pour les outils de requête. |
duration_ms | Durée réelle du contrôle + du gestionnaire. |
error | Message d'erreur si l'outil a échoué ou a été refusé. |
Les lignes de résultat des instructions SELECT sont délibérément exclues - elles peuvent être très volumineuses et contenir des données sensibles.
Destination fichier
La seule destination fournie aujourd'hui est file. Un objet JSON par ligne, fsync après chaque enregistrement, rotation de type lumberjack par taille / âge / nombre de sauvegardes.
stackql mcp \
--mcp.server.type=http \
--mcp.config '{
"server": {
"transport": "http",
"address": "127.0.0.1:9912",
"allow_unauthenticated": true,
"audit": {
"file": {
"path": "/var/log/stackql-mcp.log",
"max_size_mb": 100,
"max_backups": 5,
"max_age_days": 30
}
}
}
}'
Deux façons d'indiquer l'emplacement :
audit.file.path- un chemin de fichier complet (absolu, ou relatif au répertoire de travail courant, cwd).audit.file.dir- un répertoire ; la destination y choisit le nom de basestackql_mcp_server_<RFC3339-utc-second>.log.
Lorsqu'aucun des deux n'est défini dans mcp.config, le serveur MCP donne à dir le répertoire de travail courant comme valeur par défaut, afin que les exploitants existants observent le même comportement qu'auparavant. Le paquet générique de destination sous-jacent refuse lui-même de choisir silencieusement un répertoire - la décision "où atterrissent les journaux" est toujours prise par l'appelant.
Le chemin absolu résolu est écrit sur stderr au démarrage sous la forme sink file: /path/to/file.log.
Format de journal
Le flux d'audit a deux encodages, écrits dans la même destination fichier :
stackql mcp --mcp.server.type=stdio --mcp.log.format=jsonl # default, unchanged
stackql mcp --mcp.server.type=stdio --mcp.log.format=otel # OTLP/JSON log records
L'option prévaut sur server.audit.format dans mcp.config ("audit": {"format": "otel"}). jsonl est compatible à l'octet près avec les enregistrements décrits ci-dessus. otel écrit un objet OTLP/JSON LogsData par ligne, la forme que le récepteur otlp_json_file de l'OpenTelemetry Collector ingère telle quelle (vérifié avec otelcol-contrib 0.160.0) ; le flux atteint donc n'importe quel pipeline OTLP sans processeur de transformation :
receivers:
otlp_json_file:
include: [/var/log/stackql-mcp.log]
exporters:
debug: {}
service:
pipelines:
logs:
receivers: [otlp_json_file]
exporters: [debug]
Chaque appel d'outil produit un enregistrement de journal ; un appel passé par le contrôle d'approbation produit un second enregistrement pour la décision d'élicitation. Les enregistrements d'un même appel partagent gen_ai.tool.call.id et un identifiant de trace. Un traceparent W3C fourni par l'appelant dans params._meta est respecté ; sinon, un identifiant de trace est généré par session MCP afin que les enregistrements d'une session d'agent puissent être corrélés.
L'ensemble d'attributs émis est une interface versionnée : le scope d'instrumentation est github.com/stackql/stackql/pkg/mcp_server/audit en version 1.0.0, et schemaUrl fixe les conventions stables à https://opentelemetry.io/schemas/1.44.0. Les attributs gen_ai.* et mcp.* suivent les conventions sémantiques GenAI et MCP, qui sont au statut Development ; la version du scope est incrémentée lorsque l'ensemble change.
| Attribut | Enregistrement | Valeur |
|---|---|---|
service.name, service.version | ressource | stackql, la version de StackQL |
gen_ai.operation.name | appel d'outil | execute_tool |
mcp.method.name | les deux | tools/call sur l'enregistrement d'appel d'outil, elicitation/create sur l'enregistrement de décision |
gen_ai.tool.name | les deux | Nom de l'outil |
gen_ai.tool.call.id | les deux | Généré par appel, partagé par les deux enregistrements |
mcp.protocol.version | les deux | Révision négociée |
mcp.session.id | les deux | Identifiant de session (absent pour les requêtes HTTP sans session) |
stackql.mode | les deux | Mode du serveur |
stackql.decision | les deux | La valeur decision du tableau ci-dessus |
stackql.query | appel d'outil | SQL tel quel, pour les outils de requête |
stackql.query_class | appel d'outil | La valeur query_class |
stackql.provider | appel d'outil | Provider, pour les outils de métadonnées |
stackql.query.source | appel d'outil | Identifiant d'entrée de la Query Library, lorsqu'il est fourni |
stackql.duration_ms | appel d'outil | Durée réelle |
stackql.rows_returned | appel d'outil | Nombre de lignes, pour les outils qui renvoient des lignes |
error.type, error.message | appel d'outil | En cas d'échec : la décision de refus, ou tool_error après le contrôle |
Le corps est execute_tool <tool> / elicitation <tool> ; la gravité est INFO, ou ERROR lorsque l'appel a échoué ou a été refusé. Le contrat de masquage est identique dans les deux formats : les valeurs de résultat ne sont jamais sérialisées, seule l'instruction qui les a produites l'est.
Modes de défaillance
Lorsque la destination renvoie une erreur, le comportement de la réponse dépend de audit.failure_mode.
| failure_mode | Effet |
|---|---|
strict (valeur par défaut) | L'appel d'outil renvoie l'erreur d'audit au client même si l'outil sous-jacent a réussi. C'est voulu : mieux vaut une réponse ambiguë pour le client qu'un DELETE non détecté. |
strict_mutations | Les SELECT / lectures de métadonnées se poursuivent avec une note sur stderr ; les mutations et les opérations de cycle de vie font remonter l'erreur d'audit. |
best_effort | Toujours journaliser sur stderr et poursuivre. |
Séquencement
L'écriture d'audit a lieu après l'exécution de l'outil (ou son blocage par le contrôle) mais avant le retour de la réponse au client. En mode strict, un échec d'écriture d'audit sur un DELETE réussi signifie que la ligne a disparu mais que le client reçoit une erreur - c'est voulu, afin qu'aucune mutation ne passe sans être auditée.
Désactiver l'audit
Pour désactiver entièrement l'audit (le comportement antérieur à PR2) :
stackql mcp \
--mcp.server.type=http \
--mcp.config '{"server": {"transport": "http", "address": "127.0.0.1:9912", "allow_unauthenticated": true, "audit": {"disabled": true}}}'
Outils MCP disponibles
Lorsqu'il s'exécute en tant que serveur MCP, StackQL expose les outils suivants, sous réserve de la liste d'autorisation enabled_tools configurée. Chacun renvoie à la fois une vue texte rendue (pour le LLM) et une charge utile structurée et typée (pour les clients programmatiques). Le rendu texte par défaut est un tableau markdown pour les résultats uniformes de plusieurs lignes, ou un bloc KV markdown pour les résultats clairsemés / à un seul enregistrement. Les outils qui ont des arguments acceptent un argument facultatif format (markdown ou json) qui remplace ce rendu ; sinon, le paramètre de rendu du serveur est utilisé. Les entrées ci-dessous listent les arguments propres à chaque tâche ; ? marque les entrées facultatives.
Cliquez sur le nom d'un outil pour accéder à sa page de référence complète, avec les entrées, le comportement de contrôle et un exemple de prompt.
| Outil | Rendu | Description | Entrées |
|---|---|---|---|
server_info | KV | Identité et runtime du serveur : version de stackql, moteur SQL sous-jacent, emplacement du registre de providers, mode, option de lecture seule. Appelez-le une fois en début de session. | aucune |
list_providers | Tableau | Providers déjà téléchargés dans le cache local - sommet de la hiérarchie. | aucune |
list_services | Tableau | Services d'un provider. | provider |
list_resources | Tableau | Ressources d'un provider.service. | provider, service |
list_methods | Tableau | Méthodes d'accès (opérations HTTP) d'une ressource, avec le verbe SQL auquel chacune correspond et ses paramètres obligatoires. Appelez-le avant d'écrire toute requête - c'est ici que les paramètres WHERE obligatoires sont déduits. | provider, service, resource |
describe_method | KV | Contrat d'E/S complet d'une méthode (toujours EXTENDED) : entrées obligatoires et facultatives, et champs de sortie qu'un SELECT peut référencer. | provider, service, resource, method |
query_library_search | Tableau | Trouve des modèles de requête sélectionnés à partir d'une intention en langage naturel. En lecture seule ; les entrées de mutation nécessitent une activation explicite et sont exclues en mode read_only. | intent, provider?, service?, tags?, include_mutations?, limit? |
query_library_get | KV | Récupère un modèle et ses déclarations de paramètres. Avec un params non vide, valide les valeurs et renvoie le SQL rendu ainsi que next_tool, sans l'exécuter. | id, params? |
validate_select_query | KV | Analyse et planifie un seul SELECT sans l'exécuter. Renvoie {valid, errors}. SELECT uniquement ; exactement une instruction. | sql |
run_select_query | Tableau | Exécute un SELECT. Renvoie {rows}. Lectures uniquement. | sql, row_limit? |
run_mutation_query | KV | Exécute INSERT/UPDATE/REPLACE/DELETE sur le provider. Effets de bord réels. Renvoie {messages, timestamp}. Contrôlé par le mode du serveur. | sql |
run_lifecycle_operation | KV | Exécute une opération de cycle de vie EXEC de stackql. Renvoie {messages, timestamp}. Contrôlé par le mode du serveur. | sql |
list_registry | Tableau | Providers (et leurs versions) disponibles dans le registre configuré. À distinguer de list_providers, qui ne liste que les providers déjà téléchargés. | provider? |
pull_provider | KV | Installe un seul provider depuis le registre dans le cache local. État du cache local uniquement - aucun effet sur le plan de contrôle ou le plan de données du cloud. | provider, version? |
reload_credentials | Tableau | Recharge les identifiants depuis le fichier dotenv --env.file dans l'environnement du processus et indique l'état de résolution par provider (ok, unresolved, not_checked). Ne renvoie jamais les valeurs des secrets. Autorisé dans tous les modes. | provider? |
Consultez query_library_search avant d'écrire du SQL à partir de zéro, puis utilisez query_library_get pour inspecter et rendre un modèle correspondant. Les outils de requête acceptent aussi un argument facultatif source contenant l'identifiant de l'entrée de la Query Library, à des fins d'attribution uniquement ; l'exécution reste soumise au mode du serveur et à la politique d'approbation habituels.
describe_resource a été retiré dans StackQL v0.12.732 ; les clients MCP, les prompts ou les instructions d'agent qui l'appelaient doivent appeler à la place list_methods puis describe_method. Une ressource n'a pas de liste de champs unique, car chaque méthode d'accès renvoie sa propre forme ; les noms de colonnes proviennent donc de describe_method pour la méthode vers laquelle une requête est routée. L'instruction SQL DESCRIBE est inchangée.
Prompts MCP disponibles
Un seul prompt statique est publié.
| Prompt | Description |
|---|---|
write_safe_select | Conseils pour écrire des requêtes SELECT sûres sur les ressources stackql. Explique comment utiliser SHOW METHODS IN <provider>.<service>.<resource> pour découvrir la bonne méthode de lecture et les paramètres WHERE obligatoires. |
Options
| Option | Description |
|---|---|
--mcp.server.type | Type de serveur MCP : http, stdio ou reverse_proxy (ce dernier s'utilise avec stackql srv). |
--mcp.config | Objet de configuration JSON du serveur MCP. YAML est également accepté. |
--mcp.protocol.version | Révision du protocole la plus récente annoncée : auto (valeur par défaut), 2026-07-28 ou une révision plus ancienne telle que 2025-11-25. Consultez Fixer la révision. |
--env.file | Fichier d'identifiants de type dotenv chargé au démarrage et rechargé à la demande par l'outil reload_credentials. Consultez (Re)chargement des identifiants. |
--pgsrv.port | Port TCP du serveur de protocole filaire PostgreSQL (utilisé avec stackql srv). |
-H, --help | Affiche les informations d'aide. |
-v, --verbose | Exécute en mode verbeux avec une sortie supplémentaire. |
consultez Options globales pour des options supplémentaires
Vous devez définir les variables d'environnement requises pour l'authentification des providers avant de démarrer le serveur MCP, ou désigner un fichier d'identifiants de type dotenv avec --env.file. Pour plus d'informations, consultez Utiliser un provider.
Exemples
Serveur MCP autonome de base
Lancez un serveur MCP autonome avec l'authentification du provider et un jeton bearer pour ses clients :
export GOOGLE_CREDENTIALS=$(cat /path/to/google-credentials.json)
export STACKQL_MCP_TOKEN="$(openssl rand -hex 32)"
stackql mcp \
--mcp.server.type=http \
--mcp.config '{"server": {"transport": "http", "address": "127.0.0.1:9912", "auth_token_env_var": "STACKQL_MCP_TOKEN"}}' \
--registry='{"url": "https://registry.stackql.io/providers"}' \
--auth='{"google": {"type": "service_account", "credentialsfilepath": "/path/to/google-credentials.json"}}'
Serveur MCP avec serveur PostgreSQL (en mémoire)
Exécutez les serveurs MCP et PostgreSQL pour un accès par les deux protocoles :
export GOOGLE_CREDENTIALS=$(cat /path/to/google-credentials.json)
stackql srv \
--mcp.server.type=http \
--mcp.config '{"server": {"transport": "http", "address": "127.0.0.1:9912", "allow_unauthenticated": true}}' \
--pgsrv.port 5665 \
--registry='{"url": "https://registry.stackql.io/providers"}' \
--auth='{"google": {"type": "service_account", "credentialsfilepath": "/path/to/google-credentials.json"}}'
Serveur d'inventaire en lecture seule avec audit vers un chemin connu
Utile pour un agent d'analyse d'inventaire qui ne doit jamais effectuer de mutation :
stackql mcp \
--mcp.server.type=http \
--mcp.config '{
"server": {
"transport": "http",
"address": "127.0.0.1:9912",
"allow_unauthenticated": true,
"mode": "read_only",
"audit": {"file": {"path": "/var/log/stackql-mcp-audit.log"}}
}
}' \
--registry='{"url": "https://registry.stackql.io/providers"}' \
--auth='{"google": {"type": "service_account", "credentialsfilepath": "/path/to/google-credentials.json"}}'
Serveur d'automatisation en accès complet
Pour les pipelines d'automatisation de confiance qui ont besoin de mutations et ne peuvent pas répondre aux demandes d'élicitation. Le pipeline présente le jeton bearer contenu dans STACKQL_MCP_TOKEN :
stackql mcp \
--mcp.server.type=http \
--mcp.config '{
"server": {
"transport": "http",
"address": "127.0.0.1:9912",
"auth_token_env_var": "STACKQL_MCP_TOKEN",
"mode": "full_access"
}
}' \
--registry='{"url": "https://registry.stackql.io/providers"}' \
--auth='{"google": {"type": "service_account", "credentialsfilepath": "/path/to/google-credentials.json"}}'
Serveur MCP sécurisé avec TLS
Lancez un serveur MCP avec chiffrement TLS en mode proxy inverse :
Générez d'abord les certificats TLS (auto-signés pour le développement) :
openssl req -x509 -newkey rsa:4096 -keyout server_key.pem -out server_cert.pem -days 365 -nodes
Démarrez ensuite le serveur :
stackql srv \
--mcp.server.type=reverse_proxy \
--mcp.config '{
"server": {
"tls_cert_file": "server_cert.pem",
"tls_key_file": "server_key.pem",
"transport": "http",
"address": "127.0.0.1:9004",
"auth_token_env_var": "STACKQL_MCP_TOKEN"
},
"backend": {
"dsn": "postgres://stackql:stackql@127.0.0.1:5446?default_query_exec_mode=simple_protocol"
}
}' \
--pgsrv.port 5446 \
--registry='{"url": "https://registry.stackql.io/providers"}' \
--auth='{"google": {"type": "service_account", "credentialsfilepath": "/path/to/google-credentials.json"}}'
Tester votre serveur MCP
Le dépôt fournit un client MCP de développement (stackql_mcp_client) pour les scripts et les tests de régression. Compilez-le avec :
python cicd/python/build.py --build-mcp-client
Cela produit ./build/stackql_mcp_client.
Notez que stackql_mcp_client n'envoie aucun en-tête Authorization, de sorte que le serveur qu'il cible doit définir "allow_unauthenticated": true (comme le font les exemples ci-dessus) ; un serveur protégé par jeton lui répond par 401. Il n'annonce pas non plus la capacité d'élicitation MCP - il est destiné aux scripts non interactifs. Face à un serveur safe ou delete_safe, il reçoit le refus "client does not support elicitation" sur les appels de mutation et de cycle de vie. Pour des tests interactifs avec des demandes d'élicitation, utilisez un client MCP embarqué dans un éditeur (Claude Desktop, Cursor, Continue).
# List all available tools
./build/stackql_mcp_client exec \
--client-type=http \
--url=http://127.0.0.1:9912
# Server identity, mode, audit / registry context
./build/stackql_mcp_client exec \
--client-type=http \
--url=http://127.0.0.1:9912 \
--exec.action server_info
# Re-source the --env.file credentials file and report per-provider
# credential status - a good first diagnostic when queries fail on auth
./build/stackql_mcp_client exec \
--client-type=http \
--url=http://127.0.0.1:9912 \
--exec.action reload_credentials
# List providers already pulled into the local cache
./build/stackql_mcp_client exec \
--client-type=http \
--url=http://127.0.0.1:9912 \
--exec.action list_providers
# List providers (and versions) available in the registry
./build/stackql_mcp_client exec \
--client-type=http \
--url=http://127.0.0.1:9912 \
--exec.action list_registry
# Install a provider from the registry into the local cache
./build/stackql_mcp_client exec \
--client-type=http \
--url=http://127.0.0.1:9912 \
--exec.action pull_provider \
--exec.args '{"provider": "kafka"}'
# List services for a provider
./build/stackql_mcp_client exec \
--client-type=http \
--url=http://127.0.0.1:9912 \
--exec.action list_services \
--exec.args '{"provider": "google"}'
# List access methods for a resource (this is how an agent finds required
# WHERE parameters before writing a query)
./build/stackql_mcp_client exec \
--client-type=http \
--url=http://127.0.0.1:9912 \
--exec.action list_methods \
--exec.args '{"provider": "google", "service": "compute", "resource": "networks"}'
# Validate a SELECT without executing
./build/stackql_mcp_client exec \
--client-type=http \
--url=http://127.0.0.1:9912 \
--exec.action validate_select_query \
--exec.args '{"sql": "select name from google.compute.networks where project = '"'"'my-project'"'"';"}'
# Execute a SELECT
./build/stackql_mcp_client exec \
--client-type=http \
--url=http://127.0.0.1:9912 \
--exec.action run_select_query \
--exec.args '{"sql": "select name from google.compute.networks where project = '"'"'my-project'"'"';"}'
# Mutation - succeeds only against a full_access server, or against
# delete_safe (for INSERT/UPDATE) or safe with an elicitation-capable client.
./build/stackql_mcp_client exec \
--client-type=http \
--url=http://127.0.0.1:9912 \
--exec.action run_mutation_query \
--exec.args '{"sql": "delete from google.compute.firewalls where project = '"'"'my-project'"'"' and firewall = '"'"'old-rule'"'"';"}'
Exemples de réponses
server_info (sur un serveur en mode par défaut) :
{
"version": "0.10.444",
"commit": "abc1234",
"build_date": "2026-05-16T10:47:33Z",
"platform": "linux/amd64",
"transport": "http",
"sql_backend": "sqlite3",
"provider_registry": "https://registry.stackql.io/providers",
"mode": "safe",
"is_read_only": false
}
run_select_query :
{
"rows": [
{"name": "default"},
{"name": "pathfinders-test-01"},
{"name": "returning-test-03"}
]
}
run_mutation_query (sur un serveur full_access) :
{
"messages": ["The operation was despatched successfully"],
"timestamp": "2026-05-16T10:47:33+10:00 AEST"
}
Exemple de ligne du journal d'audit pour la même mutation :
{"timestamp":"2026-05-16T00:47:33Z","tool":"run_mutation_query","mode":"full_access","decision":"allow","query_class":"mutation_delete","sql":"delete from google.compute.firewalls where project = 'my-project' and firewall = 'old-rule';","args":{"sql":"delete from google.compute.firewalls where project = 'my-project' and firewall = 'old-rule';","row_limit":0},"duration_ms":42}
Intégration avec les assistants IA
Pour intégrer le serveur MCP de StackQL à un assistant IA, enregistrez stackql comme serveur MCP dans la configuration de l'assistant. La plupart des clients MCP embarqués dans un éditeur exécutent le serveur sur stdio ; pour ceux-ci, utilisez --mcp.server.type=stdio et l'assistant lance directement le processus. Les agents autonomes qui parlent HTTP peuvent se connecter à un processus stackql mcp --mcp.server.type=http de longue durée.
Pour Claude Desktop - y compris la fiche de l'Anthropic Connector Directory (la méthode d'installation recommandée), le MCP Bundle téléchargeable (.mcpb) et la configuration manuelle - consultez Utiliser StackQL avec Claude Desktop.
L'emplacement des fichiers de configuration varie selon le système d'exploitation et l'assistant IA. Consultez la documentation de votre assistant IA pour connaître le chemin et le format corrects.
Considérations d'architecture
Pour choisir un mode de déploiement, tenez compte des points suivants :
- Autonome (
stackql mcp) : configuration la plus simple, idéale pour le développement et pour les clients embarqués dans un éditeur surstdio. - Double serveur en mémoire (
stackql srvavecmcp.server.type=http) : un seul processus sert à la fois le protocole MCP et le protocole filaire PostgreSQL. Meilleures performances, convient à la plupart des déploiements en production. - Proxy inverse (
stackql srvavecmcp.server.type=reverse_proxy) :- permet de séparer les charges de travail entre processus ou hôtes
- prend en charge le chiffrement TLS pour des points de terminaison MCP sécurisés
- permet la mise à l'échelle indépendante des interfaces MCP et PostgreSQL
- offre de la souplesse pour l'intégration de CA d'entreprise (remarque : la prise en charge des CA d'entreprise est expérimentale)
Et séparément, en matière de sécurité :
- Commencez avec la valeur par défaut
mode: safe. Les clients compatibles avec l'élicitation (Claude Desktop, Cursor, Continue) demandent confirmation à l'utilisateur avant toute mutation. - Fixez
mode: read_onlypour les agents d'inventaire ou d'analyse qui ne doivent jamais écrire. - Fixez
mode: delete_safelorsque vous voulez une liberté de création et de mise à jour, tout en gardant un humain dans la boucle pour les opérations destructrices. - Réservez
mode: full_accessaux pipelines d'automatisation de confiance, et uniquement en association avec un journal d'audit que quelqu'un examine. - Définissez
server.auth_token_env_varsur tout écouteur HTTP que d'autres processus ou hôtes peuvent atteindre ;allow_unauthenticatedest destiné au développement local. TLS seul n'authentifie pas les clients.
Lorsque vous utilisez TLS avec des autorités de certification (CA) d'entreprise, une configuration supplémentaire peut être nécessaire. Cette fonctionnalité est expérimentale et peut nécessiter des ajustements selon votre implémentation de CA.
Pour aller plus loin
- La référence pour les développeurs du paquet est le README de
pkg/mcp_serverdans le dépôt stackql. - La documentation technique destinée aux contributeurs se trouve dans
docs/mcp.mddans le dépôt stackql et comprend des exemples de réponses détaillés pour chaque outil.