forecast-mcp
by OwnOptic
README.md
# forecast-mcp
**Give your AI a Monte Carlo forecasting engine.** A [Model Context Protocol](https://modelcontextprotocol.io) server that turns three-point estimates and historical throughput into calibrated, probabilistic forecasts: project timelines, cost ranges, and "when will it be done?" delivery dates.
Fully local. No API keys. No network calls.
---
## Why this exists
Large language models are genuinely bad at probability. Ask one for a project deadline and it will confidently invent a single number, or "simulate" a distribution it cannot actually compute. Monte Carlo forecasting is exactly the kind of work an LLM should **delegate to a tool**: run thousands of seeded random trials and report the real distribution.
`forecast-mcp` gives any MCP-capable client (Claude Desktop, Claude Code, Cursor, and others) five tools to do that properly, so instead of *"this will take about three weeks"* you get:
> P50 = 19.5 days, P80 = 24.1 days, P95 = 28.7 days, and an 84% chance of finishing within your 25-day target.
## Install
Run it straight from npm with `npx` (no install needed):
```bash
npx forecast-mcp
```
Then register it with your client. For **Claude Desktop** / **Claude Code**, add to your MCP config:
```json
{
"mcpServers": {
"forecast": {
"command": "npx",
"args": ["-y", "forecast-mcp"]
}
}
}
```
That's it. The server speaks stdio and needs no configuration, credentials, or internet access.
> **Running from source** (before the npm package is published, or to hack on it): clone this repo, run `npm install && npm run build`, then point your client at it with `"command": "node", "args": ["/absolute/path/to/forecast-mcp/dist/index.js"]`.
## Tools
| Tool | What it answers |
| --- | --- |
| `forecast_duration` | How long will the whole project take? (Monte Carlo over per-task 3-point estimates) |
| `forecast_cost` | What will it cost, with contingency? (Monte Carlo over cost line items) |
| `forecast_completion` | When will it be done, from our actual throughput? (flow-based, "no estimates") |
| `pert_estimate` | Quick analytical 3-point estimate + confidence levels (instant, no simulation) |
| `sensitivity_analysis` | Which tasks drive the uncertainty? (tornado-chart data) |
Every tool takes optimistic / most-likely / pessimistic inputs (except `forecast_completion`, which uses throughput history) and returns both a human-readable summary and structured JSON.
### Distributions
`forecast_duration`, `forecast_cost`, and `sensitivity_analysis` accept a `distribution`:
- `pert` (default) - beta-PERT, the project-management standard; weights the most-likely value.
- `triangular` - simple, bounded.
- `normal` - symmetric bell curve (std dev derived from the range).
- `lognormal` - right-skewed; models "usually fine, occasionally very late".
- `uniform` - flat between optimistic and pessimistic.
You can also override the distribution per item.
### Reproducibility
Every tool accepts an optional `seed` and **defaults to a fixed seed**, so the same inputs always produce the same forecast. Change the seed to explore alternate random streams.
## Deploying remotely (Streamable HTTP)
`npx forecast-mcp` is stdio-only, which is fine for a local client but can't be reached over a network. The same binary also speaks [Streamable HTTP](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http), so it can run as a standalone deployable service (Docker, Render, Fly, Railway, Cloud Run, a VM, etc.) that any remote MCP client can call.
**One entry point, two transports** - `node dist/index.js` picks the transport at runtime:
- No `PORT` and no `MCP_TRANSPORT` set -> **stdio** (the default, used by `npx forecast-mcp`).
- `PORT` set (most PaaS platforms set this automatically), or `MCP_TRANSPORT=http` -> **Streamable HTTP**, served at `POST /mcp`, with a `GET /healthz` health check.
The HTTP server is **stateless**: every request builds a fresh server instance (`sessionIdGenerator: undefined`, the pattern the MCP SDK recommends for this case). That's safe here because every forecast-mcp tool is a pure function - there is no session state to preserve between requests, so nothing is lost by not keeping one.
### Run it locally over HTTP
```bash
npm run build
npm run start:http # MCP_TRANSPORT=http PORT=3000 node dist/index.js
curl http://localhost:3000/healthz
```
### Docker
```bash
docker build -t forecast-mcp .
docker run -p 3000:3000 forecast-mcp
```
The image always runs in HTTP mode (that is the point of containerizing it); most platforms inject their own `PORT` at deploy time, which overrides the image's default of 3000.
### Environment variables (HTTP mode only)
| Variable | Default | Purpose |
| --- | --- | --- |
| `PORT` | `3000` | Port to listen on. Setting this alone is enough to switch to HTTP mode. |
| `MCP_TRANSPORT` | (unset) | Set to `http` to force HTTP mode even without `PORT`. |
| `HOST` | `0.0.0.0` | Interface to bind. |
| `MCP_ALLOWED_HOSTS` | (unset) | Comma-separated list of allowed `Host` header values, for DNS-rebinding protection when binding to a non-localhost address. |
### Security note
These tools are read-only pure computations with no filesystem, network, or credential access, so the blast radius of an unauthenticated call is low. Still, the server itself has no built-in authentication - if you expose it beyond a trusted network, put it behind a reverse proxy or gateway that handles auth, and set `MCP_ALLOWED_HOSTS` to suppress the DNS-rebinding warning.
## Examples
**`forecast_duration`**
```json
{
"tasks": [
{ "name": "design", "optimistic": 2, "mostLikely": 4, "pessimistic": 8 },
{ "name": "build", "optimistic": 5, "mostLikely": 10, "pessimistic": 30 },
{ "name": "test", "optimistic": 1, "mostLikely": 3, "pessimistic": 6 }
],
"unit": "days",
"target": 25
}
```
returns P50/P80/P90/P95, mean, standard deviation, a distribution sparkline, and `probabilityWithinTarget` (~0.84).
**`forecast_completion`** ("when will it be done?")
```json
{
"throughputSamples": [4, 5, 6, 5, 4, 6],
"backlog": 40,
"periodLabel": "sprint",
"startDate": "2026-07-13",
"periodDays": 14
}
```
bootstraps future sprints from your last six and returns how many sprints (and which calendar dates) it will likely take to clear 40 items. Add `splitRate` to model scope creep.
**`sensitivity_analysis`** ranks the tasks by how much each one contributes to the total variance, so you know where tightening an estimate actually moves the needle.
## Development
```bash
npm install
npm run build # compile TypeScript to dist/
npm test # build + run the vitest suite
npm run inspect # open the MCP Inspector against the built server
```
The forecasting logic lives in `src/engine/` (pure, dependency-free functions) and is exercised directly by the test suite; the tools in `src/tools/` are thin MCP wrappers.
## How it works
- Seeded PRNG (`mulberry32`) for reproducible trials.
- Beta-PERT sampling via two Gamma draws (Marsaglia-Tsang); triangular, normal (Box-Muller), lognormal, and uniform samplers included.
- Per-iteration line items are summed into a project total; percentiles are computed by linear interpolation over the sorted sample.
- `sensitivity_analysis` correlates each item's draws with the total (Pearson) and reports each item's share of variance.
- `pert_estimate` is a closed-form cross-check (its mean matches the simulation's mean to within a fraction of a unit).
## License
MIT - see [LICENSE](./LICENSE).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues