Skip to main content
Glama
pranavyadav11

location-risk-mcp

location-risk-mcp

Independent prototype, not a Precisely product and not affiliated with Precisely. Built by Pranav Yadav as a personal project. It calls Precisely's hosted MCP server with the user's own trial credentials. Decision support only: it does not make or recommend underwriting decisions.

An MCP server that gives an AI agent what it needs to pre-screen a property for a homeowners policy. It provides three tools, each shaped around a step in the agent's task:

standardise_address  ──►  enrich_location  ──►  summarise_risk_context
  messy text in            flood, wildfire,        overall level, flags ranked
  one location_id out      quake, crime, fire      by severity, evidence for
  (or candidates/none)     station, building       each flag, follow-ups, gaps

In live mode it is a task layer on top of Precisely's hosted MCP server. Precisely exposes its data services as hundreds of actions behind three generic tools (precisely_actions_search / _describe / _execute). That's ideal for discovery, but an agent running an underwriting pre-screen would have to find, sequence and interpret seven actions every time. This server does that once, deterministically:

Step

Precisely actions used

standardise_address

geo_addressing.geocode: standardised address, building-level point, PreciselyID

enrich_location

risk.flood, risk.wildfire, risk.earthquake, demographics.crime_index, risk.fire_station, property.attributes. Called in parallel by PreciselyID, so every block describes the same matched property.

summarise_risk_context

none: versioned rules over the enrichment (risk.py)

Why it is shaped this way

  • Task-shaped tools, not endpoint wrappers. The agent passes a location_id from step to step. It never carries coordinates or IDs between calls, and never has to know which of Precisely's actions holds which field.

  • Every value is citable. Outputs are typed (each tool publishes an MCP outputSchema). Each data block carries its own source: data_source (fixture or live), the Precisely action it came from, retrieved_at and the dataset vintage. Each risk flag lists the exact fields it rests on.

  • Gaps are reported, never filled. Provider placeholders (-9999, empty {value: null} objects, a crime index of 0 with no category) become gaps, not numbers. One failing action becomes a gap for that block only. If a core peril (flood or wildfire) can't be assessed, the summary says insufficient_data instead of low.

  • Corrections are surfaced. If the geocoder changed something the user typed (e.g. a different ZIP), standardise_address returns a warning to confirm with the applicant.

  • Ambiguity goes back to the user. Close-scoring candidates return status: ambiguous, and the server instructions tell the agent to ask, not pick.

  • Data minimisation. property.attributes also returns owner names, tax mailing addresses and sale history. None of that is passed to the agent; only building attributes are.

  • The risk rules are deterministic and versioned. The same input always gives the same summary, so it can be tested and audited.

  • Read-only by declaration. All tools set readOnlyHint and idempotentHint. openWorldHint is true only in live mode.

Related MCP server: PropertyScoop MCP Server

Quick start (fixture mode, no account needed)

python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/python -m pytest -q          # 24 tests, no network
.venv/bin/python scripts/demo.py       # full flow through a real MCP client over stdio

Fixture mode serves bundled synthetic data (src/location_risk_mcp/fixtures/locations.json). Every address and value in it is invented, and every response is stamped data_source: "fixture".

Live mode (your own Precisely trial)

  1. Create .env from the template, then add the API key and secret from your Precisely workspace. .env is git-ignored.

    cp .env.example .env
  2. Set PRECISELY_MODE=live. The server authenticates to https://api.cloud.precisely.com/mcp (us-east-1; set PRECISELY_MCP_URL for other regions) with the header Precisely documents: Authorization: Apikey base64(key:secret).

  3. Check the connection and run one address end to end:

    .venv/bin/python scripts/doctor.py --probe "1700 District Ave, Burlington, MA 01803"
  4. Record a live transcript:

    .venv/bin/python scripts/demo.py "<test address>" ...

Use test or sample addresses only, never real customer data.

Web UI (for demos)

.venv/bin/python -m location_risk_mcp.web      # then open http://127.0.0.1:8765

A single page: pick a country, enter an address, watch the three tool calls run with timings, and see the verdict, flags with their evidence chips, warnings, gaps and the raw MCP outputs. The page is just another MCP client: it calls the same three tools an agent would, so it shows exactly what an agent gets. It follows PRECISELY_MODE from .env, shows a FIXTURE or LIVE badge, and listens on localhost only.

Connect it to an MCP client

Claude Code:

claude mcp add location-risk -- /ABSOLUTE/PATH/location-risk-mcp/.venv/bin/python -m location_risk_mcp.server

Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "location-risk": {
      "command": "/ABSOLUTE/PATH/location-risk-mcp/.venv/bin/python",
      "args": ["-m", "location_risk_mcp.server"]
    }
  }
}

The server reads .env from the project folder. It also exposes an underwriting_prescreen prompt and, in fixture mode, a fixtures://sample-addresses resource. A matching Claude Skill is in skills/underwriting-prescreen.

Demo transcript (live mode)

Recorded on 2026-11-01 against Precisely's hosted MCP server, using addresses from Precisely's own documentation examples. Full transcript: demo/transcript.live.md. A synthetic-data run is in demo/transcript.fixture.md.

1700 District Ave, Burlington, MA 01803 → 1700 DISTRICT AVE, BURLINGTON, MA 01803 (building-level point, score 100) overall moderate

  • MODERATE flood: zone X, but 204 ft from a 100-year flood zone. Evidence: flood.zone='X', flood.distance_to_100yr_zone_ft=204. Next: check site elevation relative to the nearby flood zone. A zone-only check would have called this low.

  • wildfire (Minimal), earthquake (site class C), fire response (1.55 road miles, about 10.6 min) and building age (1979): low.

  • Gaps (reported, not filled): crime.composite_index (not populated for this block), earthquake.nearest_fault_miles.

2755 Milwaukee St, Denver, CO 80238 → 2755 N MILWAUKEE ST, DENVER, CO 80205 (score 86)

⚠ ZIP corrected: input 80238, matched 80205

overall elevated

  • ELEVATED theft_and_crime: crime index 174. MODERATE earthquake: nearest fault 12.75 mi. MODERATE building_age: built 1927.

Near the old mill → no_match: the agent stops and says so.

Layout

src/location_risk_mcp/
  server.py                  MCP server: tools, prompt, resource, agent instructions
  web.py, static/index.html  local demo UI (an MCP client of server.py)
  risk.py                    deterministic, versioned risk rules
  models.py                  typed outputs (become each tool's outputSchema)
  config.py                  settings from env/.env; never exposes secrets
  providers/precisely_mcp.py client of the hosted Precisely MCP server + response mapping
  providers/fixture.py       synthetic data, no network
  fixtures/locations.json
skills/underwriting-prescreen/SKILL.md
scripts/demo.py              end-to-end run through a stdio MCP client
scripts/doctor.py            config + connection check, live probe, action search
tests/                       server (via MCP client), rules, live mapping (canned responses)

Limits

  • Risk thresholds are illustrative, not any insurer's underwriting guidelines.

  • Risk context is US-only: every Precisely risk and property action used here covers US addresses only. Other countries (e.g. IND) are standardised and geocoded live, and the risk blocks are skipped and reported as gaps, so the verdict is insufficient_data, never a guess.

  • One MCP session per tool call; a hosted version would keep a pooled session, a shared cache keyed by location_id, and per-tenant auth on its own endpoint.

  • Precisely's hosted MCP server is in Preview, so action names and response shapes may change. The mapping turns anything unexpected into gaps, and doctor.py --probe shows them.

License

MIT. See LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Instant U.S. property intelligence for AI agents. Zoning, Buildability™ Score, ADU eligibility, flood risk, and more from 20+ government sources. Pay-as-you-go: $5 per analysis (prepaid credits). Free Score available at buildability.us. Get a key at buildability.us/api.
    5
    1
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Property intelligence API for US real estate. Returns 16+ data points for any US address: noise levels, wetlands, slope, natural light, powerline proximity, crime rates, property facing direction, zoning, public record, radon risk, natural hazards (earthquake, flood, wildfire), neighborhood demographics, falling tree risk, RF/cell tower exposure, and nearby school.
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Assesses natural hazard exposure (flood, wildfire, earthquake, coastal proximity) for a single US property address using only free, keyless public data.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides per-property multi-peril risk scores (flood, wildfire, wind, hail, crime, etc.) for an address, returning A-F grades and 0-100 scores across 25+ hazard types for insurance underwriting and due diligence.
    12 npm
    MIT