QGIS MCP Server
Drives QGIS directly from an AI agent via a TCP-connected plugin, exposing 125 tools for layer management, feature editing, processing algorithms, map rendering, styling and labeling, print layout and atlas authoring, cross-layer SQL queries, plugin development, multi-instance workflows, and system management.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@QGIS MCP Server buffer the parcels layer by 50m and add the result to the map"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Luiccian QGIS MCP
Connect QGIS to any AI agent that speaks the Model Context Protocol (MCP), so the agent drives QGIS directly: manage layers, edit features, run processing algorithms, render maps, and more.
125 MCP tools covering layer management, feature editing, processing, rendering, styling, layout & atlas authoring, cross-layer SQL, plugin development, and system management. Compatible with QGIS 3.28–4.x. Model and client agnostic: any MCP client works, among them Claude Code, Codex CLI, Gemini CLI, Qwen Code, Kimi Code CLI, GitHub Copilot CLI, opencode, LM Studio, Claude Desktop, Cursor, VS Code, Windsurf, Zed, and more.
Architecture
AI agent ←→ MCP Server (FastMCP) ←→ TCP socket ←→ QGIS Plugin (QTimer) ←→ PyQGIS APIQGIS Plugin (
qgis_listener/) - Runs inside QGIS. Non-blocking TCP socket server that processes JSON commands within QGIS's event loop.MCP Server (
src/luiccian_qgis_mcp/server.py) - Runs outside QGIS. Exposes QGIS operations as MCP tools via FastMCP.
Related MCP server: QGIS MCP
Installation
No clone needed. Requires QGIS 3.28+ and uv.
1. Install the QGIS plugin
Download the latest qgis_listener_v<version>.zip from the
releases page, then in QGIS use
Plugins > Manage and Install Plugins > Install from ZIP and pick that file.
Restart QGIS and click Start Server in the Luiccian QGIS Listener dock widget.
2. Connect your coding agent
The configurations below run the server from this repository's archive:
uvx --from https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip luiccian-qgis-mcp-server.
Once the package is published to PyPI, uvx luiccian-qgis-mcp-server is the shorter equivalent.
claude mcp add -s user qgis -- uvx --from https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip luiccian-qgis-mcp-serverScope reference:
Flag | Stored in | Visible to |
|
| You, this project |
|
| Whole team, this project |
|
| You, every project |
codex mcp add qgis -- uvx --from https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip luiccian-qgis-mcp-serverOr edit ~/.codex/config.toml directly:
[mcp_servers.qgis]
command = "uvx"
args = ["--from", "https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip", "luiccian-qgis-mcp-server"]Add to ~/.gemini/settings.json:
{
"mcpServers": {
"qgis": {
"command": "uvx",
"args": ["--from", "https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip", "luiccian-qgis-mcp-server"]
}
}
}Same layout as Gemini CLI. Add to ~/.qwen/settings.json:
{
"mcpServers": {
"qgis": {
"command": "uvx",
"args": ["--from", "https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip", "luiccian-qgis-mcp-server"]
}
}
}Add to ~/.kimi-code/mcp.json (or $KIMI_CODE_HOME/mcp.json). A .kimi-code/mcp.json
in the working directory overrides it for that project.
{
"mcpServers": {
"qgis": {
"command": "uvx",
"args": ["--from", "https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip", "luiccian-qgis-mcp-server"]
}
}
}Kimi has no mcp add subcommand - edit the JSON or use the /mcp-config TUI.
Add to ~/.copilot/mcp-config.json (directory overridable via $COPILOT_HOME):
{
"mcpServers": {
"qgis": {
"command": "uvx",
"args": ["--from", "https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip", "luiccian-qgis-mcp-server"]
}
}
}Add to ~/.lmstudio/mcp.json (%USERPROFILE%\.lmstudio\mcp.json on Windows):
{
"mcpServers": {
"qgis": {
"command": "uvx",
"args": ["--from", "https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip", "luiccian-qgis-mcp-server"]
}
}
}Add to opencode.json at your project root:
{
"mcp": {
"qgis": {
"type": "local",
"command": ["uvx", "--from", "https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip", "luiccian-qgis-mcp-server"],
"enabled": true
}
}
}Hermes stores MCP servers in config.yaml under an mcpServers block. A standalone mcp.json is ignored. You also need a small .bat launcher - running uvx directly inside Hermes causes a venv conflict (ModuleNotFoundError: No module named 'pydantic_core._pydantic_core').
Step 1 - Create %APPDATA%\Hermes\luiccian-qgis-mcp-launch.bat:
@echo off
REM Clears Hermes's venv vars so uvx uses a clean Python environment.
set VIRTUAL_ENV=
set PYTHONPATH=
set PYTHONHOME=
uvx --from "https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip" luiccian-qgis-mcp-serverStep 2 - Add to %APPDATA%\Hermes\config.yaml:
mcpServers:
qgis:
command: "C:\\Users\\<you>\\AppData\\Roaming\\Hermes\\luiccian-qgis-mcp-launch.bat"
args: []Replace <you> with your Windows username. Restart Hermes, then verify with:
Call the QGIS ping tool.Tip: The QGIS plugin's Setup & Configurator dialog has a hermes entry in the client dropdown. Select it and click Copy to get the bat file and YAML pre-filled with your local paths.
For the full guide see docs/agent-integration.md.
opencode (which runs Nous/Hermes and other models) is supported directly by the installer:
python install.py --non-interactive --clients opencodeThis writes the correct config block to ~/.config/opencode/config.json
(%APPDATA%\opencode\config.json on Windows).
To configure manually, add to your opencode.json or global opencode config:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"qgis": {
"type": "local",
"command": [
"uvx",
"--from", "https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip",
"luiccian-qgis-mcp-server"
]
}
}
}Any other agent or client that supports the MCP stdio transport can also use this server. Generic config (exact key names vary by client - see your agent's docs):
{
"mcpServers": {
"qgis": {
"command": "uvx",
"args": [
"--from", "https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip",
"luiccian-qgis-mcp-server"
]
}
}
}After starting the agent, verify by asking it to call the ping tool - it
should return {"pong": true} when the QGIS plugin is running.
For a full setup guide, troubleshooting steps, and compound-tool mode configuration see
docs/agent-integration.md.
Add to your client's MCP config file:
{
"mcpServers": {
"qgis": {
"command": "uvx",
"args": [
"--from", "https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip",
"luiccian-qgis-mcp-server"
]
}
}
}Usage
Start the plugin - In QGIS, click the Luiccian QGIS Listener toolbar button (or
Plugins>Luiccian QGIS Listener) and click "Start Server"Talk to your agent - The MCP tools appear automatically. Ask the agent to work with your QGIS project.
Example prompts
Basic workflow
You have access to QGIS tools. Do the following:
1. Ping to check the connection
2. Create a new project and save it at "/tmp/my_project.qgz"
3. Load the vector layer "world_map.gpkg" available in QGIS ("resources/data/world_map.gpkg")
4. Filter "USA" from the field "adm0_a3"
5. Render the map and show me the result
6. Save the projectLayer management
List all layers in the current project, then add a new vector layer from "/data/roads.gpkg".
Set its visibility to true and zoom to its extent.Feature editing with transaction
Start editing the "parcels" layer, add 3 new features with attributes,
commit the edits, and verify the feature count increased.Processing with background job
Start a background processing job to buffer the "rivers" layer by 100 meters.
Poll the job status until it completes, then add the result to the project.Styling and labeling
Apply a categorized style to the "landuse" layer using the "type" field.
Then add labels showing the "name" attribute with 12pt bold text.Layout creation
Create a new print layout called "Map1", add a map item, a title label,
a legend, and a scalebar. Export it as a PDF to "/tmp/map.pdf".Multi-instance workflow
List the configured QGIS instances. On the "planning" instance, load the project
at "/data/planning.qgz". On the "archive" instance, export the current project.SQL query across layers
Execute SQL to join the "parcels" and "owners" layers:
SELECT p.id, p.area, o.name FROM parcels p JOIN owners o ON p.owner_id = o.id
WHERE p.area > 1000Updating
The plugin (inside QGIS) and the MCP server (outside QGIS) must stay in sync - a newer server sending a command the older plugin doesn't know will return an error. Run diagnose after any update to verify both sides match.
Component | Remote install | Local install ( |
QGIS plugin | Download the new ZIP from the releases page and |
|
MCP server | uvx caches the downloaded archive - force an update with |
|
To auto-update instead, add --refresh-package luiccian-qgis-mcp before --from in the configs above: uvx then re-resolves this package from GitHub on every launch. Warning: this requires network at launch - the MCP server fails to start when offline - and adds ~1–3s to startup. The plain configs above use the cached version and work offline.
After updating the plugin, click Stop / Start in the Luiccian QGIS Listener dock widget (or reload via Plugins > Luiccian QGIS Listener > Reload Plugin) to load the new code without restarting QGIS.
Tools (125)
Category | Tools |
Project |
|
Layers |
|
Features |
|
Fields |
|
Editing |
|
Styling |
|
Connections |
|
Rendering |
|
Bookmarks & themes |
|
Processing |
|
Session |
|
Analysis |
|
Layouts |
|
Atlas |
|
Query |
|
Layer tree |
|
Plugins |
|
System |
|
All tools are async with human-readable titles and annotations (readOnly, destructive, idempotent). Destructive tools rely on your client's own confirmation gate, which reads the destructive annotation; set QGIS_MCP_AUTO_CONFIRM=0 to have the server elicit a second confirmation as well. Long-running tools report progress via MCP logging.
Compound tool mode
Set QGIS_MCP_TOOL_MODE=compound to reduce the granular tools to 27 grouped tools (every granular command stays reachable), cutting schema overhead per LLM turn. Each compound tool takes an action parameter plus a params object holding that action's parameters:
QGIS_MCP_TOOL_MODE=compound uv run --no-sync src/luiccian_qgis_mcp/server.py{ "action": "load", "params": { "path": "/data/city.qgz" } }Omit params for actions that take none ({"action": "ping"}).
Groups: system, project, layer, features, selection, style, canvas, render, processing, code, batch, layer_tree, plugins, variables, settings, expression, query, transform, message_log, layer_property, field, analysis, bookmarks, map_themes, active_layer.
Configuration
Environment variable | Default | Description |
|
| Host for socket connection |
|
| Port for socket connection. The QGIS plugin reads it too: set in the environment QGIS is launched from, it overrides the port saved in the plugin's dropdown for that window. |
| (unset) | Address several running QGIS windows from one server. See Multiple QGIS instances. |
| (unset) | Optional shared secret. When set, it overrides the token file and the plugin rejects any command without a matching token. See Token and authentication. |
|
| MCP transport: |
|
| Log file path (empty to disable) |
|
| File log level |
|
|
|
| on | Confirmation elicitation on destructive tools ( |
Token and authentication
By default the socket has no authentication - it binds to localhost only, but any process on the machine that can reach the port can drive QGIS (including execute_code, which runs arbitrary PyQGIS).
The recommended way to turn authentication on is the plugin: open Setup & Configurator from Plugins > Luiccian QGIS Listener, then use the Security group to Generate new token and Copy it. The token is stored once, in a per-user file that both halves read:
OS | Token file |
Windows |
|
Linux / macOS |
|
Generate new token rotates it. Both halves read the file on every command, so the new value takes effect on the next one and clients need no reconfiguration.
Revoke deletes the file and disables authentication again. The UI asks before either action.
A client configured with the old token stops working after a rotation; copy the new value into the client's
envblock only if you setQGIS_MCP_TOKENthere.
QGIS_MCP_TOKEN still wins when set: put the same value in the environment QGIS runs in and in the MCP server's environment (for example in the env block of your MCP client config) to keep the secret out of the token file. Unset it in both places to manage the token from the UI.
{
"mcpServers": {
"qgis": {
"command": "uvx",
"args": ["--from", "https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip", "luiccian-qgis-mcp-server"],
"env": { "QGIS_MCP_TOKEN": "your-long-random-secret" }
}
}
}The token is compared in constant time. When no token exists anywhere (the default), behaviour is unchanged. This raises the bar against other local users/processes; a process running as the same user can still read the token file, so it is not a sandbox.
One exception: binding the plugin to a non-loopback address requires a token. Exposing arbitrary PyQGIS execution to the network without authentication is not a state you should be able to reach by accident, so the plugin refuses to start on such an address until a token exists - from the file or from QGIS_MCP_TOKEN.
Multiple QGIS instances
One server registration can drive several running QGIS windows. Start each QGIS with the plugin on its own port, then list them in QGIS_MCP_INSTANCES as comma-separated name=port or name=host:port entries.
Set a window's port in the dropdown next to the Luiccian QGIS Listener toolbar button (the arrow beside the logo) before starting the server. That choice is saved per QGIS profile, so two windows on the same profile would both start on it; launch each with its own QGIS_MCP_PORT instead (for example QGIS_MCP_PORT=9879 qgis), which overrides the saved port without changing it. The same applies when another program already listens on 9878 (or on 9876, where Blender's MCP add-on sits by default).
{
"mcpServers": {
"qgis": {
"command": "uvx",
"args": ["--from", "https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip", "luiccian-qgis-mcp-server"],
"env": { "QGIS_MCP_INSTANCES": "default=9878,planning=9879,archive=lab-box:9880" }
}
}
}Every tool takes an optional
instanceargument (get_layers(instance="planning")). Omitting it targets the entry nameddefault, or - when no entry is calleddefault- the first entry listed, soplanning=9877,archive=9878works without renaming anything.list_qgis_instancesreturns the configured names with their host, port, and current reachability. An unknown name is rejected with the list of valid names.Instance names match
[A-Za-z0-9_-]+; entries without a host useQGIS_MCP_HOST(defaultlocalhost).Each instance has its own pooled connection and its own lock, so two QGIS windows can be driven concurrently.
Not supported with
QGIS_MCP_TOOL_MODE=compound. Compound tools carry noinstanceargument, so every call would silently hit one instance; configuring more than one instance in compound mode refuses to start rather than routing writes to the wrong QGIS.When
QGIS_MCP_INSTANCESis unset, exactly one instance nameddefaultis defined fromQGIS_MCP_HOST/QGIS_MCP_PORT- existing setups are unaffected.QGIS_MCP_TOKENis shared across instances: the same secret must be set in every QGIS.
Contributing
git clone https://github.com/LuiccianDev/qgis-mcp.git
cd qgis-mcp
python install.py # symlinks plugin + configures your MCP clientinstall.py options: --clients claude-desktop,cursor, --remote (downloads the latest release plugin ZIP and configures uvx instead of uv run), --from-zip [PATH] (installs the plugin from a ZIP archive instead of symlinking; omit PATH to build dist/qgis_listener_v*.zip), --profile myprofile, --uninstall.
Known client names: claude-desktop, cursor, vscode, windsurf, zed, claude-code, codex, opencode, hermes, kimi, gemini, qwen, copilot-cli, lmstudio.
Windows (Microsoft Store / MSIX Claude Desktop):
install.pyuses--directoryinstead ofcwdin generated configs. This is required for Store-installed Claude Desktop, which runs MCP servers in an MSIX sandbox that silently dropscwd. If you configure manually, useuv --directory "/path/to/qgis-mcp" run --no-sync src/luiccian_qgis_mcp/server.py- this works on both MSIX and standalone installs. You can identify a Store install when the config file is under%LOCALAPPDATA%\Packages\Claude_<id>\LocalCache\Roaming\Claude\instead of%APPDATA%\Claude\.
# Unit tests (no QGIS needed - mocked socket)
uv run --no-sync pytest tests/test_mcp_tools.py -v
# Integration tests (requires QGIS plugin running)
uv run --no-sync pytest tests/test_qgis_live.py -vLicense
This project is distributed under the GNU General Public License, version 2 or later.
It is derived from the upstream qgis-mcp project by Nicolas Karasiak; the original attribution
is kept in NOTICE.
QGIS plugin (
qgis_listener/) - GNU GPL v2 or laterMCP server (
src/luiccian_qgis_mcp/) - GNU GPL v2 or later
Available Tools
125 toolsadd_bookmarkAdd BookmarkA
Add a spatial bookmark to the project for quick navigation. Provide a name and extent (xmin/ymin/xmax/ymax), in crs when given, else the project CRS.
Inputs: name (required), xmax (required), xmin (required), ymax (required), +3 more.
add_featuresAdd FeaturesADestructive
Add features to a vector layer. Each feature: {attributes: {field: value}, geometry_wkt: 'POINT(1 2)'}. geometry_wkt is in the layer's CRS, or in crs when given (it is then reprojected). A geometry type the layer cannot hold is refused; invalid geometry or 2D on a Z layer comes back in warnings. Returns count of added features.
Inputs: features (required), layer_id (required), crs.
add_fieldAdd FieldC
Add a new field to a vector layer. field_type: 'string', 'int', 'double', 'bool', 'date', 'datetime'.
Inputs: layer_id (required), field_name (required), field_type (required), length, +1 more.
add_layer_from_connectionAdd Layer from ConnectionA
Load a table from a saved connection as a project layer. Pass table (+ schema), or sql to build a query layer executed by the database. For a SQL layer, geometry_column and primary_key may be needed for QGIS to map/identify the result.
Inputs: provider (required), connection (required), sql, name, +4 more.
add_layout_labelAdd Layout LabelC
Add a text label to a print layout (mm). text may contain [% expression %] for dynamic content. color is hex (e.g. '#000000').
Inputs: text (required), layout_name (required), x, y, +4 more.
add_layout_legendAdd Layout LegendA
Add a legend to a print layout, linked to a map item (defaults to the first map item). Position/size in mm. Optional layer_ids restricts the legend to specific layers.
Inputs: layout_name (required), x, y, title, +4 more.
add_layout_mapAdd Layout MapA
Add a map item to a print layout at specified position and size (in millimeters). Optional extent=[xmin, ymin, xmax, ymax] and scale override the canvas view.
Inputs: x (required), y (required), width (required), height (required), +3 more.
add_layout_pictureAdd Layout PictureB
Add a picture or SVG (logo, north arrow) to a print layout. path is an image or SVG file path. Position/size in mm.
Inputs: path (required), layout_name (required), x, y, +2 more.
add_layout_scalebarAdd Layout Scale BarC
Add a scale bar to a print layout, linked to a map item. style e.g. 'Single Box', 'Double Box', 'Line Ticks Up', 'Numeric'.
Inputs: layout_name (required), x, y, style, +3 more.
add_layout_tableAdd Layout TableC
Add an attribute table for a vector layer to a print layout. max_rows caps the number of features shown. Position/size in mm.
Inputs: layer_id (required), layout_name (required), x, y, +3 more.
add_map_themeAdd Map ThemeA
Create a map theme from the current layer visibility state. If a theme with this name exists, it will be updated.
Inputs: name (required).
add_raster_layerAdd Raster LayerC
Add a raster layer (GeoTIFF, etc.) to the project.
Inputs: path (required), name, provider.
add_table_joinAdd Table JoinC
Add a table join to a vector layer.
Inputs: join_field (required), target_field (required), join_layer_id (required), target_layer_id (required), +1 more.
add_vector_layerAdd Vector LayerC
Add a vector layer (shapefile, GeoJSON, GeoPackage, etc.) to the project.
Inputs: path (required), name, provider.
add_web_layerAdd Web LayerA
Add a web layer (XYZ, WMS, WFS) to the project. service: 'xyz', 'wms', 'wfs'. crs is optional and only meaningful for wms ('crs=' in the uri) and wfs ('srsname='): leave it unset to take whatever the service serves natively. XYZ tiles are always EPSG:3857, so requesting another CRS for them is an error rather than a silent no-op. The response reports the CRS the layer actually got.
Inputs: url (required), service (required), crs, name.
apply_map_themeApply Map ThemeAIdempotent
Apply a map theme - restores the layer visibility state saved in the theme.
Inputs: name (required).
apply_style_qmlApply Style QMLA
Apply a QGIS QML style to a layer, from a file (path) or inline QML text (qml); pass exactly one. Use it for styles the other styling tools do not model (rule-based renderers, data-defined properties, SVG fills, blend modes). Rejected, with the previous style restored, if the XML is malformed, targets the other layer kind, or QGIS loads a different renderer than the QML declares. Tip: save_style_qml on a similar layer gives a template in this QGIS version's format.
Inputs: layer_id (required), qml, path.
batch_commandsBatch CommandsA
Execute multiple commands in a single round-trip. Each command is {"type": "<command_name>", "params": {...}}. Destructive commands (batch, delete_features, execute_code, execute_connection_sql, import_layer_to_connection, reload_plugin, remove_layer, rollback_edits, set_setting) are not allowed in batch, call them individually.
Inputs: commands (required). Returns: result
cancel_processing_jobCancel Processing JobAIdempotent
Ask a running background job to stop. Its state turns 'cancelled' once QGIS has stopped it; outputs it already wrote stay on disk.
Inputs: job_id (required).
clear_selectionClear SelectionCIdempotent
Clear the selection on a layer.
Inputs: layer_id (required).
commit_editsCommit EditsA
Commit the layer's edit buffer to the data source and close the edit session.
Inputs: layer_id (required).
configure_atlasConfigure AtlasA
Configure a print layout's atlas: coverage_layer (vector layer id) drives one page per feature. Optional page_name_expression, filter_expression, sort_expression.
Inputs: layout_name (required), coverage_layer (required), enabled, sort_expression, +2 more.
create_checkpointCreate CheckpointA
Snapshot the whole project (layers, styles, labels, layouts, map themes, variables, and the features of memory layers) so restore_checkpoint can return to it. Take one before a sequence of changes you may want to undo. The user's project file is not touched. Data in files and databases is not copied, and uncommitted edits are listed under 'uncommitted_edits' because the checkpoint does not hold them. The last 20 are kept, until the plugin's server stops.
Inputs: name.
create_layer_groupCreate Layer GroupC
Create a new layer group in the layer tree. Optionally specify a parent group name.
Inputs: name (required), parent.
create_layoutCreate LayoutC
Create a new print layout. page_size: e.g. 'A4', 'A3', 'Letter'. orientation: 'landscape' or 'portrait'.
Inputs: name (required), page_size, orientation.
create_memory_layerCreate Memory LayerA
Create a new in-memory vector layer. geometry_type: Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon. fields: [{name, type}] where type is integer, double, string, date, datetime.
Inputs: name (required), geometry_type (required), crs, fields.
create_new_projectCreate New ProjectADestructive
Create a new empty QGIS project and save it to the given path. Replaces the open project; unsaved changes to it are lost.
Inputs: path (required).
create_postgresql_connectionCreate PostgreSQL ConnectionA
Validate and save a new PostgreSQL Browser-panel connection. Passwords are never accepted: credentials come from a QGIS Authentication Manager configuration, from the libpq service file (pg_service.conf), or both. connection_mode selects which parameters are required; when the user's intent is unclear, ask which mode applies before calling. endpoint_using_auth_manager: host, port, database, auth_config_id (port must be the actual database port supplied by the caller or user, this tool never assumes 5432). service_using_auth_manager: service (the name defined in pg_service.conf) and auth_config_id; database optionally overrides the service file's dbname. service_only: service; database optionally overrides dbname; do not pass auth_config_id. Parameters a mode does not use are rejected. Fails if name already exists or the database cannot be reached. ssl_mode is one of prefer (default), disable, allow, require, verify-ca, or verify-full.
Inputs: name (required), connection_mode (required), host, port, +4 more. Returns: object
create_processing_modelCreate Processing ModelA
Build QGIS Processing Model (.model3) from structured spec; save to user models folder, register in Processing Toolbox. Only call needed: algorithm discovery + param validation run in the plugin against the live registry, so do NOT call list_processing_algorithms or get_algorithm_help first. Pass keyword ('buffer') or full id ('native:buffer'); handler resolves it. Ambiguous hint returns candidate list to refine and retry. Bad param/output names reported with the valid set.
Spec: inputs: [{name, type, description?, default?, optional?, parent_layer? (for field/distance), options? (for enum)}]. Types: vector, feature_source, raster, field, number, integer, distance, string, boolean, extent, crs, point, file, folder, enum, multiple_layers. steps: [{id, algorithm, description?, parameters: {ALG_PARAM: value}}]. algorithm = keyword or full id. Param values: '@input_name' = model input value '$step_id.OUTPUT' = earlier step output '=expression' = QGIS expression at run time else = static literal (number/bool/string/list) outputs: [{name, from_step, from_output, description?}] = exposed outputs; omit to expose the last step OUTPUT as 'Result'.
Name collision appends a suffix (name_2.model3, ...). Response returns the actual 'name', the 'requested_name', and 'resolved_steps' (which algorithm each hint mapped to).
Inputs: name (required), steps (required), group, inputs, +2 more. Returns: object
delete_featuresDelete FeaturesADestructive
Delete features by feature IDs or expression filter. Provide either fids (list of ints) or expression (string), not both. Returns requested and the measured deleted count.
Inputs: layer_id (required), fids, expression.
delete_fieldDelete FieldCDestructive
Delete a field from a vector layer.
Inputs: layer_id (required), field_name (required).
diagnoseDiagnoseARead-only
Run diagnostic checks on the QGIS MCP stack. Reports QGIS version, plugin/server version match, processing providers, connected clients, and project status.
Inputs: no named parameters. Returns: object
duplicate_layerDuplicate LayerC
Duplicate a layer (including its style) under a new name.
Inputs: layer_id (required), new_name.
evaluate_expressionEvaluate ExpressionARead-only
Evaluate a standalone QGIS expression to a scalar value (e.g. aggregate('layer','sum','field'), @project_var, now()). Optional layer_id adds layer scope. Distinct from validate_expression (validate only) and field_calculator (per-feature).
Inputs: expression (required), layer_id.
execute_codeExecute CodeADestructive
Execute arbitrary PyQGIS code. Use for operations not covered by other tools. Has access to QgsProject, iface, and core QGIS classes. Returns stdout/stderr and elapsed seconds. timeout: seconds before the script is cancelled (default 55); a script that runs past it comes back with timed_out=True and the output printed so far, and its side effects stand. Raise timeout or split bulk work into several calls; QGIS is unresponsive while a script runs. A single blocking call (time.sleep, GDAL) cannot be interrupted before it returns. A script that raises or times out is a tool error carrying the traceback and output so far.
Inputs: code (required), timeout.
execute_connection_sqlExecute Connection SQLADestructive
Run SQL directly on the database behind a saved connection (server-side, not a virtual layer - use execute_sql for that). Can modify the database: DDL/DML run as issued. limit caps returned rows (-1 for all).
Inputs: sql (required), provider (required), connection (required), limit. Returns: object
execute_processingExecute ProcessingA
Execute a QGIS Processing algorithm. Use get_algorithm_help to discover parameters. Layer params accept layer IDs or file paths. Set OUTPUT to 'memory:' for temp layers. timeout: seconds before the algorithm is cancelled (default 55). Raise it for heavy raster work, or use start_processing_job, which runs in the background with no limit. load_results: add the algorithm's outputs to the project and list them in 'loaded_layers' (the processing.runAndLoadResults() behaviour). This is the only way to keep a 'TEMPORARY_OUTPUT'/'memory:' result, which is otherwise discarded when the run ends. Only vector and raster destinations are loaded, never file or folder ones. ellipsoid: ellipsoid for distance/area measurements (e.g. 'EPSG:7030' for WGS 84, 'NONE' for planimetric). Default is the open project's ellipsoid.
Inputs: algorithm (required), parameters (required), timeout, ellipsoid, +1 more.
execute_processing_batchExecute Processing BatchA
Run one algorithm once per parameter dict in 'parameters_list'. Returns a per-run result with index and success/error status. Use for applying the same operation over many inputs in a single round-trip. timeout: seconds for the whole batch (default 55); runs that would start after it has elapsed come back as 'skipped' with the completed ones intact, so raise it or split the list for big batches. ellipsoid: measurement ellipsoid for every run (e.g. 'EPSG:7030'); default is the project's.
Inputs: algorithm (required), parameters_list (required), timeout, ellipsoid.
execute_sqlExecute SQLA
SQL across loaded layers via a virtual layer; reference layers by name in FROM/JOIN. as_layer=True registers the result as a new layer (set geometry_field for spatial output); else returns rows inline, capped by limit (default 1000, negative for all) with a truncated flag. layers limits sources by layer id.
Inputs: query (required), limit, layers, as_layer, +3 more.
export_atlasExport AtlasAIdempotent
Export a configured atlas. format 'pdf' writes a single multi-page file at output_path; image formats ('png','jpg','tif') write one file per feature into the output_path directory. Call configure_atlas first.
Inputs: layout_name (required), output_path (required), dpi, format.
export_layerExport LayerAIdempotent
Export vector/raster to disk; format from output_path extension (.gpkg, .shp, .geojson, .tif, ...). target_crs (e.g. 'EPSG:4326') reprojects on export. filter_expression (vector only) exports a subset matching a QGIS expression.
Inputs: layer_id (required), output_path (required), target_crs, filter_expression.
export_layoutExport LayoutAIdempotent
Export a print layout to file. format: 'pdf', 'png', 'jpg', 'svg'. dpi: resolution (default 300).
Inputs: path (required), layout_name (required), dpi, format.
export_sessionExport Session ScriptA
Every command that changed something in this QGIS since the plugin's server started (read-only calls left out), as a Python script that replays them from the QGIS Python console. Layer ids are remapped on replay. Returns the script, or writes it to 'path' and returns the path. clear: start a new journal afterwards. Commands from every connected client are in it; a restore_checkpoint rewinds it.
Inputs: path, clear.
field_calculatorField CalculatorA
Add (if missing) + populate a field from a QGIS expression, per feature, in-place. field_type: string|int|double|bool|date|datetime (default double). Example: expression='$area', field_name='area'. $area/$length use the project's ellipsoid and units (reported back as 'measurement'), not necessarily m2/m; the area()/length() functions are planimetric in the layer CRS (measurement.planimetric_units, squared for area()); length() of a string counts characters and reports no units. Returns updated and failed counts; failed features keep their old value and first_error says why. Refused while the layer has an open edit session.
Inputs: layer_id (required), expression (required), field_name (required), length, +2 more.
find_layerFind LayerARead-only
Find layers by name pattern. Supports fnmatch wildcards (e.g. 'roads*') and substring matching.
Inputs: name_pattern (required). Returns: object
get_3d_screenshotGet 3D ScreenshotARead-only
Capture an OPEN 3D Map View as an inline image. Reuses the open view's scene + camera, rendered via a print-layout 3D map item (the 2D get_canvas_screenshot cannot capture the OpenGL 3D view). Requires a 3D map view to be open in QGIS (View > 3D Map Views > New 3D Map View). view_index selects which view when several are open; dpi controls output resolution. Optional camera overrides (applied to the capture only, leaving the live view unchanged): pitch (0 = straight down/top-down, 90 = horizontal/edge-on; ~45 = balanced oblique), heading (compass degrees), distance (metres).
Inputs: dpi, pitch, heading, distance, +1 more.
get_active_layerGet Active LayerARead-only
Get the currently active (selected) layer in the QGIS layer panel.
Inputs: no named parameters. Returns: object
get_algorithm_helpGet Algorithm HelpARead-only
Get detailed help for a processing algorithm: parameters (name, type, optional, default), outputs, and description.
Inputs: algorithm_id (required). Returns: object
get_bookmarksGet BookmarksARead-only
Get spatial bookmarks from the project. Each bookmark has a name, group, extent (xmin/ymin/xmax/ymax), and CRS.
Inputs: no named parameters. Returns: object
get_canvas_extentGet Canvas ExtentARead-only
Get the current map canvas extent and CRS.
Inputs: no named parameters. Returns: object
get_canvas_scaleGet Canvas ScaleARead-only
Get the current map canvas scale, rotation, and magnification factor.
Inputs: no named parameters. Returns: object
get_canvas_screenshotGet Canvas ScreenshotARead-only
Grab a fast screenshot of the current map canvas widget (no re-render). Returns the image inline. Much faster than render_map.
Inputs: no named parameters.
get_edit_statusGet Edit StatusARead-only
Edit state of a layer: editable, modified, undo/redo availability, and the counts of pending added/deleted/changed features.
Inputs: layer_id (required). Returns: object
get_field_statisticsGet Field StatisticsARead-only
Compute aggregate statistics (count, sum, mean, min, max, stdev) for a numeric field. For non-numeric fields returns count and distinct values.
Inputs: layer_id (required), field_name (required). Returns: object
get_layer_crsGet Layer CRSARead-only
Get the coordinate reference system (CRS) of a layer: EPSG code, description, whether geographic, and PROJ4 string.
Inputs: layer_id (required). Returns: object
get_layer_extentGet Layer ExtentARead-only
Get the spatial extent (bounding box) and CRS of a layer.
Inputs: layer_id (required). Returns: object
get_layer_featuresGet Layer FeaturesARead-only
Get features from a vector layer. Flat dicts: _fid + attributes at top level. expression filter (QGIS, e.g. "name = 'Berlin'", "population > 1000000"), limit (max 50, larger is refused; default 10), offset for paging, optional geometry in _geometry key. feature_count is the layer total; matched is the count after the expression filter.
Inputs: layer_id (required), limit, offset, expression, +1 more. Returns: object
get_layer_labelingGet Layer LabelingARead-only
Get the labeling configuration of a vector layer: enabled state, field, font size, color.
Inputs: layer_id (required). Returns: object
get_layersGet LayersARead-only
List layers in the current project with IDs, names, types, visibility, and type-specific info. Use limit/offset for pagination. Response includes total_count.
Inputs: limit, offset. Returns: object
get_layer_treeGet Layer TreeARead-only
Get the full layer tree structure with groups and layers. Returns recursive tree with type, name, visibility, and children.
Inputs: no named parameters. Returns: object
get_layout_infoGet Layout InfoBRead-only
List items in a print layout (type, id, uuid, position, size) and page count.
Inputs: layout_name (required). Returns: object
get_map_themesGet Map ThemesARead-only
Get map themes (visibility presets). Each theme stores which layers are visible.
Inputs: no named parameters. Returns: object
get_message_logGet Message LogARead-only
Get QGIS message log entries. Filter by level ('info', 'warning', 'critical', 'success', 'none') and/or tag (e.g. 'QGIS MCP'). Returns newest first.
Inputs: tag, level, limit. Returns: object
get_plugin_infoGet Plugin InfoARead-only
Get detailed info for a specific plugin: name, enabled, version, description, author, path.
Inputs: plugin_name (required). Returns: object
get_processing_jobGet Processing JobARead-only
State of a background job: 'running' (with progress 0-100), 'succeeded' (with result, loaded_layers and warnings, as execute_processing returns them), 'failed' (with error) or 'cancelled'. Omit job_id to list every job.
Inputs: job_id. Returns: object
get_processing_providersGet Processing ProvidersARead-only
List Processing providers (native, gdal, grass, saga, model, ...) with algorithm counts and active status. Use to diagnose missing algorithms.
Inputs: no named parameters. Returns: object
get_project_infoGet Project InfoARead-only
Get current project metadata: filename, title, CRS, layer count, and summary of layers.
Inputs: no named parameters. Returns: object
get_project_variablesGet Project VariablesARead-only
Get all project-level variables (key-value pairs set in Project Properties).
Inputs: no named parameters. Returns: object
get_qgis_infoGet QGIS InfoARead-only
Get QGIS version, profile path, and plugin count.
Inputs: no named parameters. Returns: object
get_raster_infoGet Raster InfoARead-only
Get raster layer info: band count, dimensions, CRS, extent, per-band statistics, nodata values.
Inputs: layer_id (required). Returns: object
get_selectionGet SelectionARead-only
Get the current selection for a layer. Returns feature IDs and count.
Inputs: layer_id (required). Returns: object
get_settingGet SettingARead-only
Read a QGIS setting by key path (e.g. 'qgis/sketching/sketching_enabled').
Inputs: key (required). Returns: object
get_unique_valuesGet Unique ValuesARead-only
Return the distinct values of a field. Use 'limit' to cap results (-1 for all). Useful before building categorized symbology or filters.
Inputs: field (required), layer_id (required), limit. Returns: object
identify_featuresIdentify FeaturesARead-only
Identify features at a point [x, y] across layers (map-click analogue). The point and tolerance are in crs when given, else the project CRS; layers in another CRS are reprojected. tolerance (in those units) expands the search; 0 = exact hit. layer_ids limits the search (default: visible vector layers). limit caps features per layer. Layers the point cannot be transformed into are listed in skipped_layers.
Inputs: point (required), crs, limit, layer_ids, +1 more.
import_layer_to_connectionImport Layer to ConnectionADestructive
Write a loaded vector layer into a saved connection as a new table (PostgreSQL, GeoPackage, ...). Fails if the table exists unless overwrite=true.
Inputs: table (required), layer_id (required), provider (required), connection (required), +2 more.
list_checkpointsList CheckpointsARead-only
List the project checkpoints: id, name, creation time, layer count.
Inputs: no named parameters. Returns: object
list_connectionsList ConnectionsARead-only
List the data source connections saved in QGIS (PostgreSQL, GeoPackage, SpatiaLite, MS SQL, Oracle, ...) - the Browser panel entries. Optionally filter by provider (e.g. 'postgres', 'ogr', 'spatialite'). Passwords are redacted from the URIs.
Inputs: provider. Returns: object
list_connection_tablesList Connection TablesARead-only
List tables reachable through a saved connection. On providers with schemas (PostgreSQL), omit schema to get the schema list first, then pass one. Returns each table's geometry column, CRS, primary key and kind.
Inputs: provider (required), connection (required), schema. Returns: object
list_layoutsList LayoutsARead-only
List all print layouts in the current project with names and page counts.
Inputs: no named parameters. Returns: object
list_pluginsList PluginsARead-only
List installed QGIS plugins with name, enabled status, and version. Set enabled_only=true to list only active plugins.
Inputs: enabled_only. Returns: object
list_processing_algorithmsList Processing AlgorithmsARead-only
Search for processing algorithms by keyword and/or provider. Returns id, name, provider for each match.
Inputs: search, provider. Returns: object
list_processing_modelsList Processing ModelsARead-only
List registered Processing models (the 'model' provider). Returns id, name, group for each. Use run_model to execute one.
Inputs: no named parameters. Returns: object
list_qgis_instancesList QGIS InstancesARead-only
List the configured QGIS instances: name, host, port, reachability, and - for each reachable one - which QGIS actually answered (version, process id, window title, profile). Use it to confirm a name maps to the window you mean before writing to it. Pass a name as the 'instance' argument of any other tool to target that QGIS window; omitting it targets the instance named 'default', or the first one listed when no instance is called 'default'.
Inputs: no named parameters. Returns: object
load_projectLoad ProjectADestructive
Load a QGIS project from a .qgs/.qgz file path. Replaces the open project; unsaved changes to it are lost. Layers whose source is missing are kept as unavailable and listed in 'unavailable_layers'.
Inputs: path (required).
move_layer_to_groupMove Layer to GroupB
Move a layer into a layer group by group name.
Inputs: layer_id (required), group_name (required).
pingPingARead-only
Check connectivity to the QGIS plugin server. Returns pong if connected.
Inputs: no named parameters. Returns: object
raster_calculatorRaster CalculatorA
Band math via the QGIS raster calculator. Reference loaded raster layers in the expression as 'LayerName@band' (e.g. '("dem@1" > 1000) * 1'). Writes a GeoTIFF to output_path. Output grid, extent and CRS taken from reference_layer (layer id or name), defaulting to the first loaded file-based raster.
Inputs: expression (required), output_path (required), reference_layer.
redo_editsRedo EditsB
Redo previously undone edit operations on a layer.
Inputs: layer_id (required), steps.
reload_pluginReload PluginADestructive
Reload a QGIS plugin by name. Cannot reload the MCP plugin itself. Useful during plugin development.
Inputs: plugin_name (required).
remove_bookmarkRemove BookmarkADestructive
Remove a spatial bookmark by its ID.
Inputs: bookmark_id (required).
remove_layerRemove LayerADestructive
Remove a layer from the project by its layer ID. This is irreversible.
Inputs: layer_id (required).
remove_layoutRemove LayoutBDestructive
Remove a print layout from the project.
Inputs: layout_name (required).
remove_map_themeRemove Map ThemeBDestructive
Remove a map theme by name.
Inputs: name (required).
rename_fieldRename FieldC
Rename a field in a vector layer.
Inputs: layer_id (required), new_name (required), old_name (required).
render_mapRender MapBIdempotent
Render the current map canvas to an image. Returns the image inline so you can see it. Optionally saves to a file path on disk.
Inputs: path, width, height.
restore_checkpointRestore CheckpointADestructive
Put the project back as it was at a checkpoint: every change since, and any uncommitted edit, is discarded. The project keeps its file name and is left unsaved. Memory layer features come back with new feature ids. Layers whose source is missing are kept as unavailable and listed in 'unavailable_layers'. export_session afterwards replays the restored state, not the undone steps.
Inputs: checkpoint_id (required).
rollback_editsRollback EditsADestructive
Discard every uncommitted change on a layer and close the edit session.
Inputs: layer_id (required).
run_modelRun ModelA
Run a Processing model by registered id (e.g. 'model:myflow') or by a .model3 file path. 'parameters' maps the model's input names to values (layer ids/paths, numbers, etc.). ellipsoid: ellipsoid for distance/area measurements (e.g. 'EPSG:7030' for WGS 84, 'NONE' for planimetric); default is the project's.
Inputs: model (required), ellipsoid, parameters.
sample_raster_valuesSample Raster ValuesARead-only
Sample raster pixel values at points. 'points' is a list of [x, y] in crs when given (reprojected to the raster), else in the raster's CRS. Omit 'band' to sample all bands. A null value is nodata when outside_extent is false; outside_extent true means the point is off the raster (often a CRS mix-up); transform_failed marks a point the raster's CRS cannot express.
Inputs: points (required), raster_layer (required), crs, band. Returns: object
save_projectSave ProjectBIdempotent
Save the current project. Optionally specify a new path.
Inputs: path.
save_style_qmlSave Style QMLC
Save a layer's style to a QGIS QML file.
Inputs: path (required), layer_id (required).
select_featuresSelect FeaturesBIdempotent
Select features in a layer by expression or feature IDs.
Inputs: layer_id (required), fids, expression.
set_active_layerSet Active LayerBIdempotent
Set the active layer in the QGIS layer panel by layer ID.
Inputs: layer_id (required).
set_canvas_extentSet Canvas ExtentAIdempotent
Set the map canvas extent. Coordinates should be in the specified CRS (default: project CRS).
Inputs: xmax (required), xmin (required), ymax (required), ymin (required), +1 more.
set_canvas_scaleSet Canvas ScaleAIdempotent
Set the map canvas scale and/or rotation. Provide scale as denominator (e.g. 50000 for 1:50000). Rotation in degrees (0-360).
Inputs: scale, rotation.
set_layer_crsSet Layer CRSA
Set the CRS of a layer (e.g. 'EPSG:4326'). This does NOT reproject data - it only changes how the layer's coordinates are interpreted.
Inputs: crs (required), layer_id (required).
set_layer_labelingSet Layer LabelingA
Configure labeling for a vector layer. Set enabled=false to disable labels. Set field_name to the attribute field to label with. Optional: font_size (float), color (hex like '#000000').
Inputs: layer_id (required), color, enabled, font_size, +1 more.
set_layer_orderSet Layer OrderAIdempotent
Reorder layer tree nodes; tree order is draw order. layer_ids is the ordered list of layer ids from top (drawn last) to bottom; unlisted layers keep their slots. Clears any custom draw order (it freezes a snapshot list - layers added later would silently draw behind everything).
Inputs: layer_ids (required).
set_layer_propertySet Layer PropertyAIdempotent
Set a layer property. Supported properties: opacity (0.0-1.0), name (string), min_scale, max_scale (float), scale_visibility (bool).
Inputs: value (required), layer_id (required), property (required).
set_layer_styleSet Layer StyleB
Set symbology. style_type: 'single' (one symbol), 'categorized' (unique values), 'graduated' (numeric ranges). field required for categorized/graduated. color_ramp: QGIS ramp name (e.g. 'Spectral', 'Viridis', 'Blues'). classes: graduated class count (default 5). opacity: layer opacity from 0.0 to 1.0 (default 1.0).
Inputs: layer_id (required), style_type (required), field, classes, +2 more.
set_layer_visibilitySet Layer VisibilityBIdempotent
Set a layer's visibility in the layer tree (show/hide on map).
Inputs: visible (required), layer_id (required).
set_project_crsSet Project CRSA
Set the project coordinate reference system (e.g. 'EPSG:4326', 'EPSG:3857'). This changes how layers are projected on the map canvas.
Inputs: crs (required).
set_project_variableSet Project VariableBIdempotent
Set a project-level variable. Variables are accessible in expressions as @key.
Inputs: key (required), value (required).
set_raster_styleSet Raster StyleA
Set raster symbology. style_type: 'singleband_pseudocolor' (color ramp over one band), 'singleband_gray', 'multiband_color' (RGB), 'hillshade'. min_value/max_value default to the band statistics. color_ramp: QGIS ramp name (e.g. 'Viridis', 'Spectral', 'RdYlGn'). classification: continuous|equal_interval|quantile. interpolation: interpolated|discrete|exact. gradient (gray): black_to_white|white_to_black. contrast: none|stretch|clip|stretch_clip. hillshade uses band, azimuth, altitude, z_factor.
Inputs: layer_id (required), style_type (required), band, azimuth, +13 more.
set_settingSet SettingCDestructive
Write a QGIS setting. Use with care - incorrect settings can affect QGIS behavior.
Inputs: key (required), value (required).
spatial_joinSpatial JoinA
Join attributes by location (native:joinattributesbylocation). predicates int list: 0=intersects 1=contains 2=equals 3=touches 4=overlaps 5=within 6=crosses (default [0]). method: 0=one-to-many 1=first match (default) 2=largest overlap. First match keeps one arbitrary match per target feature and drops the others; use 0 when several can match. join_fields = copied columns (default all). No output_path = in-memory layer. Returns joined_count (target features that found a match, whatever the method) next to target_features. warnings/warning_count report features QGIS skipped, e.g. invalid geometries under the Processing setting that skips them; fix them first (native:fixgeometries) or those features never match.
Inputs: join_layer (required), target_layer (required), method, prefix, +3 more.
start_editingStart EditingA
Open an edit session on a vector layer. Subsequent add/update/delete calls go to the undoable edit buffer instead of the data source, until commit_edits or rollback_edits.
Inputs: layer_id (required).
start_processing_jobStart Processing JobA
Run a Processing algorithm as a QGIS background task, with no time limit, and return its job id at once. QGIS stays usable while it runs. Poll get_processing_job for progress and the result; cancel_processing_job stops it. Use it instead of execute_processing for anything that may take more than a minute. Same parameters as execute_processing. A 'TEMPORARY_OUTPUT'/'memory:' vector (feature sink) output needs load_results=True, since that memory layer ends with the job; temporary files stay on disk. Algorithms that must run on QGIS's main thread are refused: use execute_processing for those.
Inputs: algorithm (required), parameters (required), ellipsoid, load_results.
transform_coordinatesTransform CoordinatesARead-only
Transform coordinates between CRS. Accepts a point {x, y}, a point list [{x, y}, ...], or a bbox {xmin, ymin, xmax, ymax}. Returns the same format. x is always longitude/easting and y latitude/northing, including for EPSG:4326. A bbox that crosses the antimeridian comes back with xmin > xmax and crosses_antimeridian: true.
Inputs: source_crs (required), target_crs (required), bbox, point, +1 more. Returns: object
undo_editsUndo EditsB
Undo the last edit operations on a layer (its own undo stack). Returns how many steps were actually undone.
Inputs: layer_id (required), steps.
update_feature_geometryUpdate Feature GeometryADestructive
Replace feature geometries. updates: [{fid: 1, geometry_wkt: 'POINT(1 2)'}]. WKT must be in the layer's CRS. Inside an edit session the change is undoable; otherwise it is written straight to the data source.
Inputs: updates (required), layer_id (required).
update_featuresUpdate FeaturesADestructive
Update feature attributes. updates: [{fid: 1, attributes: {field: value}}]. Returns count of updated features.
Inputs: updates (required), layer_id (required).
validate_expressionValidate ExpressionARead-only
Validate a QGIS expression. Returns whether it's valid, any parse errors, and referenced column names. Optionally test against a layer's fields.
Inputs: expression (required), layer_id. Returns: object
zonal_statisticsZonal StatisticsB
Per-polygon stats from a raster (native:zonalstatisticsfb). stats int codes: 0=count 1=sum 2=mean 3=median 4=stdev 5=min 6=max 7=range 8=minority 9=majority 10=variety 11=variance (default [0,1,2]). New columns prefixed by 'prefix'. No output_path = in-memory layer.
Inputs: raster_layer (required), polygon_layer (required), band, stats, +2 more.
zoom_to_layerZoom to LayerAIdempotent
Zoom the map canvas to the full extent of the specified layer.
Inputs: layer_id (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 125 tools
Most tools target distinct QGIS resources and actions, and the descriptions explicitly distinguish close pairs such as execute_sql vs execute_connection_sql and execute_processing vs start_processing_job. However, with 125 tools there are many overlapping subdomains (styling, processing, layer inspection, expression evaluation, editing), so an agent can still hesitate between several plausible tools.
The set is consistently snake_case, and most tools follow a verb_noun or action_resource pattern such as get_layer_features, add_vector_layer, or set_layer_style. There are minor deviations with noun-first tools like raster_calculator, spatial_join, batch_commands, and ping, plus some add/create and remove/delete variation.
125 tools is an extreme mismatch for a single MCP server surface, far beyond the typical well-scoped range. Even though QGIS is a large domain, the set should be grouped or narrowed; the current count creates substantial selection and context burden.
The surface is very broad, covering layers, features, editing, styling, processing, layouts, CRS, bookmarks, themes, connections, and diagnostics. Some lifecycle operations are still missing or partial, such as deleting layer groups or updating/removing individual layout items, but these are minor gaps given the overall coverage.
Maintenance
Related MCP Connectors
214 tools for AI agents over one MCP endpoint: image, video, audio, 3D, data, storage, mail, GPUs.
Connect any AI agent to 1,000+ apps and 27,000+ actions through one remote MCP server (OAuth).
Persistent memory, knowledge graph, task management and more for AI agents via MCP.
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
Related MCP Servers
- AlicenseBqualityAmaintenanceAn MCP server that enables AI assistants to directly control QGIS for tasks like layer management, feature editing, and map rendering. It provides a suite of 50 tools to execute processing algorithms and manage GIS projects through natural language commands.125429GPL 2.0
- AlicenseAqualityDmaintenanceConnect QGIS to Claude AI through the Model Context Protocol (MCP), enabling Claude to directly control QGIS — manage layers, edit features, run processing algorithms, render maps, and more.1001MIT
- AlicenseNot gradedqualityDmaintenanceConnects AI assistants (Claude, Cursor, etc.) to QGIS 4.x via MCP, enabling natural language-driven GIS workflows through 37+ tools, including data loading, processing, and spatial analysis.GPL 2.0
- AlicenseNot gradedqualityBmaintenanceConnects QGIS to any MCP-speaking AI agent, exposing 125 tools that let the agent manage layers, edit features, run processing algorithms, render and style maps, author layouts and atlases, query across layers with SQL, and administer the QGIS session. Works with any MCP client and QGIS 3.28–4.x.GPL 2.0