> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mireye.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Building agents

> Wire Mireye into a Claude / Claude Code / Cursor / custom MCP agent in five minutes.

You want your Claude agent (or Cursor agent, or any MCP-aware tool-using
LLM) to know things about US places. Today the agent either makes up
elevation values or punts to the user. With Mireye's MCP server, the
agent gets two tools that return federal-source-cited answers, plus MCP
resources for catalog discovery and prompts for common site workflows.
No prompt engineering, no fine-tuning, no proprietary data licensing.

## Install in 30 seconds

For Claude Code, use the hosted OAuth endpoint:

```bash theme={null}
claude mcp remove mireye-earth -s user   # only needed if an old stdio entry exists
claude mcp add --transport http --scope user mireye-earth https://api.mireye.com/mcp
```

Restart Claude Code, run `/mcp`, and complete browser sign-in.

For Claude Desktop, Cursor, or custom local-stdio agents, run:

```bash theme={null}
uvx mireye-mcp
```

(`uvx` ships with [`uv`](https://docs.astral.sh/uv/) — install with
`curl -LsSf https://astral.sh/uv/install.sh | sh` if you don't have it.)

Authenticate with `mireye-mcp login` or set `MIREYE_BEARER_TOKEN`,
then add to `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json theme={null}
{
  "mcpServers": {
    "mireye-earth": {
      "command": "uvx",
      "args": ["mireye-mcp"]
    }
  }
}
```

Restart Claude Desktop. Two tools — `mireye_ask` and `mireye_fetch` —
appear under the 🔌 menu. Catalog resources and prompts are available to
clients that surface those MCP primitives. Full install details
(including Cursor and custom-SDK setup) at [/mcp/installation](/mcp/installation).

## Three example agent prompts

### 1. Natural-language Q\&A

The simplest case. The user asks a question; the agent calls `mireye_ask`.

> **User**: I'm thinking about buying a small lot at 40.7128, -74.0060.
> What should I know about it?
>
> **Claude** (using `mireye_ask`): The location at 40.7128, -74.0060 is
> in lower Manhattan, NY, at an elevation of 13.15 m above NAVD88
> (USGS 3DEP). The nearest shoreline is about 764 m away (NOAA CUSP). The
> site is outside any FEMA NFHL Special Flood Hazard Area polygon, but
> the proximity to the coast means storm-surge exposure dominates flood
> risk — a certified flood-zone determination is still required for
> lending. The land cover is "Developed" (USFS LCMS); this is a
> built-up urban parcel rather than vacant land. Citations attached.

The agent picked `mireye_ask` because the user phrased a question.
Mireye's planner picked elevation, coast distance, the FEMA NFHL
flood-hazard flag, and LCMS class — the right fields for "what should
I know."

### 2. Structured workflow

The agent is filling out a structured form, so it calls `mireye_fetch` directly:

> **User**: For each of these 20 candidate sites, give me elevation,
> slope, and flood status.
>
> **Claude** (loops over the list, calling `mireye_fetch` with `fields: ["elevation", "slope_degrees", "within_floodplain_polygon"]` per
> coordinate, then builds a table from the responses).

Faster than 20 `mireye_ask` calls (no LLM planning per coordinate) and
the output is deterministic — same input always returns the same
per-field values until the source TTL expires.

### 3. Audit-trail-required reasoning

The user needs justifications, not just answers:

> **User**: Compare these three parcels for wildfire risk and tell me
> which one you'd pick. Include the source for every claim.
>
> **Claude** (calls `mireye_ask` per parcel with the wildfire question,
> then compares the three answers; the citations already attached to
> each `mireye_ask` response carry directly into the final comparison).

Because every Mireye answer comes with its citations, the agent doesn't
have to do any provenance bookkeeping — it just forwards what it got.

## When to use `mireye_ask` vs `mireye_fetch` from an agent

The rule:

> If the user's request would be answered in **natural language**, use
> `mireye_ask`. If the user's request is **structured** (a form, a
> table, a downstream computation), use `mireye_fetch`.

Concrete examples:

| User says…                                              | Tool           | Why                                          |
| ------------------------------------------------------- | -------------- | -------------------------------------------- |
| "What's the flood risk?"                                | `mireye_ask`   | NL question; planner picks the right fields. |
| "Give me elevation."                                    | `mireye_fetch` | One named field; no planning needed.         |
| "Run the wildfire underwriting preset."                 | `mireye_fetch` | Preset is structured; LLM adds no value.     |
| "Summarize this location for me."                       | `mireye_ask`   | Open-ended; planner picks broad context.     |
| "Build a CSV of slope, canopy, NDVI for these 50 lots." | `mireye_fetch` | Bulk structured pull.                        |

The agent does not need to perfectly disambiguate — calling `mireye_ask`
for a structured request just costs a little more latency and a planner
LLM call, and `mireye_ask` will still pick reasonable fields. The opposite
(`mireye_fetch` on an ambiguous question) requires the agent to guess
field names, which is worse.

## Custom agent (no Claude Desktop)

If you're building your own MCP client, the official `mcp` Python SDK
talks to the server over stdio:

```python theme={null}
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def query_mireye(question: str, lat: float, lng: float) -> dict:
    params = StdioServerParameters(command="uvx", args=["mireye-mcp"])
    async with stdio_client(params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            result = await session.call_tool(
                "mireye_ask",
                {"lat": lat, "lng": lng, "question": question},
            )
            return result.content[0].text  # JSON string

print(asyncio.run(
    query_mireye("What's the elevation?", 40.7128, -74.0060)
))
```

For agents built on TypeScript, use `@modelcontextprotocol/sdk`. For
agents not on MCP at all, just hit
`https://api.mireye.com/v1/{ask,fetch}` directly with a Mireye API
token ([Authentication](/authentication)) — the MCP server is a
convenience, not a requirement.

## Self-discovering the catalog

Long-lived MCP agents should read `mireye://catalog/fields` once at
startup to render field-picker UIs or to inform their own planner prompts.
Agents that are not using MCP can call the HTTP catalog directly:

```python theme={null}
import httpx, time

async def warm_catalog() -> dict:
    async with httpx.AsyncClient() as c:
        r = await c.get("https://api.mireye.com/v1/meta/fields")
        r.raise_for_status()
        return r.json()
```

The endpoint sets `ETag` + `Cache-Control: public, max-age=3600`. See
[/api-reference/meta-fields](/api-reference/meta-fields) for the
recommended `If-None-Match` pattern.

## What about MCP rate limits and quotas?

V1 requires account/API-token auth for `/v1/ask`, `/v1/fetch`, and MCP
tool calls. It does not yet enforce metered quotas. The Fly deploy is
sized for the early-adopter wave; if you're planning a high-volume agent
deployment, drop a line to [ansh@mireye.earth](mailto:ansh@mireye.earth) first so we can confirm
the deploy is sized accordingly.

## What about streaming responses?

MCP streaming is on the V1.5 roadmap. Today both tools return
fully-formed JSON responses after the underlying HTTP call completes
(typically 6–15 s for `mireye_ask`, 1–10 s for `mireye_fetch` depending
on preset breadth and cache warmth). If your
agent's UI shows "thinking" indicators, that's the right pattern — the
answer arrives in one block.
