Skip to main content

MapSmith ๐Ÿ”จ๐Ÿ—บ๏ธ

CI PyPI Python License: AGPL-3.0 Container MCP Ruff X Bluesky

Professional-grade geoprocessing for AI agents โ€” with provenance you can verify.

MapSmith is an open-source MCP server that gives any AI agent (Claude, ChatGPT, Copilot, Cursor, or your own) real GIS analysis capabilities: not just "make me a map", but buffers, overlays, reprojections, zonal statistics, terrain and network analysis โ€” executed by deterministic engines, never hallucinated by the model.

Ask for the result. The agent picks the tools. Every output carries its full lineage.

Why MapSmith

  • Real geoprocessing, not map CRUD. Built on the proven open geospatial stack (GDAL, GeoPandas, Shapely, and more to come: WhiteboxTools, PDAL, DuckDB Spatial, QGIS Processing via sidecar).
  • Provenance by design. Every layer MapSmith produces ships with a machine-readable lineage manifest: source datasets (with checksums), every tool executed, exact parameters, CRS decisions, software versions, timestamps. Everything needed to re-run the analysis without the LLM is in there. No AI slop.
  • The LLM orchestrates, tools compute. Geometry and numbers only ever come from deterministic tool executions โ€” never from model output.
  • Semantic tools, not a tool dump. A curated set of goal-level tools plus a searchable operation catalog (progressive discovery), because agent accuracy collapses when you expose hundreds of raw tools.
  • Model-agnostic infrastructure. Claude, GPT, Qwen, Kimi, GLM โ€” anything that speaks MCP, cloud or local. The leverage is better contracts (typed plans, actionable error codes, a searchable catalog), not weights we would have to maintain. See the manifesto.

Quickstart

# Docker (the supported path)
docker run -i --rm -v $(pwd)/data:/data -e MAPSMITH_WORKSPACE=/data ghcr.io/mapsmith-ai/mapsmith

# or from PyPI
uvx mapsmith

Add to Claude Desktop / any MCP client (stdio):

{
  "mcpServers": {
    "mapsmith": {
      "command": "uvx",
      "args": ["mapsmith"]
    }
  }
}

One-click installs:

Install in Cursor Install in VS Code

or from a terminal: code --add-mcp '{"name":"mapsmith","command":"uvx","args":["mapsmith"]}'

Then ask your agent things like:

"Take parcels.gpkg, keep only the parcels within 300 m of the river in rivers.gpkg, and give me the result with the analysis lineage."

Tools

Tool What it does
describe_dataset CRS, geometry types, schema, extent, feature count of any vector dataset
buffer_layer Metric buffer with automatic UTM estimation for geographic CRS
clip_layer Clip a layer with a mask layer
reproject_layer Reproject to any CRS (EPSG code or WKT)
spatial_join Join by spatial predicate, auto-routed to the fastest engine (SedonaDB > DuckDB > GeoPandas)
run_sql Spatial SQL (DuckDB dialect) over GeoParquet and GDAL formats
zonal_statistics Raster statistics per vector zone with exact fractional pixel coverage ([raster] extra)
hillshade Shaded relief from a DEM, in-memory Whitebox engine ([whitebox] extra)
flow_accumulation D8 flow accumulation with automatic depression filling ([whitebox] extra)
watershed Watershed delineation from a DEM and pour points ([whitebox] extra)
preview_map Interactive in-chat map (MCP Apps) of any datasets, with per-layer provenance and verification badges
validate_plan Statically validate a multi-step plan before running anything: operations, arguments, references, input files, simulated CRS flow
execute_plan Validate then run a plan step by step, with per-step provenance and a plan-level manifest
get_provenance Return the full lineage manifest of any MapSmith output
list_operations BM25-ranked catalog search; detail=true returns parameters and worked examples
server_info Version, license, available engines

Every tool that writes an output also writes <output>.provenance.json next to it โ€” and runs deterministic verification (CRS, dimensions, value invariants) whose results are recorded in the manifest before any failure is raised.

Verification runs on the way in as well as on the way out. The vector operations (buffer_layer, clip_layer, reproject_layer, spatial_join, zonal_statistics) check their inputs first for the failures that produce plausible junk: a layer with no CRS โ€” refused outright, before anything runs โ€” and an empty layer; where an operation takes two vector inputs, also extents that cannot possibly intersect. Afterwards, where an operation carries geometry through unchanged (reprojection, joins, zonal statistics), an output that is mechanically broken is repaired deterministically โ€” make_valid, at most two rounds, written to a temporary file and swapped in only once it is complete โ€” and every attempt is recorded in the manifest, because a repaired output must never look like one that was right first time. Failures needing judgement are never "fixed": an empty result, or geometries eroded away by a wrong distance, come back as named warnings with hints, in the tool result and not only in the manifest, so the agent sees them instead of assuming success.

The Docker image ships with the [raster] and [whitebox] extras included. With uvx, pick your extras: uvx --from "mapsmith[raster,whitebox]" mapsmith.

See results inside the chat

MapSmith's interactive map panel rendered inside Claude Desktop: OSM basemap, buffer and zone layers, and per-layer provenance cards with verification status

preview_map renders your layers on an interactive map panel inside Claude, ChatGPT, VS Code and every other client supporting the official MCP Apps extension โ€” pan, zoom, toggle layers, and read each layer's provenance card (operation, engine, verified โœ“) right next to the geometry it explains. The panel is fully self-contained โ€” no CDN, no bundled libraries, no telemetry โ€” with one outbound request named here rather than buried: the OpenStreetMap background tiles, which reveal the map view you are looking at (never your data), and which the panel drops to a plain backdrop when the host blocks them. On clients without MCP Apps the same call returns the preview as structured data.

Plans: reject wrong analyses before they run

In GIS-agent benchmarks, up to ~47% of failed runs involve planning mistakes โ€” missing or mis-ordered operations โ€” and CRS mismatches halve task success. MapSmith attacks this where it's cheapest: the agent submits a typed plan, and static validation rejects unknown operations (with suggestions), missing arguments, forward references, absent input files and CRS-unsuitable steps before anything executes โ€” with machine-actionable error codes the agent can repair.

{
  "goal": "buildings within 300 m of rivers",
  "steps": [
    {"id": "buf", "operation": "buffer_layer",
     "arguments": {"input_path": "rivers.gpkg", "distance_meters": 300,
                   "output_path": "rivers_300m.parquet"}},
    {"id": "cut", "operation": "clip_layer",
     "arguments": {"input_path": "buildings.parquet", "mask_path": "$buf",
                   "output_path": "at_risk.parquet"}}
  ]
}

"$buf" consumes the output of step buf; references may only point backwards, so plans are acyclic by construction. validate_plan also simulates the CRS of every intermediate dataset from the real input files. execute_plan then runs the chain with per-step provenance plus a plan-level manifest (<output>.plan.json) fingerprinting the exact plan that produced the result.

UNC hosts and NTFS alternate data streams are rejected in every path argument of every tool call, before anything touches the filesystem (on Windows even an existence check on a UNC path talks to an attacker-chosen host). Remote and virtual forms (GDAL /vsi*, https:// COGs) stay available in uncontained mode โ€” cloud-native data is a feature โ€” and are refused once a workspace is set. Validated plans are stricter by design and reject every non-local form.

Set MAPSMITH_WORKSPACE=/data to confine the server to one directory:

  • every path argument of every tool must resolve inside the workspace (checked at the MCP boundary, and again by plan validation with stable error codes);
  • the run_sql DuckDB connection is sandboxed at the engine level โ€” filesystem whitelisted to the workspace (allowed_directories + external access off, which also covers GDAL-backed ST_Read), extension install/load refused, memory and temp-disk capped (MAPSMITH_DUCKDB_MEMORY, default 4GB; MAPSMITH_DUCKDB_TEMP_LIMIT, default 8GB), configuration locked. SQL text can name any path it likes; the engine refuses to open it.

Without a workspace the server is deliberately unconfined (fine for a local stdio server on your own files); plan validation flags run_sql steps with a SQL_NOT_SANDBOXED warning in that mode. Two fine-print notes: the jail assumes a single trusted writer of the workspace filesystem (paths are resolved at check time, so symlink swaps by another local process are out of scope), and the spatial extension is fetched once per environment โ€” for air-gapped deployments pre-install it (python -c "import duckdb; duckdb.connect().install_extension('spatial')") before locking the network down. Defense in depth still applies: for real isolation run MapSmith in a container and mount only the data you want it to see; keep the HTTP transport on loopback/trusted networks until authenticated remote mode ships.

Notebook gallery

Three executable, self-contained walkthroughs in examples/: verified buffer+clip with provenance manifests, terrain & hydrology on the Whitebox engine, and a deliberately wrong plan rejected before execution and then repaired. Each generates its own synthetic data โ€” install and run.

Provenance example

{
  "mapsmith_version": "0.1.0",
  "operation": "buffer_layer",
  "parameters": {"distance_meters": 300.0},
  "inputs": [{"path": "rivers.gpkg", "sha256": "9f2cโ€ฆ", "crs": "EPSG:4326"}],
  "crs_decisions": {"analysis_crs": "EPSG:32632", "reason": "estimated UTM zone for metric buffering"},
  "engine": {"name": "geopandas", "version": "1.0.1"},
  "started_at": "2026-08-18T10:15:03Z",
  "finished_at": "2026-08-18T10:15:04Z"
}

Architecture

 AI agent (Claude / ChatGPT / Copilot / your app)
        โ”‚  MCP (stdio local ยท Streamable HTTP remote)
        โ–ผ
 โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
 โ”‚ MapSmith server                             โ”‚
 โ”‚  ยท semantic tools + operation catalog       โ”‚
 โ”‚  ยท parameter validation, CRS discipline     โ”‚
 โ”‚  ยท provenance recorder (lineage manifests)  โ”‚
 โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
 โ”‚ Engines                                     โ”‚
 โ”‚  ยท vector: GeoPandas/Shapely (built-in)     โ”‚
 โ”‚  ยท SQL/analytics: DuckDB Spatial (built-in) โ”‚
 โ”‚  ยท heavy joins: SedonaDB ([sedona] extra)   โ”‚
 โ”‚  ยท zonal stats: exactextract ([raster])     โ”‚
 โ”‚  ยท terrain/hydro: Whitebox NG ([whitebox])  โ”‚
 โ”‚  ยท qgis_process / GRASS sidecar (roadmap,   โ”‚
 โ”‚    GPL-isolated via subprocess)             โ”‚
 โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Roadmap

  • Zonal statistics (exactextract, exact fractional coverage)
  • Whitebox Next Gen adapter: hillshade, flow accumulation, watershed (in-memory, open tier)
  • Typed analysis plans: static validation against the operation registry + simulated CRS flow before execution
  • Bounded repair: feed verification failures back to the agent for limited retries
  • More terrain & hydrology: slope/aspect, stream network extraction
  • QGIS Processing sidecar (subprocess-isolated): ~900 algorithms
  • Sandboxed code-execution tool for the long tail
  • MCP Apps in-chat map panel with provenance cards (self-contained, works under the default sandbox)
  • Map panel: MapLibre vector rendering and shareable viewer URLs (raster OSM tiles already ship)
  • Remote server (Streamable HTTP + OAuth), long-job progress via MCP Tasks

Install support policy

Docker (or uvx on a machine with working wheels) is the only supported installation path. Geospatial native dependencies across three OSes are a support black hole; issues about broken local environments will be redirected here.

License

  • MapSmith server and engines: AGPL-3.0-or-later (see LICENSE)
  • Client SDK and tool-schema definitions (future sdk/): Apache-2.0

You can self-host MapSmith freely, forever. If you modify it and offer it as a service, the AGPL asks you to share your changes โ€” or talk to us about a commercial license.

"MapSmith" is a trademark of the MapSmith project โ€” see TRADEMARKS.md.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mapsmith-0.2.0.tar.gz (816.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mapsmith-0.2.0-py3-none-any.whl (86.2 kB view details)

Uploaded Python 3

File details

Details for the file mapsmith-0.2.0.tar.gz.

File metadata

  • Download URL: mapsmith-0.2.0.tar.gz
  • Upload date:
  • Size: 816.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.3

File hashes

Hashes for mapsmith-0.2.0.tar.gz
Algorithm Hash digest
SHA256 9fed5b7997dbc7ab8c66819c698f0d715a961f22e89664ae76888e6bebec8c24
MD5 da74fdc663a9bb0a23c1f2b4dd5a402c
BLAKE2b-256 c28c16eb31840e10b575ee06c31e7bcc6408d05383056ae845b40d5b0583541e

See more details on using hashes here.

File details

Details for the file mapsmith-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: mapsmith-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 86.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.3

File hashes

Hashes for mapsmith-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f1e45bbdb57592cbe5fdcf824cfbb8b388d81db0dc84d8077c88c44b88bb999e
MD5 d1ac1c7b9f11897dfe5a08d149ab1813
BLAKE2b-256 491720344b02ba812e0e6c6e7cb1b8ee349b6d699121d1f1352d74ac90a6a793

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page