# Changelog Notes for clients/agents that consume the ag-bids MCP tools and the underlying `ag-monitor` `/api/data/*` HTTP API. Newest first. ## 2026-05-30 — Grain price-received trends (real $ + change + seasonal) New national/seasonal reference layer (USDA NASS, corn back to 1908) — the macro benchmark to compare local cash bids against. Real prices and the change, not an index. ### New MCP tools - **`price_trend(commodity, geo="US", years=10)`** — monthly price *received by farmers* ($/bu) with the move: latest real price, **month-over-month and year-over-year change ($ and %)**, and seasonal context (percentile vs the same month over the last N years, normal, and range). `geo` is `US` or any 2-letter state. Conclusions, not rows. - **`price_series(commodity, geo="US", start_year?, end_year?)`** — raw monthly series ($/bu) for charting/drill-down (defaults to the recent window). ### API - `GET /api/data/price-trend?commodity=&geo=&years=` — computed trend (cents + `change_cents`/`change_pct`/`yoy_*` + `seasonal`). - `GET /api/data/price-series?commodity=&geo=&start_year=&end_year=` — raw series. - `GET /api/data/price-geographies?commodity=` — which geos (US + states) exist. All grain: corn/soy/wheat, all 50 states + US. ### Input-cost tools (real $ + change) - **`input_cost_trend(item, years=10)`** — real input price with the move. Currently `item="diesel"` (EIA U.S. retail $/gal, weekly, back to 1994): latest price + week-over-week and year-over-year change + seasonal percentile/range. (For current fertilizer $/ton, `current_input_price` (DTN) still applies; more inputs extend this same tool.) - **`input_cost_series(item)`** — raw historical series for an input. - API: `GET /api/data/input-cost-trend?item=&years=`, `GET /api/data/input-cost-series?item=`. USDA stopped publishing dollar input prices in 2014, so these use real-dollar sources (EIA) rather than an index. ## 2026-05-30 — Source geo + many more locations ### Per-source geo (API + MCP) - **`GET /api/data/sources`** now returns location geo on every source: `city, state, zip, county, latitude, longitude` (any may be `null`). The AgriCharts-fed elevators carry exact coordinates; smaller sites carry city/state/zip. - **MCP `list_sources`** gained a **Location** column (`City, ST ZIP`). `source_health` is unchanged in shape. - Sources that are national or non-physical (CBOT futures, USDA AMS, DTN fertilizer, hedge-to-arrive / "Direct" bid buckets) legitimately have `null` geo. ~43 of ~51 sources are geo-tagged. ### Many more elevator locations These flow through every data tool/endpoint automatically (`latest`, `history`, `best`, `basis_movement`/`basis_detail`, `sources`, `deliveries`). No tool signatures changed — just far more sources, all named `""`: - **Heritage Cooperative** — new co-op, **23 central/eastern-Ohio locations** (corn/soy/wheat). - **Mercer Landmark** — expanded from 2 to **all ~16 locations**. Note: the two old source names were renamed for continuity — `"Mercer Landmark — St Henry"` → `"Mercer Landmark — MPS St Henry"`, `"Mercer Landmark — Minster"` → `"Mercer Landmark — Heartland Minster"`. - **Bambauer** — now both locations incl. **Pemberton** (`"Bambauer — Jackson Center / New Knoxville"`, `"Bambauer — Pemberton"`); the old `"Bambauer Jackson Center / New Knoxville, OH"` source was renamed to the first of those. If you cache source names, refresh them — several changed and many were added. ## 2026-05-29 — Futures price + change tool ### New MCP tool - **`futures_quote(commodity, delivery?)`** — CBOT futures price and change for a grain. Reports the latest price, today's **session open**, the prior day's close, and **both** moves: **change since open** and **change on the day** (vs the previous settle). With `delivery` (e.g. `"Jul 2026"`) it resolves the listed contract that month prices against (e.g. `ZCN26`); without it, the continuous nearby. ### API changes (`ag-monitor`) - **`GET /api/data/futures?commodity=&delivery=`** — new endpoint. Returns `{ commodity, delivery, contract, symbol, quote }` where `quote` is `{ settle_date, open_cents, last_cents, prev_close_cents, change_since_open_cents, change_on_day_cents, fetched_at }` (or `null` if no data yet for that contract). `commodity` must be `corn`/`soy`/`wheat`. - **`futures_quotes` table** gained an `open_cents` column; the futures scraper now stores the session **Open** alongside the close. Rows captured before this change have `open_cents = NULL`, so `change_since_open_cents` is `null` for those until the next session is scraped. - Futures now also pull at **:30 during the CBOT day session** (on top of the hourly :00), so `last` and the changes track the session every ~30 min. ### Example questions → tool calls | Ask | Call | |---|---| | Corn Jul futures and how far it's moved today | `futures_quote(commodity="corn", delivery="Jul 2026")` | | Soy nearby futures, change on the day | `futures_quote(commodity="soy")` | ## 2026-05-29 — Flexible history + basis movement ### New MCP tools - **`basis_movement(commodity?, source?, delivery?, days=30)`** — aggregated basis trend, **one headline line per crop**. Averages every matching (elevator × delivery) series to `avg basis first → last` over the window and reports how far it moved. This is the cheap "how is basis moving overall" view. All filters optional; `commodity` (if given) must be `corn`/`soy`/`wheat`. - Positive move = **cash strengthened** vs futures (basis up); negative = weaker. - Aggregation is intentional: divergent elevators can net to "flat". When the aggregate looks flat or surprising, call `basis_detail` to see per-elevator splits. - **`basis_detail(commodity?, source?, delivery?, days=30)`** — the drill-down for `basis_movement`. **One row per (elevator, crop, delivery)** series with basis `first → last` and the move. Same optional filters. Both tools do the aggregation **server-side (in the MCP)** and return compact markdown — they do not dump every raw sample — to keep token usage low. Pattern: call `basis_movement` first, then `basis_detail` (optionally filtered) only when you need the breakdown. ### Changed MCP tools - **`price_history`** — `commodity` is now **optional** (was required). Omit it to span every crop. Output now groups by **(elevator, crop, delivery)**, surfaces **basis first → last** in each series summary, and adds a **Futures** column to the raw points table. Every filter (`commodity`, `source`, `delivery`, `days`) is optional and AND'd — pivot per elevator, per crop, per delivery, or any combination. - Raw per-row points are still only included when the window has ≤ ~60 samples; wider queries return the per-series summaries only. - **`latest_prices`** — added the **`kind`** filter (`grain` | `fertilizer`) for parity with the API. `commodity`, `source`, `delivery`, `kind` all optional. ### API changes (`ag-monitor`) - **`GET /api/data/history`** — `commodity` query param is now **optional**. When omitted, returns history across all crops. `source_id`, `delivery`, and `days` (1–730, default 30) remain optional. Response shape is unchanged: `{ "commodity": , "days": , "rows": [...] }`. Each row carries `fetched_at, source_id, source_name, commodity, delivery, bid_cents, basis_cents, futures_cents` so callers can pivot client-side. - `GET /api/data/latest` already supported optional `commodity`, `source`, `delivery`, `kind` — unchanged. ### Conventions / gotchas - All money fields are **integer cents**. `bid_cents`/`futures_cents` render as `$/bu` (4 dp) for grain and `$/ton` (2 dp) for fertilizer; `basis_cents` renders as a signed dollar value (2 dp), e.g. `-0.14`. - Basis is only meaningful for grain — the basis tools skip non-grain rows and any series with no basis on file. - `source` filtering is by **exact** elevator display name (e.g. `"Mercer Landmark — Minster"`). Use `list_sources` to get exact names. ### Example questions → tool calls | Ask | Call | |---|---| | Basis movement overall, last 7 days | `basis_movement(days=7)` | | Corn basis movement across all elevators | `basis_movement(commodity="corn")` | | Basis movement at one elevator | `basis_movement(source="Mercer Landmark — Minster")` | | Per-elevator basis breakdown for corn | `basis_detail(commodity="corn")` | | Last 7 days of history from elevator X for corn | `price_history(commodity="corn", source="…", days=7)` | | All-crop price history at one elevator | `price_history(source="…")` | | Latest grain bids only | `latest_prices(kind="grain")` |