Skip to main content

QGIS MCP

Références


Architecture

Claude Code ↔ Serveur MCP Python (uvx) ↔ socket TCP local ↔ Plugin QGIS (dock "QGIS MCP")

Le plugin QGIS crée un serveur TCP local. Le serveur MCP Python (lancé par Claude Code via uvx) s'y connecte. QGIS doit être ouvert et le serveur démarré avant de lancer Claude Code.


Prérequis

Installer uv (gestionnaire de paquets Python) si absent :

winget install astral-sh.uv

Installation

1. Plugin dans QGIS

Extensions > Installer/Gérer les extensions > chercher QGIS MCP > Installer.

Redémarrer QGIS, puis cliquer Start Server dans le dock QGIS MCP.

2. Enregistrer le MCP dans Claude Code

claude mcp add -s user qgis -- uvx --from https://github.com/nkarasiak/qgis-mcp/archive/refs/heads/main.zip qgis-mcp-server

-s user = enregistrement global (tous les projets Claude Code).

3. Vérifier

Dans une session Claude Code avec QGIS ouvert et le serveur démarré, demander diagnose — confirme la synchronisation plugin/serveur MCP.


Ordre de démarrage (à chaque session)

  1. Ouvrir QGIS
  2. Cliquer Start Server dans le dock QGIS MCP
  3. Lancer Claude Code

Authentification (optionnel, machines partagées)

Définir QGIS_MCP_TOKEN=votre-secret dans l'environnement QGIS, redémarrer le serveur, puis ajouter la même variable à la config MCP :

"env": { "QGIS_MCP_TOKEN": "votre-secret" }

Capacités principales

Catégorie Exemples
Couches Charger Shapefile, GeoJSON, WMS, PostGIS ; lister, supprimer
Traitements Buffer, intersection, statistiques zonales (1000+ algorithmes)
Symbologie Modifier couleurs, classification, étiquettes
Export PNG, PDF, carte mise en page
SQL cross-couches Requêtes spatiales directement depuis Claude
Mise en page/Atlas Créer et exporter des atlas cartographiques

Lien avec PostGIS Alteris

La base alteris_geo (79.137.14.202:5432, user alteris_admin) est directement utilisable depuis QGIS MCP : Claude peut interroger PostGIS en SQL spatial, charger le résultat comme couche QGIS, styliser et exporter en PDF — sans intervention manuelle.

Le port 5432 n'est pas exposé publiquement (pare-feu VPS). Connexion via tunnel SSH obligatoire (voir section Tunnel SSH).


Tunnel SSH vers PostGIS Alteris

Option 1 — Tunnel manuel (terminal externe)

Lancer avant QGIS/Claude Code :

ssh -L 5433:localhost:5432 debian@79.137.14.202 -N

Puis se connecter sur localhost:5433 au lieu de 79.137.14.202:5432.

Option 2 — Tunnel automatique via paramiko (PyQGIS)

Permet d'ouvrir le tunnel directement depuis un script PyQGIS sans terminal externe. Voir section Journal — 2026-06-20.


Connexion PostGIS depuis PyQGIS

Charger une couche PostGIS

from qgis.core import QgsProject, QgsVectorLayer

uri = (
    "host=localhost port=5433 dbname=alteris_geo "
    "user=alteris_admin password=Alteris2026 sslmode=disable "
    'table="altfoncier_28051"."28051_plu_zonage" (geom) sql='
)
layer = QgsVectorLayer(uri, "PLU Zonage 28051", "postgres")
QgsProject.instance().addMapLayer(layer)

Point clé — champ JSONB props

Les tables altfoncier ont leurs attributs métier dans un champ props de type JSONB. Dans PyQGIS, ce champ est un dict Python (pas une chaîne). Pour y accéder en expression QGIS :

map_get("props", 'typezone')   ✓ correct
"props" LIKE '%typezone%'      ✗ ne fonctionne pas (props n'est pas une chaîne)

Stylisation CNIG PLU (zonage)

Renderer catégorisé sur map_get("props", 'typezone') :

typezone Couleur remplissage Couleur bordure Label U #FFFF73 #A3A300 Zones urbaines AU #FFAA00 #CD6600 Zones à urbaniser A #D3FFBE #267300 Zones agricoles N #98E600 #267300 Zones naturelles et forestières
from qgis.core import QgsCategorizedSymbolRenderer, QgsRendererCategory, QgsFillSymbol

cnig = {
    'U':  ('#FFFF73', '#A3A300', 'Zones urbaines (U)'),
    'AU': ('#FFAA00', '#CD6600', 'Zones à urbaniser (AU)'),
    'A':  ('#D3FFBE', '#267300', 'Zones agricoles (A)'),
    'N':  ('#98E600', '#267300', 'Zones naturelles et forestières (N)'),
}
categories = []
for tz, (fill, border, label) in cnig.items():
    symbol = QgsFillSymbol.createSimple({
        'color': fill, 'outline_color': border, 'outline_width': '0.26'
    })
    categories.append(QgsRendererCategory(tz, symbol, label))

renderer = QgsCategorizedSymbolRenderer("map_get(\"props\", 'typezone')", categories)
layer.setRenderer(renderer)
layer.triggerRepaint()

Journal de session

2026-06-20 — Premier diagnostic validé

Première connexion réussie entre Claude Code et QGIS via MCP. Résultat du diagnose :

Vérification Résultat
QGIS 4.0.3-Norrköping
Python 3.12.13
Qt 6.11.0
Plugin MCP 0.5.0 (serveur et plugin synchronisés)
Clients connectés 1
Providers de traitement 3d, gdal, grass, model, native, pdal, project, qgis, quickosm, script
Projet ouvert Aucun (layer_count = 0)

Statut global : healthy. Stack complète et opérationnelle.

2026-06-20 — Connexion PostGIS Alteris + stylisation CNIG

    Connexion PostGIS directe (79.137.14.202:5432) → timeout (port filtré par pare-feu VPS) Tunnel SSH manuel (ssh -L 5433:localhost:5432 debian@79.137.14.202 -N) → connexion OK Couche altfoncier_28051.28051_plu_zonage chargée (20 entités, commune 28051) Stylisation CNIG appliquée et validée visuellement Point clé découvert : le champ props (JSONB PostGIS) arrive comme dict Python dans PyQGIS — utiliser map_get("props", 'typezone') en expression, pas LIKE sur chaîne Tunnel paramiko (option 2 — sans terminal externe) : à tester

    Prochaines étapes prévues :

    • Tester lale connexiontunnel PostGIS Alterisparamiko depuis QGIS via MCP (alteris_geo, 79.137.14.202:5432)PyQGIS
    • Charger une couche depuis PostGIS,Exporter la styliser, l'exportercarte en PDF via mise en page QGIS