ScenarioSim
БесплатноНе проверенA deterministic what-if scenario simulation MCP server that projects business metrics over time with exact decimal arithmetic, offering sensitivity analysis and
Описание
A deterministic what-if scenario simulation MCP server that projects business metrics over time with exact decimal arithmetic, offering sensitivity analysis and break-even solving.
README
A transparent, 100% deterministic Model Context Protocol (MCP) server that gives LLM agents a reliable what-if / scenario simulation engine.
Agents are good at describing a plan but unreliable at projecting it: they drift on multi-period arithmetic, mishandle compounding, and can't show their work. ScenarioSim offloads the simulation to an exact, explainable engine. You provide assumptions (growth rates, churn, pricing, costs, starting metrics, a time horizon); it returns projected outcomes over time, key metrics, the exact assumptions used, plus sensitivity analysis and break-even solving — each with a plain-language explanation.
Every number flows through decimal.js at 40-digit precision (never floats), so identical inputs always produce byte-identical output. The server is stateless — no database, no sessions, no clocks or randomness in the result.
This is the third product in a suite built to the same engineering standard as PrecisionCalc MCP (deterministic high-precision finance/business math) and DecisionMatrix MCP (transparent multi-criteria decision analysis): identical project structure, output philosophy, and Cloudflare Pages deployment.
🌐 Live hosted server (free, no install)
A public remote MCP server runs on Cloudflare's edge — point any Streamable-HTTP MCP client at it:
https://scenariosim-mcp.pages.dev/mcp
{ "mcpServers": { "scenariosim": {
"type": "http", "url": "https://scenariosim-mcp.pages.dev/mcp" } } }
It runs in open mode on the free tier (no key, 20 calls/day per IP). Paid plans
(Starter $12/mo · 5,000/day, Pro $39/mo · 50,000/day) are available via Stripe
Checkout — buy a plan, get an API key instantly, and send it as X-API-Key. Self-host
for unlimited calls with no keys. Landing page + pricing: https://scenariosim-mcp.pages.dev.
What it does
Six tools, all returning a uniform, agent-parseable envelope:
| Tool | Purpose |
|---|---|
run_scenario |
Main tool. Project a pre-built template or a free-form model over time → per-period projections, headline key_results, the assumptions_used, methodology, notes, and a plain-language explanation. |
sensitivity_analysis |
Vary one or more inputs (one-at-a-time) and report the impact on a target metric — with an elasticity estimate, the output range, and a ranking of the most influential inputs. |
break_even |
Solve for the input value required to make a target metric hit a target value (deterministic bisection). |
compare_scenarios |
Run 2–3 scenarios side-by-side with deltas vs a baseline and an optional winner. |
list_templates |
Discovery: every template with its inputs (defaults + units) and available outputs. |
health_check |
Version, status, and capabilities. |
Scenario templates
| id | models | primary output |
|---|---|---|
saas_growth |
subscribers + MRR/ARR from acquisition (with its own growth) and churn | ending_mrr |
pricing_change |
revenue/profit impact of a price change via price elasticity | cumulative_profit_after |
churn_impact |
retention erosion + revenue lost vs a no-churn baseline | cumulative_revenue_lost |
cost_reduction |
profit + margin impact of cutting costs | cumulative_savings |
hiring_plan |
headcount, fully-loaded payroll, revenue capacity | cumulative_payroll |
cash_runway |
cash balance forward + months-to-zero runway | runway_periods |
unit_economics |
LTV, LTV:CAC, CAC payback, per-customer margin curve | ltv_cac_ratio |
marketing_funnel |
visitors → leads → customers → revenue | total_revenue |
compound_growth |
generic single-metric compound/linear projection | ending_value |
custom |
free-form: any number of independently-growing metrics | (first metric) |
Every template accepts horizon (number of periods, 1–1200) and period_label
(day/week/month/quarter/year, which also sets annualization). Inputs you don't
provide fall back to documented defaults; unknown inputs are ignored and reported in notes.
Call list_templates for the full input/output catalog.
Consistent response envelope
Every successful response contains: status, scenario, period_label, horizon,
key_results (+ key_results_detail with units and full-precision value_exact),
projections, assumptions_used, methodology, notes, and a natural-language
explanation.
{
"status": "success",
"scenario": "saas_growth",
"period_label": "month",
"horizon": 12,
"key_results": {
"ending_customers": 449.7, "ending_mrr": 26982.1, "ending_arr": 323785.2,
"total_churned_customers": 82.4, "cumulative_revenue": 232104.6
},
"projections": [
{ "period": 0, "customers": 200, "mrr": 12000, "new_customers": 0, "churned_customers": 0 },
{ "period": 1, "customers": 234, "mrr": 14040, "new_customers": 40, "churned_customers": 6 }
],
"assumptions_used": {
"template": "saas_growth", "starting_customers": "200", "new_customers_per_period": "40",
"acquisition_growth_rate": "0", "churn_rate": "0.03", "arpu": "60",
"horizon": 12, "period_label": "month"
},
"methodology": {
"model": "SaaS Growth",
"primary_output": "ending_mrr",
"precision": "decimal.js (40 significant digits)",
"deterministic": true,
"period_convention": "Period 0 is the starting state; periods 1..12 are projected. 12 month(s) per year."
},
"notes": ["Churn is applied to the prior period's base before new customers are added."],
"explanation": "Starting from 200 customers and adding 40 per month (churn 3%), after 12 months you reach ..."
}
Errors never cross the tool boundary as exceptions — they come back as a structured, actionable envelope:
{
"status": "error",
"error": {
"type": "unknown_template",
"message": "Unknown scenario template 'saaas'.",
"hint": "Available templates: saas_growth, pricing_change, churn_impact, cost_reduction, hiring_plan, cash_runway, unit_economics, marketing_funnel, compound_growth. Call list_templates for details ..."
}
}
Design note — exact numbers: headline numbers in
key_resultsare deterministically rounded (6 dp) for easy consumption;key_results_detail[].value_exactandassumptions_usedcarry full-precision strings so no precision is lost in JSON. All internal math is exact 40-digit decimal.
Project structure
scenariosim-mcp/
├── worker-src/
│ ├── index.mjs # Cloudflare Pages Function (_worker.js): MCP over Streamable HTTP + billing routes
│ ├── engine.mjs # The deterministic simulation engine: 9 templates + 6 tools + solver + validation
│ └── billing.mjs # Stripe Checkout + KV-backed API keys, quota metering, webhook
├── server.mjs # Local stdio MCP server (same engine, no network/state)
├── site/
│ ├── index.html # Static landing / pricing / docs page
│ ├── mcp.json # Machine-readable connection manifest
│ ├── llms.txt # LLM-friendly summary
│ └── _worker.js # Built bundle (esbuild output; git-ignored)
├── tests/
│ └── engine.test.mjs # 29 core simulation-logic tests (node --test)
├── examples/
│ └── agent_example.mjs # End-to-end MCP client demo over HTTP
├── package.json # build / deploy / dev / test scripts
├── wrangler.toml # Cloudflare Pages config
├── .env.example # Optional auth/rate-limit env reference
├── LICENSE # MIT
└── README.md
Separation of concerns: engine.mjs is pure and transport-agnostic (import it
directly in tests or any Node/Deno/edge runtime); index.mjs only handles the MCP
JSON-RPC wiring, HTTP, CORS, and the auth/metering seam; server.mjs re-uses the same
engine over stdio.
Requirements
- Node 18+ (for the build, tests, and local dev). Only two dev/runtime deps:
decimal.js(math) andesbuild(bundler). - A Cloudflare account (free tier is fine) to deploy the hosted version.
Run it locally
git clone <your-fork> scenariosim-mcp && cd scenariosim-mcp
npm install
# Run the test suite (no server needed)
npm test
# Serve the MCP endpoint locally via Wrangler (builds + runs Pages dev)
npm run dev # -> http://127.0.0.1:8788/mcp
# Try the end-to-end client demo (hosted by default, or pass a local URL)
node examples/agent_example.mjs
node examples/agent_example.mjs http://127.0.0.1:8788
# Or run the dependency-light stdio server directly
node server.mjs
Quick manual call:
curl -s http://127.0.0.1:8788/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{
"name":"list_templates","arguments":{}}}'
Install via npm (stdio, no hosting)
Run the server locally over stdio with a single command — nothing to deploy:
npx -y scenariosim-mcp
Claude Desktop / any stdio MCP client (claude_desktop_config.json):
{ "mcpServers": { "scenariosim": { "command": "npx", "args": ["-y", "scenariosim-mcp"] } } }
This is the same deterministic engine as the hosted server, running on your machine.
Client configuration
Cursor — ~/.cursor/mcp.json
{ "mcpServers": { "scenariosim": {
"url": "https://scenariosim-mcp.pages.dev/mcp" } } }
Claude Desktop — claude_desktop_config.json
Claude Desktop launches stdio servers, so bridge to the HTTP endpoint with mcp-remote:
{ "mcpServers": { "scenariosim": {
"command": "npx", "args": ["-y", "mcp-remote", "https://scenariosim-mcp.pages.dev/mcp"] } } }
VS Code — .vscode/mcp.json
{ "servers": { "scenariosim": {
"type": "http", "url": "https://scenariosim-mcp.pages.dev/mcp" } } }
Windsurf — ~/.codeium/windsurf/mcp_config.json
{ "mcpServers": { "scenariosim": {
"serverUrl": "https://scenariosim-mcp.pages.dev/mcp" } } }
Any Streamable-HTTP MCP client
Point it at https://scenariosim-mcp.pages.dev/mcp (or your self-hosted URL). If
you enable auth, add X-API-Key (or Authorization: Bearer <key>) in the client's
headers.
Tools & parameters
run_scenario(template?, inputs?, metrics?, horizon?, period_label?)
- template — one of the template ids above (aliases like
saas,pricing,runway,ltv,funnelalso resolve). Omit it (or pass"custom") to run a free-form model. - inputs — the assumptions object for the template, e.g.
{ "churn_rate": 0.03, "arpu": 60 }. Also accepted asassumptions, or spread at the top level. Missing keys use documented defaults. - metrics — (custom mode) array of
{ name, start, growth_rate?, mode? }wheremodeis"compound"(default,x·(1+r)ⁿ) or"linear"(x·(1+r·n)). - horizon — number of periods to project (1–1200). Default per template (usually 12).
- period_label —
day/week/month/quarter/year(defaultmonth).
sensitivity_analysis(template, variable|variables, target_metric?, variation?, steps?, values?, min?, max?, inputs?, horizon?)
Sweeps each listed input across a range (default ±variation=0.2 around the baseline,
steps=5) while all others stay at baseline, recomputing target_metric (defaults to the
template's primary output) at each point. Returns per-variable sweep rows, an
elasticity_estimate, the output_range, and a most_influential ranking. You can also
give explicit values: [...] or a min/max grid instead of variation.
break_even(template, solve_for, target_metric?, target_value, bounds?, inputs?, horizon?)
Solves for the value of solve_for (an input name) that makes target_metric equal
target_value, via deterministic bisection with automatic bracket expansion. Returns
required_input, change_from_baseline, achieved_metric, and residual. Assumes the
metric is monotonic in the solved input over the search range; if the target can't be
bracketed it returns a clean no_solution error with the achievable range. Pass explicit
bounds: [lo, hi] to constrain (or fix) the search.
compare_scenarios(scenarios, compare_metric?, goal?, horizon?, include_projections?)
Runs 2–3 scenarios ({ name?, template, inputs }, or { name?, metrics } for custom)
and aligns their key_results, differencing each against the first (baseline). Pass
compare_metric + goal (max default | min) to rank and pick a winner. Set a shared
horizon at the top level, or per-scenario.
list_templates() / health_check()
Discovery + status. No parameters.
Example tool-call payloads
Project 12 months of SaaS growth:
{ "name": "run_scenario", "arguments": {
"template": "saas_growth",
"inputs": { "starting_customers": 200, "new_customers_per_period": 40,
"acquisition_growth_rate": 0.05, "churn_rate": 0.03, "arpu": 60 },
"horizon": 12, "period_label": "month"
} }
Which lever moves ending MRR the most?
{ "name": "sensitivity_analysis", "arguments": {
"template": "saas_growth",
"inputs": { "starting_customers": 200, "new_customers_per_period": 40, "churn_rate": 0.03, "arpu": 60 },
"variables": [ { "name": "churn_rate", "variation": 0.5 },
{ "name": "arpu", "variation": 0.3 },
{ "name": "new_customers_per_period", "variation": 0.5 } ],
"target_metric": "ending_mrr", "horizon": 12
} }
What churn keeps 90% of customers after a year?
{ "name": "break_even", "arguments": {
"template": "churn_impact",
"inputs": { "starting_customers": 1000, "arpu": 60, "new_customers_per_period": 0 },
"solve_for": "churn_rate", "target_metric": "retention_pct",
"target_value": 0.9, "horizon": 12
} }
→ required_input ≈ 0.008742 (about 0.87%/month).
Compare growth strategies:
{ "name": "compare_scenarios", "arguments": {
"scenarios": [
{ "name": "Base", "template": "saas_growth", "inputs": { "churn_rate": 0.04, "new_customers_per_period": 30 } },
{ "name": "Aggressive", "template": "saas_growth", "inputs": { "churn_rate": 0.04, "new_customers_per_period": 60 } },
{ "name": "RetentionFocus", "template": "saas_growth", "inputs": { "churn_rate": 0.015, "new_customers_per_period": 30 } }
],
"compare_metric": "ending_mrr", "goal": "max", "horizon": 12
} }
Free-form (custom) model:
{ "name": "run_scenario", "arguments": {
"metrics": [
{ "name": "revenue", "start": 10000, "growth_rate": 0.08, "mode": "compound" },
{ "name": "headcount", "start": 12, "growth_rate": 0.05, "mode": "linear" }
],
"horizon": 12
} }
Deploy on Cloudflare Pages
Same pattern as PrecisionCalc / DecisionMatrix — one build step bundles worker-src/
into site/_worker.js (Pages "advanced mode" Function), then Wrangler deploys the site/
directory.
npm install
npx wrangler login # once
# Build + deploy in one shot
npm run deploy # esbuild -> site/_worker.js, then wrangler pages deploy
Or wire it to Git: create a Pages project, set the build command to npm run build
and the output directory to site. Every push deploys automatically. The
compatibility_date and project name live in wrangler.toml.
To run fully free / private, you need no bindings, secrets, or env vars — the simulation engine is stateless and the server fails open (free tier, quota disabled).
Enabling billing (optional)
Replicate these for a paid deployment:
- KV namespace for API keys + daily usage counters, bound as
SCENARIOSIM_KVinwrangler.toml(wrangler kv namespace create SCENARIOSIM_KV). - Stripe products/prices (subscription) — put the price IDs in
[vars](PRICE_STARTER,PRICE_PRO) and the daily limits (FREE_DAILY,STARTER_DAILY,PRO_DAILY). - Stripe secrets (never in the repo):
wrangler pages secret put STRIPE_SECRET_KEY --project-name scenariosim-mcp wrangler pages secret put STRIPE_WEBHOOK_SECRET --project-name scenariosim-mcp - Webhook → create a Stripe webhook endpoint at
https://<your-domain>/webhookforcustomer.subscription.updated+customer.subscription.deleted.
Routes wired up: /checkout?plan=starter|pro → Stripe Checkout, /success provisions
and shows the API key (idempotent), /portal opens the Stripe billing portal,
/webhook handles subscription lifecycle (revoke/restore), /metrics reports usage.
Auth & rate limiting
The hosted server enforces tiered quotas in worker-src/billing.mjs:
- Identity —
identify()readsX-API-Key/Authorization: Bearer, looks the key up in KV, and falls back to per-IP free tier. (To add JWT/mTLS/per-org keys, changeextractKey+identifyonly — the engine and transport are untouched.) - Quota —
consumeQuota()is a KV daily counter (resets 00:00 UTC); the single gating point inhandleRpcwheremethod === "tools/call". (Swap for a sliding-window / token-bucket in a Durable Object or Redis for per-minute limits — see theNOTE (rate limiting)comment.) - Paywall response — over-quota / invalid / revoked keys get a structured
upsellenvelope with pricing + checkout URLs (agents can read and act on it). - Usage metering — in-memory counters at
/metrics.
ScenarioSim has no paid-only tools — every tool works on every tier; paid plans
only raise the daily quota. To make a tool paid-only, add its name to PAID_ONLY_TOOLS
in index.mjs. Because the engine is pure and stateless, none of this touches the
simulation logic.
Design decisions & assumptions
- Deterministic by construction. 40-digit decimal math,
ROUND_HALF_UPeverywhere, period-by-period iteration (notfloat**n), and no clocks/randomness in results. - Period 0 is the starting state; periods
1..horizonare projected.period_labelsets the annualization factor (month→ 12/yr, etc.), which is used for ARR/payroll. - Assumptions are echoed back in full (
assumptions_used) with defaults filled in, so a caller always knows exactly what was simulated. - Counts stay fractional for precision (e.g. 233.6 customers); round to integers in
your presentation layer if needed. This is stated in
notes. - Elasticity/growth models are intentionally simple and transparent (constant elasticity, constant per-period rates). They're honest first-order estimates, not econometric forecasts — the methodology block says so.
- break_even uses bisection with automatic bracket expansion and a fixed iteration
budget → deterministic. It assumes monotonicity of the metric in the solved input over
the range; non-monotonic/ratio metrics (with poles) return a clean
no_solutionrather than a wrong root.sensitivity_analysis/break_evenoperate on named templates (not the free-formcustommodel) and say so if misused. - Errors are data, not exceptions — every tool returns
status:"error"with a machinetypeand an actionablehint. Validation covers unknown templates/inputs/metrics, non-numeric values, bad horizons/period labels, unreachable targets, and more. - Stateless & side-effect-free — trivially cacheable, horizontally scalable, and safe to run anywhere (Cloudflare, Node, Deno, Bun).
Testing
npm test # node --test tests/*.test.mjs (29 tests, no network)
The suite pins hand-verifiable arithmetic (compound growth, LTV/CAC, elasticity, runway),
checks determinism, the multiple assumption-input shapes, period-label annualization,
custom free-form models, the sensitivity sweep + influence ranking, the break-even solver
(including the unreachable-target path), scenario comparison with goal=min, and every
error path.
Roadmap (post-MVP)
- More templates: LBO/DCF, inventory & cash-conversion cycle, ad-spend ROAS, cohort retention.
- Monte-Carlo mode: distributions on inputs → confidence bands on outcomes (seeded, still deterministic).
- Multi-variable (grid) sensitivity and tornado charts alongside one-at-a-time.
- Break-even on the free-form
custommodel and on multiple simultaneous inputs. - Per-key usage dashboard + Durable-Object quotas for stronger consistency.
License
MIT — see LICENSE.
Установка ScenarioSim
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/inity13/scenariosim-mcpFAQ
ScenarioSim MCP бесплатный?
Да, ScenarioSim MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для ScenarioSim?
Нет, ScenarioSim работает без API-ключей и переменных окружения.
ScenarioSim — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить ScenarioSim в Claude Desktop, Claude Code или Cursor?
Открой ScenarioSim на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
GitHub
PRs, issues, code search, CI status
автор: GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
автор: mcpdotdirectAmap Maps Mcp Server
MCP server for using the AMap Maps API
автор: duxiaohuiSupabase
Database, auth and storage
автор: SupabaseEverything
Reference / test server with prompts, resources, and tools.
Git
Tools to read, search, and manipulate Git repositories.
Sequential Thinking
Dynamic and reflective problem-solving through thought sequences.
Time
Time and timezone conversion capabilities.
Compare ScenarioSim with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development
