Files
ag-bids-mcp/CHANGELOG.md
T
justin 0c9bc3b328 Add futures_quote tool: CBOT price + change since open + on day
New futures_quote(commodity, delivery?) tool wraps the new /api/data/futures
endpoint: reports latest price, today's session open, prior settle, and both
moves (since open and on the day). With a delivery month it resolves the listed
contract; without it, the continuous nearby. Adds client.futures(), fmt_futures(),
tests, and a CHANGELOG entry.

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

5.3 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-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")