FastAPI-based MCP server for air quality data analysis, forecasting, and comparison across multiple cities with LLM-powered agent planning and execution
Four tools with complete input schemas and descriptions, but quality is uneven. Tool names follow verb_noun convention (scrape_, compare_, forecast_). Descriptions are present (60-120 chars) but lack actionable context for LLM selection, they state WHAT but not WHEN or WHY. Parameters have types and ranges (days 1-90, horizonDays 1-30) but lack dependency documentation (e.g., relationship between trainDays and horizonDays). No output schemas documented. Error handling and recovery guidance absent. No tool annotations (readOnlyHint/destructiveHint). Security: scrape_city performs WRITE operations (MySQL upsert) but no permission gates or audit trail visible in code.
Compute KPIs over the last N days per city (n_points, mean_pm25, min_pm25, max_pm25) and pick best/worst (lower is better).
Forecast next H days of PM2.5 for one city with SARIMAX; returns yhat + CI.
Forecast next H days for multiple cities and rank best/worst by mean predicted PM2.5.
Fetch & cache hourly PM2.5/PM10 for a city over the last N days using Open-Meteo; upserts into MySQL.
No output schemas documented. LLMs cannot plan downstream calls or extract required fields (e.g., does compare_cities return city names, KPI values, rankings?). Violates pattern:tool requirement.
Descriptions lack WHEN/WHY context. 'Compute KPIs over the last N days' does not explain when to call compare_cities vs forecast_city, or what the agent should do with the results. LLMs cannot disambiguate tool selection.
scrape_city performs destructive WRITE (MySQL upsert) but has no permission gates, confirmation step, or audit trail in visible code. Violates pattern:permission-gate and pattern:audit-trail.
No error handling guidance. If scrape_city fails (network timeout, invalid city), what should the LLM do? Retry? Call a different tool? No recovery path documented.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 53 | <=2025-11-25 | v2 |
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). scrape_city should be marked destructive; compare_cities and forecast_* should be marked readOnly. Violates current MCP spec alignment.