diff --git a/ag_bids_mcp/client.py b/ag_bids_mcp/client.py index e09053d..884cdec 100644 --- a/ag_bids_mcp/client.py +++ b/ag_bids_mcp/client.py @@ -56,10 +56,14 @@ def _get(path: str, **params: Any) -> dict | list: def latest(commodity: str | None = None, source: str | None = None, delivery: str | None = None, kind: str | None = None, zip: str | None = None, lat: float | None = None, - lng: float | None = None, radius_miles: float | None = None) -> dict: + lng: float | None = None, radius_miles: float | None = None, + include_expired: bool = False) -> dict: + # Only send include_expired when True — _get drops None, so the default + # call keeps its existing query string (current + future months only). return _get("/api/data/latest", commodity=commodity, source=source, delivery=delivery, kind=kind, - zip=zip, lat=lat, lng=lng, radius_miles=radius_miles) + zip=zip, lat=lat, lng=lng, radius_miles=radius_miles, + include_expired=True if include_expired else None) def history(commodity: str | None = None, source_id: int | None = None, diff --git a/ag_bids_mcp/server.py b/ag_bids_mcp/server.py index 0f435df..cb15794 100644 --- a/ag_bids_mcp/server.py +++ b/ag_bids_mcp/server.py @@ -176,13 +176,22 @@ def latest_prices( Field(description="Search radius in miles around the location (default 50). " "Ignored unless a ZIP or lat/lng is given."), ] = None, + include_expired: Annotated[ + bool, + Field(description="Include past/expired delivery months. Default off — only " + "the current and future months are shown. Set true only when " + "the farmer explicitly asks for historical/past delivery data."), + ] = False, ) -> str: """Snapshot of the latest scraped bid per (source, commodity, delivery). Every filter is optional and AND'd together — pivot by elevator, crop, delivery, or kind in any combination. Pass a `zip` (or `lat`+`lng`) with optional `radius_miles` to keep only elevators near the farmer, sorted - nearest-first with the distance shown.""" + nearest-first with the distance shown. + + By default this shows current + future delivery months only; expired + months are rolled off. Set `include_expired=true` for a historical view.""" cm = commodity.strip().lower() if commodity else None with track("latest_prices", commodity=cm, source=source, delivery=delivery, kind=kind, zip=zip or "", radius=radius_miles or 0): @@ -190,7 +199,8 @@ def latest_prices( if err: return err payload = client.latest(commodity=cm, source=source, delivery=delivery, kind=kind, - zip=zip, lat=lat, lng=lng, radius_miles=radius_miles) + zip=zip, lat=lat, lng=lng, radius_miles=radius_miles, + include_expired=include_expired) return fmt.fmt_latest(payload) diff --git a/tests/test_client.py b/tests/test_client.py index 3c6a0fd..bdc5542 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -71,6 +71,30 @@ def test_get_drops_none_params(monkeypatch): assert captured["params"] == {"commodity": "corn"} +def test_latest_include_expired_passthrough(monkeypatch): + client = _reload_client(monkeypatch) + captured = {} + + class FakeResp: + status_code = 200 + text = "" + def json(self): return {"count": 0, "rows": []} + + def fake_get(url, params=None, timeout=None, headers=None): + captured["params"] = dict(params or {}) + return FakeResp() + + monkeypatch.setattr(client.httpx, "get", fake_get) + + # Default: not sent, so the API applies its current+future filter. + client.latest(commodity="corn") + assert "include_expired" not in captured["params"] + + # Opt in: forwarded so the API returns expired months too. + client.latest(commodity="corn", include_expired=True) + assert captured["params"] == {"commodity": "corn", "include_expired": True} + + def test_futures_endpoint_params(monkeypatch): client = _reload_client(monkeypatch) captured = {}