GeoRescue MCP Server
<p align="center"><picture>
<source media="(prefers-color-scheme: dark)" srcset="brand/logo-horizontal.png">
<source media="(prefers-color-scheme: light)" srcset="brand/logo-horizontal-light.png">
<img src="brand/logo-horizontal-light.png" alt="GeoRescue" width="520">
</picture></p>
<p align="center"><b>Find, explain and propose fixes for broken parcel data — every change logged, nothing applied silently.</b></p>
<p align="center">
<a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-00e5ff?style=flat-square"></a>
<img alt="Python 3.13" src="https://img.shields.io/badge/python-3.13-00e5ff?style=flat-square&logo=python&logoColor=white">
<img alt="GeoPandas" src="https://img.shields.io/badge/GeoPandas-Shapely-0b1220?style=flat-square">
<img alt="DuckDB" src="https://img.shields.io/badge/DuckDB-results%20store-0b1220?style=flat-square&logo=duckdb">
<img alt="MCP" src="https://img.shields.io/badge/MCP-server-0b1220?style=flat-square">
<a href="https://github.com/knightchrism/georescue/actions/workflows/pipeline.yml"><img alt="pipeline" src="https://img.shields.io/github/actions/workflow/status/knightchrism/georescue/pipeline.yml?style=flat-square&label=pipeline"></a>
</p>
<p align="center"><a href="https://knightchrism.github.io/georescue/"><b>Live demo →</b></a> · <a href="https://knightchrism.github.io/georescue/agent.html">Ask GeoRescue (agent sessions)</a> · <a href="https://knightchrism.github.io/georescue/glossary.html">Glossary</a></p>
> **Status:** early prototype, work in progress.
> **Test demo — not authoritative.** Not a survey, title opinion, or legal determination; for testing and demonstration only.
> Results are automated, experimental **data quality test results** computed from public data. Verdicts are proposals, not findings;
> placements of deed descriptions are best-fit, not measured in the field. Consult a licensed surveyor and mapper or an attorney and the
> official records. GeoRescue is not affiliated with the City of Jacksonville, the Duval County Clerk of Courts or the Duval County
> Property Appraiser. See [TERMS.md](TERMS.md). Questions, corrections or removal requests: open an issue at
> https://github.com/knightchrism/georescue/issues
## What it does
- **Inspects** parcel layers (SHP / GPKG / GeoJSON) for invalid or empty geometry, duplicate IDs and geometries, CRS problems, out-of-bounds features, overlaps, slivers, gaps and attribute-rule violations (YAML rules, Pydantic-validated).
- **Proposes repairs on a copy** — the source file is never modified; every proposed change is written to `changelog.csv` with before/after, reason and whether it was applied (an audit trail for review).
- **Checks overlaps against the record**: appraiser legal descriptions, deed OCR, metes-and-bounds / COGO traverses and closure, compared back to the GIS fabric (`verify/`).
- **Publishes** a static dashboard with per-case evidence pages, owner names redacted by default.
- **Talks to agents** through an MCP server backed by a redacted DuckDB results store.
## Architecture
```mermaid
flowchart LR
A[Parcel layer<br/>SHP · GPKG · GeoJSON · ArcGIS REST] --> B[inspect<br/>checks.py + YAML rules]
B --> C[repair on a copy<br/>repair.py]
C --> D[(out/<br/>corrected.gpkg · changelog.csv<br/>issues.csv · diff.csv · report.html)]
B --> V[verify/<br/>PAO legal desc · deed OCR · COGO · PLSS]
D --> P[publish<br/>redact owners]
V --> P
P --> S[Static site<br/>GitHub Pages]
D --> L[load-db<br/>redacted DuckDB]
L --> M[georescue-mcp<br/>read-only tools · logs/mcp.log]
M --> AG[AI agent<br/>Claude · Cursor · ...]
```
## Quickstart
```bash
git clone https://github.com/knightchrism/georescue.git && cd georescue
uv sync --extra verify
PYTHONPATH=. uv run --extra verify pytest -q # test suite
uv run georescue inspect data.gpkg -c configs/columbia_fl.yaml
uv run georescue repair data.gpkg -c configs/columbia_fl.yaml -o out/
```
On Windows, clone to a local folder such as `C:\dev\georescue` (keep projects out of OneDrive-synced folders).
## AI / agent angle
- `georescue-mcp` exposes inspection, repair-to-a-new-folder, guarded read-only SQL, governed metrics and case lookups to any MCP client (details below).
- `scripts/mcp_demo.py` records real agent sessions; `agent_demo/` drives a visualization loop and saves before/after snapshots.
- Agents get the redacted store only — never owner names, never write access to source data.
## Tech stack
Python 3.13 · uv · GeoPandas · Shapely · pyogrio · PyProj · DuckDB · Pydantic · Typer · Jinja2 · Streamlit + Folium · MCP Python SDK · MapLibre GL JS · GitHub Actions + Pages
## Core (V1)
GIS data-quality & repair for parcel datasets. Load (SHP/GPKG/GeoJSON) → inspect → classify issues → propose repairs on a copy (every change logged) → export `corrected.gpkg`, `changelog.csv`, `issues.csv`, `diff.csv`, `summary.json`, `report.html`.
### Checks
missing/empty/invalid geometry · duplicate IDs · duplicate geometries · required attributes & types (YAML rules, Pydantic-validated) · CRS missing/unexpected · out-of-bounds · overlaps · slivers · small gaps · original-vs-corrected diff.
### Repairs (all logged: feature_id, check, action, before, after, reason, post_valid, applied)
make_valid (polygonal parts kept) · numeric text→number coercion · assign CRS if missing · optional: drop empty geoms, drop exact duplicates, trim overlaps below an area. Everything else is `flag_only`. The source file is never modified.
### Usage
```
uv sync
uv run georescue inspect data.gpkg -c configs/columbia_fl.yaml
uv run georescue repair data.gpkg -c configs/columbia_fl.yaml -o out/
uv run georescue report data.gpkg -c configs/columbia_fl.yaml -o out/
uv run streamlit run app.py # demo UI (docs/demo.png)
uv run georescue-mcp # MCP stdio server: inspect_dataset, repair_dataset
PYTHONPATH=. uv run --extra verify pytest -q
```
Real data: `uv run python scripts/fetch_columbia.py` (Columbia County FL LCParcels FeatureServer).
## Known gaps
Gap detection uses holes in the unioned fabric (misses gaps open to the outside edge); overlap trimming is greedy (higher row loses); DuckDB batch mode not implemented; no map of issue geometries in the UI (points only); type rules don't parse unit-suffixed text (e.g. "3 Ac").
## Automated vs. manual steps
| Step | Status |
|---|---|
| Inspect, classify, repair, change log, QA report | Automated (`georescue` CLI / MCP) |
| RustGIS visualization loop | Automated (`agent_demo/run_demo.py`) |
| Appraiser legal descriptions, PLSS corner tie (BLM CadNSDI) | Automated (`verify/`) |
| **Fetching recorded deed images** (myfloridacounty.com ORI) | **Manual today**: portal sits behind a human-verification check |
| Deed OCR, metes-and-bounds + curve parsing, COGO traverse, closure and GIS comparison | Automated (`verify/run_deeds.py`) |
| Final boundary position within ~3 ft | Needs a licensed surveyor |
Deed PDFs, page images, and raw county data are excluded from the repo.
## Credits
See [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) for open-source licenses and data sources, and [Data sources](#data-sources) below. Brand font: Exo 2 (SIL Open Font License, `brand/fonts/OFL.txt`).
## Live demo
Static dashboard (GitHub Pages): **https://knightchrism.github.io/georescue/**
- KPIs per check, filterable issues table, Leaflet map of *flagged parcels only* (small GeoJSON, not the 584 MB county layer),
per-overlap case files (verdict, confidence, ORB refs, deed closure/acreage, overlay PNGs) and run history.
- Basemap: OpenStreetMap tiles. The COJ Duval orthoimagery has no published licence, so imagery-backed figures are **not** published;
case pages use the plain (no-imagery) overlay PNGs.
```bash
PYTHONPATH=. uv run --extra verify georescue run --config configs/duval_fl.yaml # -> out/runs/<ts>/, out/latest/
PYTHONPATH=. uv run --extra verify georescue publish # -> site/
python -m http.server -d site 8765 # preview locally
```
Automation: `.github/workflows/pipeline.yml` (weekly cron + manual dispatch) runs the pipeline on a bbox extract
(`configs/duval_fl_ci.yaml`), fetching parcels at runtime, and deploys `site/` to Pages.
To enable: push the repo to GitHub, then *Settings → Pages → Source: GitHub Actions*, and allow Actions under *Settings → Actions*.
Only invalid-geometry repair is ever auto-applied; every other fix is a proposal recorded in `changelog.csv`.
## Data sources
GeoRescue does not own the data below and is not affiliated with, or endorsed by, any of these sources. Their records are maintained
for their own purposes (for example, assessment) and, as the Property Appraiser states for its data, are **not intended for legal use**
such as conveyances or boundary determinations.
- City of Jacksonville GIS — parcels (CityBiz/Parcels service): https://maps.coj.net/coj/rest/services/CityBiz/Parcels/MapServer/0 · home/disclaimer: https://maps.coj.net/
- Duval County Property Appraiser: https://paopropertysearch.coj.net/Basic/Search.aspx (disclaimer shown on the search site)
- Duval County Clerk of Courts — Official Records: https://or.duvalclerk.com · disclaimer: https://www.duvalclerk.com/disclaimer
Owner and person names are removed from the public site (`georescue publish` redacts by default; `--no-redact-owners` is for private local builds only).
## Ask GeoRescue (MCP server)
`georescue load-db` loads the latest run into a **redacted** DuckDB results store, `out/georescue.duckdb`. It holds the tables `issues`, `cases`, `verdicts`, `deed_traverses`, `runs` and `glossary`, and it never contains owner names. `georescue run` refreshes it automatically. The MCP server (`uv run --extra verify georescue-mcp`, stdio) exposes these tools:
`inspect_dataset`, `repair_dataset` (writes a repaired copy into a new folder only), `list_tables`, `describe_table`, `run_query` (single SELECT/WITH, guard + row cap + 10 s timeout), `list_metrics`/`get_metric` (governed metrics in `semantic/metrics.yml`), `get_case`, `find_issues`, `explain_issue` and `compare_runs`. All calls are logged to `logs/mcp.log`.
`scripts/mcp_demo.py` drives the server over stdio through realistic questions and records the real calls and outputs to `examples/agent_sessions.{json,md}`. The site's [Ask GeoRescue](https://knightchrism.github.io/georescue/agent.html) page renders those sessions. Each answer is filled in by a fixed template from the tool outputs. The page also has Claude Desktop / Cursor config snippets for running it yourself. These are recorded sessions and test results, not authoritative.
The server structure, SQL guard, metrics layer, logging and demo are adapted from the author's own [census-pipeline](https://github.com/knightchrism/census-pipeline) (MIT). GeoRescue keeps its existing MCP SDK (`mcp>=2.3`, `MCPServer`).
## Glossary
The site's [glossary](https://knightchrism.github.io/georescue/glossary.html) (generated by `georescue publish` from `src/georescue/glossary.py` and the config thresholds) explains every issue type the checks emit — what it means, why it matters, how it is detected, what (if anything) is done automatically — plus terms like verdict, confidence, deed traverse/COGO, misclosure, POB, ORB, IoU and PAO. All results are proposed test results, not authoritative.
## Terms
See [TERMS.md](TERMS.md). Questions, corrections or removal requests: open an issue at https://github.com/knightchrism/georescue/issues
## License
Code: MIT, see [LICENSE](LICENSE). Third-party software and data keep their own licenses and terms ([THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)).
TDQS
Scored across 11 tools
Most tools target distinct resources or actions, and descriptions clarify boundaries such as inspect_dataset for parcel datasets versus find_issues for latest-run issues. Minor overlap remains between inspect_dataset and find_issues, and between run_query and governed metric tools, but the intended use cases are separable.
All tools use snake_case verb_noun names with clear, predictable verbs such as list_, get_, find_, inspect_, repair_, and compare_. Singular/plural noun choices are appropriate to each operation and remain consistent throughout.
Eleven tools is well scoped for a dataset inspection, repair-proposal, results-querying, metrics, and case-review server. Each tool covers a meaningful operation without obvious redundancy.
The surface covers inspection, repair proposal generation, results-store discovery/querying, governed metrics, case lookup, issue filtering/explanation, and run comparison. Minor gaps exist around listing cases or runs directly and applying a repair, but core workflows are supported.