Guide · IA & agents
Claude Code et PostgreSQL en lecture seule
Rôle limité, pgpass, et le serveur MCP que la doc Claude Code montre pour PostgreSQL. Pages relues le 18 octobre 2026, rien n'a été exécuté.
Relier Claude Code à PostgreSQL passe par un serveur MCP, pas par une option claude postgres. Le protocole, sur la page d'introduction relue le 18 octobre 2026, est un standard ouvert pour brancher une application d'IA sur des outils et des données extérieurs. Claude Code documente la connexion dans sa page MCP. PostgreSQL documente les rôles, les droits, l'URI de connexion et le fichier de mots de passe. Ce guide assemble ces pages. Il n'a exécuté aucune commande, et il n'a reçu aucune ligne d'une base.
Deux guides du site couvrent un terrain voisin, sans le remplacer. Utiliser MCP avec Claude Code pose le cadre. Connecter MCP à PostgreSQL traite le pilote côté base, pas les commandes claude mcp relues ici. Si le serveur doit être le vôtre, créer un serveur MCP en TypeScript est l'autre piste. La page MCP de Claude Code dit aussi qu'un serveur qui rapporte du contenu externe expose à l'injection de prompt. Une base n'est pas un fichier statique : une cellule peut contenir une instruction. Un rôle en lecture seule limite les écritures. Il ne filtre pas ce que le modèle lit.
Prérequis
Claude Code installé et authentifié, d'après le quickstart MCP. L'installation de la commande est dans Installer Claude Code. Il faut aussi une instance PostgreSQL de test, pas la production. Vous devez pouvoir créer un rôle, donc avoir le privilège CREATEROLE ou être superuser, selon la page CREATE ROLE.
Le dépôt des serveurs de référence MCP, relu le même jour, classe le serveur PostgreSQL parmi les serveurs archivés. La ligne dit « read-only database access with schema inspection » et renvoie vers le dépôt archivé. Ce guide ne donne pas la commande npx de ce serveur archivé : elle n'a pas été relue sur sa page. Le chemin que la doc Claude Code montre, elle, est un autre paquet.
Le serveur que la page Claude Code montre
La section « Example: Query your PostgreSQL database », sur la page MCP relue en markdown le 18 octobre 2026, cite DBHub, paquet @bytebase/dbhub. Ce n'est pas un serveur Anthropic. La page dit qu'il se connecte par la chaîne passée à --dsn, et qu'il faut un utilisateur de base en lecture seule pour que les requêtes lancées par Claude ne puissent pas modifier les données. La page ne dit pas que le paquet impose lui-même une transaction en lecture seule. Ne le supposez pas.
Commande de la page, non rejouée :
claude mcp add --transport stdio db -- npx -y @bytebase/dbhub \
--dsn "postgresql://readonly:***@prod.db.com:5432/analytics"
Le nom d'hôte de l'exemple est prod.db.com, base analytics, utilisateur readonly, port 5432. Le mot de passe apparaît comme *** dans la page markdown relue. Ne remplacez pas ces astérisques par un secret sur la ligne de commande. La page CREATE ROLE de PostgreSQL avertit qu'un mot de passe en clair peut finir dans l'historique du client ou dans le journal du serveur. L'hôte prod de l'exemple n'est pas un premier essai.
Pour confirmer le démarrage, la page dit de lancer /mcp et de vérifier que la ligne db montre une coche. Puis elle propose des questions du type chiffre d'affaires du mois. Ces questions supposent une base métier. Elles ne sont pas un test de connexion. Ne les posez pas sur une base dont vous n'avez pas borné le rôle.
claude mcp add s'exécute dans le terminal, pas dans une session claude, selon le quickstart. Le -- sépare les options de Claude Code de la commande du serveur. Sans lui, un drapeau du serveur peut être lu comme un drapeau de claude. Le quickstart dit aussi que la première vérification d'un serveur lancé par npx peut afficher un échec de connexion pendant le téléchargement du paquet. Attendre et relancer claude mcp list est le geste documenté, pas changer de paquet tout de suite.
Un rôle qui ne peut pas tout faire
CREATE ROLE ajoute un rôle au cluster, visible dans toutes les bases du cluster. Sans option, NOSUPERUSER, NOCREATEDB et NOCREATEROLE sont les défauts. LOGIN n'est pas le défaut, sauf si vous passez par CREATE USER, qui implique LOGIN. L'exemple de la page, non rejoué :
CREATE ROLE jonathan LOGIN;
jonathan est le nom de l'exemple. Prenez un autre nom si celui-ci existe déjà. Ne copiez pas l'exemple suivant de la même page, qui pose un mot de passe dans la commande SQL (CREATE USER davide WITH PASSWORD ...). La page dit que ce mot de passe voyage en clair, et que psql a une commande \password pour le changer ensuite. Ce guide ne réécrit pas la syntaxe de \password : elle est nommée sur la page CREATE ROLE, pas détaillée dans l'extrait de psql relu.
Les droits se donnent avec GRANT. Le synopsis, relu le 18 octobre 2026, prévoit notamment CONNECT sur une base, USAGE sur un schéma, et SELECT sur une table. Les exemples de la page sont autres (GRANT INSERT ON films TO PUBLIC, GRANT ALL PRIVILEGES ON kinds TO manuel). Les trois lignes suivantes sont donc composées à partir du synopsis, avec les noms d'exemple jonathan et films. Elles n'apparaissent pas telles quelles dans la doc, et elles n'ont pas été exécutées. Remplacez la base, le schéma et la table :
GRANT CONNECT ON DATABASE mydb TO jonathan;
GRANT USAGE ON SCHEMA public TO jonathan;
GRANT SELECT ON TABLE films TO jonathan;
GRANT sur une table n'étend pas les droits aux séquences, y compris celles des colonnes SERIAL. La page le dit. Un SELECT qui appelle nextval peut donc échouer même après un SELECT sur la table. C'est une raison de plus de tester sur une copie, pas une raison de donner ALL PRIVILEGES.
Le propriétaire d'une table a tous les droits par défaut. Le rôle du serveur MCP ne doit pas être ce propriétaire. La page GRANT dit qu'il n'est pas nécessaire d'accorder des privilèges au propriétaire. Inversement, ne connectez pas Claude Code avec le rôle qui a créé les tables.
Lecture seule, au sens de PostgreSQL
SET TRANSACTION connaît READ ONLY. La page dit qu'une transaction en lecture seule interdit, entre autres, INSERT, UPDATE, DELETE, MERGE, COPY FROM hors table temporaire, ainsi que CREATE, ALTER, DROP, GRANT, REVOKE et TRUNCATE. Ce n'est pas une absence de toute écriture disque. La page le dit : c'est une notion de haut niveau.
SET TRANSACTION sans BEGIN ou START TRANSACTION préalable émet un avertissement et n'a pas d'effet. Pour les transactions suivantes de la session, le synopsis donne SET SESSION CHARACTERISTICS AS TRANSACTION, avec READ ONLY parmi les modes. La ligne suivante est composée à partir de ce synopsis. Les exemples de la page portent sur les snapshots, pas sur cette forme. Elle n'a pas été exécutée :
SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY;
Le paramètre default_transaction_read_only, sur la page des défauts client, commande le même statut par défaut. Le défaut documenté est off, donc lecture-écriture. Un rôle applicatif qui n'a reçu que SELECT reste le verrou principal. La caractéristique de transaction est un second verrou, pas un remplacement du GRANT.
L'URI de connexion, section 32.1.1.2, a la forme postgresql://[userspec@][hostspec][/dbname][?paramspec]. Parmi les exemples valides de la page : postgresql://localhost/mydb et postgresql://user@localhost. Le schéma peut être postgresql:// ou postgres://. Une substitution de l'exemple DBHub, pour une base locale et sans mot de passe dans la commande, serait :
claude mcp add --transport stdio db -- npx -y @bytebase/dbhub \
--dsn "postgresql://jonathan@localhost/mydb"
Ce n'est pas la commande de la page Claude Code. C'est son --dsn remplacé par une URI de la doc PostgreSQL, avec le rôle de l'exemple CREATE ROLE. Non rejouée. Si le nom db existe déjà dans la config locale, le quickstart dit que claude mcp add échoue. claude mcp remove retire l'entrée. S'il existe à plusieurs portées, il faut --scope.
Ne pas mettre le secret dans le dépôt
Par défaut, claude mcp add écrit en portée locale : vous seul, ce projet, dans ~/.claude.json. --scope user vise tous vos projets, toujours dans ~/.claude.json. --scope project écrit .mcp.json à la racine, prévu pour être commité. Une chaîne avec un secret n'a rien à faire dans ce fichier. La page MCP le dit pour les serveurs à identifiants que vous ne voulez pas dans le contrôle de version : portée locale.
Le fichier de mots de passe libpq est ~/.pgpass sur Unix, ou %APPDATA%\postgresql\pgpass.conf sur Windows. Format relu :
hostname:port:database:username:password
Le premier champ peut être *. Les entrées plus précises viennent en premier. Sur Unix, si les permissions laissent le groupe ou le reste lire le fichier, il est ignoré. La page donne :
chmod 0600 ~/.pgpass
Commande non rejouée. N'écrivez pas le mot de passe avec une commande shell qui resterait dans l'historique. La page décrit le format. Elle ne donne pas de echo vers le fichier.
psql peut recevoir une URI via -d, et une meta-commande seule via -c. Assemblage non exécuté, à partir de ces deux options et de l'URI documentée :
psql -d postgresql://localhost/mydb -c '\dp'
\dp liste tables, vues et séquences avec leurs privilèges. C'est le contrôle de droits nommé dans le manuel psql, pas une preuve que le serveur MCP est connecté.
La page libpq avertit aussi : si des utilisateurs non fiables accèdent à une base qui n'a pas un schéma d'usage sûr, retirer les schémas inscriptibles par tous du search_path au début de session. Un agent qui envoie du SQL arbitraire est dans ce cas. Le détail du motif sûr est sur la page des schémas, non recopiée ici.
Erreur fréquente
Coller l'exemple prod.db.com avec un vrai mot de passe dans le terminal, puis committer .mcp.json parce que --scope project semblait « plus propre pour l'équipe ». La portée projet est faite pour partager un serveur. Elle n'est pas faite pour partager un secret. La portée locale garde la définition dans le fichier maison. Le mot de passe, s'il faut un mot de passe, va dans .pgpass avec chmod 0600, pas dans la commande claude mcp add.
L'autre message, pendant le premier npx, est un échec de connexion alors que le paquet se télécharge encore. Le quickstart le décrit pour un serveur local. Relancer claude mcp list après un court délai est le geste écrit. Si l'échec reste, lancer la commande du serveur directement dans le terminal montre l'erreur sous-jacente. Pour un paquet npx, la page quickstart le fait avec l'exemple Playwright. Le même geste, appliqué au paquet de la page MCP et non rejoué :
npx -y @bytebase/dbhub
Sans --dsn, ce lancement ne reprend pas la configuration Claude Code. Il sert à voir si Node et le paquet répondent. La page quickstart dit : si la commande démarre et attend, le serveur lui-même peut tourner, et il faut comparer avec claude mcp get et le séparateur --. Si la commande échoue, le message nomme ce qui manque.
Vérification
Dans l'ordre, et seulement sur la base de test :
psql -V
-V imprime la version de psql et quitte. C'est le contrôle que le client est là. Il ne parle pas à votre rôle applicatif.
Puis \dp via le psql -c ci-dessus, pour voir si jonathan a bien SELECT et pas le reste. Puis, hors session :
claude mcp list
Le quickstart associe ✔ Connected à un serveur prêt, et ✘ Failed to connect à une absence de réponse. Certains consoles Windows affichent d'autres glyphes. Dans une session, /mcp est le contrôle que la page de l'exemple PostgreSQL nomme : une coche sur la ligne db. Aucun de ces états n'a été observé ici. Une coche ne dit pas que le rôle est en lecture seule. Ça, c'est \dp et les GRANT, pas le statut MCP.
Sources
Pages relues le 18 octobre 2026 :
- Connect Claude Code to tools via MCP, y compris la version markdown de la même page pour la section PostgreSQL
- Connect to MCP servers
- What is the Model Context Protocol (MCP)?
- README des serveurs de référence MCP
- CREATE ROLE
- GRANT
- SET TRANSACTION
- Client Connection Defaults
- Connection URIs
- The Password File
- psql
Sources recontrôlées le 19 octobre 2026. Les GRANT, le SET SESSION CHARACTERISTICS et l'URI locale dans claude mcp add sont des assemblages signalés comme tels. Le serveur PostgreSQL archivé n'est pas proposé comme installation. Pas de capture, pas de tarif, pas de résultat de requête.