Corridor-MCP
by longfinnish
README.md
# Corridor-MCP
Read-only MCP server (Streamable HTTP) giving Claude direct, credentialed access
to parcel data. Credentials live in one server-side place — environment
variables on this server — instead of being pasted into project files where
they go stale silently.
Four tools, no more:
| Tool | Source | Credentials |
|---|---|---|
| `parcel_by_point(lat, lon, radius_m=100)` | Regrid `/api/v2/parcels/point` | `REGRID_TOKEN` |
| `parcel_by_owner(owner_name, county, state2)` | Regrid `/api/v2/parcels/query` (owner ilike, county+state scoped — mandatory, unscoped queries time out) | `REGRID_TOKEN` |
| `parcels_by_size(lat, lon, radius_mi, min_acres)` | Regrid polygon query (80 sq mi cap → max radius ≈ 5.04 mi, validated before calling) | `REGRID_TOKEN` |
| `county_parcel_query(county_source, owner_name?, parcel_id?)` | County ArcGIS directly (`laramie_wy`, `lincoln_la`) | none — works even when the Regrid token is dead |
All ArcGIS requests pass `outSR=4326` explicitly. Lincoln Parish stores no
lat/lon fields, so centroids are computed in code. Note: the Lincoln server
refuses to export parcel geometry (verified 2026-08-01 — `returnGeometry=true`
comes back geometry-less), so the server falls back to one
`returnExtentOnly` query per parcel and uses the bbox midpoint (capped at 60
parcels per query; beyond that lat/lon are null and the summary says so).
Adding a county is a config entry in `lib/counties.js`, not a code change.
**Where the live Regrid token is stored:** the single source of truth is the
Cloudflare Pages secret `REGRID_TOKEN` on the `corridor-map` Pages project
(production), consumed by `functions/api/regrid.js` in Corridor-Map. Cloudflare
secrets are write-only — to obtain the value for this server, copy it from the
Regrid dashboard (app.regrid.com → account → API tokens), not from Cloudflare.
The token in `Corridor_Intelligence_API_keys_v3.txt` (ends `6U8CEc`) is dead;
do not use it.
## Environment variables
| Variable | Purpose |
|---|---|
| `REGRID_TOKEN` | Regrid API token (tools 1–3). Never logged, never returned in responses. |
| `MCP_AUTH_TOKEN` | Bearer token this server requires on **every** request. The server refuses to start without it. |
Generate a strong `MCP_AUTH_TOKEN`:
```bash
openssl rand -hex 24
```
## Deploy on Replit
1. Replit → **Create App → Import from GitHub** → `longfinnish/Corridor-MCP`.
2. In the app's **Secrets** pane add:
- `REGRID_TOKEN` — the live token from the Regrid dashboard (see above; **not** the dead one ending `6U8CEc`).
- `MCP_AUTH_TOKEN` — output of `openssl rand -hex 24`.
3. Run once in the workspace (`npm install` runs automatically; the server
starts with `npm start`). The console should show `corridor-mcp listening`.
4. **Deploy** (Autoscale — the server is stateless). Note the deployment URL.
5. Claude.ai → Settings → Connectors → **Add custom connector**:
- URL: `https://<your-app>.replit.app/mcp`
- Auth header: `Authorization: Bearer <MCP_AUTH_TOKEN>`
Unauthenticated requests to any path (including `/`) get **401** by design;
a 401 from the bare URL still proves the server is up.
## Acceptance checks (expected values verified 2026-08-01; county rolls drift)
Set up once:
```bash
URL="https://<your-app>.replit.app"
TOKEN="<MCP_AUTH_TOKEN>"
call () { curl -s -X POST "$URL/mcp" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d "$1"; echo; }
```
**1. Regrid owner search — Washburn / Laramie WY.** Expect 6 parcels, ~72
total acres: Washburn Fam Liv Tr (14.0), Washburn William (35.92), Washburn
Laurie (5.2), Washburn Robert W (7.35), Washburn Ross R (4.81), Washburn
Douglas E (4.42).
```bash
call '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"parcel_by_owner","arguments":{"owner_name":"washburn","county":"Laramie","state2":"WY"}}}'
```
**2. County source agrees with Regrid.** Same 6 parcels, matching acreages
(71.7 total `net_acres`):
```bash
call '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"county_parcel_query","arguments":{"county_source":"laramie_wy","owner_name":"washburn"}}}'
```
**3. Coordinates are geographic, not projected.** In check 2's output every
parcel must have `lat` ≈ 41.x and `lon` ≈ -104.x. Millions ⇒ `outSR` was not
applied ⇒ the build is wrong. For Lincoln Parish, computed centroids must land
in 32.x / -92.x:
```bash
call '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"county_parcel_query","arguments":{"county_source":"lincoln_la","owner_name":"smith"}}}'
```
**4. Polygon cap is enforced by name.** Expect a clear error citing the 80
square mile cap — not a timeout, not an empty result:
```bash
call '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"parcels_by_size","arguments":{"lat":41.19,"lon":-104.75,"radius_mi":6,"min_acres":100}}}'
```
**5. Dead Regrid token degrades loudly, county tool survives.** With
`REGRID_TOKEN` set to a deliberately invalid string, checks 1 and 4 (with a
legal radius) must return the plain-language dead-token message naming the
Regrid dashboard; check 2 must still return parcels.
**6. Missing/wrong bearer ⇒ 401, no data:**
```bash
curl -s -i -X POST "$URL/mcp" -H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":6,"method":"tools/list"}' | head -1
```
## Constraints
- **Read only.** No write, create, update, or delete operations of any kind.
- `REGRID_TOKEN` and `MCP_AUTH_TOKEN` are never hardcoded, logged, echoed, or
included in any tool response or error.
- Regrid 401 "Token is no longer valid" is handled explicitly: tools 1–3
report that the token is dead and must be rotated in the Regrid dashboard.
This exact failure motivated the build.
- **No CEII data touches this server.** PSS/E model data cannot run on cloud
infrastructure under NIST 800-171.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing