MapSmithBLOCK
Professional-grade GIS geoprocessing over MCP, with a verifiable provenance manifest on every output
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
[](https://doi.org/10.5281/zenodo.22213091)
[](https://github.com/mapsmith-ai/MapSmith/actions/workflows/ci.yml) [](https://pypi.org/project/mapsmith/) [](https://github.com/mapsmith-ai/MapSmith/pkgs/container/mapsmith) [](https://modelcontextprotocol.io) [](LICENSE)
Ask a question about your data. Get an analysis — and the record that proves it.
Most GIS servers hand an agent a tool to run. MapSmith takes the question, works out the analysis — usually several operations, in an order that has to be right — validates the plan before a single file is touched, runs it, and leaves a record of every step — which bytes went in, with which parameters and CRS decisions, and which checks ran — that somebody else can read afterwards and rerun to confirm.
Try it
Point any MCP client at MapSmith (one JSON block) and ask, in your own words:
Which parcels lie within 1.5 km of the river and sit at 120 m or lower? Give me the mean elevation and the ground area of each.
That is five operations, two coordinate systems and forty-eight checks. What actually happens is below — the plan, the step that gets rejected for reading something a later step produces, the CRS decision behind every metric step, and an answer you can work out on paper before MapSmith sees the files. That rejection is structural, and so is every other one: a plan that is well formed and answers the wrong question runs instead, which is [measured and written down further down this page](#pla
6dfd3ce07595OBSERVED · 2026-10-08Connect
Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control.
claude mcp add mapsmith -- uvx mapsmith==0.8.0
claude mcp add mapsmith:0.8.0 -- docker run -i --rm ghcr.io/mapsmith-ai/mapsmith:0.8.0:None
Exposed tools (28)
22 read · 6 write · 0 destructive.
| Tool | Risk | Description |
|---|---|---|
aspect | read | Aspect from a DEM: downslope azimuth in degrees, 0 = north. GeoTIFF in/out. |
buffer_layer | read | Buffer all features by a distance in meters. |
centroid_layer | read | One point per feature: the geometric centroid, computed in a metric CRS. |
clip_layer | read | Clip a layer to the area of a mask layer. CRS are aligned automatically. |
convert_format | read | Convert a vector dataset between formats; the target is chosen by the |
describe_dataset | read | Inspect a dataset, vector or raster, before analysing it. |
dissolve_layer | write | Merge features into one geometry per value of `by` (or one feature in all). |
execute_plan | write | Validate, then execute a geoprocessing plan step by step. |
explode_layer | read | Split multi-part geometries into one feature per part (attributes copied). |
flow_accumulation | read | D8 flow accumulation from a DEM (GeoTIFF in/out). Depressions are filled first. |
get_provenance | read | Return the manifest of the ONE operation that wrote this dataset. |
hillshade | read | Shaded relief from a DEM: GeoTIFF in, GeoTIFF out (values scaled 0-32767). |
list_operations | read | Find the operation you need. **Say what you have and what you want** — it matters more than the words you search with. |
measure_area | read | Area per feature in SQUARE METRES, written to a named column, with the |
merge_layers | write | Append two or more layers into one (schema union, attributes aligned by name). |
nearest_join | read | Attach each feature |
overlay_layers | write | Set-theoretic overlay of two layers: intersection (default), union, |
preview_map | read | Show datasets on the interactive in-chat map panel (MCP Apps). |
reproject_layer | read | Reproject a layer to a target CRS, e.g. |
run_operation | write | Run ANY catalog operation by name, including the ones with no tool of |
run_sql | write | Run spatial SQL (DuckDB dialect, ST_* functions, read_parquet/ST_Read for files). |
server_info | read | MapSmith version, licensing, and available engines. |
simplify_layer | read | Simplify geometries (Douglas-Peucker, topology preserved) with the drift |
slope | read | Slope gradient from a DEM: GeoTIFF in, GeoTIFF out. |
spatial_join | read | Join by spatial predicate (intersects/within/contains). |
validate_plan | read | Statically validate a multi-step geoprocessing plan BEFORE running anything. |
watershed | read | Watershed of each pour point: DEM + points in, basin raster out (GeoTIFF). |
zonal_statistics | read | Statistics of a raster within each vector zone (exact fractional pixel coverage). |
Trust audit
BLOCKgrade D · trust 63/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | FAIL |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | PASS |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- none-observed
- Network
- declared (1 observation(s))
- Shell
- declared (1 observation(s))
- Dependencies
- pinned
- Secrets in source
- found
Findings (20)
computed = eval(
DATABASE_URL: postgresql://mapsmith:mapsmith@postgres:5432/mapsmith
origins = ["http://127.0.0.1:*", "http://localhost:*", "http://[::1]:*"]
model or the user. The sharp case: refusing `ATTACH 'postgres://user:pw@...'`
"ATTACH 'postgres://user:shh@host/db' AS pg",
monte_baldo_dem.tif
monte_baldo_s2.tif
mount_st_helens_dem.tif
.zenodo.json
for bad in ("__import__(chr(111))", "b1 + x", "open(f)", "b1 % 2", "b1; b2"):url = f"http://127.0.0.1:{server.server_address[1]}/remote.geojson"vrt = _write_vrt(tmp_path, f"/vsicurl/http://127.0.0.1:{server.port}/x.geojson")vrt = _write_vrt(tmp_path, f"/vsicurl/http://127.0.0.1:{server.port}/x.geojson")vrt = _write_vrt(tmp_path, f"http://127.0.0.1:{server.port}/x.geojson")png = base64.b64decode(result["png_data_uri"].split(",", 1)[1])Both matchers now read one definition of what a credential name looks
DuckDB's `aws` extension and read this machine's real cloud credentials back through a tool
DuckDB's `aws` extension and read the host's real cloud credentials back through
<div><h3>Never fetches code on a model's word</h3><p>A statement that says <code>INSTALL</code> or <code>LOAD</code> is refused in both modes since 0.4.0 — an <code>INSTALL</code> is an HTTPS fetch of
docs/images/map-panel.png
Gates applied: no_behavioural_pass.
6dfd3ce07595full audit observations/trust-audit/mcp-server/mapsmith-ai__mapsmith.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-08 | 6dfd3ce07595 | BLOCK | D | 63 | first audit |
Questions
What is the MapSmith MCP server?
Professional-grade GIS geoprocessing over MCP, with a verifiable provenance manifest on every output
What tools does MapSmith expose?
28 in total: 22 read-only, 6 that write, and 0 that can delete or overwrite. Every one is listed on this page with its risk.
Is MapSmith safe to connect to an agent?
No — not without reading the findings first. The audit graded it D (63/100) and found 2 critical or high issues in the source. Each one is listed on this page with the file and line it is on.
What credentials does MapSmith need?
No credential environment variables were found in its source, so it appears to need none.
How does MapSmith run?
It speaks stdio and streamable-http, so it runs as a local process your client starts. It is published on PyPI as mapsmith.
How current is this page?
The grade is for one exact copy of the source (6dfd3ce07595), read on 2026-10-08. The repository is watched and re-audited when it changes.