875a190983
Exposes live + historical ag-bids commodity data (from the ag-monitor service at agbids.paul.farm) as MCP tools, sitting behind MetaMCP at https://mcp.jpaul.io/metamcp/ag-bids/mcp. Pattern mirrors zerto-docs-rag with one addition: HTTP Basic auth in front of the streamable-HTTP transport so namespace guessers can't reach the tools. Stdio transport is unaffected (used by local Claude Desktop dev). Tools (markdown returns, ~15 LOC each): best_local_bid(commodity) — where to sell corn/soy/wheat today, for the current calendar month only current_lime_price() — latest lime quotes ($/ton) current_input_price(product?) — MAP / Potash / Lime latest_prices(...) — filtered snapshot price_history(...) — per-(source,delivery) trend list_sources / list_commodities / list_deliveries source_health() — healthy / stale / down buckets todays_summary() — same shape as morning brief snapshot Data path: ag-bids-mcp -> X-API-Key -> /api/data/* on ag-monitor (reuses BRIEF_API_KEY). Tests: 24 covering the httpx client, markdown formatters, HTTP Basic middleware (401/200), and JSONL usage logging. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
96 lines
3.0 KiB
Markdown
96 lines
3.0 KiB
Markdown
# ag-bids-mcp
|
|
|
|
Model Context Protocol server exposing live + historical commodity price data
|
|
collected by [ag-monitor](https://git.jpaul.io/justin/ag-bids). Sits behind
|
|
the user's MetaMCP gateway at `https://mcp.jpaul.io/metamcp/ag-bids/mcp`.
|
|
|
|
## What it does
|
|
|
|
Lets an LLM client (Claude Desktop, OpenWebUI, anything that speaks MCP) ask
|
|
plain-English questions like:
|
|
|
|
- "What's the best place to sell corn today?"
|
|
- "What's the current price of lime?"
|
|
- "Show me the corn basis trend at Andersons Greenville over the last 30 days."
|
|
- "Which sources are stale or failing?"
|
|
|
|
## How it talks to data
|
|
|
|
All data is read from ag-monitor over HTTPS:
|
|
|
|
```
|
|
ag-bids-mcp ── X-API-Key ─► https://agbids.paul.farm/api/data/*
|
|
```
|
|
|
|
Endpoints used: `/api/data/latest`, `/history`, `/best`, `/inputs`, `/sources`,
|
|
`/deliveries`. See the [ag-monitor source](https://git.jpaul.io/justin/ag-bids)
|
|
for the contract.
|
|
|
|
## Authentication
|
|
|
|
This MCP enforces **HTTP Basic** auth in front of the FastMCP HTTP transport.
|
|
Set both:
|
|
|
|
```
|
|
AG_BIDS_MCP_USER=<your username>
|
|
AG_BIDS_MCP_PASS=<your password>
|
|
```
|
|
|
|
MetaMCP is configured to inject `Authorization: Basic <b64>` on every upstream
|
|
call. Direct access without the header returns `401`.
|
|
|
|
If either env var is unset the server refuses to start (fail closed).
|
|
|
|
## Local dev (stdio)
|
|
|
|
```bash
|
|
python3 -m venv venv && source venv/bin/activate
|
|
pip install -r requirements.txt
|
|
cp .env.example .env # fill in AG_BIDS_API_KEY + AG_BIDS_MCP_USER/PASS
|
|
MCP_TRANSPORT=stdio python -m ag_bids_mcp.server
|
|
```
|
|
|
|
Wire into Claude Desktop's `claude_desktop_config.json`:
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"ag-bids": {
|
|
"command": "/path/to/venv/bin/python",
|
|
"args": ["-m", "ag_bids_mcp.server"],
|
|
"env": {
|
|
"MCP_TRANSPORT": "stdio",
|
|
"AG_BIDS_API_URL": "https://agbids.paul.farm",
|
|
"AG_BIDS_API_KEY": "...",
|
|
"AG_BIDS_MCP_USER": "x",
|
|
"AG_BIDS_MCP_PASS": "y"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
(The Basic auth check is skipped automatically when `MCP_TRANSPORT=stdio` since
|
|
stdio has no HTTP layer.)
|
|
|
|
## Deploy (MetaMCP host)
|
|
|
|
See [deploy/README.md](deploy/README.md). Container image is pulled from
|
|
`git.jpaul.io/justin/ag-bids-mcp:latest`; Watchtower on the MetaMCP host
|
|
auto-updates it every 5 minutes.
|
|
|
|
## Tools exposed
|
|
|
|
| Tool | Returns |
|
|
|---|---|
|
|
| `best_local_bid(commodity)` | Where to sell `corn`, `soy`, or `wheat` for this month's delivery — markdown one-liner + table |
|
|
| `current_lime_price()` | Latest lime quotes across all manual-entry sources |
|
|
| `current_input_price(product?)` | MAP / Potash / Lime — all three or one |
|
|
| `latest_prices(commodity?, source?, delivery?)` | Snapshot table, optionally filtered |
|
|
| `price_history(commodity, source?, delivery?, days?)` | Compact time series |
|
|
| `list_sources()` | Active scrapers + last-success timestamps |
|
|
| `list_commodities()` | corn, soy, wheat, map, potash, lime |
|
|
| `list_deliveries(commodity)` | Posted delivery labels, chronological |
|
|
| `source_health()` | Stale / failing / healthy summary |
|
|
| `todays_summary()` | Same shape as the morning brief snapshot |
|