Ask GeoRescue
scripts/mcp_demo.py starts the GeoRescue MCP server over stdio and calls its tools exactly as an AI agent would; the outputs below are the real responses from the owner-name-redacted results store, and each answer is filled in by a fixed template from those outputs (no AI model wrote it). All results are automated, experimental data quality test results — proposals, not findings. Recorded 2026-10-26T16:12:51+00:00.Tools: inspect_dataset · repair_dataset · list_tables · describe_table · run_query · list_metrics · get_metric · get_case · find_issues · explain_issue · compare_runs
Q: Why is Parcel A flagged?
get_case ✓
arguments
{
"case_id": "0015420010__0015315300"
}output
{
"case": {
"case_id": "0015420010__0015315300",
"parcel_a": "001542 0010",
"parcel_b": "001531 5300",
"check": "contained_parcel",
"overlap_sqft": 107875.71,
"proposal": "cut 001531 5300 from 001542 0010",
"direction": "cut smaller from larger",
"confidence": "medium",
"rationale": "smaller parcel lies ~100% inside larger; stacked/un-carved parent polygon",
"status": "proposed",
"orb_refs": {
"001542 0010": [
"19870-00841",
"17966-00196",
"16276-02117",
"12781-02349",
"11954-01118",
"10417-00883"
],
"001531 5300": [
"00056-00042",
"11504-02030"
]
},
"basis": "deed-checked",
"run_id": "20261026T160815+0000"
},
"deed_check": {
"case_id": "0015420010__0015315300",
"parcel_a": "001542 0010",
"parcel_b": "001531 5300",
"verdict": "Owner of 001542 0010 GIS polygon over-includes Owner of 001531 5300 001531 5300; cut Owner of 001531 5300 from Owner of 001542 0010 (contained_parcel: cut smaller from larger)",
"confidence": "high",
"confidence_score": 0.85,
"orb": "ORB 19870-841",
"evidence": [
"ORB 19870-841 closes 1:353363 (misclosure 0.007 ft), COGO 7.963 ac vs stated 7.83",
"Record fits GIS-minus-Owner of 001531 5300 (8.11 ac) with IoU 0.981, Hausdorff 6.1 ft, zero rotation/shift",
"Owner of 001531 5300 inside record tract: 0%; GIS Owner of 001542 0010 10.59 = 8.11 + Owner of 001531 5300 2.48 ac",
"Deed's 60 ft ingress/egress strip is an easement ('Together with'), not fee - consistent with excluding the northern strip",
"Parent 17966-196 (3.41 ac, folio 001542-0100) closes 1:294k and lies within Tract 8"
],
"caveat": "no monument/PLSS tie; placement is best-fit to GIS (it lands at 0,0 offset, which is itself corroborating)",
"closure_precision": "1:353363",
"closure_ratio": 353363.0,
"misclosure_ft": 0.007,
"n_calls": 6.0,
"perimeter_ft": 2393.44,
"acres_record_cogo": 7.963,
"acres_record_stated": 7.83,
"fit_iou": 0.734,
"status": "proposed (test result)"
},
"issues": [
{
"feature_id": "001542 0010",
"check": "contained_parcel",
"severity": "error",
"message": "001531 5300 is 100.0% inside 001542 0010 (107875.71 units^2); proposal: cut smaller from larger|contained_row=154045|other_row=154045",
"metric": 1.0000000000000002
}
],
"other_cases_for_parcel": 0,
"note": "Automated, experimental data quality test result \u2014 a proposal, not a survey, boundary determination or legal advice."
}Answer (template from tool outputs): Case 0015420010__0015315300 pairs parcel 001542 0010 (Parcel A) with 001531 5300 (Parcel B); check: contained_parcel. First-pass proposal: cut 001531 5300 from 001542 0010 (confidence medium). Deed check (ORB 19870-841): proposed verdict — Owner of 001542 0010 GIS polygon over-includes Owner of 001531 5300 001531 5300; cut Owner of 001531 5300 from Owner of 001542 0010 (contained_parcel: cut smaller from larger) (confidence high); traverse closes 1:353363 (misclosure 0.007 ft), best-fit IoU 0.734. 1 issue(s) on these parcels. Proposal only.
Q: Which overlaps are high confidence?
run_query ✓
arguments
{
"sql": "SELECT c.case_id, c.\"check\", c.basis, coalesce(v.confidence, c.confidence) AS confidence, c.proposal FROM cases c LEFT JOIN verdicts v USING (case_id) WHERE coalesce(v.confidence, c.confidence) = 'high' ORDER BY 1"
}output
{
"columns": [
"case_id",
"check",
"basis",
"confidence",
"proposal"
],
"rows": [
{
"case_id": "0015420010__0015315300",
"check": "contained_parcel",
"basis": "deed-checked",
"confidence": "high",
"proposal": "cut 001531 5300 from 001542 0010"
},
{
"case_id": "0130300010__0130300300",
"check": "contained_parcel",
"basis": "deed-checked",
"confidence": "high",
"proposal": "cut 013030 0300 from 013030 0010"
}
],
"row_count": 2,
"truncated": false
}Answer (template from tool outputs): 2 case file(s) have high confidence: 0015420010__0015315300 (contained_parcel, deed-checked); 0130300010__0130300300 (contained_parcel, deed-checked). Confidence is a heuristic about the data, not a finding.
Q: What does sliver_polygon mean?
explain_issue ✓
arguments
{
"check": "sliver_polygon"
}output
{
"term": "sliver_polygon",
"kind": "check",
"name": "Sliver polygon",
"what": "A parcel that is extremely small or extremely thin \u2014 a narrow strip rather than a normal lot.",
"why": "Slivers are frequently leftovers of mismatched lines, though some are real (strips, easements, remnants).",
"how": "Area below 50 sq ft (Florida East State Plane, US feet) (sliver_max_area) or thinness score below 0.02 (sliver_max_compactness; 4\u03c0\u00b7area \u00f7 perimeter\u00b2, where a circle is 1 and a long thin strip approaches 0).",
"action": "Proposal only \u2014 reported for review.",
"causes": "Boundary mismatches between neighbours, remnant strips, right-of-way pieces.",
"glossary_url": "https://knightchrism.github.io/georescue/glossary.html#sliver_polygon"
}Answer (template from tool outputs): Sliver polygon: A parcel that is extremely small or extremely thin — a narrow strip rather than a normal lot. Detection: Area below 50 sq ft (Florida East State Plane, US feet) (sliver_max_area) or thinness score below 0.02 (sliver_max_compactness; 4π·area ÷ perimeter², where a circle is 1 and a long thin strip approaches 0). Automatic action: Proposal only — reported for review.
Q: How many missing owner names are there?
get_metric ✓
arguments
{
"name": "issues_by_check",
"group_by": "check"
}output
{
"metric": "issues_by_check",
"label": "Issues by check",
"unit": "issues",
"sql": "SELECT \"check\", count(*) AS issues_by_check FROM issues GROUP BY 1 ORDER BY 2 DESC NULLS LAST",
"columns": [
"check",
"issues_by_check"
],
"rows": [
{
"check": "gap",
"issues_by_check": 1090
},
{
"check": "sliver_polygon",
"issues_by_check": 995
},
{
"check": "attribute_missing",
"issues_by_check": 271
},
{
"check": "overlap",
"issues_by_check": 37
},
{
"check": "geometry_invalid",
"issues_by_check": 14
},
{
"check": "contained_parcel",
"issues_by_check": 5
}
],
"row_count": 6,
"truncated": false,
"caveats": [
"Automated, experimental data quality test results on public data; verdicts are proposals, not findings.",
"Not a survey, boundary determination, title opinion or legal advice."
]
}run_query ✓
arguments
{
"sql": "SELECT count(*) AS n FROM issues WHERE \"check\" = 'attribute_missing' AND message LIKE 'LNAMEOWNER%'"
}output
{
"columns": [
"n"
],
"rows": [
{
"n": 271
}
],
"row_count": 1,
"truncated": false
}Answer (template from tool outputs): 271 attribute_missing issues in the latest run; 271 of them are an empty owner-name field (LNAMEOWNER). Names themselves are never exposed by this server.
Q: Show me the deed closure for the deed-checked cases
get_metric ✓
arguments
{
"name": "deed_closure_ratio",
"group_by": "case_id"
}output
{
"metric": "deed_closure_ratio",
"label": "Deed traverse closure ratio",
"unit": "1:N (higher is better)",
"sql": "SELECT \"case_id\", max(closure_ratio) AS deed_closure_ratio FROM verdicts WHERE closure_ratio IS NOT NULL GROUP BY 1 ORDER BY 2 DESC NULLS LAST",
"columns": [
"case_id",
"deed_closure_ratio"
],
"rows": [
{
"case_id": "0015420010__0015315300",
"deed_closure_ratio": 353363.0
}
],
"row_count": 1,
"truncated": false,
"caveats": [
"Traverses come from OCR'd deed text and best-fit placement; not field measurements.",
"Automated, experimental data quality test results on public data; verdicts are proposals, not findings.",
"Not a survey, boundary determination, title opinion or legal advice."
]
}Answer (template from tool outputs): Deed traverse closure ratios (1:N, higher is better): case 0015420010__0015315300: 1:353,363. From OCR'd deed text; not field measurements.
Q: What changed since the last run?
compare_runs ✓
arguments
{}output
{
"before": {
"run_id": "20261022T210008+0000",
"finished": "2026-10-22T21:02:52.034572+00:00",
"features": 408934,
"issues_total": 2976
},
"after": {
"run_id": "20261026T160815+0000",
"finished": "2026-10-26T16:12:46.395051+00:00",
"features": 408950,
"issues_total": 2412
},
"by_check": {
"attribute_missing": {
"before": 837,
"after": 271,
"change": -566
},
"contained_parcel": {
"before": 5,
"after": 5,
"change": 0
},
"gap": {
"before": 1089,
"after": 1090,
"change": 1
},
"geometry_invalid": {
"before": 14,
"after": 14,
"change": 0
},
"overlap": {
"before": 36,
"after": 37,
"change": 1
},
"sliver_polygon": {
"before": 995,
"after": 995,
"change": 0
}
},
"changed": {
"attribute_missing": {
"before": 837,
"after": 271,
"change": -566
},
"gap": {
"before": 1089,
"after": 1090,
"change": 1
},
"overlap": {
"before": 36,
"after": 37,
"change": 1
}
}
}Answer (template from tool outputs): Comparing run 20261022T210008+0000 with 20261026T160815+0000: issues 2976 -> 2412. Changed checks: attribute_missing 837->271, gap 1089->1090, overlap 36->37
Q: (Safety) Can an agent delete data?
run_query ✗ refused
arguments
{
"sql": "DROP TABLE cases"
}output
{
"error": "Error executing tool run_query: UnsafeQueryError: only SELECT / WITH queries are allowed"
}Answer (template from tool outputs): The server refused: Error executing tool run_query: UnsafeQueryError: only SELECT / WITH queries are allowed (read-only by design).
Run it yourself
- Install uv and clone the repo, e.g. to
C:\Users\knigh\Documents\GitHub\georescue. - In that folder:
uv sync --extra verify, thenuv run georescue run -c configs/duval_fl_ci.yaml(fetches public COJ parcels; it also buildsout/georescue.duckdb) or, if you already haveout/latest, justuv run georescue load-db. - Add the server to Claude Desktop (Settings → Developer → Edit Config,
claude_desktop_config.json):{ "mcpServers": { "georescue": { "command": "uv", "args": [ "run", "--directory", "C:\\Users\\knigh\\Documents\\GitHub\\georescue", "--extra", "verify", "georescue-mcp" ], "env": { "PYTHONPATH": "C:\\Users\\knigh\\Documents\\GitHub\\georescue" } } } } - or to Cursor (
.cursor/mcp.jsonin the project, or Settings → MCP):{ "mcpServers": { "georescue": { "command": "uv", "args": [ "run", "--directory", "C:\\Users\\knigh\\Documents\\GitHub\\georescue", "--extra", "verify", "georescue-mcp" ], "env": { "PYTHONPATH": "C:\\Users\\knigh\\Documents\\GitHub\\georescue" } } } } - Restart the app and ask e.g. “Why is parcel 001542 0010 flagged?” or “What does sliver_polygon mean?”. Calls are logged to
logs/mcp.log.
The store is read-only (SELECT-only guard, row cap, timeout) and owner names are redacted by default. repair_dataset only writes a repaired copy into a new folder. Results are test results, not surveys or legal advice. MCP server pattern adapted from the author's census-pipeline (MIT).