# Free weather API and MCP server for AI agents

One call per place, sized for your context. Guide: https://groundhog.markets/llms.txt

line ≈321 tokens, 7 forecasts · MET Norway alone 20,159 tokens, 1 forecast. Measured on a fixed NYC example; the live body below can differ.

## Quickstart

curl · line:

```
curl "https://groundhog.markets/api/v1/blend?place=new-york-city"
```

curl · week:

```
curl "https://groundhog.markets/api/v1/blend?place=new-york-city&size=week"
```

Claude Code:

```
claude mcp add --transport http groundhog https://groundhog.markets/mcp
```

Cursor · mcp.json:

```
{
  "mcpServers": {
    "groundhog": {
      "url": "https://groundhog.markets/mcp"
    }
  }
}
```

## Other clients

| Client | Setup |
|---|---|
| Claude Desktop, claude.ai | Settings → Connectors → Add custom connector → https://groundhog.markets/mcp |
| VS Code · .vscode/mcp.json | `{"servers":{"groundhog":{"type":"http","url":"https://groundhog.markets/mcp"}}}` |
| Windsurf · mcp_config.json | `{"mcpServers":{"groundhog":{"serverUrl":"https://groundhog.markets/mcp"}}}` |
| Any MCP client | Streamable HTTP: POST JSON-RPC 2.0 to https://groundhog.markets/mcp, no session. No key. |

## Sizes

| size | What | Bytes | Tokens | JSON tokens |
|---|---|---|---|---|
| line | One day: median high and low, n, groups, highs range, rain, now, alerts, compact credits | 616 B | ≈321 | ≈761 |
| week | One row per day: median, ranges, n, rain, plus alerts and compact credits | 936 B | ≈566 | ≈1,931 |
| table | Each source per day, then median, ranges, n, rain, now, alerts, full credits | 2.9 KB | ≈1,567 | ≈6,954 |
| series | 72 h every 3 h: a fixed source set, ENS p10/p90, median, n, full credits | 2.8 KB | ≈1,564 | ≈2,175 |

Bytes and tokens of the New York City example bodies. Tokens: Claude Opus 5.5 count_tokens. line and week carry one compact credit line; table and series the full lines.

## Endpoints

| Method | Path | Returns |
|---|---|---|
| GET | `/api/v1/blend` | The blend at a size (main call) |
| GET | `/api/v1/blend?variable=rain` | Rain: members' share of 0.01 in or more and heavier, amounts by source, so far today, month to date |
| GET | `/api/v1/blend?size=runs` | Trading fields: each source's newest runs by day, run_utc, fetched_at; NBM XND, P12, Q12 |
| GET | `/api/v1/nbm?stn=` | NBM text columns of one run + the day view |
| GET | `/api/v1/history` | As-issued history: daily, nbm, obs; run, lead, asof (no look-ahead) |
| GET | `/api/v1/history/files` | Bulk history files, gzip TSV per day and month |
| GET | `/api/v1/places?q=` | Find a place: slug, name, tier, stations |
| GET | `/api/v1/sources` | Sources: group, licence, runs, status, credit |
| GET | `/api/v1/status` | Freshness per source, jobs, version |
| GET | `/api/v1/markets?place=` | Weather markets: station, rule, so far, ours, result. No prices |
| GET | `/api/v1/receipts` | Our settle value vs the venue's result, last 30 days |
| GET | `/api/v1/schema.json` | JSON Schema of every JSON body |
| GET | `/api/v1` | Every endpoint, one line each |
| GET | `/openapi.json` | OpenAPI 3.1 |
| GET | `/mcp/server-card` | MCP server card |
| GET | `/credits` | Every full credit line, text/plain |
| POST | `/mcp` | MCP, stateless JSON-RPC 2.0 |
| GET | `/llms.txt` | Agent guide, under 5 KB |
| GET | `/llms-full.txt` | The guide plus params, fields, examples, errors |
| GET | `/p/new-york-city.md` | A place page as Markdown |
| GET | `/agents.md, /sources.md, /about.md` | These pages as Markdown |
| GET | `/health` | {"ok":true}, no auth |

## Params

| Param | Values | Default |
|---|---|---|
| place | slug · name · City, ST · ICAO · lat,lon; repeat up to 10× (line, week) | required |
| date | today · tomorrow · +N (%2BN or N in a URL) · YYYY-MM-DD | today before 15:00 local, else tomorrow |
| days | 1–7 | line 1 · week, table 7 |
| size | line · week · table · series · runs | line |
| format | md · tsv · json | line md, else tsv |
| units | F · C | °F in the US, else °C |
| hours, step | 24–168 · 1, 3, 6 (series) | 72 · 3 |
| include_6h | 0 · 1 (alias alt) | 0: 6-hourly max/min left out while ≥ 4 others remain |
| all | 0 · 1 (table) | 0; 1 adds twin and stale rows |
| credits | compact · full · short | line, week compact; else full |
| runs | 1–4 (size=runs) | 1 |
| variable | temp · rain | temp |
| win, stn | lst · cal (rain) · a settle station of the place, e.g. KORD | lst at US daily-rain settle stations, else cal · every one (≤ 2) |

Any other param → 400 bad_param, with the valid list in the body.

## MCP

Streamable HTTP at https://groundhog.markets/mcp. Tool output is the REST body. Errors come back as tool results with `isError: true`.

| Tool | Args | Returns |
|---|---|---|
| forecast | place (string or array ≤ 10), date?, days?, size?, format?, units?, hours?, step?, include_6h?, credits? | The REST body, byte for byte |
| places | q, limit? (≤ 10) | Slugs; full blend or grid only |
| sources | — | Licence, latest run, age, status |
| markets | place? (string or array ≤ 10), family?, date?, size?, format?, credits? | Station, rule, so far, ours, result; no args: the market cities |
| receipts | days?, venue?, family? | Our value vs the venue's result, every miss |
| search, fetch | query · id | Places by name; a place's 7-day forecast |
| history | kind?, place? \| stn?, from, to?, source?, run? \| lead? + cycle? \| asof?, format? | As-issued rows with fetched_at and origin |

Sent on initialize: Weather for any place: forecast (size=line, week or table; date=today, tomorrow or +N; variable=rain for rain) and markets(place) for each weather market's station, rule and number so far. Units are in every answer. Keep the Credits line and link the Page URL when you repeat numbers.

## HTTP

- Auth: None: no key. 120 units/min per client (1 per place, 2 per lat,lon).
- Limit: 120 units/min: 1 per place, 2 per lat,lon or grid-only place. RateLimit-* headers show what is left.
- ETag: Weak W/"…"; If-None-Match → 304. Helps polling scripts; LLM fetch tools ignore it.
- Cache-Control: private, max-age=60 · gzip over 1 KB
- Notes: Delays, partial coverage and resolution notes are in the body, never only in headers.
- 400 bad_param: Unknown or malformed param. Lists the valid ones.
- 404 unknown_place: No match. Lists what to try.
- 422 out_of_range: Date or hours outside the forecast.
- 429 rate_limited: Over 120 units/min. The retry time is in the body.
- 503 warming_up: First boot. The retry time is in the body.
- 503 overloaded: Too many requests in flight. Retry in 5 s.

Page: https://groundhog.markets/agents
