How a policy researcher pins shape versions, pulls ACS B19013 across 2010/2015/2020, and ships a citeable URL plus a GeoJSON appendix any reviewer can re-render a year later.
Reproducibility in spatial work fails most often at the silent step: the shapefile changed under you. The U.S. Census re-releases TIGER every year; counties merge, FIPS codes get reassigned, your 2018 analysis no longer matches its own underlying boundaries when you re-run it in 2026.
Maps MCP fixes this with versioned shape collections — every collection has explicit, immutable versions (e.g., tiger-2010, tiger-2020), and every report you publish pins the version it was rendered against. A reviewer who hits /v/<your-slug> a year later sees the same numbers and the same boundaries.
This walkthrough is the smallest reproducible-research workflow that exercises that property: median household income by U.S. county across three ACS 5-year vintages (2010, 2015, 2020).
{
"name": "list_shape_versions",
"arguments": { "collection": "us-counties" }
}
Output something like:
[
{ "slug": "tiger-2010", "ingested_at": "2025-01-15T...", "shape_count": 3142 },
{ "slug": "tiger-2015", "ingested_at": "2025-01-15T...", "shape_count": 3142 },
{ "slug": "tiger-2020", "ingested_at": "2025-01-15T...", "shape_count": 3143 },
{ "slug": "tiger-2024", "ingested_at": "2025-09-02T...", "shape_count": 3143 }
]
Note the 3142 → 3143 jump: Connecticut replaced counties with planning regions in 2022. The shape collection records this; your analysis must too.
One call per vintage, each pinning its corresponding shape version:
{
"name": "census_acs",
"arguments": {
"collection": "us-counties",
"version": "tiger-2010",
"year": 2010,
"variables": ["B19013_001E"],
"slug": "counties-income-2010"
}
}
# repeat with version: tiger-2015 / year: 2015 / slug: counties-income-2015
# repeat with version: tiger-2020 / year: 2020 / slug: counties-income-2020
You now have three workspace datasets, each provenance-pinned to a specific TIGER vintage + ACS year. Re-running this in 2030 produces the same rows because the versions are immutable.
{
"name": "compare_shape_versions",
"arguments": {
"collection": "us-counties",
"v1": "tiger-2010",
"v2": "tiger-2020"
}
}
Returns which counties were added, removed, or had boundary changes between the two versions. For the CT case, you get the affected FIPS codes and can choose how to handle them (often: aggregate to a common parent region, or exclude from the time-series analysis with a footnote).
{
"name": "compare_versions_narrative",
"arguments": {
"collection": "us-counties",
"v1": "tiger-2010",
"v2": "tiger-2020"
}
}
Claude drafts the explainer paragraph you can drop into the methods section.
The renderer is single-panel per report; for a small-multiples manuscript figure, publish three reports and stack the iframes (or PNG img tags) side by side in your CMS or HTML appendix.
for (const year of [2010, 2015, 2020]) {
await mcp.call("create_report", {
slug: `county-mhi-${year}`,
name: `U.S. county median household income — ACS ${year}`,
public: true, // citeable URL
config: {
collection: "us-counties",
version: `tiger-${year}`, // version-pinned, immutable
datasets: [{
slug: `counties-mhi-${year}`,
field: "B19013_001E",
palette: "sequential",
classify: { method: "natural_breaks", bins: 7 },
}],
},
});
}
Three citeable URLs: /v/county-mhi-2010, /v/county-mhi-2015, /v/county-mhi-2020. Each report stores its config verbatim; re-rendering a year later produces an identical figure because the shape version is pinned.
Roadmap note: server-side small-multiples (one URL → N panels in one PNG) is on the roadmap. The three-iframe pattern is today's workaround and works fine for manuscript appendices.
# Bare-FeatureCollection GeoJSON — citeable supplemental material:
GET https://mapsmcp.com/v/county-mhi-2020/data.geojson
# CSV for downstream stats packages:
GET https://mapsmcp.com/v/county-mhi-2020/data.csv
# Full JSON envelope (geojson + config + breaks + palette):
GET https://mapsmcp.com/v/county-mhi-2020/data.json
# Static PNG for the manuscript (retina-grade):
GET https://mapsmcp.com/v/county-mhi-2020.png?width=2400&height=1500&dpi=3
# Static SVG (infinite-resolution vector):
GET https://mapsmcp.com/v/county-mhi-2020.svg?width=2400&height=1500
# Or pull the same FeatureCollection programmatically:
mcp.call("build_geojson", { slug: "county-mhi-2020" })
The GeoJSON has every county's geometry from the appropriate TIGER vintage plus the joined ACS value. Reviewers can re-render in QGIS or run their own checks; no proprietary format anywhere.
tiger-2010 means exactly that snapshot of TIGER, forever.year: 2010 means the 2006-2010 5-year estimates, not whatever's current..geojson + .csv + .png are all standard formats. No lock-in.For a citation in a paper, you'd put the URL plus a footnote noting the shape version and ACS year. For an appendix you'd attach the GeoJSON. For peer review you'd hand over a workspace API key — the reviewer re-runs each MCP call and gets identical output.
tiger-2024 for the boundary change.us-tracts (~84K nationally) for intra-county variation. ACS at tract resolution surfaces the urban / rural divide invisible at county scale.disaggregate_acs to areal-interpolate any ACS variable from tracts down to precincts, school districts, or custom polygons. Same call shape, just specify target_collection.