Skip to main content
Glama
poptarts-mcp

poptarts-mcp

by aito-do
README.md
# poptarts-mcp

Public [Model Context Protocol](https://modelcontextprotocol.io/) server for DigitalOcean App Platform.

## Surfaces

| Surface | Behavior |
| --- | --- |
| MCP tool `get_droplet` | Proxies DigitalOcean droplets MCP **`droplet-get`** using `DO_API_TOKEN`, with chaos outcomes. |
| MCP tool `list_droplets` | Proxies **`droplet-list`**. Optional `page` / `perPage`. |
| MCP tool `get_random_poptart_flavor` | Random Pop-Tarts flavor with the **same** chaos outcomes. |
| MCP tools `start_valkey_cpu_burn` / `stop_valkey_cpu_burn` / `get_valkey_cpu_burn_status` | Stackable Valkey CPU burn jobs (Lua `EVAL` loop). |
| `GET /droplet/:id` | Same as `get_droplet` (HTTP **500** on simulated failure). |
| `GET /droplets` | Same as `list_droplets` (`?page=&per_page=`). |
| `GET /flavor` | Same as `get_random_poptart_flavor`. |
| `GET /valkey/cpu-burn` | Active job count + sample of running jobs. |
| `POST /valkey/cpu-burn` | **Stack another** 5-minute burn job (`{ iterations?, durationMs? }`). Alias: `/start`. |
| `POST /valkey/cpu-burn/stop` | Abort **all** burn jobs. |

### Chaos outcomes

Each chaotic request independently picks one of (~25% each):

1. **error_4xx** — simulated client error (`400` / `401` / `403` / `404` / `429`)
2. **error_5xx** — simulated server error (`500` / `502` / `503`)
3. **delayed** — sleep ~10s, then succeed
4. **ok** — succeed immediately

Override with `CHAOS=error_4xx|error_5xx|error|delayed|ok|random` (`error` ≡ `error_5xx`).

### Logging + tracing

Tools emit structured JSON logs: **info** on success, **error** on chaotic failure or DO API errors.

Each tool log includes chosen `traceId` / `spanId` / `traceparent` / `traceSource` when present (no full header dump).

Trace preference order:

1. MCP `_meta.traceparent` / `_meta.tracestate` (MCP SDK `TRACEPARENT_META_KEY`)
2. HTTP `traceparent` / `tracestate`
3. Zipkin B3 `x-b3-traceid` / `x-b3-spanid`
## Local development

```bash
export DO_API_TOKEN=dop_v1_...
npm install
npm run dev
# MCP:      http://127.0.0.1:8080/mcp
# Droplet:  http://127.0.0.1:8080/droplet/123456789
# Droplets: http://127.0.0.1:8080/droplets
# Flavor:   http://127.0.0.1:8080/flavor
# Valkey:   curl -X POST http://127.0.0.1:8080/valkey/cpu-burn -H 'content-type: application/json' -d '{}'
# Health:   http://127.0.0.1:8080/health
```

Environment:

| Variable | Default | Meaning |
| --- | --- | --- |
| `DO_API_TOKEN` | _(required for droplet)_ | DigitalOcean personal access token (Bearer) |
| `VALKEY_URL` | _(required for CPU burn)_ | Valkey URL (`rediss://…`). Also accepts `REDIS_URL` / `DATABASE_URL` |
| `VALKEY_CPU_BURN_ITERATIONS` | `2000000` | Lua loop iterations per `EVAL` |
| `VALKEY_CPU_BURN_DURATION_MS` | `300000` | Per-job lifetime (5 minutes) |
| `VALKEY_CPU_BURN_MAX_JOBS` | `2500` | Cap on concurrent stacked jobs |
| `CHAOS` | `random` | Force `error_4xx`, `error_5xx`, `error`, `delayed`, `ok`, or `random` |
| `CHAOS_DELAY_MS` | `10000` | Sleep when outcome is `delayed` |
| `DROPLET_CHAOS` / `DROPLET_CHAOS_DELAY_MS` | — | Legacy aliases for `CHAOS` / `CHAOS_DELAY_MS` |
| `PORT` | `8080` | HTTP listen port |
| `ALLOWED_HOSTS` | _(unset)_ | Optional Host allowlist |

### Valkey CPU burn

Each `POST /valkey/cpu-burn` (or MCP `start_valkey_cpu_burn`) starts **one** long-lived job: a dedicated Valkey connection that loops a busy Lua `EVAL` for **5 minutes**. Jobs **stack** — fire hundreds/thousands of requests to keep the Valkey command thread pegged. Every request is logged with its parameters. `POST /valkey/cpu-burn/stop` aborts all jobs.

```bash
# Stack many 5-minute jobs
for i in $(seq 1 200); do
  curl -sS -X POST https://<app>/valkey/cpu-burn \
    -H 'content-type: application/json' -d '{}' &
done
wait
```

## Deploy to DigitalOcean App Platform

1. Create the app from `aito-do/poptarts-mcp` (Dockerfile, port `8080`, health `/health`).
2. Set secret `DO_API_TOKEN` in App Platform env (encrypted).
3. Or: `doctl apps create --spec .do/app.yaml` then set the secret in the UI / `doctl`.

```bash
doctl apps create --spec .do/app.yaml
```

## Connect an MCP client

```text
https://<your-app>.ondigitalocean.app/mcp
```

```json
{
  "mcpServers": {
    "poptarts": {
      "url": "https://<your-app>.ondigitalocean.app/mcp"
    }
  }
}
```

## License

MIT