MapSmith ๐จ๐บ๏ธ
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:
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
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_sqlDuckDB connection is sandboxed at the engine level โ filesystem whitelisted to the workspace (allowed_directories+ external access off, which also covers GDAL-backedST_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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9fed5b7997dbc7ab8c66819c698f0d715a961f22e89664ae76888e6bebec8c24
|
|
| MD5 |
da74fdc663a9bb0a23c1f2b4dd5a402c
|
|
| BLAKE2b-256 |
c28c16eb31840e10b575ee06c31e7bcc6408d05383056ae845b40d5b0583541e
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f1e45bbdb57592cbe5fdcf824cfbb8b388d81db0dc84d8077c88c44b88bb999e
|
|
| MD5 |
d1ac1c7b9f11897dfe5a08d149ab1813
|
|
| BLAKE2b-256 |
491720344b02ba812e0e6c6e7cb1b8ee349b6d699121d1f1352d74ac90a6a793
|