mcp
qgis-cli mcp
qgis-cli mcpmcp 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
# See what the server offers without starting a sessionqgis-cli mcp --list-toolscapabilities 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:
claude mcp add --transport stdio qgis -- /path/to/qgis-cli mcpTools
| Tool | Arguments | Status |
|---|---|---|
capabilities | — | Live |
crs_info | auth_id | Live |
plan_tiles | bounds, zoom | Live |
project_info | project | Live |
render_map | project, output, extent, width, height, crs, dpi, layers, layout | Native QGIS backend |
export_features | project, layer, output, filter, bbox, fields | Native 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:
{ 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 mcpHow it is built
crates/qgis-mcp the server: tool definitions, schemas, handlerscrates/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
*_reportfunction inqgis-mcp, which is what the unit tests call. The tool layer only serialises. crates/qgis-cli/tests/mcp_stdio.rsspawns the real binary and drives it throughinitialize,tools/listandtools/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:
cargo build --release -p qgis-cli --no-default-features