Skip to main content
Glama

MapSmith

DOI

CI PyPI Container MCP License: AGPL-3.0

Professional-grade GIS geoprocessing for AI agents — with provenance you can verify.

mapsmith.dev — a real terrain analysis and the manifest that came with it. Both are build products: the figure is rendered from GeoTIFFs MapSmith writes, so the page cannot drift from what the software does.

MapSmith is an open-source MCP server that gives an AI agent real GIS analysis — buffers, overlays, reprojections, zonal statistics, terrain and hydrology — executed by GeoPandas, DuckDB Spatial, exactextract and Whitebox Workflows, never written by the model. Every dataset it produces lands on disk next to a lineage manifest: inputs with checksums, the exact parameters, the CRS decisions and why, engine versions, and the deterministic checks that ran on the result.

Ask for the result. The agent picks the tools. You can check the work afterwards.

The manifest is a specified format, not MapSmith's private output: JSON Schema, a toolchain-free validator, a conformance suite, and a hundred-line emitter that never imports MapSmith. Records carry spec_version, and CI validates real MapSmith output against the spec's own validator. The specification is archived and citable as 10.5281/zenodo.22205213.

Evidence before promises: an A/B on GABench whose headline is a null result — with the analysis that took our own positive number apart — a correctness suite in its own organisation, Argleton, whose published run grades MapSmith on thirty-one traps with answers computed on paper and has already sent six defects back here, notebooks on a real USGS DEM of Mount St. Helens, an in-chat map panel that shows the verification status of every layer it draws, and a measurement of our own tool discovery that retracted two numbers this page had already published — including the one in the bullet list below.

Quickstart

Add MapSmith to any MCP client over stdio (Claude Desktop, Claude Code, Cursor, VS Code):

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

Docker is the supported path, and confines the server to the directory you mount:

{
  "mcpServers": {
    "mapsmith": {
      "command": "docker",
      "args": ["run", "-i", "--rm",
               "-v", "/absolute/path/to/your/data:/data",
               "-e", "MAPSMITH_WORKSPACE=/data",
               "ghcr.io/mapsmith-ai/mapsmith"]
    }
  }
}

One-click installs:

Install in Cursor Install in VS Code

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

To check it runs before wiring a client, uvx mapsmith starts the server on stdio (Ctrl-C to quit) — it speaks MCP, not a CLI, so a silent prompt means it is working.

This page describes 0.4.0, which is what that command installs. When main runs ahead of the published artifact this paragraph says so and names the difference — a reader should never have to find out by calling a tool that is not there.

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."

The Docker image includes the [raster] and [whitebox] extras. With uvx, pick your own: uvx --from "mapsmith[raster,whitebox]" mapsmith. 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, and issues about broken local environments will be redirected here.

Two things about the image, because they change what happens on your machine: it sets MAPSMITH_WORKSPACE=/data itself (the -e above is explicit, not required) and runs as uid 1000, so pass --user $(id -u):$(id -g) if the directory you mount belongs to another user; and it is built for amd64 only, so on Apple Silicon it runs under emulation.

Related MCP server: NodeAPI

What you get back

Every dataset comes with the file below, written next to it as <output>.provenance.json — enough to re-run the analysis without the model that asked for it:

{
  "spec_version": "1.0.0-draft.3",
  "producer": {"name": "mapsmith", "version": "0.4.0"},
  "operation": "buffer_layer",
  "parameters": {"distance_meters": 300.0},
  "inputs": [{
    "path": "rivers.gpkg",
    "sha256": "b24b884f49eee431133d443d842557d3ed21f3978e2c4b1e8e072fd1240effe8",
    "crs": "EPSG:4326"
  }],
  "crs_decisions": {"analysis_crs": "EPSG:32632", "reason": "estimated UTM zone for metric buffering"},
  "engine": {"name": "geopandas", "version": "1.0.1"},
  "environment": {},
  "verification": [
    {"name": "crs_matches", "passed": true, "detail": "expected EPSG:4326, got EPSG:4326"},
    {"name": "feature_count_exact", "passed": true, "detail": "expected 1, got 1"}
  ],
  "started_at": "2026-08-18T10:15:03Z",
  "finished_at": "2026-08-18T10:15:04Z"
}

This block is checked against the specification's own validator by tests/test_showcase.py, because the page that says records carry spec_version had an example without one for two releases — and this is the record a third-party implementer copies.

Trimmed for the page, not for the file: the real record also carries the output's own path and hash, any geometry MapSmith had to repair, and the notes it made about how the inputs were handled — and every check says whether it was critical and, when it failed, what to do about it. get_provenance returns it for any output.

Why MapSmith

  • Real geoprocessing, not map CRUD. Built on the proven open geospatial stack: GDAL, GeoPandas, Shapely, DuckDB Spatial, Whitebox Workflows and exactextract ship today (more to come: QGIS Processing via sidecar).

  • Provenance by design. Every layer MapSmith produces ships with a machine-readable lineage manifest — source datasets with checksums, tools 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 engines compute, the model orchestrates. Geometry and numbers only ever come from deterministic tool executions — never from model output.

  • Semantic tools, not a tool dump — and a catalog built for thousands. 28 goal-level tools plus a searchable operation catalog, because tool-selection accuracy degrades once a few dozen tools are exposed at once, and fastest when two of them apply to the same input. Capability count has no such ceiling, so capability lives in the catalog. Search narrows it on what you declare and then hands over what survives rather than ranking it for you, because measurement said ranking is the wrong verb — see Finding the right operation.

  • 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.

Tools

Tool

What it does

describe_dataset

CRS, schema/bands, extent, nodata and statistics of any vector or raster dataset

buffer_layer

Metric buffer with automatic UTM estimation for geographic CRS

clip_layer

Clip a layer with a mask layer

overlay_layers

Set-theoretic overlay (intersection/union/difference/…); dropped lower-dimension pieces are declared in the manifest

dissolve_layer

Merge features per key; the aggregation is recorded in the manifest and the group count verified

nearest_join

Nearest neighbour with the distance in meters, UTM-measured on geographic CRS (decision recorded)

explode_layer

Multi-part to single-part, with the part count verified in closed form

measure_area

Area in m², always: ground on the ellipsoid, or planar converted with the CRS's own declared linear unit (survey feet are not metres). Invalid rings repaired before measuring, and a plane that is not equal-area here comes back with the ratio against the ground area

merge_layers

Append layers (schema union); null-filled columns are named in the manifest, the count verified against the sum

simplify_layer

Douglas-Peucker with the drift measured: area/length before and after recorded in the manifest

centroid_layer

Geometric centroids computed in a metric CRS, never on degrees (decision recorded)

convert_format

Convert between GeoParquet/GeoPackage/GeoJSON by output extension, re-read and verified (count and CRS). Two conversions are refused with the reason rather than performed: shapefile output, which truncates field names to 10 characters silently, and GeoJSON for a non-WGS84 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)

slope

Slope gradient from a DEM in degrees, percent or radians; geographic-CRS DEMs refused ([whitebox] extra)

aspect

Downslope azimuth from a DEM, 0 = north; flat cells are −1, not nodata ([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 a provenance card and verification status per layer

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

Catalog search: narrows on what you declare, then returns the surviving set to choose from (status: "choose") or a ranking by engine — BM25, embeddings, or auto; detail=true returns parameters and worked examples

run_operation

Run any catalog operation by name, including those with no tool of their own; arguments validated against the catalog before anything runs

server_info

Version, license, available engines

Finding the right operation

Those are the tools an agent chooses between. Behind them the catalog holds every operation MapSmith can perform — 74 today, and 49 of them have no tool of their own — and it is built to hold thousands. (Two of the 74 are marked planned and say so when asked: the roadmap is in the catalog on purpose, so an agent can answer "not yet" instead of inventing a call.)

The split is the design: tool-selection accuracy degrades past a few dozen exposed tools, while capability count has no such ceiling. That makes reaching scale a retrieval problem, so it is treated as one — and measured like one.

First it narrows, deterministically, on things the caller already knows. Every entry declares what data it takes (vector, raster, dataset, plan, none), what it hands back (dataset:vector, dataset:raster, answer, description), whether it demands a projected CRS, and which family it belongs to.

Measured over 118 answerable requests written by two other model families from job scenarios — a hydrologist with a flood report, a surveyor arguing with a field measurement — neither of which was shown this catalog, because a model handed the entry writes a paraphrase of the entry:

what the caller declares

candidates left

BM25, found@3

embeddings, found@3

right answer in what comes back

nothing — words alone

74

31%

18%

31%

what data I have

48

32%

21%

33%

+ what I want back

30

45%

38%

53%

+ how many datasets I have

16

58%

53%

98%

Two ranking columns, and that is a correction. This table used to carry one, computed with the default engine — which is the embedding one where its model loads and BM25 where it does not. So the published figures were a measurement of what the machine could download, and a CI run that met a 429 from Hugging Face recomputed the first row as 28% where this page said 18%. Not a flaky test: a number that had never been reproducible on a machine without the model, published under a sentence promising it could be checked.

The two also differ in a way worth seeing, and this page had it backwards until 2026-08-30. It said the embedding engine overtakes BM25 once the facets have narrowed. It does not overtake it anywhere: BM25 leads at every row of the table above, by seven to twelve points, and the gap is widest at the fullest declaration. An exact term either matches or does not, and the entries that survive a full declaration are told apart by the words that distinguish them — which is what distinguishes is for. The embedding engine earns its place on the phrasings it has never seen, not on the ranking once the set is small.

The last column is not an accuracy figure — it is a property, and the 98% rather than 100% is worth a sentence. The narrowing never drops the right operation: that is asserted per entry and holds for all 74. What the column measures is whether the surviving set was small enough to hand over WHOLE, and for a handful of requests it still is not, so those fall back to a ranked shortlist and the answer can be outside the top three. Ranking decides the order; it does not decide membership; and the 3% is the gap between "cannot lose the answer" and "can show you all of it".

The third row is the scaling wall, and we hit it in one afternoon. On 2026-08-29 the catalogue went from 51 operations to 61. Two rows of that table got worse: the commonest surviving set went from 26 candidates to 34, past the point where the whole set can be handed over, and delivered fell from 100% to 45% while found@3 fell from 48% to 36%. Adding capability had made discovery worse — the failure this page had predicted at eight hundred operations and met at sixty-one.

Raising the threshold would have postponed it by about ten operations. What fixed it is the fourth row: how many datasets you are holding. That is a fact about your situation — one layer or two — not a guess about our vocabulary, it is derivable from each operation's own signature so a test can check the declaration against the code, and it takes the median surviving set from 34 to 9. The catalogue grew by a fifth and discovery got better, but only because a facet arrived with it. That is the trade this design makes, stated rather than discovered later.

It happened again the next day, and this is what watching a curve is for. On 2026-08-30 the catalogue went from 61 operations to 71. Every ranking figure in that table fell — 28% to 25% bare, 34% to 27% on the input kind — and the delivered column of the second row fell from 48% to 27%, because more requests now leave a set too large to hand over whole. The bottom row did not move: 97%, the same as at 61. Ten more operations, no new facet, and the guarantee held, which is the first time growth has been absorbed by the facets already there. (Not «and at 51»: that bottom row is the arity facet, and dataset_inputs did not exist at 51 operations. The 100% quoted above at that size is the row above it. Two different rows under one sentence is the kind of comparison this page exists to refuse.)

And again at 74, with two operations that a caller is unusually likely to want. select_features and extract_layer are the remedies MapSmith's own error messages had been recommending, so they sit in the busiest corner of the facet space: the average surviving set went from 16 to 17 and the second row's delivered did not move. The bottom row held at 97% for the third catalogue size running. The margin to the wall is now 13. (Those are the figures as measured on 2026-08-31. They were recomputed on 2026-09-01 against human answers — see the note under the table — which moved them without any catalogue change: the surviving set reads 16 and the bottom row 98%. A paragraph about a transition keeps the figures of the transition.)

That is the shape of the trade, and it says when the next facet is due. The figure to watch is not found@3 — a ranker will always get worse as the catalogue grows, and it is a hint. It is the average surviving set at the fullest declaration, the fourth column of that table: 9 at 51 operations, 14 at 61, 16 at 72, 16 at 74. When that crosses 30, delivery stops being a property and starts being a ranking again, and the answer is another fact the caller already knows, not a bigger threshold. (It said median until 2026-08-29, and published the mean: the median at 74 is 14. The distribution is skewed — most requests leave a small set and a few leave a large one — so the two numbers say different things and the mean is the pessimistic one, which is the right one to watch.)

The requests, both labels and the harness are all in the repository: tests/data/discovery_queries.json and benchmarks/discovery_report.py, which recomputes every number above from those files with no network and no model — so they can be checked rather than believed, and tests/test_discovery_report.py fails if this page and the harness disagree. The one exception is the 69%: reproducing that needs the model that did the choosing, and the report says so where it stops.

So it hands over the set instead of picking for you. Below thirty survivors list_operations answers with status: "choose": every candidate, ordered as a hint that says it is a hint, each carrying the sentence that separates it from its neighbours. The threshold is 30 because that is where the surviving set almost always sits: over those 118 requests its median is 14 and it exceeds 30 for two of them — which is the 98% in the table above, seen from the other side. The payload is about 2,100 tokens, less than one wrong operation costs to run and undo.

(That sentence used to say the set had a median of 26 and never exceeded 30. It was false before this catalogue reached 72 operations and nobody noticed, because the test that checks this page against the harness read the table and not the prose around it. It reads both now.)

Three measurements say this is the right shape, and the third is the one that settles it:

our ranking puts the answer in the top three

58%

a model handed the same candidates and asked to choose gets its first pick right

69%

the two labellers who wrote the ground truth agree with each other

70%

These figures went up on 2026-09-01 because the measurement changed, not because the ranker did. Somebody who does this work answered all fifty of the requests the two model labellers had disagreed on, and a request can have more than one acceptable answer: two experienced analysts reach the same result with different tools. So a hit is now counted against every operation a professional would accept rather than against one label, and found@3 rose four to five points. Nothing in the ranking code changed. Read the other way round, the older figures were understating by that much — they scored a system as having failed when it returned the other defensible answer — and the honest description of this table is the answer is among the ones a professional would accept, which is a property, not an accuracy.

Where the secondary answers came from is recorded rather than smoothed over: the primary on each of those fifty is a human choice, and the secondaries were proposed by a third model and adopted wholesale rather than judged one at a time. Two different strengths of evidence, and the file says which is which.

The two model figures are dated: the labels were written on 2026-08-28, against a catalogue of 51 operations. It now has 74, so for any request whose right answer is one of the 23 added since, neither labeller could have been right — the answer was not in the catalogue to name. Measured on the first four requests a person has answered by hand, two of the four have both labellers wrong, and both of those two name operations that did not exist on the 28th. So "both labellers wrong" and "both labellers chose badly" are not the same number, and the honest thing is to say when the labels were made rather than to quietly benefit from the difference. Human answers are replacing them one at a time — benchmarks/ingest_answers.py is how they get in, and every figure above is computed against a human answer where there is one.

All three are over the same 118 requests, which matters: agreement measured over all 155 requests in the file is 68%, and the difference is the 21 pairs where both labellers agreed a request was unanswerable — true, and the easy half. Quoting that 68% beside a 58% computed over the 118 would be comparing two populations, which this table did for half a day.

The last row is a ceiling, not a baseline, and the second row sits at it rather than below it. When two competent labellers disagree three times in ten about which operation answers a request, "the right one" is not a single value to rank toward, and a system scoring above that is fitting one annotator rather than getting better. Two GIS analysts with thirty years each do the same job with different tools and neither is wrong.

That is why the answer is a set and why its reason field says, in words, that the order is a hint and that two defensible candidates are a question for the person who made the request. The caller — an agent with the conversation in context — knows things no ranking can. Where it does not, the human does.

The remaining honesty: the ceiling was measured between two language models. Whether human GIS analysts agree with each other more, less, or about the same is unmeasured, and until it is, these numbers are reported as agreement with model-written labels and never as accuracy.

The family is the one facet that orders instead of filtering, and that is a correction. It used to be a hard filter like the others. It is not like the others: input kind and projected-CRS are facts about the data in hand and output kind is what the caller wants, but family is a guess about our taxonomy, which the caller cannot see. Measured, it removed six candidates out of sixteen — and when the guess was wrong it removed the right operation, with no error, leaving a confident answer assembled from neighbours. Every request in the independent set has 4.4 plausible families. That is the silent-failure class Argleton measures in other people's systems, sitting in our own discovery layer, so it now sorts: declaring the family lifts it to the front and costs positions when wrong, never the answer. The hard cut stays available on catalog.applicable, where asking for it means it.

We do not need a model to extract those facets, because the caller is one. An MCP client is an LLM with the context we lack — it knows what file it is holding and what it is trying to produce. So list_operations asks for them in its schema, and its description leads with why. This is the same shape as LlamaIndex's Auto-Retrieval or LangChain's Self-Querying, minus the model those have to host: here it is already on the other end of the protocol. A geographic raster is never offered slope, because slope refuses one — a property of the data, checked in code, no model in the loop.

Then it ranks, with two engines that both always run. list_operations takes engine: auto (the default), lexical, or vector. Every result carries the engine that produced it, because a BM25 score of 10.03 and a cosine of 0.38 are not on the same scale.

engine

what it is

what it guarantees

autothe default

The embedding engine, falling back to BM25 when the model cannot be loaded

An answer on a machine with no network, and a field saying which engine gave it

lexical — words

Okapi BM25, ~40 lines, no model and no network ever

Identical scores on every machine; term-sorted accumulation, because float addition is not associative

vector — meaning

Static embeddings — a token lookup plus pooling, no transformer, no GPU. Model revision pinned in the source, 512 dimensions, ~130 MB fetched once

Bit-identical across calls in one process (measured, multiprocessing off), with the vectors pinned by a golden-vector test — so a change in the model, the tokenizer or the pooling fails a test instead of an analysis

The default was lexical until the measurement said otherwise, and the measurement is the interesting part. Golden queries written by whoever wrote the catalog share its vocabulary, so they test word overlap dressed as retrieval: on those, BM25 scores 100% found@1 and embeddings 60%. Re-phrased the way somebody with a problem actually phrases it — "the coastline is 400000 nodes and the browser dies" rather than "simplify the geometry" — the finding reversed, on a catalogue of fifty-one entries. It has since reversed back, and both engines degrade as the catalog grows:

catalog size

BM25 found@3

embeddings found@3

10

77%

80%

30

65%

58%

74

50%

40%

This table used to say the opposite, and the reversal is the finding. Published at 10/30/51 it read 78/83, 47/65, 40/55 — embeddings ahead at every size — and the sentence under it said BM25 degrades faster, which is why the embedding engine became a dependency rather than an extra. Recomputed today the crossover has moved: embeddings still lead on ten entries, and from thirty up BM25 leads by a margin that widens with size. Part of that is the catalogue itself, because the distractors are drawn from it and it has grown from fifty-one entries to seventy-four — which is the point rather than a caveat. The near-neighbour effect the eight-hundred-operation test predicted has arrived in our own catalogue, and the two tables that used to disagree now agree.

The curve is recomputed by tests/test_retrieval_degradation.py and compared with this table, so it cannot go stale again in silence — which it did for three catalogue sizes.

And that finding does not survive being scaled up — measured the same day it was published. The distractors above are drawn from our own seventy-four entries, which are semantically spread out. Growing this catalog means adding near neighbours: hundreds of raster and terrain operations that resemble each other. Re-run against 800 real GIS operations, taken from a library that ships them with their own descriptions, the ranking reverses and the embedding engine degrades faster:

catalog size

BM25 found@3

embeddings found@3

74 — our own entries, no foreign distractors

50%

40%

200

48%

25%

800

35%

20%

Embeddings blur near neighbours; an exact term either matches or does not. These two measurements used to disagree, and both were kept because they answered different questions: which engine suits the catalog we have, and which survives the catalog we plan. They agree now — the near-neighbour effect this one predicted has arrived in our own catalogue, so BM25 leads at both scales, and the second question has the answer neither. The embedding engine is still the default, and the measurement that made it one no longer says so: that is a decision to take rather than a number to quietly restate. At 800 entries the better engine is wrong two times in three, so scale will not be bought by choosing a better ranker. test_retrieval_at_scale.py keeps the projection under measurement rather than under opinion.

And the narrowing does not scale on its own either — this page claimed otherwise and was wrong. It said the facets leave sixteen candidates at 800 operations just as they do at 200. The sixteen is real and it is produced almost entirely by family: those 803 operations are all raster-in, raster-out, so input kind and output kind cut nothing at all, and only the taxonomy does — a choice among 43 families that the caller has to guess. Which is exactly the facet that must not filter.

So the open problem has a sharper shape than "ranking is hard". What is needed at a thousand operations is more facts a caller can state without knowing our taxonomy — how many inputs an operation takes, whether it changes geometry or only attributes, whether the output has the same number of features as the input. Those are structural properties of the operation, they are checkable against the code rather than declared by hand, and they separate the pairs a bag of words cannot: spatial_join from overlay_layers, flow_accumulation from extract_streams. That work is not done, and until it is, the honest claim is the measured one: the guarantee above holds at seventy-four operations, not at eight hundred.

How an entry has to be written is a published specification, not a convention: docs/catalog-entry-spec.md, with a normative JSON Schema that every entry validates against in CI. Each field is there because a measurement said so — including the two that measured to nothing and are documented as such, because a spec that only reports what worked is an advertisement.

And discoverability is a contract per operation, not an average. A catalog-wide 90% found@3 over fifty entries means five are invisible and the average will not say which. So every available entry is probed with its own first worked example, with its own facets declared (test_discovery_contract.py, parameterised over the catalog, so a new operation is under contract the moment it is added). Two things are required of it: the facets the entry declares must never drop that entry, and the entry must reach the caller.

Its rank is no longer one of them, and removing that is the point. The contract used to demand the top three. That looks like a discovery contract and is a ranking contract, with one bad property: the only way to repair a failure is to reword the entry until the ranker likes it. Fifty entries tuned that way score nineteen points better on examples we wrote than on requests written by anyone else — that gap is measured, and it is where a published 70% on this page turned into 51% overnight. A test whose repair procedure is fit the text to the scorer manufactures the number it reports. What remains under contract is the part that is deterministic and ours; rank inside the delivered set is still measured, and no longer fails a build.

The old form still earned its place the first time it ran. centroid_layer advertised “label points for a polygon layer” and ranked below point_on_surface. The ranking was right: a centroid can fall outside its own polygon, which is Argleton trap 014 — our catalog was recommending the defect our own suite measures. The example changed, not the score.

And when the two engines agree on nothing, the search says so instead of answering. This is the failure that measurement turned up in our own product: asked "send an email to my accountant", the embedding engine returned idw_interpolation with the same confidence as a real answer — a silent error in the layer whose job is to prevent them. A similarity threshold does not fix it, because there is no line to draw: "convert this mp4 to a gif" scores above sixteen of twenty genuine queries. What does separate them is the two rankers landing on nothing in common — mean top-3 overlap 0.90 of 3 when an answer exists, 0.18 when it does not. So a query the catalog cannot place comes back as status: "unsure", carrying both engines' guesses and the question that narrows the catalog deterministically: what kind of data do you have. It fires on 9 of 11 unanswerable queries and suppresses 1 correct answer in 20.

And when the facets leave nothing at all, it says which declaration did it. Zero candidates used to fall through the branch above and come back as "0 operations survive, which is few enough to read" — prose that means nothing and, worse, an empty candidate list, which an agent reads as MapSmith cannot do this. It was found by the discovery log below on its first real session: "how much land is in each of these parcels" with produces="answer" left nothing, while measure_area computes exactly that and declares dataset:vector because it writes the areas into a column. So that case is now its own answer — each declaration with the number of operations that would survive without it, smallest first — and it is arithmetic, not ranking.

Below the choose threshold it stops refusing and becomes a warning instead — order_is_weak on the delivered set. Refusing made sense while the search was deciding; handing over every candidate is not deciding, so the disagreement reverts to being evidence about the order, which is the only thing it was ever evidence about.

The applicability filter above runs first for both engines — otherwise the guarantee would only be true of one of them, and there is a test that says so.

Then it runs, tool or no tool. Most catalog operations have a tool of their own; the newer ones increasingly do not, and run_operation(operation, arguments) runs those by name. This is deliberate: capability count has no ceiling, but the exposed tool list has one, so the catalog is allowed to grow faster than the tool list. Arguments are checked against the catalog before anything executes — unknown operation (with a "did you mean", from the same ranking), missing or misnamed argument, wrong type, path outside the workspace — and every error carries a stable code. Execution goes through the same path as execute_plan, so an operation cannot behave one way alone and another way inside a plan.

Both engines embed the identical document text (catalog.document_text), so a comparison between them measures the ranking and nothing else. Three test files keep the rest under measurement rather than under opinion: the degradation curve over our own catalog, the projection against 800 real neighbouring operations, and a discoverability contract per entry. That is what turns the scaling limit into a curve you can watch rather than a number someone guessed.

Determinism is the reason for building it this way rather than reaching for a hosted embedding API: that would make tool discovery a network call whose answer can change under you, and an agent that finds a different tool tomorrow for the same question is not reproducible, whatever its manifest says. The one network access left is the model download on first use, at the pinned revision; after that the vector engine is local, and an install that never makes it keeps BM25, and the engine field of every result says which one answered.

Making it better with your own requests, without a model that drifts

The 155 requests behind those percentages were written by two language models. They are the best set we could build without users, and they are not what users ask: a real request names the file somebody actually has and the words their field actually uses.

So MapSmith can record its own. Set MAPSMITH_DISCOVERY_LOG to a file path and each search is written as one JSON line together with the operation that was run after it — the query, the facets declared, which engine ranked it, every candidate delivered, and where in that list the chosen one sat:

MAPSMITH_DISCOVERY_LOG=/data/discovery.jsonl   # then work normally for a while
python benchmarks/log_to_cases.py /data/discovery.jsonl

For the part that needs eyes rather than a pipe, there is a dashboard — see below.

log_to_cases.py prints those lines as rows shaped like tests/data/discovery_queries.json and flags the two that matter: a run the ranking did not put first (the answer was on screen and the order was wrong) and a search nothing followed (a request the catalog did not serve). It prints; it never writes. Which rows become test cases is a person's call.

None of this trains anything, and that is the design. A ranker that learns from what callers pick learns from an ordering it produced: the operation shown first gets picked more, gets learned as correct, gets ranked first harder — a confident answer nothing contradicts, which is the exact failure this product exists to measure. The model revision stays pinned, held there by a golden-vector test, so the same query gets the same answer next year. What improves instead is the catalog text — a phrasing, a distinguishes that does not distinguish — as a diff somebody can read and revert. That loop is not the weak option: it is what took found@3 from 18% to 58% and delivery to 98%.

The log is off unless the variable is set, holds queries and operation names and nothing else (no dataset paths, no arguments), is guarded by MAPSMITH_WORKSPACE like any other path MapSmith writes, and never leaves the machine — nothing reads it back. Your queries describe your work; treat the file that way, and delete it when you are done.

One question, end to end

Everything above is about one step. Here is a whole question — six parcels, a river, an elevation grid, and five operations picked out of 74 — with the search, the arguments and the verification of each step as they were actually recorded.

Nothing in this section is drawn. benchmarks/worked_example.py builds fixtures whose answer can be worked out on paper, asks the catalogue in the words of the problem, validates and runs the plan, reads the manifests, and writes what follows; tests/test_worked_example.py fails if this page and that script disagree. The position column is BM25's rather than the default engine's, because a published figure should not depend on whether a model download succeeded on the machine that built the page — the narrowing, which is the point, is identical on both. Two things worth watching: the middle column, where the catalogue goes from 74 operations to a handful the caller can read; and the CRS column, where every metric operation says which coordinate system it moved the data into and why.

flowchart TB
  ASK["<b>Parcels within 1.5 km of the river whose mean ground elevation is at most 120 m, with the elevation and the ground area of each</b>"]
  ASK --> PLAN{{"plan validated<br/>before anything runs"}}
  PLAN -. "rejected: FORWARD_REFERENCE" .-> BAD["'mask_path' references '$buffer' which runs later — move step 'buffer' before 'near'"]
  BAD:::bad
  BUFFER["<b>buffer_layer</b><br/>74 operations &rarr; 29 candidates &rarr; chosen<br/>CRS EPSG:32610<br/>9/9 checks"]
  PLAN --> BUFFER
  NEAR["<b>clip_layer</b><br/>74 operations &rarr; 14 candidates &rarr; chosen<br/>12/12 checks"]
  BUFFER --> NEAR
  HEIGHT["<b>zonal_statistics</b><br/>74 operations &rarr; 4 candidates &rarr; chosen<br/>CRS EPSG:4326<br/>7/7 checks"]
  NEAR --> HEIGHT
  AREA["<b>measure_area</b><br/>74 operations &rarr; 29 candidates &rarr; chosen<br/>CRS WGS 84 &#40;ellipsoidal&#41;<br/>10/10 checks"]
  HEIGHT --> AREA
  FILTER["<b>select_features</b><br/>74 operations &rarr; 29 candidates &rarr; chosen<br/>CRS EPSG:4326<br/>10/10 checks"]
  AREA --> FILTER
  OUT[["3 parcels, each with elevation and ground area"]]
  FILTER --> OUT
  classDef bad stroke-dasharray: 4 3

what the agent asks for

it declares

candidates

picked

at position

“everything within one and a half kilometres of the river”

vector, dataset:vector, 1 dataset(s)

29 of 74

buffer_layer

2

“keep only the parcels that fall inside that strip”

vector, dataset:vector, 2 dataset(s)

14 of 74

clip_layer

1

“how high is the ground under each of these parcels”

raster, dataset:vector, 2 dataset(s)

4 of 74

zonal_statistics

3

“how big is each one on the ground”

vector, dataset:vector, 1 dataset(s)

29 of 74

measure_area

1

“drop the ones where the ground is above 120 metres”

vector, dataset:vector, 1 dataset(s)

29 of 74

select_features

2

step

operation

arguments that mattered

CRS decision, recorded

checks

buffer

buffer_layer

distance_meters=1500

EPSG:32610 — estimated UTM zone for metric buffering on a geographic CRS

9/9

near

clip_layer

mask_path=$buffer

12/12

height

zonal_statistics

zones_path=$near, stats=['mean', 'min']

EPSG:4326 — zones and raster share the same CRS

7/7

area

measure_area

input_path=$height, method=geodesic

WGS 84 (ellipsoidal) — ground area computed on the ellipsoid the layer's CRS names; no map plane is involved, so no projection distortion enters

10/10

filter

select_features

input_path=$area, by=field_between, field=mean, maximum=120

EPSG:4326 — no CRS change: selecting rows does not touch coordinates

10/10

Every step is inside the plan, the last one included: select_features took 4 rows and returned 3, with a manifest like every other write. This step used to run outside the plan, because the only operation that could answer it was run_sql — which takes its inputs inside a SQL string, declares zero datasets, and therefore cannot join the plan's dataflow. That boundary is deliberate and has not moved: substituting $step into arbitrary strings would be a grammar in which a planner assembles a path out of text. What changed is that it is no longer the only way to ask.

The answer, which can be worked out on paper before MapSmith sees the files: the parcels are squares of 0.0015° at 46.2°N, so each is about 119 m by 167 m, and the elevation ramps west to east across the fixture.

name

mean

min

area_m2

North Field

104.85

104.14

19303.33

Mill Meadow

110.51

109.8

19303.33

Old Orchard

117.58

116.87

19303.33

The rejected plan is the honest half. Steps in the wrong order are the dominant failure class in the agent benchmark, so the example includes one and shows what the validator says about it, before any file is touched. It earned that place while this was being written: the first version of the plan passed distance_m where the operation declares distance_meters, and the validator named the argument and listed the three it accepts.

Formats

Format

Read

Write

GeoParquet 1.0 / 1.1 — WKB plus geo metadata

yes

yes, every path

GeoParquet 2.0 — Parquet-native GEOMETRY/GEOGRAPHY logical types

yes, including files that carry no geo key at all

yes on the SQL path: run_sql writes both layers into one file

GeoPackage, Shapefile, FlatGeobuf, GeoJSON, …

anything pyogrio/GDAL opens

via GDAL

GeoTIFF / COG

yes

outputs of the [raster] and [whitebox] engines

GeoParquet 2.0 moves geometry into Parquet's own logical types and makes the geo key optional, so "a Parquet file with geometry in it" no longer implies that key. MapSmith reads the CRS from the logical type when it is the only place it exists — the spec default, an authority string, projjson:<key>, or the whole PROJJSON document inline, which is what DuckDB writes. run_sql emits both layers (geoparquet_version 'BOTH'), so one output file satisfies a 2.0-native reader and a GeoPandas 1.x one; the GeoPandas writer path stays 1.x because GeoPandas 1.1 caps schema_version there.

One declaration is deliberately refused rather than guessed: srid:<n>. The spec defines it as a numeric identifier and names no authority — its own example is srid:0 — so reading it as EPSG:<n> would be inventing a coordinate system and recording it as fact.

Choosing the stack, and never swapping it in silence

MAPSMITH_STACK picks the geoprocessing stack once, at the start. The default is opensource — GDAL, GeoPandas, DuckDB, Whitebox — and needs no licence. esri routes to ArcPy on a machine that has ArcGIS Pro installed, through a subprocess and files, because ArcPy lives in Pro's own interpreter. MapSmith ships no part of it and takes no licence to look: what a session can reach is read from the metadata the installer left on disk, and server_info reports it, so a caller learns it before planning five steps around it rather than at the first failure.

The rule that makes the choice worth making is what happens at the edges. When the chosen stack cannot do something, MapSmith says which of three things is true — there is no such tool, this licence tier does not include it, or it would need an online service — because those lead to three different decisions and one word for all of them leads to none. Where a route exists and cannot run, the manifest names the engine that actually produced the numbers and why the preferred one did not: an engine quietly replaced by another is a record that is true and a number nobody chose.

One operation is routed today: buffer_layer. Everything else runs on the open source stack whatever MAPSMITH_STACK says. That is the state of the wiring rather than a property of the design, and it is written here because the alternative was a defect: a table declaring three routes while one operation consulted the router meant requesting the stack ran two of them elsewhere with nothing in the manifest saying so. It was fixed before this release by shortening the table, not the sentence.

Two things this is not. It is not a comparison: MapSmith calls what you have installed, and this repository publishes no scores for anybody's engine but the ones Argleton grades in public. And it is not equivalence: two further operations were measured against both stacks on the same fixture and deliberately left unrouted, because matching geometry is not the whole story — on a dissolve the other stack drops every attribute, so a pipeline that dissolves and then reads a column would find the column on one stack and nothing on the other. That is a difference to record before it is a route to offer.

Verification, in and out

Every tool that writes a dataset also writes <output>.provenance.json beside it and verifies its own work — CRS agreement, geometry validity, raster dimensions, count and extent invariants — recording the results in the manifest before raising anything, so the audit trail survives the error.

Verification runs on the way in as well. Before an operation touches your data, MapSmith checks the failures that produce plausible junk: an input with no CRS is refused outright, because metric maths on unknown units is how a confidently wrong answer gets made; an empty input, or two layers whose extents cannot possibly overlap, comes back as a named warning with a hint — in the tool result, not only in the manifest, so the agent sees it instead of assuming success. (The join fast paths, DuckDB and SedonaDB, only ever receive inputs that already share a known CRS; they verify their output and diagnose an empty join.)

An output whose geometry is mechanically broken — typically invalidity inherited from an invalid input — is repaired deterministically: make_valid, at most two rounds, written to a temporary file and swapped in only once it is complete, and skipped rather than risked where a rewrite could drop data (a multi-layer GeoPackage is refused, not rewritten — extract_layer copies the one you mean into its own dataset, with the container and the layers left behind named in its manifest). Every attempt lands in the manifest and in the tool result, because a repaired output must never look like one that was right the first time. Failures that need judgement are never "fixed": an empty result, or geometries eroded away by a wrong distance, come back as warnings with hints for the agent to act on.

And a manifest can say which configuration produced the numbersenvironment, section 3.8 of the manifest specification, empty when there is nothing to say. What made it concrete: a GeoTIFF and the .aux.xml file beside it can declare different georeferencing, and GDAL prefers the sidecar by documented design, because that is how somebody overrides georeferencing they know to be wrong. Both readings are the library behaving exactly as written, and on one fixture the same file gives an area four times larger and an origin a hundred kilometres away. There is nothing upstream to fix and everything to state, so describe_dataset reports both sources when a raster has two, and twelve operations that read a raster's grid directly refuse instead — zonal statistics, resampling, clipping, reclassification, band maths, reprojection, band extraction, band statistics, locating an extreme cell, sampling at points, the elevation profile and the line of sight — naming both readings and saying how to choose. Describing is different from computing: a file with two georeferencings is a thing to be told about, not a coin to flip. This is the multi-layer refusal (#29) on a second axis — the format's default answering a question the caller never asked.

The terrain and sampling operations do not refuse yet, and saying "any operation that computes" would be the promise-with-no-caller this release already found once: the terrain engine catches the same file by a different route, because it compares its own reading of the grid against GDAL's and stops when they differ, but its message names neither the sidecar nor the way out. Sampling a raster at points does not catch it at all. Extending the refusal to the remaining raster operations is on the roadmap below.

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 the chat — pan, zoom, toggle layers, and read each layer's provenance card (operation, engine, and one of three honest states: verified ✓, verification failed, or not verifiable when no critical check ran) right next to the geometry it explains. Field-tested on Claude Desktop; it renders in any client that implements the official MCP Apps extension, and on clients without it the same call returns the preview as structured data.

The panel is 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. The preview is deliberately lossy (simplified geometry, capped feature counts): the dataset of record stays on disk with its manifest.

Plans: reject wrong analyses before they run

In GISAgentBench — 349 practitioner-sourced tasks over 128 GIS APIs — the best frontier agent completes 32.7% of tasks under strict scoring, and planning defects dominate the failures: missing operations in 28.3% of failed runs and wrong operation order in 18.4% (multi-label, so up to ~47% involve a planning mistake), against 7.8% for parameter errors. MapSmith attacks this where it is 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.

Confinement

UNC hosts and NTFS alternate data streams are refused 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 — are refused by default since 0.2.2 and need MAPSMITH_ALLOW_REMOTE=1; a workspace refuses them whatever that setting says (details below). Validated plans are stricter by design and reject every non-local form, opt-in or not.

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 in the engine itself, because SQL text is out of reach of a textual path check: filesystem whitelisted to the workspace (allowed_directories + external access off, which also covers GDAL-backed ST_Read), memory and temp disk capped (MAPSMITH_DUCKDB_MEMORY, default 4GB; MAPSMITH_DUCKDB_TEMP_LIMIT, default 8GB), configuration locked. SQL can name any path it likes; the engine refuses to open it.

MAPSMITH_DISCOVERY_LOG is the one path MapSmith writes to that no tool argument names, so it goes through the same check: outside the workspace it is refused, and the refusal disables the log and says so on stderr rather than failing the search that triggered it.

Without a workspace, file access is deliberately unconfined — fine for a local stdio server on your own files — and plan validation flags run_sql steps with a SQL_NOT_SANDBOXED warning. Code execution is closed in both modes, and since 0.4.0 the layer that closes it is the right one: INSTALL and LOAD in a statement are refused outright, because an INSTALL is an HTTPS fetch of a native binary run in this process on SQL a model wrote. Until 0.4.0 only the implicit forms were off, and an audit installed DuckDB's aws extension and read this machine's real cloud credentials back through a tool result — the whole story is in SECURITY.md, including why none of the four existing layers saw it. Extensions already loaded keep working, spatial included; to acquire others, name them where the agent cannot reach: MAPSMITH_ALLOW_EXTENSIONS=postgres,azure in the environment of the process that starts the server. Behind that, community extensions stay off (shellfs turns a filename into a shell command), unsigned extensions are refused, DuckDB's HTTP and S3 filesystems are disabled, and the configuration is locked.

The network is closed too, unless you open it. Remote and virtual forms — GDAL /vsi*, https:// COGs — are refused by default in path arguments and inside run_sql text, because the path is written by the model rather than by you: a third-party dataset carrying "the updated layer lives at https://evil.tld/x.gpkg" was otherwise enough to have GDAL parse attacker-chosen bytes in-process. Set MAPSMITH_ALLOW_REMOTE=1 to allow them — cloud-native data is a real use case and the capability is gated, not removed. A workspace refuses them regardless, since containment and "fetch whatever URL the model names" cannot both be true. The test suite asserts every branch by counting requests at a loopback server (tests/test_duckdb_sandbox.py). The full threat model — and what is explicitly not covered — is in SECURITY.md.

Fine print, because it changes how you deploy this: the path jail assumes a single trusted writer of the workspace filesystem (paths are resolved at check time, so a symlink swap by another local process is out of scope); the DuckDB spatial extension is fetched once per environment by MapSmith itself, through the Python API rather than by any statement, so on air-gapped machines pre-install it (python -c "import duckdb; duckdb.connect().install_extension('spatial')") before locking the network down; and the HTTP transport has no authentication in this release, so keep it on loopback or a trusted network. For real isolation, run the container and mount only the data you want it to see.

The dashboard

Everything this project knows about itself is computed somewhere and most of it is printed once and lost, which is how a number ages into a claim. benchmarks/dashboard.py gathers it into one self-contained HTML file — no CDN, no fonts, no analytics, works with the network off:

python benchmarks/dashboard.py --log /data/discovery.jsonl --argleton ../argleton
  • Operations — every entry, and whether a caller actually reaches it. Asked twice: with words alone, and with the facets a caller knows. Three outcomes are kept apart — a rank, an answer that did not contain the entry, and a search that declined because the two rankers shared nothing. Collapsing the third into the second is the first thing this page got wrong about itself, and it drew ten working operations as broken.

  • Search quality — the facet ablation for both rankers, and the degradation curve as the catalog grows, which is the measurement the embedding engine became a dependency for.

  • TrapsArgleton's families and what each engine does with them, MapSmith included and not flattered. With --argleton <path> it reads a checkout and shows the per-family detail; without one it falls back to the vendored citation and says so.

  • Answer the open questions — the requests where the two model labellers named different operations, and the cases the discovery log recorded, answered by clicking. The percentages recompute against your answers as you give them, and they come back out as JSON. This is the open question the published figures rest on: two labellers agreeing 70% of the time is the ceiling of a task with no single right answer, and the only way past it is somebody who has done the job.

  • Trend — each generation appends a row beside the page, so the numbers are a series rather than a snapshot. Identical consecutive rows are dropped: rebuilding five times must not manufacture a trend.

It is a snapshot — a new operation or a new trap appears when it is generated again — and regenerating keeps every answer already given, because answers are stored against the text of each question rather than its position.

We measured whether this actually helps

Claims about agent performance are cheap, so docs/benchmarks.md reports an A/B on GABench — 57 executable GIS tasks over a 133-tool server, scored by its deterministic evaluator — where the only variable is whether the agent's typed plan is validated before the solver runs.

The honest headline is a null result, on a frontier model and on a small one, and the interesting part is why:

Arm A (no gate)

Arm B (gate)

Sonnet 5 — TAO / PEA

0.824 / 0.430

0.781 / 0.425

Haiku 4.5 — TAO / PEA

0.660 / 0.320

0.714 / 0.366

Haiku looks like a clean win until you notice the gate only fired on 4 of 57 plans, and that the 53 tasks it never touched moved by just as much: the aggregate delta is run-to-run variance, and measuring that noise floor (2–5 points per metric on a single repetition) is the reusable result. What survives is narrower — on the plans it did repair, tool selection improved by +0.19 TAO — and it points at where the failures actually are: PEA around 0.4 in every arm, i.e. wrong parameters and missing outputs at execution time, which is why MapSmith enforces its plans at the execution boundary and verifies inputs and outputs at runtime rather than advising an agent that improvises.

Three further arms then measured the configuration MapSmith actually ships — the plan enforced, no improvisation between validation and execution — over 375 runs, and the result cuts both ways: enforcing reproduces its own score 3–18× more tightly than an improvising solver, and it does not beat it on accuracy (parity on tool selection, measurably worse on ordering). One of those arms also refuted a conclusion this page had published two arms earlier; the correction is kept in place rather than edited away.

The harness is in benchmarks/gabench-ab/, including the split_analysis.py that took our own win apart and the rep_analysis.py that bars every delta against a measured noise floor.

Three executable walkthroughs in examples/: verified buffer+clip with provenance manifests, terrain and hydrology on a real 520×520 USGS DEM of Mount St. Helens, and a deliberately wrong plan rejected before execution and then repaired. The terrain notebook also shows what happens when reality bites: that DEM is stored with the standard TIFF predictor, which Whitebox Workflows 2.x does not undo when reading (upstream report), so MapSmith detects it, converts the input first, and discloses the workaround in the manifest.

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)             │
 └─────────────────────────────────────────────┘

When not to use MapSmith

  • You need an authenticated remote server today. The Streamable HTTP transport has no authentication in this release: anyone who can reach the endpoint can run every tool against everything the process can see. Loopback or a trusted network only (SECURITY.md).

  • You want a sandbox for arbitrary agent code. MapSmith confines paths and the SQL engine; there is no code-execution tool yet, and a path jail is not a container.

  • You need cartography. No styling, no layouts, no print composer. Outputs are datasets, plus a lossy read-only preview panel — not maps you publish.

  • Your data lives in a database. MapSmith reads and writes files (GeoParquet, GeoPackage, anything GDAL opens). There is no PostGIS engine and no database catalog — the [postgres] extra is for the optional job ledger, not for data.

  • Your data lives in object storage. Since 0.2.2 remote and virtual paths are refused unless you set MAPSMITH_ALLOW_REMOTE=1, and refused whatever that setting says under a workspace — which is what the container runs with by default. DuckDB's own HTTP and S3 filesystems stay off in every mode, so read_parquet('s3://…') does not work even with the opt-in: fetch the data down first, or run unconfined with remote reads on.

  • You want the full breadth of a desktop GIS. 28 tools plus a catalog that tells the agent what does not exist yet. The ~900 QGIS Processing algorithms are on the roadmap, not in the box.

  • You expect plan validation to make a weak model strong. Our own A/B says advisory validation upstream of an improvising solver does approximately nothing at aggregate level — and the enforced configuration MapSmith ships, measured afterwards, did not beat it on accuracy either. What enforcement buys is reproducibility (the numbers).

  • You want us to debug your local geospatial toolchain. Docker, or uvx where the wheels work, are the only supported paths; a hand-built native GDAL stack is not, on purpose.

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

  • Runtime verification: input preconditions, warnings with hints in the tool result, bounded deterministic repair recorded in the manifest

  • MCP Apps in-chat map panel with provenance cards (self-contained, works under the default host sandbox)

  • GeoParquet 2.0: read Parquet-native geometry types (including files with no geo key), write both layers from the SQL path — the GeoPandas writer path follows when GeoPandas lifts its schema_version cap and 2.0.0 stops being a release candidate

Next, in the order we intend to do it. The linked items carry a written spec — a roadmap line without one is a wish, so the rest get theirs before work starts on them:

  • A suite for the failure every existing benchmark misses — a result that is wrong and reported as successful. It exists, it is not here, and it is not ours to grade: Argleton lives in its own organisation under Apache-2.0, because an evaluation that lives inside the thing it evaluates is easy to dismiss in one line. Closed-form truth, no model in the evaluator, fixtures rebuilt rather than vendored.

    Its published results measure MapSmith, and what they say about us is why they are linked from here. On the current run — all twenty-nine families — MapSmith answers every trap correctly: 0.00 silent errors over 31 traps, nothing skipped. One of the thirty-one is not an answer at all but a refusal: a raster and the sidecar beside it declare different georeferencing, both readings are GDAL behaving as documented, and the right move is to stop and say so rather than pick one. That family arrived on 2026-08-31, the morning after the list of twenty-seven was closed, and it is the reason a manifest can now name its environment (see the changelog).

    The twenty-ninth arrived on 2026-09-02 and is the one that reads oddly until you see it: a survey plot whose easement ring is wound the same way as its outline. A shapefile carries no nesting, so which ring is a hole is decided by the winding and by nothing else — the easement comes back as a second shell and its area is added, flattering the owner by 6.9% with a correct bounding box, a correct CRS and no warning. MapSmith repairs it and records the repair, which is the only reason the number is right.

    Two of the last four caught defects here, and both are fixed. A DEM whose rows run south to north made a 5.7 degree slope come back as 45, with the output raster written at the origin and all five verification checks green — the coordinate system had survived and only the geotransform had not. And a pipe network with a treatment plant in the same layer totalled 3000 m of pipe where there are 2000, the plant's perimeter added in silence.

    Before those, grid registration was the one MapSmith could not attempt at all when it was published: a DEM that declares its values sit at grid nodes rather than filling cells, where every position moves half a cell if you ignore the tag. Nothing here read the tag, and no operation reported where a cell is. Both are fixed, in one module rather than at the point of failure, because the defect was in every place that turned an index into a coordinate. The run itself also separates the passes it earned from the ones it did not: the mismatched-CRS join and the feet-as-metres unit are MapSmith's own discipline, the Web Mercator pass comes from a default (ground area is geodesic unless you ask for the plane) rather than from care, and the TIFF-predictor pass is still rasterio's. The datum-ballpark pass is the newest and the least flattering: MapSmith failed that trap on 2026-08-26 — 74 m out, with a manifest recording a successful reprojection — and the pass is the fix, not the original behaviour. The run where it failed is still published. The finding from the first run stands and matters more than the score: that 0 and MapSmith's verification had nothing to do with each other — seven checks passed on that trap and not one of them looks at whether the number is right. A provenance manifest records what was done; it does not certify that it was right, and this README used to imply otherwise by promising a run "with verification disabled". There is no such switch and we are not adding one.

    Six defects have come back from it, which is the return we wanted from putting the suite outside: the datum-ballpark failure above — 74 m out with a manifest recording a successful reprojection, the most serious of the three because nothing in the output looked wrong; a multi-layer container resolved silently to its default layer, answering 4 features where the truth was 31 (#29, filed before the trap was published — extract_layer is the way out of that refusal now); a south-up DEM whose georeferencing was dropped on read, so a 5.71° slope came back as 45° with five green checks; totals over a layer holding lines and polygons together, where a plant's fence line was added to 2 km of pipe in silence and every individual row stayed right; two probes answered unsupported because nothing could say where a raster's lowest cell was; and three probes that came back unsupported because MapSmith had no area operation at all — measure_area exists because a trap said so, and it carries the first check here that asks whether the number is right rather than whether the operation ran. #25 is closed against Argleton rather than left open here.

  • Agent-loop repair: hand verification failures back to the agent as structured, actionable errors, with a bounded retry budget recorded in the manifest. Our own measurements say the runtime error message is the information channel that works

  • Tool contracts that carry their own rules: argument constraints enforced and stated, and errors that name the rule rather than only the violation. The one intervention in our benchmark work that moved a metric past its noise floor

  • A project brief for the requests that are a chain, not a call. A third of real requests are not one operation: on the fifty hardest requests in our own set — the ones two model labellers disagreed about, answered by hand on 2026-09-01 — sixteen have "this is a sequence" as the answer or as a defensible second answer. To those, handing back a set of candidates is the wrong shape: none of the candidates does what was asked. So the answer becomes a brief: what has to happen, in what order, which engines this machine has, and which decisions the caller has to make before anything runs — the extensive-or-intensive choice in an areal interpolation, the buffer width that lives in a regulation rather than in the request, the base length of a gradient. Today those surface one at a time, as refusals.

    Two constraints are part of the plan rather than details of it. The brief is a rendering of an already-validated plan, never a preamble to one: build the plan, validate it, then narrate the validated plan — and every sentence in it has to trace back to a declared field, so a claim that traces back to nothing is a claim somebody invented, which is checkable by machine. And MapSmith installs nothing: the brief names what is missing and prints the command, and a person runs it. The reason is dated — see SECURITY.md on why INSTALL in a SQL statement is refused in both modes since 0.4.0. A server that installs on authorisation is the same shape with a consent dialog in front, and the consent comes from somebody who has just read persuasive prose written by the process asking for it.

    Depends on the item above: the brief reads the rules the tools declare, so there is less to derive from without them.

  • Satellite embeddings as a first-class input: per-zone embedding vectors (multiband zonal statistics) and similarity rasters against a reference location, over the open AlphaEarth annual dataset (CC-BY 4.0 COGs). Deterministic arithmetic on a raster — no model inference in MapSmith — with the tile, year and reference vector recorded in the manifest

  • Authenticated remote mode (OAuth on the existing Streamable HTTP transport) and long-job progress via MCP Tasks. This is the item that closes the one limitation SECURITY.md declares outright: the HTTP transport has no authentication today

  • Slope and aspect (Whitebox, closed-form tested; geographic-CRS DEMs refused)

  • Stream network extraction (Whitebox, from a flow-accumulation grid; the threshold and its unit recorded in the manifest)

  • More terrain & hydrology: curvature (six kinds, the kind required because profile and plan answer opposite questions), flow direction (d8/rho8/dinf/fd8, with the direction-code table written into the manifest — the engine's own manual documents its default table backwards, so a name would not have been enough), Euclidean distance and IDW interpolation

  • The ambiguous-georeferencing refusal on every raster operation rather than the twelve that read the grid directly. The three sampling operations were added on 2026-09-02 — sample_raster_at_points was the worst gap in the product, since the same DEM answered 10.0 and 30.0 with no sidecar and 2.0 and 6.0 with a 40 m one, five times out with no warning. What is left is the terrain engine, which stops on the same file for a different reason — its own reading of the grid disagrees with GDAL's — and whose message names neither the sidecar nor the way out

  • Map panel: MapLibre vector rendering, and an export of the panel as a self-contained HTML file you host yourself (raster OSM tiles already ship). No hosted viewer — MapSmith runs on your machine and we would rather not own your maps

  • Not planned, and closed as such on 2026-09-01: a sandboxed code-execution tool for the long tail. A typed plan is the same efficiency win in a shape that can be refused for a stated reason before anything runs; a model-authored script keeps the arithmetic in the engines but moves the composition — engine, order, units, CRS — into text nobody validated, and then emits a manifest that is true about the library and silent about the part that decided

  • QGIS Processing sidecar (subprocess-isolated): ~900 algorithms. By far the largest item on this list — parameter mapping and error handling for an external process, not an afternoon

License and project

  • 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.

Nothing here has been funded so far. funding.json lists, in the FLOSS/fund format, the two pieces of work money was asked for: a public suite of geospatial traps with hand-computable answers, and the provenance manifest as a specification other tools can implement. Both were built anyway, unfunded, and are archived with DOIs; the entries stay in the file marked inactive, so the estimate can be read against what came of it.

Release notes are in CHANGELOG.md, how to contribute in CONTRIBUTING.md, how to report a vulnerability in SECURITY.md. "MapSmith" is a trademark of the MapSmith project — see TRADEMARKS.md. Updates: LinkedIn · X · Bluesky.

Available Tools

28 tools
aspectA
Idempotent

Aspect from a DEM: downslope azimuth in degrees, 0 = north. GeoTIFF in/out.

FLAT CELLS ARE -1, not nodata — mask them before averaging aspect over an area, or the average is plausibly wrong. DEMs in a geographic CRS are refused (see slope): reproject to a projected CRS first. Requires the [whitebox] extra.

ParametersJSON Schema
NameRequiredDescriptionDefault
dem_pathYes
z_factorNo
output_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

It discloses non-obvious behaviors beyond the annotations: flat cells are -1 rather than nodata, geographic CRS DEMs are refused, and the whitebox extraction dependency is required. The idempotentHint and destrictiveHint are not contradicted.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The main definition is front-loaded, warnings are clearly separated, and every sentence carries actionable information. It is compact without losing needed context.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and annotations covering the safety/idempotence profile, the description covers key edge cases, preconditions, and dependencies. The only notable gap is z_factor param semantics, preventing a perfect score.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It does map 'GeoTIFF in/out' to dem_path and output_path, but z_factor is completely undocumented in both the schema and the free-text description, leaving its scaling role unexplained.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description defines the resource and output clearly: 'Aspect from a DEM: downslope azimuth in degrees, 0=north' and 'GeoTIFF in/out'. This distinguishes it from terrain siblings like slope and hillshade, though it lacks an explicit action verb such as 'Computes'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives concrete usage preconditions: mask FLAT cells before averaging, reproject geographic CRS to projected CRS, and install the whitebox extra. It also points to slope for related CRS behavior, but doesn't explicitly state when to prefer a sibling tool over this one.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

buffer_layerA
Idempotent

Buffer all features by a distance in meters.

Geographic-CRS inputs are reprojected to an estimated UTM zone for the metric operation and back; the decision is recorded in the provenance manifest. A warnings key in the result flags a suspicious-but-valid outcome with a hint — e.g. a negative distance that eroded every geometry away.

ParametersJSON Schema
NameRequiredDescriptionDefault
input_pathYes
output_pathYes
distance_metersYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, the description discloses non-obvious behavior: geographic CRS inputs are reprojected to a UTM zone for the metric operation and back, the decision is recorded in the provenance manifest, and a warnings key flags suspicious valid outcomes. This adds meaningful operational context that annotations alone do not provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and front-loaded with the core action. Each subsequent sentence adds meaningful detail about reprojection, provenance, or warnings without filler or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value structure is already covered. The description sufficiently covers operation scope, distance units, projection handling, provenance, and warnings. Minor gaps such as explicit output_path overwrite behavior are not critical given the idempotent and non-destructive annotations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 0% description coverage, so the tool description must compensate. It clarifies that distance is in meters and that all features are buffered, which adds real value. However, input_path and output_path semantics are left entirely to inference, so the compensation is only partial.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource: 'Buffer all features by a distance in meters.' It clearly identifies the core operation and distinguishes it functionally from siblings like clip_layer or dissolve_layer, though it does not explicitly name or contrast those sibling tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the title and first sentence: use this when you need to buffer features by a metric distance. There is no explicit guidance about when not to use it or which sibling tool to prefer for related operations, so the guidance is present only by implication.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

centroid_layerA
Idempotent

One point per feature: the geometric centroid, computed in a metric CRS.

Geographic-CRS inputs are measured in an estimated UTM zone (decision recorded in the manifest) and returned in the input CRS — a planar centroid of degree coordinates lands in the wrong place, quietly. The output is verified: same feature count, Point geometry, input CRS. Note the manifest's caveat: the centroid of a concave or multi-part feature can fall outside it. Inputs without a CRS are refused.

ParametersJSON Schema
NameRequiredDescriptionDefault
input_pathYes
output_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses several non-obvious behaviors beyond the annotations: the estimated-UTM fallback for geographic CRS, the risk of planar centroids of degree coordinates being wrong, the verification of output invariants, the caveat about centroids falling outside concave/multi-part features, and refusal of CRS-less inputs. This is rich, honest transparency with no contradiction to the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The one-sentence summary is front-loaded, and every subsequent sentence adds a distinct caveat or fact: CRS projection behavior, output verification, centroid-location caveat, and refusal condition. No filler or redundant phrasing.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the critical behavioral risks, output guarantees, and input constraints. An output schema exists for return-value structure, and annotations cover idempotence and non-destructiveness. Nothing essential for selecting and correctly invoking this tool is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 0% description coverage, and the description does not explicitly define input_path or output_path. However, it does add meaning by explaining input CRS requirements, the output CRS behavior, and the refusal condition, which indirectly informs both parameters. Path parameters are also fairly self-descriptive, so the gap is moderate rather than severe.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a precise, specific statement: 'One point per feature: the geometric centroid, computed in a metric CRS.' It clearly names the operation, the resource (a layer), and the output shape, making the tool's purpose unmistakable even among many geometry siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear operational context: geographic-CRS inputs are handled via an estimated UTM zone, inputs without a CRS are refused, and results are returned in the input CRS. It does not explicitly name alternatives or state when not to use this tool, but the conditions are concrete and actionable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

clip_layerA
Idempotent

Clip a layer to the area of a mask layer. CRS are aligned automatically.

A warnings key in the result means the analysis ran but something is worth your attention (typically an empty result, or inputs whose extents do not overlap); each entry carries a hint. Inputs without a CRS are refused.

ParametersJSON Schema
NameRequiredDescriptionDefault
mask_pathYes
input_pathYes
output_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (idempotentHint=true, destructiveHint=false, readOnlyHint=false), the description discloses meaningful behavior: automatic CRS alignment, refusal of inputs without a CRS, and the warnings key with hints about empty results or non-overlapping extents. This gives the agent important runtime expectations. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded: the core operation is stated in the first sentence, and the second paragraph efficiently covers warnings and CRS restrictions. Every sentence adds useful information; there is no fluff or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the simple three-parameter input, the presence of an output schema, and annotations covering idempotency and destructiveness, the description covers the essential caveats: CRS handling, refusal behavior, and warning semantics. Nothing critical appears missing for an agent to invoke and interpret the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It clarifies roles by naming 'a layer' and 'a mask layer', and adds the CRS requirement for inputs. However, it does not directly explain each path parameter or the meaning of output_path, relying on self-explanatory parameter names. Partial compensation only.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Clip') and resource ('a layer' clipped to 'a mask layer'), making the core action clear. It also adds relevant CRS alignment context. However, it does not explicitly distinguish this tool from sibling spatial operations like overlay_layers or spatial_join, so it stops short of full differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The use case is implied by the name and first sentence: clip when you need to cut a layer to a mask extent. It also states prerequisites (inputs must have a CRS) and warning behavior. But it never explicitly says when to use this tool versus alternatives, nor lists exclusions or alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

convert_formatA
Idempotent

Convert a vector dataset between formats; the target is chosen by the output extension (.parquet, .gpkg, .geojson).

The output is re-read and verified: same feature count, same CRS. Two conversions are refused with the reason: shapefile (field names truncated to 10 characters, silently) and GeoJSON for non-WGS84 layers (RFC 7946 is WGS84 by definition — reproject first). Invalid geometry carried through is repaired deterministically and reported in a 'repairs' key.

ParametersJSON Schema
NameRequiredDescriptionDefault
input_pathYes
output_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (readOnlyHint=false, idempotentHint=true, destructiveHint=false), the description discloses substantial behavior: output is re-read and verified for feature count and CRS, specific conversions are refused, and invalid geometry is repaired deterministically with a 'repairs' key. This gives the agent a precise model of side effects and outcomes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences cover purpose, target-selection, verification, refusals, and repair behavior with no filler. The most important defining behavior is front-loaded, and every sentence adds operational value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the return value is covered structurally. The description covers key edge cases and verification behavior that an agent needs to invoke the tool correctly. It falls slightly short of a 5 by not explicitly stating supported input formats or format-specific limitations beyond the two refusals.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the burden. It adds essential meaning to output_path by stating that the target format is chosen by its extension and enumerates supported formats, but it gives no details about input_path formats or whether they are auto-detected. The parameter names are self-explanatory, but some explicit input semantics are missing.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb ('Convert') and resource ('vector dataset'), and immediately identifies the target-selection mechanism (output extension). It clearly distinguishes this from sibling geoprocessing tools like reproject_layer or buffer_layer by focusing purely on format conversion.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states when to use the tool via the extension-driven target and provides concrete exclusions: shapefile and non-WGS84 GeoJSON conversions are refused, with 'reproject first' implicitly pointing to reproject_layer. It does not explicitly name reproject_layer as the alternative, but the context is clear enough.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

describe_datasetA
Read-onlyIdempotent

Inspect a dataset, vector or raster, before analysing it.

Vector: CRS, geometry types, schema, extent, feature count. A MULTI-LAYER container (e.g. a GeoPackage holding several layers) is described per layer — name, feature count, geometry type, CRS — because operations refuse containers with no chosen layer: extract the layer you mean first (run_sql: SELECT * FROM ST_Read(path, layer='name') with an output_path). Raster (.tif): CRS, grid size, resolution, bands with dtype, nodata and masked statistics (nodata cells counted separately). Call this first on any dataset you have not inspected yet — most silent GIS errors start with wrong assumptions about CRS, units, nodata or which layer you are on. Raster inspection requires the [raster] extra.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the tool as read-only and idempotent, so the description adds extra behavioral context: per-layer description for containers, the refusal of operations on unchosen layers, the [raster] extra requirement, and the distinction between nodata and masked statistics. No contradiction exists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is longer than average but well-structured with clear vector/raster sections and front-loaded purpose. Each sentence adds useful behavior or usage context, though it could be tightened without losing value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity and the presence of an output schema, the description covers the important edge cases: multi-layer containers, raster-specific requirements, nodata handling, and when to extract a layer first. It is complete enough for an agent to decide when and how to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, but it never explicitly names or describes the single required parameter. It implicitly refers to a 'dataset' and uses 'path' in the run_sql example, yet an agent still lacks clear semantics about the expected argument format, type, or identifier.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Inspect a dataset, vector or raster, before analysing it.' It clearly distinguishes the tool's scope from siblings by detailing vector, raster, and multi-layer container behavior, so an agent can tell it apart from related GIS tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says to call this tool first on any uninspected dataset and warns that silent GIS errors often stem from wrong assumptions. It also provides a concrete follow-up action for multi-layer containers, naming run_sql with an example query, which gives strong when-to-use and when-to-do-something-else guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

dissolve_layerA
Idempotent

Merge features into one geometry per value of by (or one feature in all).

aggfunc — first (default), last, sum, mean, median, min, max or count — is applied to the other columns and RECORDED in the manifest: a sum reported where a mean was meant is a plausible wrong number nobody can see. Features with a null by key are dropped by the grouping and the manifest counts them. The output feature count is verified against the number of distinct keys, so a wrong grouping fails loudly instead of shipping.

ParametersJSON Schema
NameRequiredDescriptionDefault
byNo
aggfuncNofirst
input_pathYes
output_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the annotations by disclosing that the aggfunc choice is recorded in the manifest, that features with a null by key are dropped and counted, and that the output feature count is verified against distinct keys so a wrong grouping fails loudly. These failure-mode details are not available elsewhere and do not contradict the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core operation and every subsequent sentence adds a concrete behavioral caveat: manifest recording, null dropping, and fail-loud verification. There is no filler, redundancy, or wasted wording.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Together with the provided annotations and output schema, the description covers parameter semantics, null behavior, aggregation defaults, and failure mode, which is enough for an agent to select and invoke the tool correctly. Missing details are either schema-present or non-essential for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must carry the burden. It does this well by explaining the two non-obvious parameters: `by` as the grouping value with null meaning one feature in all, and `aggfunc` as an enumerated aggregation with 'first' as the default. `input_path` and `output_path` are left to their self-explanatory names, which is acceptable but not fully elaborated.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Merge features into one geometry per value of `by`' and also specifies the all-features fallback. This clearly distinguishes dissolve_layer from sibling tools like explode_layer and merge_layers even without naming them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description communicates that this is the dissolve-by-attribute operation and clarifies when a null grouping key dissolves all features into one. However, it does not explicitly name alternatives or state when not to use this tool, so usage guidance is implied rather than direct.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

execute_planA
Idempotent

Validate, then execute a geoprocessing plan step by step.

The plan is re-validated first (an invalid plan runs nothing). Steps run in order; "$step_id" references resolve to the outputs of earlier steps. Every step writes its own provenance manifest, and a plan-level manifest (.plan.json, with the plan sha256 and per-step outcomes) ties them together. Execution stops at the first failing step; outputs already produced stay on disk with their manifests. Same plan format as validate_plan — validate first, then execute.

A step_warnings key in the response means the plan ran but some step produced a suspicious result (an empty output, non-overlapping inputs): read it before treating a completed plan as a correct one.

ParametersJSON Schema
NameRequiredDescriptionDefault
planYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds substantial behavior beyond the annotations: invalid plans run nothing, steps execute in order, execution stops at the first failing step, outputs already produced stay on disk, every step writes a provenance manifest, and a plan-level manifest records the plan sha256 and per-step outcomes. It also discloses the step_warnings signal for suspicious results. This is rich, non-obvious behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but well-organized, front-loading the core purpose before explaining execution behavior, failure semantics, and warnings. It is longer than a minimal description, but the length is justified by the complexity of execution. The only minor redundancy is reiterating 'validate first, then execute' after the opening sentence already says 'Validate, then execute.'

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a multi-step execution tool, the description covers the essential operating envelope: validation, ordering, failure handling, provenance manifests, and the step_warnings caveat. It also notes that outputs persist after partial failure, which is critical for an agent reasoning about side effects. With an output schema present, the description is complete enough for correct invocation and interpretation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although the top-level plan parameter has no description in the schema, the description compensates by explaining key semantics: steps run in order, '$step_id' references resolve to earlier step outputs, and manifests are tied to the last output. It also cross-references validate_plan for the exact plan format. The nested schema definitions cover the structural details, so the description adds meaningful semantic value without needing to restate every field.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Validate, then execute a geoprocessing plan step by step.' It clearly distinguishes this from validate_plan by stating that execution re-validates first and that the plan format matches validate_plan. The resource and behavior are unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context on when execution happens: only after re-validation, and only valid plans run anything. It also points to validate_plan with 'Same plan format as validate_plan — validate first, then execute.' However, it does not explicitly say when to prefer this over run_operation or when not to use it, so exclusions are missing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

explode_layerA
Idempotent

Split multi-part geometries into one feature per part (attributes copied).

The output feature count is verified against the number of parts counted before the engine ran, so a lost part fails loudly instead of shipping. Inputs without a CRS are refused.

ParametersJSON Schema
NameRequiredDescriptionDefault
input_pathYes
output_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, the description adds meaningful behavioral details: attributes are copied to each output feature, output feature count is verified against the pre-run part count so lost parts fail loudly, and inputs without a CRS are refused. These constraints and failure semantics are not visible in the schema or annotations and materially help an agent anticipate tool behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences with no filler. The main action is front-loaded in the first sentence, and each subsequent sentence adds a distinct piece of information: attribute handling, failure verification, and CRS requirement. Nothing is repetitive or tangential.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the presence of an output schema and meaningful annotations, the description covers the core behavior, the output semantics, and key operational constraints. An agent has enough information to select this tool and understand the important failure and requirement conditions without needing to inspect additional resources.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate for missing parameter documentation. It adds some useful semantics: 'Inputs without a CRS are refused' constrains input_path, and 'attributes copied' hints at output behavior. However, it does not explicitly clarify what input_path and output_path should contain, their supported formats, or the relationship between them, leaving part of the burden on parameter names.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Split') and a precise resource ('multi-part geometries into one feature per part'), with a note that attributes are copied. This clearly conveys the operation and distinguishes it from sibling tools like dissolve_layer, merge_layers, or centroid_layer, which perform different geometry transformations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use the tool: when multi-part geometries need to be exploded into single-part features. However, it does not explicitly state when not to use it, mention prerequisites beyond CRS, or name alternative sibling tools for comparison. The usage guidance is functional but not explicit about exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

flow_accumulationA
Idempotent

D8 flow accumulation from a DEM (GeoTIFF in/out). Depressions are filled first.

out_type: 'cells' (upslope cell count, includes the cell itself) or 'sca' (specific catchment area). log_transform=True for visualization-friendly values. Requires the [whitebox] extra.

ParametersJSON Schema
NameRequiredDescriptionDefault
dem_pathYes
out_typeNocells
output_pathYes
log_transformNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark it as non-read-only, non-destructive, and idempotent. The description adds valuable algorithmic behavior (depressions are filled first) and an environment requirement (whitebox extra), which would not be discoverable from annotations or schema. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact, front-loads the core operation, and uses linne breaks to separate optional parameter guidance. No redundant or filler sentences.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a four-parameter raster tool with an output schema and annotations, the description conveys the algorithm, both optional parameters, and a hard dependency. It might not enumerate edge cases or precise path requirements, but nothing essential to selecting or invoking the tool is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description compensates by defining out_type values ('cells' vs 'sca') and log_transform's purpose. The opening 'GeoTIFF in/out' clarifies dem_path and output_path roles. It doesn't add path-format details, but the parameter names plus these explanations are sufficient.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence names the exact algorithm ('D8 flow accumulation'), the input ('a DEM'), and the I/O format ('GeoTIFF in/out'). This is enough to distinguish it from sibling terrain tools like slope, hillshade, or watershed. The added 'Depressions are filled first' further specifies the computation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context: it is for deriving upslope accumulation from a DEM and even notes a dependency prerequisite (whitebox extra). It does not explicitly name alternative tools or state when not to use it, so the agent must infer routing from the tool name and siblings. Overall the context is clear enough, but exclusions/alternatives are absent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_provenanceA
Read-onlyIdempotent

Return the full lineage manifest of a MapSmith output dataset.

ParametersJSON Schema
NameRequiredDescriptionDefault
output_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, openWorldHint=false, and idempotentHint, covering safety. The description adds the useful scoping phrase 'full lineage manifest', but it does not disclose edge-case behavior such as invalid paths or the completeness of lineage traversal. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence with no filler, action first, and a concrete object. Every word contributes to telling the agent what the tool does.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter read-only tool with an output schema and strong annotations, the description is nearly complete. The only notable gap is explicit parameter documentation, which is already reflected in the parameter_semantics score.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the description does not explicitly explain output_path. It only implies via 'MapSmith output dataset' that the parameter is a path to such a dataset. For a low-coverage schema, the description should compensate more directly.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Return') and a precise object ('full lineage manifest of a MapSmith output dataset'). This clearly distinguishes it from the sibling tools, which are all spatial processing or server utilities.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes clear that the tool is for retrieving provenance of a MapSmith output dataset, so the context of use is implied. However, it does not explicitly state when to prefer this tool over alternatives or mention exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

hillshadeA
Idempotent

Shaded relief from a DEM: GeoTIFF in, GeoTIFF out (values scaled 0-32767).

azimuth = sun direction in degrees (default 315, NW); altitude = sun angle above the horizon (default 30). DEMs without a CRS are rejected. Requires the [whitebox] extra.

ParametersJSON Schema
NameRequiredDescriptionDefault
azimuthNo
altitudeNo
dem_pathYes
z_factorNo
output_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the annotations by disclosing output value scaling (0-32767), the meaning and defaults of azimuth and altitude, rejection of DEMs without a CRS, and the dependency on the [whitebox] extra. This gives the agent a clear picture of what the operation does and how it behaves.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact, front-loaded with the core transformation, and includes only essential behavior, parameters, and constraints. Every sentence earns its place with no redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the input/output format, value scaling, key parameter defaults, a validation constraint, and a runtime dependency. It is nearly complete, but omits any explanation of z_factor and does not state whether existing output files are overwritten; these are minor given the output schema and annotations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description compensates for azimuth and altitude by explaining their units, defaults, and interpretation, and implies that dem_path/output_path are GeoTIFF inputs/outputs. However, z_factor is not described at all, leaving a meaningful parameter semantically unexplained.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly identifies the tool's purpose: generating shaded relief from a DEM, with a specific GeoTIFF-to-GeoTIFF transformation. This is distinct from sibling terrain tools like slope, aspect, and flow_accumulation because it names the output product ('shaded relief') and the processing model ('GeoTIFF in, GeoTIFF out').

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives useful usage conditions: DEMs must have a CRS, and the [whitebox] extra is required. However, it does not explicitly state when to choose hillshade over alternative terrain-analysis siblings (e.g., slope or aspect), so the usage guidance is implied rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_operationsA
Read-onlyIdempotent

Find the operation you need. Say what you have and what you want — it matters more than the words you search with.

Ranking alone does not scale, and this is measured rather than assumed. Over 118 requests written by other models against this catalog, searching by words alone finds the right operation in the top 3 a quarter of the time. Declaring what you already know does not make the ranking better — it makes the ranking unnecessary, because few enough operations survive that you get all of them:

facets you declare              candidates left   ranked@3   in the answer
(none)                                       51        25%             25%
input_kind                                   33        29%             43%
input_kind + produces                        21        48%            100%

That last column is not an accuracy figure. It is what happens when nothing is dropped: the right operation was in the answer for all 118 requests, by construction rather than by ranking.

So fill these in whenever you know them, and you usually do:

  • input_kind — what you are holding: 'vector' (points, lines, polygons), 'raster' (a grid, a GeoTIFF), 'dataset' (either), 'plan', or 'none'.

  • produces — what you want back: 'dataset:vector', 'dataset:raster', 'answer' (a number, nothing written), 'description' (what something IS, rather than a computation over it), 'plan_result'.

  • category — the family, when you know it: vector, raster, terrain, hydrology, inspection, sql, network, planning, provenance, visualization, bridge. Unlike the others this one only ORDERS the results — a wrong guess about our families costs you positions, never the answer, so guessing is safe.

  • projected — pass False if your data is in a geographic CRS (degrees), and every operation that would refuse it disappears from the results.

  • dataset_inputs — how many datasets you are holding for this step: 1 if you have one layer, 2 if the operation combines two. This is the facet that makes a large catalog usable: on the current one it takes the surviving set from a median of 34 to 9, because "clip these parcels with that boundary" and "simplify these parcels" are different questions and you already know which one you have.

query is then plain words for what you are trying to do, and it breaks the tie inside what is left. Describe the PROBLEM rather than the operation: "the coastline has too many vertices and the browser dies" works as well as the name of the tool, and better when you do not know the name.

If the answer comes back as a single entry with status: "choose", that is the normal case and it is asking you to pick. It carries every operation that survived, in relevance order, each with the sentence saying what it is NOT for. The order is a hint and nothing else: our ranking puts the right operation in the top three 48% of the time, while a model reading the same candidates and choosing gets its first pick right 69% — and 70% is where the two model labellers who wrote the ground truth agree with EACH OTHER, so there is often no single right answer to rank toward. You have context no ranking has: which file is open, what ran a minute ago, what the person actually asked for. Use it. And if two candidates would both be defensible, ask them — that is a better move than picking one silently, and it is what a GIS analyst would do.

A order_is_weak field means the two rankers shared nothing in their top three, which usually means the request does not match this catalog well: read the candidates instead of trusting the order, and say so if none of them fits.

If the answer comes back with status: "unsure", the two ranking engines agreed on nothing and the set was too large to hand over — usually the request was not understood rather than impossible. It carries both engines' guesses and a question; answering the question with the facets above is the fastest way through.

If the answer comes back with status: "none_apply", nothing you declared can be true at once — no ranking ran. It lists each declaration and how many operations would come back without it, smallest first, so the one that is excluding everything is the first line. The common case is produces: several operations compute the number you want and write it into a column instead of returning it, so they declare dataset:vector. If nothing in relax helps, MapSmith probably does not do this — say so rather than running a neighbour.

detail=True adds parameters and worked example calls: use it on the exact operation name before calling an unfamiliar tool. An empty query lists everything that survives the facets, planned operations included.

engine selects the ranker and every result says which one ran: 'auto' (the default) prefers embeddings and falls back to BM25 where the model cannot load; 'lexical' is BM25 alone, deterministic and network-free; 'vector' forces embeddings. The default changed on measurement, not preference, and the facets above matter far more than this choice.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
queryNo
detailNo
engineNoauto
categoryNo
producesNo
projectedNo
input_kindNo
dataset_inputsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond readOnlyHint/idempotentHint, it discloses that ranking is measured and limited, that order_is_weak can occur, and exactly what each status value (choose, unsure, none_apply) means and what the agent should do. It also explains engine behavior including fallback and determinism. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long, but the length is earned: it uses bolded facet names, a table of measured effects, and status-based sections that map to response handling. Some statistical passages could be tightened, but the structure front-loads the core guidance and separates it clearly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with no parameter descriptions and complex response semantics, this is complete: it explains all output statuses, how to interpret order_is_weak, what detail=True returns, how engine affects ranking, and how to recover from none_apply. The agent has enough context to use it correctly without opening schemas.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description carries the full burden and succeeds: it defines input_kind, produces, category, projected, dataset_inputs, query, detail, and engine with concrete allowed values and intended meaning. Only limit is not explicitly described, but the practical behavior of the returned set is covered thoroughly.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening line 'Find the operation you need' names a specific verb and resource, and the description clarifies it is a catalog-search/ranking tool rather than a GIS operation, distinguishing it from siblings like run_operation or buffer_layer. It also defines its exact scope: searching/filtering the operation catalog by facets and query.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use guidance: fill facets when known, use detail=True on the exact operation name before calling an unfamiliar tool, use empty query to list everything, and respond differently per status (choose/unsure/none_apply). It even tells the agent when not to continue ('MapSmith probably does not do this — say so rather than running a neighbour').

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

measure_areaA
Idempotent

Area per feature in SQUARE METRES, written to a named column, with the total in the result.

method='geodesic' (default) measures ground area on the ellipsoid the layer's CRS names: no map plane, so no projection distortion. method= 'planar' measures in the layer's own CRS and converts with its declared linear unit — a layer in US survey feet is not assumed to be in metres — and is refused on a geographic CRS, where an area would be in square degrees.

Two things this tool does that a bare area call cannot: invalid geometry is repaired BEFORE measuring (the planar area of a self-intersecting ring is the signed shoelace, a number matching no region, returned without complaint) and every repair is recorded; and a planar measurement is compared against the ground area, so a plane that is not equal-area here comes back with a warnings entry carrying the ratio — Web Mercator at 42° reports 1.80× the land it covers.

ParametersJSON Schema
NameRequiredDescriptionDefault
methodNogeodesic
input_pathYes
area_columnNoarea_m2
output_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, the description discloses important non-obvious behaviors: invalid geometry is repaired before measuring, repairs are recorded, planar results are compared with ground area and may return a warnings ratio, and planar is refused on geographic CRS. Nothing contradicts the idempotentHint or other annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and units, then provides method details and edge-case behavior in a compact, dense structure. Every sentence adds meaningful information with no filler or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with no parameter description coverage, the description covers operation semantics, units, method trade-offs, refusal behavior, repair behavior, and warning output. An agent has enough context to select parameters and interpret results, especially since an output schema exists.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description carries the burden. It richly explains the `method` parameter including defaults, refusal conditions, and unit conversion behavior, and clarifies that area is written to a named column. It does not explicitly detail `input_path`, `output_path`, or the default `area_column` name, though these are inferable from context and schema defaults.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states the exact action: compute area per feature in square metres, write it to a named column, and include a total in the result. This clearly distinguishes it from sibling geometry operations like buffer, centroid, or dissolve.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives strong method-selection guidance: geodesic as the default for ground area, planar for layer-CRS area, and explicitly refuses planar on geographic CRS. It does not name an alternative sibling tool, but area measurement is unique among the listed siblings, so the internal method guidance is sufficient.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

merge_layersA
Idempotent

Append two or more layers into one (schema union, attributes aligned by name).

Layers are reprojected to the FIRST layer's CRS when they differ; the decision is recorded in the provenance manifest. Columns present in only some inputs are null-filled in the others and the manifest names them — data that looks measured and is actually absent is a silent error. The output feature count is verified against the sum of the input counts. Inputs without a CRS are refused. This is an append, not a geometric union: use dissolve_layer to merge geometries afterwards.

ParametersJSON Schema
NameRequiredDescriptionDefault
input_pathsYes
output_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond annotations by disclosing reprojection behavior, null-filling of missing columns, provenance manifest recording, feature count verification, and refusal of inputs without a CRS. It also warns about the silent-error risk of measured-looking absent data. No contradiction with annotations exists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded in the first sentence, and every following sentence adds a distinct, important behavioral fact. The extended caveats about null-filling and CRS handling are necessary for correct use, not filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a moderately complex data-merging operation with only two parameters and an output schema available, the description covers the key conditions, failure modes, and relationships to sibling tools. Nothing essential is missing for an agent to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides only names and types, so the description carries the semantic burden. It meaningfully clarifies that input_paths expects two or more layers and that the operation writes to output_path, while also explaining processing details like CRS reprojection. It doesn't explicitly bind each parameter name, but given only two parameters that map naturally, this is a strong-enough compensation for 0% schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific action: 'Append two or more layers into one', clarifies schema union and attribute alignment, and explicitly distinguishes itself from a geometric union. This makes the tool's purpose unmistakable and separates it from siblings like dissolve_layer.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear usage context: layers are reprojected to the first layer's CRS, inputs without CRS are refused, and it explicitly tells the agent to use dissolve_layer for geometric merging instead. This is exemplary when-to-use versus when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

nearest_joinA
Idempotent

Attach each feature's nearest neighbour from another layer, with the distance IN METERS in a named column.

Geographic-CRS inputs are measured in an estimated UTM zone (decision recorded in the manifest) and returned in the input CRS — a nearest distance in degrees is the classic silent error of this operation, and it cannot happen here. max_distance_meters drops pairs farther than that; an emptied result comes back with a warnings entry, never silently.

ParametersJSON Schema
NameRequiredDescriptionDefault
left_pathYes
right_pathYes
output_pathYes
distance_columnNonearest_distance_m
max_distance_metersNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already signal idempotence and non-destructiveness; the description adds the critical CRS safety behavior—estimated UTM measurement for geographic inputs, return in input CRS, and prevention of the classic degrees error—plus the warnings entry on emptied results. This is exactly the behavioral context an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core operation is front-loaded in the first sentence, followed by two high-value caveats (CRS handling and max_distance behavior). No filler or repetition; every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a join tool with an output schema and safety annotations, this is complete: it explains the operation, the main failure mode it prevents, the distance filter, and the warning behavior. Nothing material is missing for an agent to call it successfully.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description must carry parameter meaning, and it does for distance_column (IN METERS, named) and max_distance_meters (drops pairs beyond threshold). left_path, right_path, and output_path are sufficiently clear from their names, though the description does not elaborate on them.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific operation: attach each feature's nearest neighbour from another layer and add a named distance column. The 'nearest neighbour' and 'distance in meters' wording sets it apart from the generic spatial_join sibling.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies this is the tool for nearest-neighbour joins and describes conditions under which behavior changes (geographic CRS, max_distance_meters), but it never explicitly says when to use it instead of spatial_join or other siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

overlay_layersA
Idempotent

Set-theoretic overlay of two layers: intersection (default), union, identity, symmetric_difference or difference.

The overlay layer is reprojected to the input CRS when they differ; the decision is recorded in the provenance manifest. Overlay pieces of lower dimension than the inputs (shared edges, corner contacts) are dropped, and the manifest says so. Inputs without a CRS are refused; an empty result comes back with a warnings entry, never as a silent success.

ParametersJSON Schema
NameRequiredDescriptionDefault
howNointersection
input_pathYes
output_pathYes
overlay_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses important behaviors beyond the annotations: reprojection and provenance recording, dropping lower-dimensional pieces, refusing inputs without CRS, and reporting empty results with warnings. This is exactly the kind of contextual side-effect information an agent needs, and it does not contradict the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core operation and each subsequent sentence adds a distinct behavioral detail without redundancy or fluff. It is compact yet information-dense.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 4-parameter tool with an output schema, the description covers the operation variants, CRS mismatch behavior, geometric dimension handling, validation failures, and empty-result warnings. Nothing essential for selecting or invoking the tool is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does: it explains the 'how' values and clarifies the roles of input and overlay layers. It doesn't explicitly document the path parameters, but their names are self-explanatory and the behavior around the overlay result is conveyed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific operation ('Set-theoretic overlay of two layers') and enumerates the allowed variants, so an agent immediately knows what the tool does. This distinguishes it from siblings like clip_layer or merge_layers because it names the exact set-theoretic semantics.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when the tool applies, including CRS handling and edge cases, but it does not explicitly name alternatives or say when not to use it. The set-theoretic operation definition is enough to imply the main use case.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

preview_mapA
Read-onlyIdempotent

Show datasets on the interactive in-chat map panel (MCP Apps).

Pass the paths of one or more MapSmith outputs or source datasets (vector or GeoTIFF). Layers are previewed in EPSG:4326 with simplified geometry and capped feature counts sized to fit client limits; each layer card shows its provenance summary and verification status. Read-only: the datasets of record stay on disk. On clients without MCP Apps support the same payload is returned as structured data.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathsYes
max_featuresNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnly/idempotent annotations, the description discloses projection to EPSG:4326, simplified geometry, capped feature counts, provenance summaries, and verification status. It also states that datasets of record stay on disk, reinforcing the read-only characterization. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and structured into input, rendering behavior, safety, and fallback. Every sentence adds meaningful eligibility or behavioral context, with no redundant or filler content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers input types, projection, simplification, feature limits, layer-card content, safety, and the no-MCP-Apps fallback. The only meaningful omission is explicit semantics for max_features, which is minor because the parameter has a sensible default and the cap is described behaviorally.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description thoroughly explains the paths parameter as MapSmith outputs/source datasets, vector or GeoTIFF. However, max_features is never explicitly named; 'capped feature counts sized to fit client limits' only indirectly hints at it, and schema description coverage is 0%, so the agent gets no direct documentation of how to control the cap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific action ('Show datasets') and a concrete resource ('interactive in-chat map panel'), and clarifies it is a read-only preview. It effectively distinguishes this tool from transformation/analysis siblings like buffer_layer or run_sql without needing to inspect schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear eligibility guidance: paths of MapSmith outputs or source datasets, vector or GeoTIFF, plus fallback behavior on clients without MCP Apps support. However, it does not explicitly name sibling alternatives or state when not to use this tool, so it falls short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

reproject_layerA
Idempotent

Reproject a layer to a target CRS, e.g. 'EPSG:32632' or a WKT string.

Inputs without a CRS are refused. Geometry passes through unchanged, so an invalid input yields an invalid output: mechanically broken geometry is repaired deterministically and reported in a repairs key — read it, the geometry type may have changed.

ParametersJSON Schema
NameRequiredDescriptionDefault
input_pathYes
target_crsYes
output_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds substantial behavior beyond the annotations: geometry passes through unchanged, invalid inputs yield invalid outputs, broken geometry is repaired deterministically, repairs are reported in a `repairs` key, and geometry type may change. This is rich, decision-relevant context that the annotations do not provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded: the core action and CRS examples appear first, followed by essential warnings. Every sentence earns its place, and the warning about CRS-less inputs is clearly separated without padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the critical operational caveats: CRS requirement, pass-through geometry, deterministic repair, and the `repairs` key. Since an output schema exists, return-value documentation is not the description's burden. Minor gaps remain around path parameter details, but the tool is usable as described.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It adds meaning for `target_crs` by giving concrete examples and clarifies that the input layer must already have a CRS. However, it does not explain `input_path` or `output_path` semantics beyond their names, such as expected formats, overwrite behavior, or path types.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource: 'Reproject a layer to a target CRS'. It further clarifies acceptable CRS forms ('EPSG:32632' or a WKT string), making the tool's purpose concrete and distinguishing it from generic format-conversion or geometry-operation siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context: use this tool to reproject a layer to a specified target CRS, and it explicitly states when not to use it by refusing inputs without a CRS. It does not name sibling alternatives, so it stops short of full 'use X instead' routing, but the usage boundary is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_operationA
Idempotent

Run ANY catalog operation by name, including the ones with no tool of their own — which is most of them, and increasingly so.

The tools above are the handful an agent reaches for constantly. The catalog holds every operation MapSmith can perform, and it grows faster than the tool list on purpose: tool-selection accuracy degrades past a few dozen exposed tools, while capability count has no such ceiling. Discover with list_operations (use detail=true to get parameters and worked examples), then call it here.

Arguments are validated against the catalog BEFORE anything runs — unknown operation, missing or misnamed argument, wrong type, path outside the workspace — and the errors come back with stable codes, so a failed call tells the planner what to fix instead of what went wrong. Execution goes through the same path as execute_plan, so an operation cannot behave one way here and another way in a plan.

ParametersJSON Schema
NameRequiredDescriptionDefault
argumentsYes
operationYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, the description discloses that arguments are validated before execution, errors use stable codes, validation covers unknown operations and path safety, and execution follows the same path as execute_plan. This adds meaningful behavioral context. No contradiction with the annotations is apparent; the generic 'any operation' framing does not directly conflict with idempotentHint or destructiveHint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The main purpose is front-loaded in the first sentence. The later paragraphs explain the catalog growth rationale and validation behavior, which are useful but somewhat expansive; still, each part carries information an agent needs to use a generic dispatch tool safely.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a generic operation runner with an open-ended arguments object, the description is complete: it names the discovery tool, tells how to get parameter details, explains error behavior, and connects execution semantics to execute_plan. The output schema exists, so return values do not need explanation here, and annotations already cover the idempotency/safety profile.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides 0% description coverage and arguments is an opaque object, but the description compensates by explaining that parameters are validated against the catalog and that list_operations with detail=true returns exact parameters and worked examples. It gives the agent a concrete path to resolve parameter semantics without attempting to enumerate a dynamic catalog.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Run ANY catalog operation by name', which is a specific verb plus resource and immediately clarifies this is the generic catch-all runner. It explicitly distinguishes itself from the dedicated siblings by explaining that most operations have no tool of their own and that list_operations is the discovery mechanism.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly says to discover operations with list_operations (using detail=true) and then call them here, and it frames the listed tools as the 'handful an agent reaches for constantly.' It does not explicitly state 'use a dedicated sibling when one exists,' but the context strongly implies this is the fallback for the long tail of operations.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_sqlA
Destructive

Run spatial SQL (DuckDB dialect, ST_* functions, read_parquet/ST_Read for files).

Without output_path: returns up to 50 preview rows. With output_path (.parquet): materializes the full result as GeoParquet with a provenance manifest.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYes
output_pathNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the destructiveHint annotation, the description discloses preview vs. materialization behavior and the creation of a provenance manifest. It doesn't mention overwrite semantics or failure behavior, but annotations already flag destructive potential.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no filler. The first sentence establishes the core purpose and syntax focus; the second efficiently distinguishes the two execution modes. Well front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers both parameters, preview limits, output format, and provenance, which is strong for a SQL runner. Minor omissions like error handling and exact path constraints are acceptable given the annotations and output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the burden for parameters. It meaningfully explains both query (spatial SQL dialect/functions) and output_path (preview vs. GeoParquet materialization), going beyond raw names.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool runs spatial SQL using DuckDB dialect with ST_* functions and file-reading helpers, giving a specific verb and resource. It doesn't explicitly contrast with sibling tools like run_operation, but the raw SQL scope is evident.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear conditional usage: omit output_path for preview rows or provide a .parquet output_path for full materialization. It gives actionable context but does not mention alternatives or exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

server_infoA
Read-onlyIdempotent

MapSmith version, licensing, and available engines.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag readOnlyHint and idempotentHint, and the description adds that the result contains version, licensing, and engine availability. This adds useful context about what the endpoint exposes and is fully consistent with the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single concise sentence carries the full meaning with no filler and leads directly with the tool's purpose. Every word earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a parameterless read-only info endpoint with an output schema and readOnly/idempotent annotations, the description covers all necessary decision points. No missing context could prevent an agent from safely invoking it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters and schema coverage is 100%, so there are no parameter semantics that the description needs to add. The description correctly focuses on the returned information rather than arguments.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the exact resource (MapSmith server) and the specific facts returned: version, licensing, and available engines. It is clearly distinguishable from the sibling GIS data tools, which all perform spatial operations rather than expose server metadata.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Although it doesn't explicitly name alternatives, the description makes the intended use obvious: call this to inspect server capabilities or licensing status. No exclusions or alternative routing are needed because it is effectively the only metadata/information tool among the siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

simplify_layerA
Idempotent

Simplify geometries (Douglas-Peucker, topology preserved) with the drift measured: the manifest records total area and length before and after.

Geographic-CRS inputs are simplified in an estimated UTM zone (decision recorded) and returned in the input CRS — a tolerance in degrees is a different distance at every latitude. On projected CRS the tolerance is interpreted in the CRS units. The feature count is verified unchanged; vertex counts before/after are in the result. Inputs without a CRS are refused.

ParametersJSON Schema
NameRequiredDescriptionDefault
input_pathYes
output_pathYes
tolerance_metersYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, the description discloses significant behavioral detail: drift is measured in the manifest, feature count is verified unchanged, vertex counts before/after are included, topology is preserved, and non-CRS inputs are refused. These details materially affect how an agent interprets results and plans calls.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact yet information-dense. Every sentence adds a necessary behavioral or CRS-related detail, and the primary purpose is stated first. No filler or redundant restatement of the tool name appears.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simplification tool with three parameters and an output schema, the description covers the algorithm, topology preservation, CRS handling, tolerance units, output measurements, feature-count verification, and refusal conditions. Nothing essential for correct invocation or interpretation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description carries the parameter-semantics burden. It thoroughly explains tolerance behavior across geographic and projected CRS, which is essential for correctly using tolerance_meters. input_path and output_path remain self-explanatory, so no further description is needed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Simplify geometries', and further specifies the algorithm (Douglas-Peucker) and a key invariant (topology preserved). This clearly differentiates it from sibling tools like buffer_layer, explode_layer, or dissolve_layer.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear operational context, especially around CRS handling: geographic inputs are simplified in estimated UTM and returned in the input CRS, projected inputs use CRS units, and missing CRS causes refusal. It does not explicitly name alternatives or state when not to use this tool, but the guidance is sufficient for a geometry-simplification operation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

slopeA
Idempotent

Slope gradient from a DEM: GeoTIFF in, GeoTIFF out.

units: degrees (default), percent or radians. DEMs in a geographic CRS are refused — degree cells with meter elevations give plausible but wrong values everywhere; reproject to a projected CRS first. The CRS decision is recorded in the provenance manifest. Requires the [whitebox] extra.

ParametersJSON Schema
NameRequiredDescriptionDefault
unitsNodegrees
dem_pathYes
z_factorNo
output_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond annotations by disclosing supported units, refusal of geographic CRS with a rationale about plausible but wrong values, provenance recording, and the whitebox dependency. These traits are not visible in the annotations or schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded in the first sentence, and the remaining sentences contain only high-value caveats and dependencies. There is no filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers purpose, units, CRS restriction, provenance, and dependency, and an output schema exists for return details. The only notable gap is the unexplained z_factor parameter, which has a default and is likely optional for typical calls.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema property descriptions, the description must carry parameter meaning. It explains units values/default and implies dem_path/output_path roles via the GeoTIFF in/out wording, but z_factor remains undefined, leaving one of four parameters semantically opaque.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific operation (slope gradient from a DEM) with clear input/output format (GeoTIFF in, GeoTIFF out). This makes it easy to distinguish from sibling terrain tools like hillshade or aspect.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear usage context and crucial preconditions: geographic CRS DEMs are refused and must be reprojected, and the whitebox extra is required. It doesn't name alternative tools, but it provides enough guidance on when to invoke slope correctly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

spatial_joinA
Idempotent

Join by spatial predicate (intersects/within/contains).

engine='auto' routes to the fastest available engine for the inputs: SedonaDB (heavy joins, 10-180x) > DuckDB (GeoParquet fast path) > GeoPandas. A warnings key in the result flags an empty join or inputs whose extents do not overlap, each with a hint. Inputs without a CRS are refused.

ParametersJSON Schema
NameRequiredDescriptionDefault
engineNoauto
left_pathYes
predicateNointersects
right_pathYes
output_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds rich behavioral details beyond annotations: engine routing precedence, a warnings key for empty or non-overlapping joins, and refusal of inputs lacking a CRS. These are non-obvious behaviors an agent could not infer from the schema or annotations, and there is no contradiction with the idempotentHint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three tight sentences with no filler. The core operation is front-loaded, followed by engine routing and key warnings, with every sentence contributing new information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter join tool, the description covers predicate choices, engine selection strategy, warning behavior, and a failure condition. An output schema is provided separately, so return values need not be described here. The definition is complete enough for an agent to invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the burden. It explains engine values and predicate options in some detail, while left_path, right_path, and output_path are left to name inference. These names are self-explanatory, so the gap is minor.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence 'Join by spatial predicate (intersects/within/contains)' names the action, resource, and allowed predicates, which clearly distinguishes it from sibling tools like nearest_join and overlay_layers. An agent can immediately understand what operation is performed.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives concrete guidance on engine selection, explaining when SedonaDB, DuckDB, or GeoPandas is preferred. It also states a hard precondition: inputs without a CRS are refused. It does not explicitly contrast this tool with nearest_join, but the predicate-based wording implies the appropriate use case.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

validate_planA
Read-onlyIdempotent

Statically validate a multi-step geoprocessing plan BEFORE running anything.

Write the plan as steps in execution order; each step has a unique id, an operation name from list_operations, and its arguments. Use "$step_id" as an argument value to consume the output dataset of an earlier step. Checks: operations exist and are installed, arguments complete and well-typed, references resolve backwards (mis-ordered steps are rejected), input files exist, outputs don't collide, and CRS flow is simulated end-to-end from the real input files. Returns machine-actionable errors/warnings/notes plus the simulated output CRS per step. Nothing is executed and nothing is written.

Example plan: {"goal": "wells at risk", "steps": [ {"id": "buf", "operation": "buffer_layer", "arguments": {"input_path": "wells.gpkg", "distance_meters": 300, "output_path": "buf.parquet"}}, {"id": "cut", "operation": "clip_layer", "arguments": {"input_path": "$buf", "mask_path": "zone.gpkg", "output_path": "risk.parquet"}}]}

ParametersJSON Schema
NameRequiredDescriptionDefault
planYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint and idempotentHint annotations, the description details exactly what validation covers: operation existence, argument completeness/typing, backward reference resolution, file existence, output collision checks, and CRS flow. It also states the return shape (errors/warnings/notes plus simulated CRS) and explicitly promises no side effects: 'Nothing is executed and nothing is written.'

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is longer than average, but it earns the length by covering validation semantics, plan structure, reference syntax, and return behavior. The example plan is helpful. A small amount of redundancy exists ('BEFORE running anything' vs. 'Nothing is executed'), but overall the structure is logical and front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a validation tool with one complex nested parameter and no need to document return values thanks to the output schema, this description is complete. It tells the agent what the input must look like, what checks will be performed, what the result contains, and that the tool has no side effects. Nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single `plan` parameter is thoroughly explained: steps in execution order, unique ids, operation names from list_operations, and the crucial `$step_id` reference syntax for consuming earlier outputs. The description even provides a concrete example plan. This compensates fully for the 0% schema description coverage at the top level.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a precise verb and object: 'Statically validate a multi-step geoprocessing plan BEFORE running anything.' It clearly distinguishes this from execution-oriented siblings like execute_plan and run_operation, and the details about validation checks reinforce what the tool is for.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes the usage context explicit: validate before executing, and use operation names from list_operations. It doesn't explicitly name execute_plan as the follow-up tool, but the 'BEFORE running anything' framing and the contrast with execution-oriented sibling tools give an agent clear guidance on when this tool applies.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

watershedA
Idempotent

Watershed of each pour point: DEM + points in, basin raster out (GeoTIFF).

Basins get 1-based IDs following the pour-point feature order; cells not draining to any point stay nodata. Points are aligned to the DEM CRS automatically (decision recorded). Requires the [whitebox] extra.

ParametersJSON Schema
NameRequiredDescriptionDefault
dem_pathYes
output_pathYes
pour_points_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations, the description discloses the 1-based ID ordering, nodata behavior for non-draining cells, automatic CRS alignment with a recorded decision, and the whitebox dependency. These are meaningful behavioral details an agent would not otherwise know.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, each earning its place: purpose, output semantics, and dependency/CRS behavior. The most important information is front-loaded in the first sentence.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a three-parameter raster-processing tool, this description covers purpose, output format, ID semantics, nodata behavior, CRS handling, and required extra. Nothing essential is missing for an agent to select and invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has no parameter descriptions, so the description must compensate. It maps dem_path to DEM, pour_points_path to pour points, and output_path to the basin raster GeoTIFF, and adds CRS alignment context. This is sufficient for correct invocation, though explicit per-parameter naming is absent.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific operation (watershed delineation), states the inputs (DEM, pour points), and the output (basin raster GeoTIFF). This clearly differentiates it from sibling tools like flow_accumulation or hillshade.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage clearly: use when you need watersheds from a DEM and pour points. It does not explicitly name alternatives or exclusion cases, but the specialized input/output pattern gives enough context for an agent to select it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

zonal_statisticsA
Idempotent

Statistics of a raster within each vector zone (exact fractional pixel coverage).

stats: subset of count/sum/mean/median/min/max/stdev/variance/majority/minority/ variety (default: count, mean, min, max). Zones are aligned to the raster CRS automatically; the decision is recorded in the provenance manifest. Zones without a CRS are refused; warnings and repairs keys in the result flag a suspicious outcome or geometry MapSmith had to repair. Requires the [raster] extra.

ParametersJSON Schema
NameRequiredDescriptionDefault
statsNo
zones_pathYes
output_pathYes
raster_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses important behaviors beyond the annotations: automatic CRS alignment with provenance recording, refusal of zones without CRS, result repair/warning keys, and the [raster] extra dependency. This gives an agent a realistic model of side effects and failure modes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and well-organized: core purpose first, then stats options, then edge-case behavior. Every sentence adds operational value without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a raster/vector analysis tool with an output schema available, the description covers what the tool does, accepted stats, defaults, CRS handling, failure conditions, and installation prerequisite. Nothing essential is missing for a knowledgeable agent to invoke it safely.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description compensates meaningfully by enumerating the valid stats values and the default set. The three path parameters are self-explanatory from the domain language, though the description does not provide file-format or coercion details for them.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the operation: computing raster statistics within vector zones, with the distinctive detail of exact fractional pixel coverage. It differentiates itself from sibling raster tools like hillshade or slope by focusing on zonal aggregation rather than surface derivation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The context of use is clear: summarizing a raster by vector zones, with specifics about how zones are handled. It does not explicitly name alternative tools or when-not-to-use conditions, but the raster/zone framing sufficiently implies the intended scenario.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 28 tool updatesv0.3.0
    • First observedaspect
    • First observedbuffer_layer
    • First observedcentroid_layer
    • First observedclip_layer
    • First observedconvert_format
    • First observeddescribe_dataset
    • First observeddissolve_layer
    • First observedexecute_plan
    • First observedexplode_layer
    • First observedflow_accumulation
    • First observedget_provenance
    • First observedhillshade
    • First observedlist_operations
    • First observedmeasure_area
    • First observedmerge_layers
    • First observednearest_join
    • First observedoverlay_layers
    • First observedpreview_map
    • First observedreproject_layer
    • First observedrun_operation
    • First observedrun_sql
    • First observedserver_info
    • First observedsimplify_layer
    • First observedslope
    • First observedspatial_join
    • First observedvalidate_plan
    • First observedwatershed
    • First observedzonal_statistics

TDQS

A4/5.0
Disambiguation4/5

Each named tool targets a distinct GIS operation, and the descriptions carefully delineate near-neighbors such as overlay_layers vs spatial_join and merge_layers vs dissolve_layer. The main ambiguity is run_operation, which can execute several operations that also have dedicated tools, but the descriptions make clear it is the fallback for catalog-only operations.

Naming Consistency4/5

The overwhelming majority of tools follow a verb_noun snake_case pattern (buffer_layer, reproject_layer, validate_plan, preview_map). The handful of noun-style terrain tools (slope, aspect, watershed) and server_info are minor, recognizable deviations rather than a style mix.

Tool Count3/5

Twenty-eight tools is at the high end and exceeds the comfortable range, but the broad vector/raster/terrain/planning scope means each tool covers a real, distinct capability. The sheer count is mitigated by list_operations and run_operation, yet the surface still feels heavier than a typical well-scoped MCP server.

Completeness4/5

The set covers the full analytical lifecycle: inspect, transform, join, raster-analyze, plan, execute, preview, and audit via provenance manifests. Common operations such as raster calculation or attribute-only joins are not first-class tools, but run_sql and the generic run_operation gateway provide workable paths to those capabilities.

Maintenance

ActivityMaintained
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Machine-native GIS processing API for AI agents and developers. Convert, reproject, validate, repair, buffer, clip, dissolve, and tile vector geodata across 25 endpoints. Pay-per-use USDC on Solana Mainnet ($0.01/op). No accounts, no API keys. Remote MCP SSE.
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    Exposes ArcGIS Pro geoprocessing capabilities to LLMs via the arcpy library, enabling automated spatial analysis and data management. It provides a comprehensive suite of tools for vector geoprocessing, terrain analysis, and raster operations designed for GIS workflows.
    4
    -
  • A
    license
    B
    quality
    B
    maintenance
    Enables AI agents to become geospatially intelligent assistants with tools for location search, smart routing, round trip planning, reverse geocoding, isochrone analysis, route visualization, geofence management, and interactive map display.
    8
    29
    7
    Apache 2.0

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mapsmith-ai/mapsmith'

If you have feedback or need assistance with the MCP directory API, please join our Discord server