Skip to main content
Glama
README.md
# Maple

Unified MCP server for agent observability, safety control, and behavior evolution.

Maple is the "Sentry + Git" layer for high-agency agents:
- Observe every step
- Replay/fork risky branches
- Audit and intervene with guardrails
- Learn from anonymized traces to evolve safer skills

Built with `mcp-use` + Apps SDK widgets.

## What Is Implemented

### 1) Observability + Control
- `observe_session`: capture and render timeline widget
- `replay_fork`: branch from any step and simulate forward
- `audit_risk`: rule + anomaly risk dashboard
- `guard_action`: allow/block/pending with quarantine support
- `ingest_session_event`: stream external bridge events into active trace

### 2) ML Anomaly Detection (Simple Embeddings)
- `ml_anomaly_report`: embedding-based behavior outlier detection
- Lightweight hash embeddings + cosine similarity baseline
- Supports community baseline from anonymized shared traces

### 3) Network Effects
- `share_trace_anon`: anonymize and publish trace patterns to shared pool
- `suggest_evolved_skills`: generate evolved skill suggestions from shared traces
- Behavior signatures + shared dataset create compound data advantage

### 4) YC App Layer (Moat / Traction / Revenue)
- `yc_app_brief`: live YC-ready narrative generated from product metrics
- Emphasizes:
  - Moat: trace + fork + risk label data flywheel
  - Traction: OpenClaw integration and safety intervention activity
  - Revenue: freemium ladder (Free, Pro $9, Team $29, Enterprise $99)

## MCP Tools

- `observe_session`
- `replay_fork`
- `audit_risk`
- `ml_anomaly_report`
- `guard_action`
- `ingest_session_event`
- `share_trace_anon`
- `suggest_evolved_skills`
- `yc_app_brief`
- `list_traces`
- `export_trace`

## API Endpoints

- `GET /health`
- `GET /judge` (judge standalone page)
- `GET /api/traces`
- `GET /api/traces/:traceId`
- `GET /api/community/stats`
- `GET /api/community/traces`
- `GET /api/yc/brief?focus=full|moat|traction|revenue`
- `GET /api/firewall/state`
- `POST /api/firewall/chat`
- `POST /api/firewall/decision` (strict pre-execution allow/block gate)

## Key Project Files

- `index.ts`: tool + route orchestration
- `src/core/risk-engine.ts`: rule engine + embedding anomaly integration
- `src/ml/embeddings.ts`: simple embedding implementation
- `src/ml/anomaly-detector.ts`: cosine-sim anomaly detection
- `src/network/anonymizer.ts`: anonymized trace transformation
- `src/network/shared-trace-store.ts`: community pool + skill suggestions
- `src/strategy/yc-narrative.ts`: moat/traction/revenue narrative builder
- `resources/trace-timeline/widget.tsx`
- `resources/replay-simulator/widget.tsx`
- `resources/risk-dashboard/widget.tsx`

## Quick Start

```bash
npm install
npm run dev
```

Inspector: `http://localhost:3000/inspector`

## Hardcoded Demo Stack (OpenClaw + Maple)

This repo now includes a one-command hardcoded demo setup:

- OpenClaw gateway on `ws://127.0.0.1:19001`
- OpenClaw bridge adapter on `http://127.0.0.1:8787`
- Maple API key generated at startup (or provided via env)
- Bridge token generated at startup (or provided via env)

```bash
OPENCLAW_VERSION=<pin-a-version> npm run demo:install-openclaw
npm run demo:up
```

Then open:

- Judge GUI: `http://localhost:3000/judge`
- Inspector: `http://localhost:3000/inspector`

### Guided Demo Mode (No Manual JSON)

The Judge GUI now has **Guided Demo Controls** so you can run the full flow without Inspector copy/paste:

1. Enter API key and click `Connect`
2. Click `Run Full Flow`

Or step through:

1. `1) Start`
2. `2) Audit`
3. `3) Block`
4. `4) Fork`

Judge page now includes **Firewall Chat** in Control view:
- Ask natural-language questions ("status update", "why blocked?", "what should we do next?")
- Chat replies are generated from live firewall context (`/api/firewall/state`)

This uses internal demo APIs:

- `POST /api/demo/start`
- `POST /api/demo/audit`
- `POST /api/demo/block`
- `POST /api/demo/fork`
- `POST /api/demo/full`

`demo:up` also auto-opens both pages on macOS (set `DEMO_OPEN_BROWSER=0` to disable).

### Single-Trace Agent Action Logging (Hackathon)

For a reliable judge demo, run one stable trace and append every action to it.

```bash
MAPLE_API_KEY=local-demo-key npm run trace:demo
```

What this does:

- Starts (or reuses) one trace for a stable `sessionId`
- Logs all agent actions through `POST /api/openclaw/events` using the same `traceId`
- Includes `type`, `actor`, `prompt/message`, `command`, `url`, `toolName`, and unique `eventId`
- Runs a preflight firewall preview and logs Maple's block/allow message into the same trace

Open `http://localhost:3000/judge`, then select the printed trace ID to see `#0, #1, #2...`.

If you want to integrate this into your own runtime, use:

- `scripts/maple-trace-logger.mjs`
- `logAction(...)` for generic events
- `logWebGet(...)`, `logMarketplaceSearch(...)`, `logMarketplaceToolCall(...)` wrappers

Example:

```js
import { createMapleTraceLogger } from "./scripts/maple-trace-logger.mjs";

const logger = createMapleTraceLogger({
  baseUrl: "http://localhost:3000",
  apiKey: process.env.MAPLE_API_KEY,
  sessionId: "maple-live",
});

await logger.startRun({ reuseLatest: true });
await logger.logAction({
  type: "tool_call",
  actor: "agent",
  toolName: "web_get",
  prompt: "Fetch provider docs",
  url: "https://docs.mcp.so/providers",
});
```

### Hackathon Gateway Mode (9 Curated MCP Tools)

Canonical startup (local + Railway) for single-source hackathon routing:

```bash
npm start
```

Equivalent local alias:

```bash
npm run hackathon:up
```

This starts a local downstream MCP app (`toolhub`) and route-locks Maple so all downstream calls go through it.
Marketplace mode is canonically disabled in this build; execution only routes through cleared downstream apps.

Included tools (diverse coverage):

1. `web_search` (general web search)
2. `web_fetch` (browser-style page fetch/extraction)
3. `wikipedia_summary` (encyclopedia knowledge)
4. `github_repo_info` (code/repo intelligence)
5. `weather_forecast` (real-time practical data)
6. `slack_post_message` (messaging integration via Slack)
7. `hn_search` (live tech/news discovery on Hacker News)
8. `arxiv_search` (academic/research paper search)
9. `openlibrary_search` (books and publication lookup)

Slack config for `slack_post_message`:

- Incoming webhook mode: set `SLACK_WEBHOOK_URL`
- Bot mode: set `SLACK_BOT_TOKEN` and optionally `SLACK_DEFAULT_CHANNEL`

Verify wiring end-to-end:

```bash
npm run hackathon:verify
```

Stop services:

```bash
npm run hackathon:down
```

Implementation files:

- `scripts/hackathon-toolhub.mjs` (downstream MCP server with 9 tools)
- `scripts/hackathon-up.sh` (starts toolhub + Maple in deterministic route-lock mode)
- `scripts/hackathon-verify.sh` (smoke tests for routed tool calls through Maple)
- `scripts/hackathon-down.sh` (stops Maple + toolhub)

Stop local demo processes:

```bash
npm run demo:down
```

## Environment

```bash
MCP_URL=http://localhost:3000
OPENCLAW_BRIDGE_URL=http://localhost:8787
OPENCLAW_BRIDGE_TOKEN=your_token
MAPLE_API_KEY=your_long_random_key
MAPLE_LOCK_BRIDGE_TARGET=true
```

`observe_session` falls back to mock only when `source=auto`.
For `source=openclaw`, bridge failures are returned as errors (no silent mock downgrade).

### API Key Auth

- Auth methods: `x-api-key: <key>` or `Authorization: Bearer <key>`
- Protected surfaces: MCP endpoints (`/mcp`, `/sse`) and internal APIs (`/api/*`)
- Auth is fail-closed by default. Set `MAPLE_API_KEY` or `MAPLE_API_KEYS`.
- Optional local-only bypass: `MAPLE_ALLOW_NO_AUTH=true` (not recommended).
- `GET /health` remains public for deployment health checks

### Bridge Lockdown (Maple-First Routing)

- Set `MAPLE_LOCK_BRIDGE_TARGET=true` to deny per-request `bridgeUrl` / `token` overrides.
- Bridge override is denied by default.
- Optional local-only override: `MAPLE_ALLOW_BRIDGE_OVERRIDE=true`.
- In production, bridge override lock is enabled automatically.
- In production, `OPENCLAW_BRIDGE_URL` and `OPENCLAW_BRIDGE_TOKEN` must be explicitly set.
- This forces all OpenClaw bridge traffic through configured `OPENCLAW_BRIDGE_URL` + `OPENCLAW_BRIDGE_TOKEN`.
- Override attempts return `403 Bridge override denied`.

### Pre-Execution Firewall Decision API

- `POST /api/firewall/decision` evaluates a candidate action before execution.
- `enforce=true` (default): persist decision into trace and quarantine on deny.
- `enforce=false`: preview mode (no trace mutation), useful for dry-run checks.

### Firewall Status Chat API

- `GET /api/firewall/state` returns normalized live firewall context for a trace/session.
- `POST /api/firewall/chat` answers status questions using that context.
- Body accepts `message`, optional `traceId` / `sessionId`, and `includeContext`.
- `POST /api/chat/stream` powers the Judge UI chatbot and can use AI with provider fallback.
- If `OPENAI_API_KEY` and/or `ANTHROPIC_API_KEY` are set, Maple enables AI mode with automatic fallback.
- If both model providers fail, Maple falls back to deterministic rules-based firewall answers.

Optional chat model environment variables:

```bash
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
MAPLE_FIREWALL_CHAT_PRIMARY=openai   # openai | anthropic
MAPLE_FIREWALL_CHAT_OPENAI_MODEL=gpt-4o-mini
MAPLE_FIREWALL_CHAT_ANTHROPIC_MODEL=claude-sonnet-4-6
MAPLE_FIREWALL_CHAT_TIMEOUT_MS=15000
```

### Firewall Hardening (mcpwall-inspired)

Maple now enforces deterministic firewall policy checks on every trace step before risk scoring:

- First-match rules for high-risk behavior (`pipe-to-shell`, destructive commands, credential/secret access)
- Secret scanning + in-place redaction with marker: `[REDACTED BY MAPLE]`
- Automatic quarantine (`guardStatus=block`) when deny rules hit
- JSONL firewall audit logs at `~/.maple/firewall-logs/YYYY-MM-DD.jsonl`

Optional environment variables:

```bash
MAPLE_FIREWALL_ENABLED=true
MAPLE_FIREWALL_DEFAULT_ACTION=allow   # allow | deny | log_only
MAPLE_FIREWALL_LOG_DIR=~/.maple/firewall-logs
```

## Demo Script (2-3 min)

1. `observe_session` on an OpenClaw session
2. `audit_risk` to surface risky steps
3. `ml_anomaly_report` to show embedding anomalies
4. `guard_action` block a risky step
5. `replay_fork` from blocked step with safe edits
6. `share_trace_anon` to publish anonymized pattern
7. `suggest_evolved_skills` from community data
8. `yc_app_brief` to show moat/traction/revenue narrative

## Example Calls

```json
{
  "tool": "ml_anomaly_report",
  "input": {
    "traceId": "<trace-id>",
    "useCommunityBaseline": true,
    "threshold": 0.58,
    "topAnomalies": 5
  }
}
```

```json
{
  "tool": "share_trace_anon",
  "input": {
    "traceId": "<trace-id>",
    "taskLabel": "Inbox triage",
    "objective": "Safely automate inbound support triage",
    "tags": ["support", "email", "guarded"]
  }
}
```

```json
{
  "tool": "suggest_evolved_skills",
  "input": {
    "query": "safe inbox triage automation",
    "limit": 3,
    "minConfidence": 0.4
  }
}
```

## Current Limits

- Persistence is in-memory for hackathon speed
- Embedding model is intentionally simple (fast + local)
- External model providers are optional for firewall chat; rules mode works without them

## Deploy

```bash
npm run deploy
```

### Railway Deployment (Recommended)

Yes, Maple can run on Railway with production safeguards.

This repo now includes `railway.json`, so Railway can use canonical settings automatically:

- Build command: `npm run build`
- Start command: `npm run start`
- Health check path: `/health`

Required environment variables:

```bash
NODE_ENV=production
HOST=0.0.0.0
MCP_URL=https://<your-railway-domain>
MAPLE_API_KEY=<long-random-key>
MAPLE_LOCK_BRIDGE_TARGET=true
OPENCLAW_BRIDGE_URL=<bridge-url-reachable-from-railway>
OPENCLAW_BRIDGE_TOKEN=<bridge-token>
MAPLE_FIREWALL_ENABLED=true
```

Important notes:

- Railway provides `PORT` automatically; do not hardcode it.
- `scripts/hackathon-start.sh` is Railway-safe and no longer requires a local `.env` file to boot.
- In production, Maple enforces API key auth and requires explicit `OPENCLAW_BRIDGE_URL` + `OPENCLAW_BRIDGE_TOKEN`.
- Do not use `localhost` for `OPENCLAW_BRIDGE_URL` unless the bridge runs in the same container.
- If bridge connectivity is unavailable during demo, use `source=mock` to keep UI + guardrail flow live.