Metadata-Version: 2.4
Name: mireye-earth-mcp
Version: 0.1.0
Summary: MCP server for Mireye Earth — federal-source-cited geospatial data for any MCP-aware agent.
Project-URL: Homepage, https://mireye-earth.fly.dev
Project-URL: Repository, https://github.com/mireye/mireye-earth
Author: Mireye
License: TBD
Keywords: claude,cursor,geospatial,mcp,mireye,model-context-protocol
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27
Requires-Dist: mcp<2.0,>=1.2
Description-Content-Type: text/markdown

# mireye-earth-mcp

Expose Mireye Earth's `/v1/ask` and `/v1/fetch` endpoints to any MCP-aware
agent (Claude Desktop, Claude Code, Cursor, custom agents built on the
`mcp` Python SDK) as native tools — no HTTP wiring required.

This is a standalone PyPI package (`mireye-earth-mcp`) with only two
runtime dependencies — `httpx` and `mcp`. It does not pull in the
geospatial backend, so there's no GDAL / rasterio / DuckDB build step.

The server is a ~100-line stdio adapter with zero business logic: each
tool handler POSTs to the deployed Mireye HTTP API and returns the
response verbatim, preserving per-field provenance, citations, and
honest-pattern `partial_failures`.

---

## What the agent gets

Two tools, both prefixed `mireye_` so they sort together and don't
collide with generic `ask` / `fetch` tools from other MCP servers:

| Tool            | When the agent should call it                                                                  |
|-----------------|------------------------------------------------------------------------------------------------|
| `mireye_ask`    | The caller asked a question about a US place ("is this in a flood zone?", "wildfire risk?").   |
| `mireye_fetch`  | The caller wants specific named fields ("elevation and slope here") or is powering a workflow. |

Two matching prompts (`mireye_ask`, `mireye_fetch`) are also registered.
Claude Code surfaces MCP prompts as slash commands under the form
`/mcp__<server>__<prompt>` — concretely `/mcp__mireye-earth__mireye_ask`
and `/mcp__mireye-earth__mireye_fetch`. The slash format isn't
customizable; the main path for most users is still natural chat ("what
elevation is 40.7128, -74.006?"), with the model choosing the tool.

There is no third `list_fields` tool. Agents that need the catalog can
hit `GET /v1/meta/fields` via plain HTTP — the endpoint sets a 1-hour
`Cache-Control` and an `ETag`, so a long-lived agent fetches it once.

---

## Install — one command with `uvx`

```bash
uvx mireye-earth-mcp
```

That's it. `uvx` (bundled with [`uv`](https://docs.astral.sh/uv/))
downloads the package into a managed cache, runs the entry point, and
the next invocation is instant. No venv to manage, no `pip install`,
no native builds.

If you don't have `uv`:

```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```

Plain pip also works:

```bash
pip install mireye-earth-mcp
mireye-earth-mcp  # entry point
```

---

## Wire it into Claude Desktop

Edit `~/Library/Application Support/Claude/claude_desktop_config.json`
(macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):

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

Restart Claude Desktop. The two tools (`mireye_ask`, `mireye_fetch`)
appear under the 🔌 menu.

To point at a self-hosted deployment instead of the default Fly URL:

```json
{
  "mcpServers": {
    "mireye-earth": {
      "command": "uvx",
      "args": ["mireye-earth-mcp"],
      "env": {
        "MIREYE_BASE_URL": "https://your-deploy.example.com"
      }
    }
  }
}
```

---

## Wire it into Claude Code

One-liner:

```bash
claude mcp add mireye-earth -- uvx mireye-earth-mcp
```

That writes the config and reloads MCP. Slash commands appear as:

- `/mcp__mireye-earth__mireye_ask <lat> <lng> <question>`
- `/mcp__mireye-earth__mireye_fetch <lat> <lng> [fields] [preset]`

Or just chat naturally — Claude Code will call the tool when relevant.

---

## Wire it into Cursor

Cursor's MCP config lives at `~/.cursor/mcp.json` (global) or
`<repo>/.cursor/mcp.json` (workspace). Same shape as Claude Desktop:

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

Open **Cursor → Settings → MCP** and confirm `mireye-earth` shows two
green tools.

---

## Wire it into a custom agent

If you're building an MCP client with the `mcp` Python SDK, point its
`StdioServerParameters` at the installed entry point:

```python
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

params = StdioServerParameters(command="uvx", args=["mireye-earth-mcp"])

async with stdio_client(params) as (read, write):
    async with ClientSession(read, write) as session:
        await session.initialize()
        tools = await session.list_tools()
        # tools.tools is [mireye_ask, mireye_fetch]

        result = await session.call_tool(
            "mireye_ask",
            {"lat": 40.7128, "lng": -74.0060, "question": "elevation?"},
        )
```

---

## Configuration

| Env var            | Default                          | Purpose                          |
|--------------------|----------------------------------|----------------------------------|
| `MIREYE_BASE_URL`  | `https://mireye-earth.fly.dev`   | HTTP base URL the tools POST to. |
| `MIREYE_TIMEOUT_S` | `60`                             | Per-request timeout in seconds.  |

There is no auth in V1. `X-API-Key` is planned for V2 once we open
metered access.

---

## Troubleshooting

**Server doesn't appear in Claude Desktop.** Check that `uvx` resolves
on the PATH used by the GUI app (macOS launches GUI apps with a minimal
PATH). Test from a terminal: `which uvx`. If empty, install `uv`:
`curl -LsSf https://astral.sh/uv/install.sh | sh`. If `uvx` lives at
`/Users/you/.local/bin/uvx`, use the absolute path in `command`.

**Tools not appearing under the 🔌 menu after restart.** Watch
`~/Library/Logs/Claude/mcp-server-mireye-earth.log`. The server logs to
stderr on startup; you should see `[mireye-earth-mcp] starting
base_url=…`. If there's no log, `uvx` isn't being invoked — usually a
PATH issue.

**`ConnectError` / `ReadTimeout`** on the first tool call. The HTTP API
runs on Fly with auto-stop enabled, so the first request after idle wakes
the machine (~5–15 s cold start). Increase `MIREYE_TIMEOUT_S` to 90 if
you are repeatedly hitting timeouts.

**HTTP 400 `coord_out_of_bounds`.** Mireye is US-only in V1. The accepted
envelope is `lat ∈ [18, 72]`, `lng ∈ [-180, -65]` — covering the lower 48,
Alaska, Hawaii, and US territories.

**HTTP 400 `fields_unknown`.** The field name is not in the catalog. Hit
`https://mireye-earth.fly.dev/v1/meta/fields` to see the canonical list.
Common surprises: `elevation_m` is `elevation`, `floodplain` is
`within_floodplain_polygon`.

**HTTP 4xx/5xx in general.** The MCP server intentionally passes errors
through. The body of the tool error contains the structured `detail`
returned by FastAPI — agents can read `detail.error` and `detail.message`
to recover.

**Auth errors.** V1 has no auth. If you are seeing `401`/`403`, you are
probably hitting a private deploy that wraps the API in a reverse proxy
with auth in front of it — talk to the deploy operator.

---

## What this server does NOT do

- **No caching.** The HTTP API has its own disk cache; double-caching at
  the MCP layer adds latency and staleness with no benefit.
- **No coordinate / field validation.** The HTTP API validates and returns
  structured 400s. Re-validating here just hides the real error.
- **No streaming.** MCP streaming responses are V1.5.
- **No auth.** Pass-through only; V2 will surface `X-API-Key` once the
  HTTP API has it.
- **No in-process imports of `mireye_earth`.** The server talks to the API
  over HTTP only, so it ships as a separate slim PyPI package
  (`mireye-earth-mcp`) and can be installed without the data backend.

---

## Releasing

This package is published from this directory on every `v*` tag on the
main repo. To release locally:

```bash
cd mcp_server
python -m build
twine upload dist/*
```
