Skip to main content
Mireye keeps the callable MCP tool list intentionally small: mireye_ask, mireye_proximity, mireye_fetch, mireye_geocode, mireye_lookup, mireye_request_field, and mireye_field_request_status. Catalog discovery is exposed as MCP resources, and common workflows are exposed as prompts, so agents get better context without paying for extra tool-choice clutter.

Tools

If the caller asked a question, use mireye_ask. If the caller named fields or a preset, use mireye_fetch. If the caller gave an address instead of a coordinate, call mireye_geocode first — or, if the input might be ambiguous, isn’t a clean address (a coordinate or an APN), or you want a parcel attached, call mireye_lookup instead. If the caller wants drive times, drive-time screens, or a labor shed — anything about the relationship BETWEEN coordinates rather than one point — use mireye_proximity. If the catalog doesn’t have the field the caller needs, call mireye_request_field — and poll the request_id it returns with mireye_field_request_status.
mireye_ask, mireye_proximity, mireye_fetch, mireye_geocode, and mireye_lookup are read-only and idempotent; the ask/fetch schemas constrain latitude and longitude to the supported US envelope and cap fields at 50 items. mireye_request_field creates state (a request, sometimes a build ticket) and is idempotent only when you pass an idempotency_key; mireye_field_request_status is read-only.

mireye_ask

Answers a natural-language question about a US coordinate with citations to named public-agency, open-data, and licensed sources.
Give either lat+lng or address, never both:
With an address, the response carries a geocode block. If parcel_grade is false the location was estimated from the street rather than matched to a building — and the caveat is appended to the answer text itself, so it travels with the prose even if you relay only that. Use this for questions like “is this in a flood zone?”, “what is the wildfire risk?”, or “what kind of building is at this address?”.

mireye_fetch

Fetches exact catalog fields or preset bundles with per-field provenance.
address works here too, in place of lat+lng:
Check geocode.parcel_grade before trusting parcel-specific fields. false means the coordinate was interpolated along a street centerline — up to ~2.9 km out in rural areas, which is far enough to describe a neighbouring property. Named fields and presets can be combined; Mireye unions and deduplicates the resolved fields, then enforces the 50-field cap.

mireye_geocode

Resolves a US street address to a coordinate you can pass to the other tools.
Always read accuracy_type before using the coordinate. rooftop sits on the parcel; range_interpolation is estimated along a street centerline and can be ~2.9 km out in rural areas — far enough to describe a neighbouring property. Compare normalized_address against what the user typed, too: a match in the wrong town is returned honestly rather than as an error. Two failure modes an agent should handle differently:
  • address_too_coarse — the address only resolved to a ZIP/city/county centroid. Do not retry; ask the user for a street number. The upstream answers 200 with a city centroid for a nonexistent address, so this rejection is what stands between a typo and a confidently wrong answer.
  • address_not_found — no match at all. Also not retryable.
The result also carries source — the authority behind the coordinate, e.g. City of New York or TIGER/Line® from the US Census Bureau. That is a second quality signal independent of accuracy_type: municipal parcel data and a federal street-centerline file are not equally good. Full contract: POST /v1/geocode.

mireye_lookup

Turns a messy human locator — an address, a "lat,lng" pair, or an APN — into canonical join keys: a coordinate, resolved address, and (when it’s safe to) a parcel.
Unlike mireye_geocode, this detects genuine ambiguity. A single top-ranked geocode match can never reveal that a comparably-good alternative existed — an unqualified “1100 King St W, Toronto” can land on Ontario or Ohio at similar confidence. mireye_lookup checks multiple candidates, so an ambiguous input comes back as disposition: "clarify" with a candidates array instead of a silent pick:
Always check disposition first:
  • resolved — a coordinate and confidence, plus a parcel block when the geocode cleared parcel-quality accuracy. Also carries free area/hazard/ market context gathered concurrently with the parcel lookup: jurisdiction codes (state, block/block-group, congressional district, CBSA/metro area), elevation, FEMA flood-zone fields, a county_market bundle, Opportunity Zone status, and timezone — see POST /v1/lookup’s full contract for the complete field list. Every one degrades independently to null on its own failure.
  • clarify — genuinely ambiguous. Present candidates to the user; never auto-pick one.
  • no_match — an honest failure with a reason (e.g. apn_not_supported_in_v1 for APN-only input, which isn’t supported yet).
A parcel-lookup failure never demotes a good geocode. resolved can still come back with parcel_unavailable: true and a parcel_unavailable_reason (e.g. the vendor’s own quota being exhausted) rather than an error — the geocode succeeded even when the parcel attempt didn’t. Swapped coordinates are rejected, not guessed. "-73.9,40.7" where "40.7,-73.9" was meant comes back as a bounds-error tool failure, never a best-effort nearest-match. Check parcel_grade before re-using the coordinate. On a resolved response it is false when the geocoder could only interpolate the point along the street rather than match it to a rooftop, and precision_note says so in prose. The parcel in that response is still correct — a street-tier lookup matches Regrid by the situs address, never by the estimated pin — but the top-level lat/lng can sit on the neighbouring property, so passing it to mireye_fetch or mireye_ask returns that neighbour’s data. Use parcel.interior_point_lat / interior_point_lng for downstream point queries instead: a coordinate guaranteed to fall inside the matched parcel. Both parcel_grade and precision_note are absent when no geocode ran (a coordinate you supplied) or when there is no single coordinate yet (clarify / no_match). Full contract: POST /v1/lookup.

mireye_proximity

Computes driving-time distance, nearest-candidate ranking, proximity screening, or labor-shed statistics across multiple US + Canada coordinates in one call — what mireye_fetch/mireye_ask do for a single point, this does for a whole matrix of them.
Note the extra req nesting — the tool takes one argument, req, whose shape is the same discriminated union as POST /v1/proximity’s body (op: "distance" | "nearest" | "screen" | "labor_shed"). Every origin, destination, and anchor is a coordinate or a street address — never a named place. An airport’s name, a substation’s name, or any other landmark is not an address and will fail to resolve. To reach named infrastructure, use nearest’s curated set (@airports, @substations, @power_plants, @rail, @ports, @urban_areas) or supply that place’s own coordinate directly. Send the most precise locator you have, and disclose anything you filled in yourself. A vague locator doesn’t fail loudly upstream — it matches a real but wrong place. "1412 market street" matches a town called Market in West Virginia; "SFO airport" matches a town called Airport in North Carolina, at full confidence. Both are refused, and the resulting 422 carries unresolved_accuracy_types (a place tier means you sent a name, not an address) plus caller_guidance. You can usually repair this where a plain program can’t — you have context and world knowledge, so you can tell that a request mentioning SFO probably means Market Street in San Francisco. That ability carries an obligation: if you retry using anything you inferred rather than what your caller supplied — a city, state, ZIP, or a coordinate substituted for a place name — say so explicitly when you report the result (“the address had no city; I assumed San Francisco”). Never present an inferred location as though the caller specified it, and ask instead of guessing when you aren’t confident. Every response echoes paid_driving_calcs (what pricing charged for, computed from the request shape, never from how many locators happened to resolve) and notes (coverage + traffic honesty labels — durations reflect typical traffic, not real-time, and coverage is US + Canada driving only). Read notes on a success too: per-item failures are dropped silently from the results, so a 200 can be missing rows you asked for, and notes is where that is announced. Report anything dropped, any leg flagged unreachable_or_snapped (a null duration means no road route was found — do not present its distance as drivable), and any tracts_unreachable on a labor shed. A per-item resolution failure never fails the whole request for bulk destinations/candidates — only a required role (an op’s origin(s), or screen’s anchors) failing entirely raises a structured, non-retryable tool error; an overloaded worker or an exhausted shared driving-matrix budget raises a structured, retryable one instead. Cap your own spend with max_credits, on any op. A request priced above it is refused with a 422 stating the exact price, before the driving matrix is charged. A request over the service ceiling gets that same 422 telling you to pass max_credits — and a labor_shed over a dense metro clears the ceiling routinely (a 15-minute Los Angeles shed prices at 18,792 credits). For labor_shed specifically, send estimate: true first: the tract prefilter that sets the price is free, so the estimate is exact and costs nothing. Full contract, all four ops with worked examples and the pricing formula: POST /v1/proximity. Always pass idempotency_key for agent-originated requests — the same key replays the existing request’s state instead of filing a second build. Check disposition first, the same vocabulary as the POST response:
  • matched_existing / partial — the catalog already answers it. The response includes a live sample at your own first location and the exact resume call (a ready-to-send mireye_fetch-equivalent request) — no build, no wait.
  • near_miss_confirm — something close exists; the reason names what differs (basis, units, threshold). Either use its resume call, or re-file with the offered field named in extra.constraints.must_not_be.
  • accepted_new — queued. Store the returned request_id in durable task state (not conversation context) and poll it with mireye_field_request_status.
  • rejected — a typed rejection_code and routing_hint, never a bare no.
A genuinely ambiguous example_locations entry comes back as a stateless location clarify (candidates, no request created) — present the candidates to the user, never auto-pick one. Optional fields worth setting when you have the context: use_case and decision_threshold (what decision this feeds, and the value that flips it) sharply improve match quality; requested_fields pre-splits a bundled ask into atomic sub-questions; context_blob is echoed verbatim in every poll and callback. The rarer structured fields (area_of_interest, expected_volume, freshness, constraints, known_sources, output_preference) go in extra, verbatim — see the full shapes on POST /v1/field-requests. Filing a request never spends /v1/fetch credits; plans carry a separate included build allowance, visible as field_requests_included on GET /v1/users/me/usage. Full contract: POST /v1/field-requests.

mireye_field_request_status

Polls a field request filed with mireye_request_field.
Store request_id in durable task state, not conversation context — a new-field build takes hours, and the session that filed the request is almost certainly gone by the time it’s done. status moves through intake (received/screeningmatched / awaiting_confirm / rejected / queued) and then, once queued, the build lifecycle (claimedbuildingin_reviewapprovedpublishinglive, or blocked/expired). estimated_ready_at is the promise made at acceptance, read back verbatim — it never slides forward on poll. When status is live, execute the resume call in the response — the exact /v1/fetch request that answers the original ask. Requests are visible only to the credential that filed them: an id that doesn’t exist, or belongs to someone else, is the same field_request_not_found 404 either way, never a 403. Full contract: GET /v1/field-requests/{request_id}.

Resources

Use resources for read-only catalog context instead of adding catalog tools: The hosted MCP endpoint serves these from the same in-memory payload as GET /v1/meta/fields. The local stdio adapter fetches that endpoint and caches it for one hour with ETag support.

Prompts

Prompts package common agent workflows while leaving the tool names stable:

Errors

MCP tool failures include actionable JSON fields such as code, message, http_status, request_id, tool, and retryable. Agents should retry only when retryable is true, refresh catalog context for fields_unknown, and ask the user to authenticate for mcp_auth_required. See /api-reference/errors for the HTTP API error catalog and /api-reference/fetch for preset semantics.