Skip to main content
Glama

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 API
  1. QGIS Plugin (qgis_listener/) - Runs inside QGIS. Non-blocking TCP socket server that processes JSON commands within QGIS's event loop.

  2. 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-server

Scope reference:

Flag

Stored in

Visible to

-s local (default)

.mcp.json (gitignored)

You, this project

-s project

.mcp.json (committed)

Whole team, this project

-s user

~/.claude.json

You, every project

codex mcp add qgis -- uvx --from https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip luiccian-qgis-mcp-server

Or 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-server

Step 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 opencode

This 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

  1. Start the plugin - In QGIS, click the Luiccian QGIS Listener toolbar button (or Plugins > Luiccian QGIS Listener) and click "Start Server"

  2. 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 project

Layer 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 > 1000

Updating

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 (git clone)

QGIS plugin

Download the new ZIP from the releases page and Install from ZIP again

git pull, then re-run python install.py (it re-links the plugin)

MCP server

uvx caches the downloaded archive - force an update with uvx --refresh-package luiccian-qgis-mcp --from https://github.com/LuiccianDev/qgis-mcp/archive/refs/heads/main.zip luiccian-qgis-mcp-server, then restart your MCP client

git pull then restart the MCP server process

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

load_project, create_new_project, save_project, get_project_info, set_project_crs

Layers

get_layers, add_vector_layer, add_raster_layer, add_web_layer, remove_layer, find_layer, create_memory_layer, set_layer_visibility, zoom_to_layer, get_layer_extent, set_layer_property, get_layer_crs, set_layer_crs, get_active_layer, set_active_layer, add_table_join, export_layer

Features

get_layer_features, add_features, update_features, update_feature_geometry, delete_features, select_features, get_selection, clear_selection, get_field_statistics, get_unique_values

Fields

add_field, delete_field, rename_field, field_calculator

Editing

start_editing, commit_edits, rollback_edits, get_edit_status, undo_edits, redo_edits

Styling

set_layer_style (single, categorized, graduated), set_raster_style (pseudocolor, gray, RGB, hillshade), apply_style_qml, save_style_qml, get_layer_labeling, set_layer_labeling

Connections

list_connections, create_postgresql_connection, list_connection_tables, add_layer_from_connection, import_layer_to_connection, execute_connection_sql

Rendering

render_map, get_canvas_screenshot, get_3d_screenshot, get_canvas_extent, set_canvas_extent, get_canvas_scale, set_canvas_scale

Bookmarks & themes

add_bookmark, get_bookmarks, remove_bookmark, add_map_theme, get_map_themes, apply_map_theme, remove_map_theme

Processing

execute_processing, execute_processing_batch, list_processing_algorithms, get_algorithm_help, get_processing_providers, create_processing_model, list_processing_models, run_model, start_processing_job, get_processing_job, cancel_processing_job

Session

create_checkpoint, list_checkpoints, restore_checkpoint, export_session

Analysis

raster_calculator, zonal_statistics, sample_raster_values, spatial_join

Layouts

list_layouts, export_layout, create_layout, add_layout_map, add_layout_label, add_layout_legend, add_layout_scalebar, add_layout_picture, add_layout_table, get_layout_info, remove_layout

Atlas

configure_atlas, export_atlas

Query

execute_sql, evaluate_expression, identify_features

Layer tree

get_layer_tree, create_layer_group, move_layer_to_group, duplicate_layer, set_layer_order

Plugins

list_plugins, get_plugin_info, reload_plugin

System

ping, diagnose, list_qgis_instances, get_qgis_info, get_raster_info, get_message_log, execute_code, batch_commands, validate_expression, get_project_variables, set_project_variable, get_setting, set_setting, transform_coordinates

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

QGIS_MCP_HOST

localhost

Host for socket connection

QGIS_MCP_PORT

9878

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.

QGIS_MCP_INSTANCES

(unset)

Address several running QGIS windows from one server. See Multiple QGIS instances.

QGIS_MCP_TOKEN

(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.

QGIS_MCP_TRANSPORT

stdio

MCP transport: stdio or streamable-http

QGIS_MCP_LOG_FILE

~/.local/share/luiccian-qgis-mcp/server.log

Log file path (empty to disable)

QGIS_MCP_LOG_LEVEL

INFO

File log level

QGIS_MCP_TOOL_MODE

granular

granular (125 tools) or compound (27 grouped)

QGIS_MCP_AUTO_CONFIRM

on

Confirmation elicitation on destructive tools (execute_code, remove_layer, delete_features, ...) is skipped by default: your client already asks before running them, so it was a second prompt for the same call. Set to 0/false/no/off to elicit anyway - worth it only for a client that runs tools unattended.

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

%APPDATA%\luiccian-qgis-mcp\token

Linux / macOS

$XDG_CONFIG_HOME/luiccian-qgis-mcp/token (default ~/.config/luiccian-qgis-mcp/token)

  • 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 env block only if you set QGIS_MCP_TOKEN there.

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 instance argument (get_layers(instance="planning")). Omitting it targets the entry named default, or - when no entry is called default - the first entry listed, so planning=9877,archive=9878 works without renaming anything.

  • list_qgis_instances returns 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 use QGIS_MCP_HOST (default localhost).

  • 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 no instance argument, 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_INSTANCES is unset, exactly one instance named default is defined from QGIS_MCP_HOST/QGIS_MCP_PORT - existing setups are unaffected.

  • QGIS_MCP_TOKEN is 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 client

install.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.py uses --directory instead of cwd in generated configs. This is required for Store-installed Claude Desktop, which runs MCP servers in an MSIX sandbox that silently drops cwd. If you configure manually, use uv --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 -v

License

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.

Available Tools

125 tools
add_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 FeaturesA
Destructive

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 ThemeA
Idempotent

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 JobA
Idempotent

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 SelectionC
Idempotent

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 ProjectA
Destructive

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 FeaturesA
Destructive

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 FieldC
Destructive

Delete a field from a vector layer.

Inputs: layer_id (required), field_name (required).

diagnoseDiagnoseA
Read-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 ExpressionA
Read-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 CodeA
Destructive

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 SQLA
Destructive

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 AtlasA
Idempotent

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 LayerA
Idempotent

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 LayoutA
Idempotent

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 LayerA
Read-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 ScreenshotA
Read-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 LayerA
Read-only

Get the currently active (selected) layer in the QGIS layer panel.

Inputs: no named parameters. Returns: object

get_algorithm_helpGet Algorithm HelpA
Read-only

Get detailed help for a processing algorithm: parameters (name, type, optional, default), outputs, and description.

Inputs: algorithm_id (required). Returns: object

get_bookmarksGet BookmarksA
Read-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 ExtentA
Read-only

Get the current map canvas extent and CRS.

Inputs: no named parameters. Returns: object

get_canvas_scaleGet Canvas ScaleA
Read-only

Get the current map canvas scale, rotation, and magnification factor.

Inputs: no named parameters. Returns: object

get_canvas_screenshotGet Canvas ScreenshotA
Read-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 StatusA
Read-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 StatisticsA
Read-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 CRSA
Read-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 ExtentA
Read-only

Get the spatial extent (bounding box) and CRS of a layer.

Inputs: layer_id (required). Returns: object

get_layer_featuresGet Layer FeaturesA
Read-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 LabelingA
Read-only

Get the labeling configuration of a vector layer: enabled state, field, font size, color.

Inputs: layer_id (required). Returns: object

get_layersGet LayersA
Read-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 TreeA
Read-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 InfoB
Read-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 ThemesA
Read-only

Get map themes (visibility presets). Each theme stores which layers are visible.

Inputs: no named parameters. Returns: object

get_message_logGet Message LogA
Read-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 InfoA
Read-only

Get detailed info for a specific plugin: name, enabled, version, description, author, path.

Inputs: plugin_name (required). Returns: object

get_processing_jobGet Processing JobA
Read-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 ProvidersA
Read-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 InfoA
Read-only

Get current project metadata: filename, title, CRS, layer count, and summary of layers.

Inputs: no named parameters. Returns: object

get_project_variablesGet Project VariablesA
Read-only

Get all project-level variables (key-value pairs set in Project Properties).

Inputs: no named parameters. Returns: object

get_qgis_infoGet QGIS InfoA
Read-only

Get QGIS version, profile path, and plugin count.

Inputs: no named parameters. Returns: object

get_raster_infoGet Raster InfoA
Read-only

Get raster layer info: band count, dimensions, CRS, extent, per-band statistics, nodata values.

Inputs: layer_id (required). Returns: object

get_selectionGet SelectionA
Read-only

Get the current selection for a layer. Returns feature IDs and count.

Inputs: layer_id (required). Returns: object

get_settingGet SettingA
Read-only

Read a QGIS setting by key path (e.g. 'qgis/sketching/sketching_enabled').

Inputs: key (required). Returns: object

get_unique_valuesGet Unique ValuesA
Read-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 FeaturesA
Read-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 ConnectionA
Destructive

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 CheckpointsA
Read-only

List the project checkpoints: id, name, creation time, layer count.

Inputs: no named parameters. Returns: object

list_connectionsList ConnectionsA
Read-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 TablesA
Read-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 LayoutsA
Read-only

List all print layouts in the current project with names and page counts.

Inputs: no named parameters. Returns: object

list_pluginsList PluginsA
Read-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 AlgorithmsA
Read-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 ModelsA
Read-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 InstancesA
Read-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 ProjectA
Destructive

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).

pingPingA
Read-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 PluginA
Destructive

Reload a QGIS plugin by name. Cannot reload the MCP plugin itself. Useful during plugin development.

Inputs: plugin_name (required).

remove_bookmarkRemove BookmarkA
Destructive

Remove a spatial bookmark by its ID.

Inputs: bookmark_id (required).

remove_layerRemove LayerA
Destructive

Remove a layer from the project by its layer ID. This is irreversible.

Inputs: layer_id (required).

remove_layoutRemove LayoutB
Destructive

Remove a print layout from the project.

Inputs: layout_name (required).

remove_map_themeRemove Map ThemeB
Destructive

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 MapB
Idempotent

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 CheckpointA
Destructive

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 EditsA
Destructive

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 ValuesA
Read-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 ProjectB
Idempotent

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 FeaturesB
Idempotent

Select features in a layer by expression or feature IDs.

Inputs: layer_id (required), fids, expression.

set_active_layerSet Active LayerB
Idempotent

Set the active layer in the QGIS layer panel by layer ID.

Inputs: layer_id (required).

set_canvas_extentSet Canvas ExtentA
Idempotent

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 ScaleA
Idempotent

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 OrderA
Idempotent

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 PropertyA
Idempotent

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 VisibilityB
Idempotent

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 VariableB
Idempotent

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 SettingC
Destructive

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 CoordinatesA
Read-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 GeometryA
Destructive

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 FeaturesA
Destructive

Update feature attributes. updates: [{fid: 1, attributes: {field: value}}]. Returns count of updated features.

Inputs: updates (required), layer_id (required).

validate_expressionValidate ExpressionA
Read-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 LayerA
Idempotent

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

    B3.2/5.0

    Scored across 125 tools

    Disambiguation3/5

    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.

    Naming Consistency4/5

    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.

    Tool Count1/5

    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.

    Completeness4/5

    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

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      B
      quality
      A
      maintenance
      An 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.
      125
      429
      GPL 2.0
    • A
      license
      A
      quality
      D
      maintenance
      Connect 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.
      100
      1
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      Connects 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
    • A
      license
      Not graded
      quality
      B
      maintenance
      Connects 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