Files
ag-bids-mcp/CHANGELOG.md
T
justin 03c6c540ef
CI / test (push) Successful in 17s
CI / build-push (push) Successful in 30s
Add fertilizer to input-cost tools (regional $/ton, USDA AgTransport)
input_cost_trend/input_cost_series now accept six fertilizers (urea, uan,
anhydrous, dap, map, potash) alongside diesel, with an optional `geo` region
(default Cornbelt). Real $/ton + MoM/YoY change + seasonal context.

- client: pass geo through; add input_cost_geographies
- server: expand VALID_INPUTS; geo param + docstrings
- format already unit-aware ($/ton) and geo-aware
- README tools table now lists the reference/trend + input-cost tools
- CHANGELOG: regional fertilizer input-cost release notes
- tests: fertilizer $/ton + region formatting

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 15:59:33 -04:00

11 KiB
Raw Blame History

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 — Regional fertilizer input costs (real $/ton + change)

Real U.S. regional retail fertilizer prices now feed the input-cost tools, so the advisor can reason about fertilizer the same way it does diesel and grain — actual dollars and the move, not an index. Source: USDA AgTransport (monthly, $/ton, history back to 2023).

Changed MCP tools (fertilizer added to the existing input-cost tools)

  • input_cost_trend(item, geo?, years=10)item now accepts six fertilizers in addition to diesel: urea, uan, anhydrous (anhydrous ammonia), dap, map, potash. Returns the latest real $/ton, month-over-month and year-over-year change ($ and %), and seasonal context.
    • New optional geo = AgTransport region; defaults to Cornbelt. Other regions: U.S. Gulf NOLA, Northern Plains, Southern Plains, Southeast, Northeast, California, Pacific Northwest, South Central, Central Florida, Tampa (not every product is published for every region).
    • diesel is unchanged — national U.S. $/gal, weekly; geo is ignored for it.
  • input_cost_series(item, geo?) — raw monthly $/ton series for any fertilizer (or the diesel $/gal weekly series), region-selectable.

Seasonal percentile for fertilizer is computed over a short history (2023+), so it deepens over time; the price and YoY/MoM change are solid now.

API

  • GET /api/data/input-cost-trend?item=&geo=&years=geo added.
  • GET /api/data/input-cost-series?item=&geo=geo added.
  • GET /api/data/input-cost-geographies?item=new: lists the regions a given input has data for (plus its default_geo).

Example questions → tool calls

Ask Call
Cornbelt urea price and how it's moved input_cost_trend(item="urea")
Anhydrous ammonia in the Southern Plains input_cost_trend(item="anhydrous", geo="Southern Plains")
Potash $/ton history input_cost_series(item="potash")
Which regions have DAP prices (API) GET /api/data/input-cost-geographies?item=dap

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 "<Co-op> — <Location>":

  • 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=<grain>&delivery=<label?> — 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_historycommodity 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/historycommodity query param is now optional. When omitted, returns history across all crops. source_id, delivery, and days (1730, default 30) remain optional. Response shape is unchanged: { "commodity": <str|null>, "days": <int>, "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")