Skip to main content
Glama
README.md
# foro-demo-mcp

A tiny **demo MCP server in TypeScript** with no build step — five tools, streamable HTTP, made to deploy on [foro.sh](https://foro.sh) in about a minute.

## Tools

| Tool | What it does |
| --- | --- |
| `hello` | Greet someone — proves the round trip works |
| `roll_dice` | Roll `count` dice with `sides` faces |
| `remember` | Store a value under a key (in-memory) |
| `recall` | Read a value back — state persists between calls |
| `whoami` | Show the caller's verified identity (`X-Foro-*` headers) |
| `get_my_orders` | Pattern A demo: call your backend as the verified user |
| `server_info` | Runtime info: port, node version, uptime (never secrets) |

## Auth: two sides

```
[User + AI client] ──① inbound: who calls?──▶ foro gate ──▶ your tool code ──② outbound──▶ your backend
                      token or OAuth JWT       injects X-Foro-*    reads identity        service key + X-User-Id
```

- **① Inbound (foro handles it):** Settings → Server access → `token` (one shared
  bearer token, no per-user identity) or `oauth` (each user signs in; the gate
  verifies their JWT and injects `X-Foro-Subject` / `X-Foro-Org` / `X-Foro-Scopes`,
  stripping anything the client tried to spoof). `whoami` shows what arrives.
- **② Outbound (you write it):** set `BACKEND_URL` (plain) and `BACKEND_API_KEY`
  (secret) in foro → Secrets, redeploy. `get_my_orders` then calls your backend
  with the service key **plus** `X-User-Id` from the gate, so your backend knows
  *which* user the call is on behalf of (Pattern A).

Never ask users to paste their backend API key as a tool argument — it would end
up in LLM context and transcripts. Identity arrives as a gate-verified header.

## Run locally

```sh
npm install
npm start          # → http://0.0.0.0:8000/mcp  (PORT env var overrides)
```

No `tsc`, no bundler: Node ≥ 22.18 runs the TypeScript directly via native type stripping.

## Deploy on foro.sh

1. Sign in at [foro.sh](https://foro.sh) with GitHub
2. **New project → I have a repo** → pick this repo, branch `main`
3. Click **Deploy** — foro reads `package.json` (`main`, `engines`), installs with npm, health-checks, and goes live
4. Copy your `https://<slug>.foro.sh` URL and project bearer token from the Overview tab

foro injects `PORT`, which this server reads automatically. State in `remember`/`recall` lives in the container's memory until it restarts.

## Connect an agent

**Claude Desktop / Claude Code** (Settings → Developers → Edit Config):

```json
{
  "mcpServers": {
    "foro-demo": {
      "type": "http",
      "url": "https://<slug>.foro.sh/mcp",
      "headers": { "Authorization": "Bearer <your-foro-token>" }
    }
  }
}
```

**OpenCode** (`opencode.json`):

```json
{
  "mcp": {
    "servers": {
      "foro-demo": {
        "type": "remote",
        "url": "https://<slug>.foro.sh/mcp",
        "oauth": false,
        "headers": { "Authorization": "Bearer {env:FORO_DEMO_TOKEN}" }
      }
    }
  }
}
```

Any client that speaks MCP over streamable HTTP works — Cursor, VS Code, Windsurf, Codex.

## Notes

- Stateless HTTP mode: a fresh server + transport per request, no session tracking
- The bearer-token check is performed by foro's gate in front of this server
- `server_info` deliberately reports only non-sensitive values

## License

MIT