Skip to main content
Glama
README.md
# MADMAX — Multi-Agent Dynamic Matrix

**An Enterprise AI Workforce OS.** A Planner launches a *mission* into a live
ecosystem of specialist tools, discovers them **over the Model Context Protocol**,
plans an execution order, runs each tool, verifies the results, holds a council
vote, and synthesizes an executive report — streaming every step to a Mission
Control UI in real time.

> **What makes this real:** the seven specialist capabilities are served by a
> **NitroStack MCP server** and consumed by the orchestrator through the official
> MCP client SDK. Discovery is a real `listTools()` call and execution is a real
> `callTool()` over Streamable HTTP — not an in-memory registry pretending to be
> MCP. Swap in any other MCP server and the Planner keeps working unchanged.

Built for the **Enterprise AI & Workplace Automation** track: the missions, tools,
and prompts are modelled on the cross-domain decisions operations teams actually
automate (approval routing, vendor evaluation, risk/compliance sign-off).

---

## Why it exists

Most "AI agent" demos are one LLM call behind a system prompt. Real operational
decisions aren't like that: a request touches finance, risk, and compliance at
once, needs more than one specialist, and shouldn't be trusted until it's been
checked. MADMAX models that explicitly and makes the orchestration **visible** —
discovery, planning, execution, verification, and a recorded vote — instead of
hiding it inside one prompt.

Crucially, the specialists are **MCP tools behind a protocol boundary**. They
have no handle to each other and cannot call one another. The Planner is the
*only* thing that sequences work. That's not a stylistic choice — it's enforced
by the architecture.

## Architecture at a glance

```
┌────────────────────────────┐         Streamable HTTP (MCP)        ┌──────────────────────────────┐
│  Orchestrator (MCP client) │  ───  listTools() / callTool()  ───► │  NitroStack MCP server        │
│  • Planner (LLM)           │                                      │  7 tools:                     │
│  • retry + recovery        │ ◄─── structured tool results ─────   │  research, finance, risk,     │
│  • council vote            │                                      │  compliance, strategy,        │
│  • report synthesis        │                                      │  verification, report         │
│  • WebSocket gateway       │                                      └──────────────────────────────┘
└──────────────┬─────────────┘
               │ WebSocket (typed events)
               ▼
     Mission Control UI (real-time execution graph, confidence chart, transcript, vote, replay)
```

Two processes, one repo. See [`ARCHITECTURE.md`](ARCHITECTURE.md) for the full breakdown.

## Quickstart

**Requirements:** Node.js ≥ 20.18.

```bash
# 1. install
npm install

# 2. (optional) configure
cp .env.example .env
#    Set ANTHROPIC_API_KEY=... for live Claude output. If you skip this entirely,
#    MADMAX still boots — it auto-runs in labelled MOCK mode (the UI shows a
#    "MOCK LLM" banner), so a fresh clone works with zero configuration.

# 3. run both services (tools MCP server + orchestrator/UI)
npm run dev

# 4. open the Mission Control UI
open http://localhost:4000
```

Type a goal (or pick a preset) and click **Launch Mission**. The tools server
(`:4001/mcp`) and the orchestrator + UI (`:4000`) start together.

### Troubleshooting

- **"Cannot reach the orchestrator" in the UI.** The backend isn't running (or
  isn't up yet). Start it with `npm run dev` and reload `http://localhost:4000`.
  The UI auto-retries the connection on launch, so a slow first boot resolves on
  its own — you only see this banner if the orchestrator is genuinely down.
- **Opened the page from disk (`file://`).** The UI must be served by the
  orchestrator so it can reach the WebSocket. Use `http://localhost:4000`, not
  the file path.
- **No API key.** Not required for a demo — MADMAX auto-falls back to labelled
  MOCK mode. Set `ANTHROPIC_API_KEY` for live model output.

### Verify it end-to-end without a key

```bash
npm run smoke
```

This boots the real NitroStack MCP server, connects the real MCP client,
discovers the tools over the protocol, and runs a complete mission in offline
mode — asserting every pipeline stage fired. If this prints `PASS`, the whole
system is wired correctly on your machine.

## The seven tools

| Tool | Input | Output |
|---|---|---|
| `research` | `businessGoal` | summary, insights[], sources[], confidence |
| `finance` | `proposal` | roi, costAnalysis, financialRisk, confidence |
| `risk` | `proposal` | riskScore (0–100), risks[], confidence |
| `compliance` | `proposal` | complianceScore (0–100), issues[], confidence |
| `strategy` | `proposal`, `context` | recommendation, tradeoffs[], priority, confidence |
| `verification` | `allOutputs` | confidenceScore, verificationSummary, contradictions[] |
| `report` | `verifiedResults`, `goal` | executiveReport, confidence |

Each is a **pure** capability: it reasons over its own input via the LLM and
returns validated structured output. Full schemas in [`API.md`](API.md).

## How a mission runs

1. **Discovery** — the orchestrator calls `listTools()` on the MCP server.
2. **Plan** — the Planner (one LLM call) chooses which tools to run, in what
   order, with what inputs — constrained to the discovered tool set.
3. **Execute** — each planned tool runs via `callTool()`, with real retry and
   failure recovery (a failed call is retried, then skipped, never faked).
4. **Verify** — the `verification` tool cross-checks the aggregated outputs.
5. **Vote** — a council vote is **derived from the actual tool outputs**
   (verification confidence ≥ 0.6; risk score ≤ 60), not scripted.
6. **Report** — the `report` tool synthesizes the executive brief.

Every step emits a typed event over WebSocket; the UI is a pure projection of
that event stream. See [`API.md`](API.md) for the event contract and
[`DEMO.md`](DEMO.md) for the judge-facing walkthrough.

## Offline / demo-safety mode (honest by design)

`MOCK_LLM=true` runs the entire pipeline with deterministic, **clearly-labelled**
stub outputs and no API key — for CI, offline development, and as a live-demo
safety net if conference wifi or the API misbehaves. It is **off by default**,
the UI shows a `MOCK LLM` banner whenever it's on, and every stub value is tagged
`[MOCK]`. Nothing fabricated is ever presented as a real model response. The real
default path calls Anthropic.

## Project structure

```
src/
  shared/events.ts            # the typed event contract (backend ⇄ UI)
  llm/provider.ts             # Anthropic provider + labelled offline mock
  servers/tools-mcp/
    tools.ts                  # 7 MCP tools via one DRY factory
    server.ts                 # NitroStack server bootstrap (HTTP transport)
  orchestrator/
    mcpClient.ts              # real MCP client (listTools / callTool)
    planner.ts                # the sole orchestrator: plan→execute→verify→vote→report
    eventBus.ts               # per-mission typed event bus
    server.ts                 # Express static UI + health + WebSocket gateway
frontend/index.html           # Mission Control UI (projection of the event stream)
scripts/
  smoke.ts                    # offline end-to-end test
  patch_frontend.py           # how the UI was wired to the backend (reproducible)
```

## Scripts

| Script | What it does |
|---|---|
| `npm run dev` | Run tools server + orchestrator/UI together (hot reload). |
| `npm run dev:tools` | Run only the NitroStack MCP tools server. |
| `npm run dev:orch` | Run only the orchestrator + UI. |
| `npm run smoke` | Offline end-to-end pipeline test (no key required). |
| `npm run typecheck` | TypeScript type checking. |

## Deployment

The MCP tools server is designed to deploy to **NitroCloud** (git push, auto-SSL,
serverless). Point the orchestrator's `MCP_SERVER_URL` at the deployed URL. See
[`DEPLOY_NITROCLOUD.md`](DEPLOY_NITROCLOUD.md).

## Known limitations

- **Council vote** uses fixed thresholds on real tool outputs; a production
  version would size the council to the mission and let voters reason in natural
  language.
- **No persistence of mission history server-side** — the UI keeps ecosystem
  metrics in `localStorage`; the backend is currently stateless between missions.
- **NitroStack logs a benign OAuth provider warning at startup** when auth isn't
  configured (`Cannot resolve token "OAUTH_CONFIG"`). The server starts and runs
  normally; MADMAX doesn't enable OAuth. It's framework noise, not an error in
  MADMAX.
- **Single MCP server** — the Planner is built to discover across multiple MCP
  servers, but only one (the MADMAX tools server) is wired today.

## Roadmap

1. Multiple MCP servers (e.g. a real ticketing/ERP server) discovered together.
2. Server-side mission history + audit-trail export.
3. Dynamic-size consensus council with natural-language reasoning.
4. Scheduled/triggered missions, not just user-initiated ones.

## License

MIT.