Add price_trend / price_series MCP tools (USDA NASS grain)
Real $/bu price + MoM/YoY change + seasonal percentile context for corn/soy/ wheat, US + states, deep history. Wraps the new /api/data/price-trend and /api/data/price-series endpoints. Changelog updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -246,6 +246,63 @@ def basis_detail(
|
||||
return fmt.fmt_basis_detail(_filter_source(payload, source))
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def price_trend(
|
||||
commodity: Annotated[
|
||||
str, Field(description="Grain: 'corn', 'soy', or 'wheat'.")
|
||||
],
|
||||
geo: Annotated[
|
||||
str,
|
||||
Field(description="'US' or a 2-letter state (e.g. 'OH', 'IA'). Default US."),
|
||||
] = "US",
|
||||
years: Annotated[
|
||||
int, Field(ge=1, le=120, description="Baseline window for the seasonal normal/percentile."),
|
||||
] = 10,
|
||||
) -> str:
|
||||
"""USDA NASS monthly price *received by farmers* ($/bu) with the change.
|
||||
|
||||
Returns the latest real price plus month-over-month and year-over-year moves
|
||||
(dollars + percent) and where it sits seasonally (percentile vs the same
|
||||
month over the last N years, normal, and range). This is the macro/seasonal
|
||||
benchmark to compare local cash bids against — corn history goes back to 1908."""
|
||||
cm = commodity.strip().lower()
|
||||
g = geo.strip().upper()
|
||||
with track("price_trend", commodity=cm, geo=g, years=years):
|
||||
if cm not in VALID_GRAIN:
|
||||
return f"`commodity` must be one of: {sorted(VALID_GRAIN)}"
|
||||
return fmt.fmt_price_trend(client.price_trend(commodity=cm, geo=g, years=years))
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def price_series(
|
||||
commodity: Annotated[
|
||||
str, Field(description="Grain: 'corn', 'soy', or 'wheat'.")
|
||||
],
|
||||
geo: Annotated[
|
||||
str, Field(description="'US' or a 2-letter state. Default US."),
|
||||
] = "US",
|
||||
start_year: Annotated[
|
||||
int | None, Field(description="Optional first year (default: ~last 5 yrs of the full series).")
|
||||
] = None,
|
||||
end_year: Annotated[int | None, Field(description="Optional last year.")] = None,
|
||||
) -> str:
|
||||
"""Raw monthly price-received series ($/bu) for charting / drill-down.
|
||||
|
||||
Use price_trend for the headline; use this when you need the actual monthly
|
||||
numbers. Defaults to the recent window unless you pass a start_year."""
|
||||
cm = commodity.strip().lower()
|
||||
g = geo.strip().upper()
|
||||
with track("price_series", commodity=cm, geo=g):
|
||||
if cm not in VALID_GRAIN:
|
||||
return f"`commodity` must be one of: {sorted(VALID_GRAIN)}"
|
||||
# Default to a readable recent window if no range given.
|
||||
if start_year is None and end_year is None:
|
||||
from datetime import datetime
|
||||
start_year = datetime.utcnow().year - 5
|
||||
payload = client.price_series(commodity=cm, geo=g, start_year=start_year, end_year=end_year)
|
||||
return fmt.fmt_price_series(payload)
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def list_sources() -> str:
|
||||
"""All active scrapers + their last-success timestamps and any pending failures."""
|
||||
|
||||
Reference in New Issue
Block a user