Skip to main content
Glama
README.md
# mcp-sandbox

**A free, open MCP server for developers and GenAI evaluations.**

Every tool returns a stable, improbable **canary token** โ€” something a model
would never volunteer on its own. If the token shows up in a response, the call
really reached this Model Context Protocol (MCP) server. If it doesn't, the tool
was never invoked. That makes it a clean fixture for learning MCP, wiring up
clients, and asserting on tool calls in CI and evals.

๐ŸŒ **Live server:** `https://mcp.heptafox.com/mcp`  ยท  ๐Ÿ“– **Guide:** [mcp.heptafox.com](https://mcp.heptafox.com/)

---

## What is mcp-sandbox?

A public [MCP](https://modelcontextprotocol.io) server of **deterministic test
fixtures**. Each tool returns a fixed canary string instead of real data, so you
can prove a response originated from the server rather than the model's training
or context.

## Why use it?

When you're building or testing an agent, you usually *don't* want to point it at
a production MCP server. You want a deterministic endpoint that always returns a
known value. mcp-sandbox is that endpoint:

- ๐ŸŽ“ **Learn MCP** โ€” connect a real server in minutes, no API keys or data setup.
- ๐Ÿ”Œ **Test clients** โ€” confirm your client actually calls tools and relays output.
- โœ… **Verify integrations** โ€” prove the MCP layer works end to end.
- ๐Ÿšฆ **Smoke tests** โ€” a one-call health check for CI/CD pipelines.
- ๐Ÿงช **Automated evals** โ€” assert on a stable token, not on fuzzy model prose.

## Who is it for?

Developers learning MCP ยท AI application & agent-framework developers ยท QA
engineers ยท GenAI evaluation frameworks ยท CI/CD integration testing.

## Supported MCP clients

Works with any MCP-compatible client over streamable HTTP, including:

Claude Desktop ยท Claude Code ยท Cursor ยท Google ADK ยท LangChain ยท CrewAI ยท
OpenAI Agents SDK ยท MCP Inspector

## Features

- โœจ **Stable canary tokens** โ€” deterministic output you can assert on exactly.
- ๐ŸŒ **Streamable HTTP transport** โ€” the modern MCP transport, endpoint `/mcp`.
- ๐Ÿ”‘ **Bearer-token auth check** โ€” a tool to verify auth reached the server.
- ๐Ÿชถ **Zero setup** โ€” no API keys, no accounts, no data.
- ๐Ÿ†“ **Free & open source** โ€” Apache-2.0.

## Learning progression

The tools are ordered so you can climb from "is it connected?" to "did auth
arrive?" one concept at a time:

| Level | Tool         | Auth   | Params | Teaches            |
|:-----:|--------------|:------:|:------:|--------------------|
| 1     | `identity`   | No     | No     | Connectivity       |
| 2     | `echo`       | No     | Yes    | Passing parameters |
| 3     | `auth_check` | Bearer | No     | Authentication     |

## Tools

### `identity` โ€” connectivity check
No params. Returns a fixed ID string. Show it verbatim to confirm the server answered.

```
MCP-SANDBOX canary 7Q9X-ZK42-VORTEX-PARSNIP
```

### `echo` โ€” parameter passing
Params: `message: str`, `repeat: int = 1`. Sends your text through the server and
returns it inside a fixed wrapper, repeated `repeat` times.

```
MCP-SANDBOX echo 4F7T-ECHO-START >>> your text <<< 4F7T-ECHO-END
```

### `auth_check` โ€” authentication
No params (reads the `Authorization` header). Verifies the server saw your
`Bearer` token.

```
MCP-SANDBOX auth OK 9B3K-AUTHED-MARIGOLD      # valid token
MCP-SANDBOX auth FAIL 9B3K-NOAUTH-CINDER      # missing/invalid token
```

## Authentication

`auth_check` is gated by a **public development Bearer token**:

```
Authorization: Bearer mcp-sandbox-dev-C7H2-KPMERCHANT
```

This is a shared smoke-test token for integration testing โ€” **it is public and
is NOT a production credential.** It only gates `auth_check`.

## Quick Start

### Use the hosted server

**Claude Code** โ€” one command:

```bash
claude mcp add --transport http mcp-sandbox https://mcp.heptafox.com/mcp \
  --header "Authorization: Bearer mcp-sandbox-dev-C7H2-KPMERCHANT"
```

**Claude Desktop** โ€” config is stdio-only, so bridge through `mcp-remote` in
`claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "mcp-sandbox": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote", "https://mcp.heptafox.com/mcp",
        "--header", "Authorization: Bearer mcp-sandbox-dev-C7H2-KPMERCHANT"
      ]
    }
  }
}
```

**Raw HTTP** โ€” call the endpoint directly:

```bash
curl -X POST https://mcp.heptafox.com/mcp \
  -H "Authorization: Bearer mcp-sandbox-dev-C7H2-KPMERCHANT" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
       "params":{"name":"identity","arguments":{}}}'
```

> **Endpoint is `/mcp` โ€” no trailing slash.** `/mcp/` 307-redirects to `/mcp`,
> and some clients drop the POST body across the redirect. Always use `/mcp`.

### Run it locally

```bash
uv sync
uv run server.py        # guide at http://127.0.0.1:8000/ , MCP at /mcp
```

Inspect it with the MCP Inspector โ€” point it at `http://127.0.0.1:8000/mcp`:

```bash
npx @modelcontextprotocol/inspector
```

## Examples

Ask any connected model to call a tool, then assert on the token it relays:

> **Prompt:** Call the mcp-sandbox `identity` tool and show me what it returned.
>
> **Expected:** `MCP-SANDBOX canary 7Q9X-ZK42-VORTEX-PARSNIP`

If the token appears, the call reached this server. If the model answers without
it, the tool was never invoked.

## QA & GenAI Evaluations

In evals, **assert on the raw tool result** (`result.content[0].text`), not on the
model's natural-language summary โ€” the token is stable, the wording isn't.

```python
import asyncio
from fastmcp import Client

async def main():
    async with Client("https://mcp.heptafox.com/mcp") as c:
        result = await c.call_tool("identity", {})
        assert "7Q9X-ZK42-VORTEX-PARSNIP" in result.content[0].text

asyncio.run(main())
```

## Roadmap

- More beginner-friendly tools (error simulation, streaming, structured output)
- OAuth and additional authentication examples
- Client integration examples (Cursor, Google ADK, LangChain, CrewAI, OpenAI Agents SDK)
- Ready-made evaluation scenarios and tutorials

Have an idea? [Open an issue or discussion.](https://github.com/heptafox/mcp-sandbox/issues)

## Contributing

Contributions are welcome โ€” especially beginner-friendly tools, client examples,
and docs. New tools are just `@mcp.tool` functions in `server.py`, each returning
a unique canary string. See [CONTRIBUTING.md](CONTRIBUTING.md) to get started.

## Deploy your own

The hosted instance runs on AWS Lightsail (Ubuntu) behind nginx + Let's Encrypt.
To self-host: `uv sync`, run via `deploy/mcp-sandbox.service` (systemd), front
with `deploy/nginx.conf` + `certbot --nginx -d <domain>`, and open ports 80/443
only โ€” the app binds to localhost and nginx proxies `/mcp` in. Step-by-step below.

<details>
<summary>Full deploy steps (AWS Lightsail, Ubuntu)</summary>

1. **Instance + DNS** โ€” create an Ubuntu Lightsail instance, point your domain's
   A record at its static IP, and open ports **80 + 443** in the Lightsail
   firewall. Leave 8000 closed; the app listens on localhost only.
2. **App**
   ```bash
   curl -LsSf https://astral.sh/uv/install.sh | sh
   git clone <repo> ~/mcp-sandbox && cd ~/mcp-sandbox && uv sync
   ```
3. **systemd** โ€” copy `deploy/mcp-sandbox.service` to `/etc/systemd/system/`, then:
   ```bash
   sudo systemctl daemon-reload
   sudo systemctl enable --now mcp-sandbox
   ```
4. **nginx + TLS**
   ```bash
   sudo apt install -y nginx certbot python3-certbot-nginx
   # deploy/nginx.conf is set for mcp.heptafox.com; copy to /etc/nginx/sites-available/,
   # symlink into sites-enabled/, then:
   sudo certbot --nginx -d mcp.heptafox.com
   sudo systemctl reload nginx
   ```

Verify: `systemctl status mcp-sandbox` and `curl -i https://<domain>/mcp`.

</details>

## License

[Apache License 2.0](LICENSE). By contributing you agree your contributions are
licensed under Apache-2.0.