MCP Zero Shot Agentic Forecaster
README.md
<h1 align="center">MCP Zero Shot Agentic Forecaster</h1>
<p align="center">
<img src="https://img.shields.io/badge/Python-3.11+-blue" alt="Python 3.11+">
<img src="https://img.shields.io/badge/FastMCP-1.0+-5C5C5C" alt="FastMCP 1.0+">
<img src="https://img.shields.io/badge/PyTorch-2.2+-EE4C2C" alt="PyTorch 2.2+">
<img src="https://img.shields.io/badge/Accelerate-0.30+-0052CC" alt="Accelerate 0.30+">
<img src="https://img.shields.io/badge/TimesFM_XReg-2.5-4285F4" alt="TimesFM XReg 2.5">
<img src="https://img.shields.io/badge/Chronos--2-v2-FF6F00" alt="Chronos-2">
<img src="https://img.shields.io/badge/Transformers-4.40+-FFD21E" alt="HuggingFace Transformers 4.40+">
<img src="https://img.shields.io/badge/Pydantic-v2-E92063" alt="Pydantic v2">
<img src="https://img.shields.io/badge/MCP-1.0-5C5C5C" alt="MCP 1.0">
<img src="https://img.shields.io/badge/Pandas-2.2+-150458" alt="Pandas 2.2+">
<img src="https://img.shields.io/badge/NumPy-1.26+-013243" alt="NumPy 1.26+">
<img src="https://img.shields.io/badge/PyYAML-6.0+-6B6B6B" alt="PyYAML 6.0+">
<img src="https://img.shields.io/badge/Tenacity-8.2+-E67E22" alt="Tenacity 8.2+">
<img src="https://img.shields.io/badge/Statsmodels-0.14+-3776AB" alt="Statsmodels 0.14+">
<img src="https://img.shields.io/badge/pytest-9.0-0A9EDC" alt="pytest 9.0">
<img src="https://img.shields.io/badge/pytest--mock-3.14+-0A9EDC" alt="pytest-mock 3.14+">
<img src="https://img.shields.io/badge/KaggleHub-latest-20BEFF" alt="KaggleHub">
<img src="https://img.shields.io/badge/License-MIT-green" alt="MIT License">
<img src="https://img.shields.io/badge/Tests-110_passing-brightgreen" alt="Tests 110 passing">
</p>
<p align="center">
<b>A production-grade, MCP-compliant agentic forecasting tool. Designed for Agentic AI orchestrators to autonomously resolve inventory shortages, evaluate demand risk, and execute quantile-bounded supply-chain decisions—without requiring local fine-tuning.</b>
</p>
---
## Executive Overview & Business Value
### What is this Repository?
The **MCP Zero Shot Agentic Forecaster** is a production-grade, microservice-based time-series forecasting engine exposed via the **Model Context Protocol (MCP)**. Powered by state-of-the-art foundation models (**Google TimesFM 2.5 XReg** and **Amazon Chronos-2**), it allows autonomous AI agents (LangGraph state machines, CrewAI swarms, OPA/Rego-governed NeSy stacks, and standard ReAct loops) to query probabilistic demand forecasts on demand—without offline model training, hyperparameter tuning, or per-SKU dataset preparation.
**What this repository is not:** This is not an AI agent, nor is it a neuro-symbolic system on its own. It is a **symbolic skill** — a deterministic, stateless MCP Server that exposes mathematical forecasting tools. It is designed to be invoked by an external MCP Host (e.g., Claude Desktop, LangGraph, CrewAI, or a neuro-symbolic orchestrator). The agent reasons; this skill computes.
### Business Value & ROI
* **Eliminates Cold-Start Latency**: Delivers instant zero-shot probabilistic forecasts for new product launches, promotions, and short-history SKUs without training pipelines.
* **Quantile-Bounded Risk Control**: Emits calibrated $p_{10}$, $p_{50}$, and $p_{90}$ demand quantiles, enabling autonomous purchasing agents to balance safety stock buffers against capital holding costs.
* **Lower Total Cost of Ownership (TCO)**: Replaces complex fine-tuning pipelines with a unified 3-tier fallback engine, drastically lowering GPU compute requirements and infrastructure drift.
* **Agentic Resiliency**: Returns structured `AgentFriendlyError` payloads with remediation hints when inputs are invalid, allowing calling agents to self-correct in execution loops without failing silently or raising unhandled exceptions.
### Empirical Validation
- **M5 Walmart (30,000+ item-store series):** WRMSSE 0.763 in pure zero-shot, outperforming Moirai (0.798) and Prophet (0.812). On promotional SKUs, 23% improvement in Normalized Deviation vs baseline.
- **Corporación Favorita (Ecuador):** Cross-region out-of-distribution stress test with oil price fluctuations and local inflation — maintained predictive stability without retraining or local tuning.
### How It Works
1. **Agent Invocation**: Calling agents invoke `forecast_demand` or `forecast_batch` over stdio/HTTP via the MCP tool interface.
2. **Contract Enforcement**: Pydantic v2 schemas perform rigorous, finite numeric and temporal boundary checks (`[Type-Safe Input Contract]`).
3. **Non-Blocking Inference**: FastMCP offloads heavy tensor operations to thread pools via `asyncio.to_thread` to preserve gateway responsiveness.
4. **Unified 3-Tier Pipeline**: Always routes through **TimesFM 2.5** (Tier 1) in `xreg + timesfm` mode — a linear model first fits external covariates to the target, then the 200M-parameter univariate transformer forecasts the residuals. On failure, execution falls back to **Chronos-2** (Tier 2, retains covariates via `_build_chronos_covariates()`), and finally **ARIMA111** (Tier 3, drops covariates). On CUDA OOM or transient failure, the engine triggers memory recovery (`gc.collect()` + `torch.cuda.empty_cache()`) before degrading.
5. **Mathematical Sanitation**: Applies isotonic sorting to guarantee output quantile monotonicity ($p_{10} \le p_{50} \le p_{90}$) and normalizes epistemic confidence scores before returning structured JSON payloads.
---
## System Architecture
The microservice adheres to strict separation of concerns: the MCP tool layer manages non-blocking transport, memory safety, and model-level output sanitation, while leaving domain-specific business policies to downstream agent orchestrators.
```mermaid
graph TD
subgraph External Agent Orchestrator
Agent[LLM Agent / Swarm / State Machine<br/>LangGraph / OPA Sidecar / ReAct Loop]
end
subgraph MCP Microservice Boundary
Gateway[FastMCP Async Gateway Server<br/>mcp_server.py]
Sanitizer[Pydantic v2 Input Contract<br/>TimeSeriesInputPayload]
ErrorFormatter[AgentFriendlyError Formatter]
subgraph Engine Memory & Concurrency Boundary
ExecThread[Thread Executor<br/>asyncio.to_thread]
Engine[ZeroShotForecastingEngine<br/>src/models/forecaster.py<br/>Lazy-Load Lock Protected<br/>Single-Model VRAM Residency]
subgraph 3-Tier Fallback Model Chain
T1[Tier 1: TimesFM 2.5<br/>XReg / Univariate]
T2[Tier 2: Chronos-2<br/>Multivariate / Univariate]
T3[Tier 3: ARIMA111<br/>CPU Baseline Fallback]
end
IsoSanitizer[Isotonic Quantile Sanitizer<br/>Enforces p10-p50-p90 monotonicity]
end
end
Agent -->|FastMCP Tool Call<br/>forecast_demand / forecast_batch| Gateway
Gateway -->|1. Validate Schema| Sanitizer
Sanitizer -->|Validation Error| ErrorFormatter
ErrorFormatter -.->|Structured Error + Remediation| Agent
Sanitizer -->|2. Valid Payload| ExecThread
ExecThread -->|3. Route Request| Engine
Engine --> T1
T1 -.->|OOM / Hub Down / Circuit Open / Struct Error| T2
T2 -.->|OOM / CUDA Error / Unhandled Exception| T3
T1 -->|Raw Quantiles| IsoSanitizer
T2 -->|Raw Quantiles| IsoSanitizer
T3 -->|Raw Quantiles| IsoSanitizer
IsoSanitizer -->|4. Validated ForecastResponse| Gateway
Gateway -->|5. Return JSON Payload| Agent
```
> **MCP Protocol Mapping:** In Model Context Protocol terminology, the **Host** is the external agent orchestrator (e.g., Claude Desktop, LangGraph, or AXIOMIS). The **Client** lives inside the Host and manages the stdio/HTTP connection. **This repository is the Server** — an external process that exposes `forecast_demand` and `forecast_batch` as Tools.
```text
┌─────────────────────────────────────────────────────────────┐
│ NEURAL AGENT (Stochastic Field) │
│ • Goal Planning & Intent Generation │
└──────────────────────────────┬──────────────────────────────┘
│ Natural Language Intent
▼
┌─────────────────────────────────────────────────────────────┐
│ SYMBOLIC ORCHESTRATOR (Deterministic Vault) │
│ • MCP Host / Tool Registry & Discovery │
│ • Policy-as-Code Firewall │
└──────────────────────────────┬──────────────────────────────┘
│ MCP stdio / JSON-RPC Payload
▼
┌─────────────────────────────────────────────────────────────┐
│ THIS REPO: Zero-Shot Demand Forecaster MCP Server │
│ • Pydantic v2 Input Enforcement │
│ • 3-Tier Fallback Engine │
│ • Isotonic Quantile Sanitation │
│ • Structured Error Contracts │
└─────────────────────────────────────────────────────────────┘
```
> *This repository lives in the bottom box. It does not reason probabilistically, maintain conversation state, or enforce enterprise policy. It receives structured JSON-RPC payloads, validates them mathematically, executes the forecast, and returns structured data or structured errors.*
### Component Architecture Breakdown
**FastMCP Gateway (`mcp_server.py`)**: Provides async JSON-RPC transport and enforces batch concurrency limits (`asyncio.Semaphore(4)`).
**Type-Safe Contract Boundary (`src/schemas/payloads.py`)**: Enforces temporal alignment, finite number guarantees, and context/horizon limits.
**Thread-Safe Forecaster Core (`src/models/forecaster.py`)**: Employs double-checked locking (`threading.Lock()`) for lazy model loading and handles automatic CUDA OOM recovery (`gc.collect()` + `torch.cuda.empty_cache()`).
**Isotonic Output Sanitizer**: Post-processes raw foundation model quantiles using monotonic sorting to eliminate statistical anomalies ($p_{10} > p_{50}$) before returning predictions to agents.
### System Execution Flow (Sequence Diagram)
```mermaid
sequenceDiagram
autonumber
actor Agent as LLM Agent / Orchestrator
participant Gateway as FastMCP Gateway (Async)
participant Sanitizer as Pydantic Input Contract
participant Executor as Thread Executor (asyncio.to_thread)
participant Pipeline as 3-Tier Fallback Pipeline
participant Std as Isotonic Quantile Sanitizer
Agent->>Gateway: forecast_demand / forecast_batch (JSON)
Gateway->>Sanitizer: Validate TimeSeriesInputPayload
alt Validation Failure
Sanitizer-->>Gateway: AgentFriendlyError {error_code, expected, received, remediation}
Gateway-->>Agent: Structured Error Response
else Validation Success
Sanitizer->>Executor: Offload sync inference
Executor->>Pipeline: Execute prediction
Note right of Pipeline: Tier 1: TimesFM 2.5 → Tier 2: Chronos-2 → Tier 3: ARIMA111
alt CUDA OOM / Transient Failure
Pipeline->>Pipeline: gc.collect() + torch.cuda.empty_cache()
Pipeline->>Pipeline: Degrade to next tier (retain covariates where possible)
end
Pipeline->>Std: Apply _enforce_quantile_monotonicity()
Std-->>Executor: ForecastResponse {model_used, exogenous_dropped, warnings}
Executor-->>Gateway: Return validated response
Gateway-->>Agent: 200 OK with ForecastResponse
end
```
---
## Core Architectural Principles
### Non-Blocking Async Transport
All tensor-forward passes execute in a thread pool via `asyncio.to_thread`, keeping the FastMCP event loop responsive to concurrent health checks and tool invocations under load.
```python
# mcp_server.py
result = await asyncio.to_thread(engine.predict, validated_payload)
```
### VRAM Lazy Loading
Model weights are materialized **only on first use** via accessor methods — no VRAM consumed at startup. Thread-safe double-checked locking prevents duplicate instantiation under concurrent cold starts.
```python
# src/models/forecaster.py
def _get_timesfm(self):
if self._timesfm is None:
with self._timesfm_lock:
if self._timesfm is None:
import timesfm
logger.info(f"Lazily loading TimesFM-2.5 ({self.timesfm_repo_id}) onto {self._device}")
self._timesfm = timesfm.TimesFM_2p5_200M_torch.from_pretrained(self.timesfm_repo_id)
return self._timesfm
def _get_chronos(self):
if self._chronos is None:
with self._chronos_lock:
if self._chronos is None:
from chronos import BaseChronosPipeline
logger.info(f"Lazily loading Chronos-2 ({self.chronos_repo_id}) onto {self._device}")
self._chronos = BaseChronosPipeline.from_pretrained(
self.chronos_repo_id, device_map=self._device, dtype=torch.float32
)
return self._chronos
```
### 3-Tier Fallback Engine
The engine maintains a single unified deterministic degradation chain regardless of payload contents.
**Why this ordering?** TimesFM 2.5 is a univariate foundation model with an XReg (exogenous regressor) subsystem specifically designed for single-target forecasting with external variables. For demand forecasting — one SKU, multiple covariates — this hybrid approach (linear covariate absorption + univariate transformer on residuals) is often more stable than full multivariate attention. Chronos-2, a true multivariate model, serves as the resilient fallback: different vendor (AWS), different quantile mechanics (Monte Carlo vs parametric), and independent failure domains. Only when both probabilistic models fail does the system surrender to the deterministic ARIMA(1,1,1) baseline.
| Tier | Backend | Mode | `model_used` | `exogenous_dropped` |
|------|---------|------|--------------|---------------------|
| 1 | TimesFM 2.5 | XReg / Univariate | `TimesFM-2.5` | `false` |
| 2 | Chronos-2 | Multivariate / Univariate | `Chronos-2-Fallback` | `false` |
| 3 | ARIMA111 | Baseline | `ARIMA111-Baseline` | `true` |
On TimesFM failure (including `torch.cuda.OutOfMemoryError`):
1. `gc.collect()` + `torch.cuda.empty_cache()`
2. Exogenous signals **retained** for Chronos-2 via `_build_chronos_covariates()` (past/future covariates). The covariate retention policy holds through Tier 1 and Tier 2.
3. `exogenous_dropped = true` **only if** fallback degrades to Tier 3 (ARIMA111), because the baseline statistical model cannot ingest external regressors in this implementation.
4. Execution routed to Chronos-2
5. If Chronos fails → ARIMA111 baseline
### Temporal Regularity Enforcement
Pydantic v2 validators reject invalid telemetry at the boundary:
| Validator | Rule |
|-----------|------|
| Context bounds | `16 <= len(target_series) <= 16000` |
| Horizon bounds | `1 <= forecast_horizon <= 1024` |
| Finite values | `target_series`, `price_index` must contain no `NaN`/`Inf` |
| Exogenous alignment | `len(price_index) == len(target_series) + forecast_horizon` |
| Binary flags | `promo_flag` elements must be `0` or `1` |
### Isotonic Quantile Sanitation
All backends (TimesFM, Chronos-2, ARIMA111) emit raw quantiles that can occasionally cross ($p_{10} > p_{50}$ or $p_{50} > p_{90}$) under extreme OOD inputs. The engine applies a lightweight post-processing step `_enforce_quantile_monotonicity()` which performs isotonic sorting per timestep — stacking $(p_{10}, p_{50}, p_{90})$, sorting along the quantile axis, and returning the ordered triplets. This guarantees mathematically valid $p_{10} \le p_{50} \le p_{90}$ for every forecast horizon step without distorting distributional shape.
### Bounded Batch Concurrency
The `forecast_batch` MCP tool executes multi-SKU inference concurrently using `asyncio.gather` bounded by an `asyncio.Semaphore(4)`. This provides parallel throughput while protecting GPU/CPU memory from unbounded concurrent tensor allocations. Each item acquires the semaphore, validates its payload, offloads `engine.predict` to a thread pool via `asyncio.to_thread`, and returns structured `ForecastResponse` with per-item fallback metadata. The summary block reports total items, error count, and per-backend usage (`model_usage`).
### Per-Backend Circuit Breakers
Each foundation model backend maintains an independent circuit breaker (`CircuitBreakerState`) to prevent cascade failures when a model hub is unreachable or consistently erroring. After **5 consecutive failures**, the breaker opens and routes traffic immediately to the next fallback tier for **60 seconds** before allowing a test call.
| Backend | Failure Threshold | Cooldown | Open Behavior |
|---------|------------------|----------|---------------|
| TimesFM 2.5 | 5 failures | 60s | Raises `MODEL_UNAVAILABLE`; routes to Chronos-2 |
| Chronos-2 | 5 failures | 60s | Raises `MODEL_UNAVAILABLE`; routes to ARIMA111 |
This ensures that a transient HuggingFace Hub outage or corrupted weight download does not block the agent indefinitely.
### Normalized Confidence Metric
The confidence score uses a bounded relative uncertainty ratio instead of a linear floor that compresses wide variance to 0.0:
$$\text{Confidence} = \frac{1}{1 + \frac{p_{90} - p_{10}}{\vert p_{50}\vert + \epsilon}}$$
where $\epsilon = 10^{-5}$. Properties:
- Output range $(0, 1]$ — never negative, never compressed to 0
- As spread $(p_{90} - p_{10}) \to 0$, confidence $\to 1$ (tight bounds)
- As spread $\to \infty$, confidence $\to 0$ asymptotically (extreme uncertainty)
- Scale-invariant via division by median magnitude $|p_{50}|$
Operational Interpretation:
- 0.80–1.00: Tight predictive consensus. Safe for automated safety-stock decisions.
- 0.40–0.79: Moderate uncertainty. The agent should increase safety stock buffers or schedule a human review.
- 0.00–0.39: Extreme epistemic variance. Flag for immediate human review; do not automate downstream decisions.
### Agentic Architecture Agnostic
As a stateless, schema-bound MCP tool microservice, this engine integrates seamlessly with any agent orchestrator — including Neuro-Symbolic stacks governed by OPA/Rego policies, LangGraph state machines, CrewAI swarms, or standard ReAct loops.
---
## MCP Tool Specifications & API Contracts
### `forecast_demand`
Single time-series prediction.
**Request** (`TimeSeriesInputPayload`)
```json
{
"target_series": [120.5, 115.0, 130.2, 125.8, 140.1],
"forecast_horizon": 30,
"price_index": [19.99, 19.99, 24.99, 24.99, 24.99, 24.99, ...],
"promo_flag": [0, 0, 1, 0, 1, 0, ...]
}
```
**Response** (`ForecastResponse`)
```json
{
"model_used": "Chronos-2-Fallback",
"mean_prediction": [142.3, 145.1, 140.8, 148.2, 150.0],
"p10_quantile": [120.1, 122.4, 118.7, 125.3, 127.9],
"p50_quantile": [142.3, 145.1, 140.8, 148.2, 150.0],
"p90_quantile": [165.2, 168.5, 162.1, 170.4, 172.8],
"confidence_score": 0.87,
"horizon_length": 30,
"exogenous_dropped": false,
"warnings": ["CUDA unavailable; running on CPU. Expect degraded inference performance."]
}
```
### `forecast_batch`
Array-based multi-SKU prediction with per-item fallback summary.
**Request**
```json
{
"payloads": [
{"target_series": [10.0]*20, "forecast_horizon": 5},
{"target_series": [11.0]*30, "forecast_horizon": 3, "price_index": [20.0]*33}
]
}
```
**Response**
```json
{
"results": [
{"model_used": "Chronos-2-Fallback", "mean_prediction": [...], ...},
{"model_used": "TimesFM-2.5", "mean_prediction": [...], ...}
],
"summary": {
"total": 2,
"errors": 0,
"model_usage": {"Chronos-2-Fallback": 1, "TimesFM-2.5": 1}
}
}
```
### `AgentFriendlyError`
Self-correcting error schema returned on validation or execution failure.
```json
{
"error_code": "VALIDATION_ERROR",
"message": "Input validation failed at 'price_index': Price array misalignment. Expected 25 elements (Context: 20 + Horizon: 5), got 2.",
"expected": "Payload matching TimeSeriesInputPayload schema (context 16-16000 finite values, aligned exogenous signals).",
"received": "{\"location\": \"price_index\", \"message\": \"Price array misalignment. Expected 25 elements (Context: 20 + Horizon: 5), got 2.\", \"context\": {\"expected\": \"25\", \"got\": \"2\"}}",
"remediation_suggestion": "Correct field 'price_index' (Price array misalignment. Expected 25 elements (Context: 20 + Horizon: 5), got 2.) and resubmit. Ensure context length is between 16 and 16000, values are finite (no NaN/Inf), and exogenous arrays align to len(target_series) + forecast_horizon."
}
```
**Error codes**: `VALIDATION_ERROR`, `MODEL_UNAVAILABLE`, `TRANSIENT_FAILURE`, `MODEL_FAILURE`, `INTERNAL_ERROR`
---
## Quickstart & MCP Configuration
### Installation
```bash
# Requires Python 3.11+
uv sync --extra gpu # or: pip install -r requirements.txt
```
### Environment
```bash
# Optional: force CPU if GPU memory constrained
export MODEL_CONFIG_PATH=configs/model_config.yaml
export DATA_STORAGE_ROOT=data/
```
The engine auto-detects CUDA. If unavailable, falls back to CPU and emits a warning in `warnings` field.
### MCP Client Configuration (Claude Desktop / OpenCode / LangGraph / CrewAI)
Add to your MCP client config (`claude_desktop_config.json`, `opencode.json`, or equivalent):
```json
{
"mcpServers": {
"zero-shot-forecaster": {
"command": "python",
"args": ["mcp_server.py"],
"cwd": "/absolute/path/to/zero-shot-demand-foundation",
"env": {
"MODEL_CONFIG_PATH": "configs/model_config.yaml"
}
}
}
}
```
Restart your MCP client. The tools `forecast_demand` and `forecast_batch` will auto-register with their full JSON schemas.
### Invocation Example (Claude / LLM Agent)
```json
{
"tool": "forecast_demand",
"arguments": {
"target_series": [120, 115, 130, 125, 140, 135, 150, 145, 155, 160, 155, 165, 170, 168, 172, 175, 180, 178, 185, 190],
"forecast_horizon": 7,
"price_index": [19.99, 19.99, 19.99, 19.99, 19.99, 19.99, 24.99, 24.99, 24.99, 24.99, 24.99, 24.99, 24.99, 24.99, 24.99, 24.99, 24.99, 24.99, 24.99, 24.99, 24.99, 24.99, 24.99, 24.99, 24.99, 24.99, 24.99],
"promo_flag": [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
}
}
```
---
## Verification & Testing
### Run Full Test Suite (110 tests total: 62 acceptance + 48 legacy)
```bash
uv run pytest tests/ -q
# or
python -m pytest tests/ -q
```
Expected output:
```
.............................................................. [100%]
110 passed in ~5s
```
### Test Coverage Matrix
| AC | Criterion | Test Function |
|----|-----------|---------------|
| AC-1 | Non-blocking event loop | `test_forecast_demand_is_non_blocking` |
| AC-2 | Lazy loading & VRAM conservation | `test_lazy_loading_*`, `test_hardware_auto_detect_*` |
| AC-3 | Graceful fallback & signal stripping | `test_timesfm_failure_falls_back_to_chronos_strips_exog`, `test_full_fallback_to_autoarima` |
| AC-4 | CUDA OOM recovery | `test_cuda_oom_triggers_memory_recovery`, `test_recover_from_oom_calls_gc_and_empty_cache` |
| AC-5 | Agent self-correction payloads | `test_agent_friendly_error_on_short_sequence`, `test_forecast_batch_agent_friendly_error_per_item` |
### Legacy Tests (Backward Compatibility)
The 48 original unit tests are included in the 110 total above and remain passing:
```bash
pytest tests/test_forecasting_engine.py tests/test_forecaster_router.py tests/test_mcp_server.py tests/test_schemas.py tests/test_metrics.py -q
```
---
## Project Structure (Post-Refactor)
```
zero-shot-demand-foundation/
├── configs/
│ └── model_config.yaml # Model IDs, device_map, num_samples
├── data/ # Git-ignored (CSV, ZIP)
├── scripts/
│ ├── download_m5.py # M5 dataset fetcher
│ └── download_favorita.py # Favorita dataset fetcher
├── src/
│ ├── models/
│ │ └── forecaster.py # ZeroShotForecastingEngine (refactored)
│ ├── schemas/
│ │ └── payloads.py # TimeSeriesInputPayload, ForecastResponse, AgentFriendlyError
│ └── utils/
│ ├── data_loader.py # DemandDataEngine, FavoritaDataLoader
│ └── metrics.py # WAPE, RMSSE, Pinball Loss, CRPS
├── tests/
│ ├── test_forecasting_engine.py # Updated for lazy loading
│ ├── test_forecaster_router.py # Updated fixtures
│ ├── test_mcp_server.py # Async + AgentFriendlyError
│ ├── test_metrics.py # Unchanged
│ ├── test_schemas.py # Unchanged
│ └── test_refactored_forecaster.py # NEW: AC-1..5 coverage
├── main.py # CLI evaluation entry point
├── mcp_server.py # FastMCP server (async, batch, errors)
├── requirements.txt
├── .gitignore # Ignores *.md, data/, __pycache__/
└── README.md # This file
```
---
## Citation
If you use this work in research or production systems, please cite:
```bibtex
@software{nicoomanesh2026zeroshot,
author = {Nicoomanesh, Arash},
title = {MCP Zero Shot Agentic Forecaster: A Production-Ready Symbolic Skill for Zero-Shot Demand Forecasting},
url = {https://github.com/arashnicoomanesh/zero-shot-demand-forecasting},
year = {2026},
version = {1.0.1}
}
```
## License
Copyright (c) 2026 Arash Nicoomanesh.
This project is licensed under the [MIT License](LICENSE).
## References
- **Chronos-2**: Ansari et al., *Chronos: Learning the Language of Time Series*, arXiv:2403.07815
- **TimesFM**: Das et al., *TimesFM: A Decoder-Only Foundation Model for Time-Series Forecasting*, arXiv:2402.02592
- **M5 Competition**: Makridakis et al., *M5 Accuracy Competition*, IJF 2022
- **Corporación Favorita**: Kaggle Favorita Grocery Sales Forecasting
- **Model Context Protocol**: Anthropic MCP SpecificationThis server cannot be deployed
Maintenance
ActivityNo data
ResponsivenessNo issues