Skip to content

mcp

qgis-cli mcp

Terminal window
qgis-cli mcp

mcp starts a Model Context Protocol server on stdin/stdout. Any MCP client — Claude Desktop, Claude Code, Cursor, the MCP inspector — can then discover the qgis-rs tools and call them.

The server is bundled into the qgis-cli binary: there is nothing else to install, no Node runtime, no virtual environment. The implementation lives in the qgis-mcp crate and speaks MCP over the standard newline-delimited JSON-RPC stdio transport.

Quick start

Terminal window
# See what the server offers without starting a session
qgis-cli mcp --list-tools
capabilities List the qgis-rs tools and report loaded-backend availability…
crs_info Describe a coordinate reference system: its name, units and…
plan_tiles Count and enumerate the XYZ tiles that cover an EPSG:4326 area…
project_info Describe a QGIS project file: its format, size and where to…
render_map Render a QGIS project to a path-based image artifact…
export_features Export a layer's features to a path-based GeoJSON or CSV artifact…

Register it with Claude Desktop (claude_desktop_config.json):

{
"mcpServers": {
"qgis": {
"command": "/path/to/qgis-cli",
"args": ["mcp"]
}
}
}

Or with Claude Code:

Terminal window
claude mcp add --transport stdio qgis -- /path/to/qgis-cli mcp

Tools

ToolArgumentsStatus
capabilities—Live
crs_infoauth_idLive
plan_tilesbounds, zoomLive
project_infoprojectLive
render_mapproject, output, extent, width, height, crs, dpi, layers, layoutNative QGIS backend
export_featuresproject, layer, output, filter, bbox, fieldsNative QGIS backend

Coordinates are EPSG:4326 (longitude,latitude) unless a tool says otherwise.

Call capabilities first: it returns the same catalogue as --list-tools, with a available flag per tool, so a client can tell a working tool from one that will answer with an error.

crs_info

{ "auth_id": "EPSG:3857" }
{
"auth_id": "EPSG:3857",
"name": "WGS 84 / Pseudo-Mercator",
"units": "meters",
"geographic": false
}

plan_tiles

Counts a tile pyramid without rendering it — the same arithmetic tiles --dry-run uses.

{ "bounds": "14,50,15,51", "zoom": "10-14" }
{
"bounds": "14,50,15,51",
"zoom": "10-14",
"total_tiles": 4568,
"levels": [
{ "zoom": 10, "x_min": 551, "x_max": 554, "y_min": 342, "y_max": 347, "tiles": 24 }
]
}

project_info

{ "project": "/maps/warsaw.qgz" }
{
"path": "/maps/warsaw.qgz",
"format": "qgz",
"size_bytes": 48120,
"crs": null,
"layer_count": null,
"note": "CRS, layer count and extent are only available through the native QGIS project reader"
}

render_map and export_features

Both validate their arguments and dispatch to the loaded native QGIS manager. The manager writes the requested artifact and returns JSON metadata containing the filesystem path, format and byte count (plus dimensions for an image or feature count for an export). The response does not inline or base64-encode artifact bytes. A build without the QGIS feature reports these tools as unavailable through capabilities and returns a backend error when called.

Talking to it by hand

The transport is newline-delimited JSON-RPC, so nc-style experimentation works:

Terminal window
{
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"shell","version":"0"}}}'
echo '{"jsonrpc":"2.0","method":"notifications/initialized"}'
echo '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
sleep 1
} | qgis-cli mcp

How it is built

crates/qgis-mcp the server: tool definitions, schemas, handlers
crates/qgis-cli `qgis-cli mcp` starts it inside a Tokio runtime
  • rmcp — the official Rust MCP SDK — provides the protocol, the stdio transport and the #[tool] macros that generate each tool’s JSON Schema from its Rust argument struct.
  • Each tool is a thin wrapper over a pure *_report function in qgis-mcp, which is what the unit tests call. The tool layer only serialises.
  • crates/qgis-cli/tests/mcp_stdio.rs spawns the real binary and drives it through initialize, tools/list and tools/call, so the handshake is covered end to end.

Disable it at build time with --no-default-features, which drops rmcp and Tokio from the binary:

Terminal window
cargo build --release -p qgis-cli --no-default-features