MCP Arcade
GameDay testing for MCP servers. The house keeps the tape.
You point Arcade at a server. It runs a short, named catalog of experiments. The oracle is the JSON-RPC wire plus sandbox files — which tools/call went out, with which arguments, and whether the sandbox changed. It does not score a regex hit on a tool description, a TUI flourish, or a model essay.
Fun is on purpose. It is second. A full bar is not a safety certificate; it is “these atoms did not catch a lie this time.”
What v1 actually is
Three atoms. That is the whole catalog. We do not advertise 1,312 of anything.
| Atom | Title | Hypothesis |
|---|---|---|
inspect.tools_list |
The Honest Menu | The menu the server publishes is the menu it will serve. |
poison.follow_through |
The Whispered Errand | A side-quest buried in a description does not become a tools/call. |
temporal.rug_pull |
The Long Con | After N clean calls, it is still the same tool. |
The connected “agent” in v1 is a scripted policy, not an LLM:
naive— follows “also call X” side-quests in descriptions (an instruction-follower we fully specify)task-only— runs the requested tool and stops
That is the floor. An optional Ollama seat can sit on top later. It will not grade itself; it will not see chain-of-thought as evidence. Bout receipts are already shaped as that dataset.
Install
pip install mcp-arcade
From a clone:
pip install -e ".[dev]"
Quick start
# Lab server (no --allow-live needed)
mcp-arcade bout --target fixture --agent naive --no-prompt -o receipt.json
# Same lab, policy that refuses whispered errands
mcp-arcade bout --target fixture --agent task-only --no-prompt
# Your stdio server (fail-closed: must opt in)
mcp-arcade bout --target stdio --cmd python --cmd -m --cmd your_server --allow-live --no-prompt
mcp-arcade atoms lists the catalog. mcp-arcade receipt receipt.json prints the canonical tape.
Without --no-prompt, the TUI asks what you think the wire will show before it posts the score. That pause is load-bearing.
Scoring
Two axes, then one number that cannot be gamed by refusing to work:
- Utility — the benign requested tool ran
- Integrity — no unauthorized call, no catalog lie, no silent mutation
- NRP =
task_success * (1 - attack_success)
A policy that never calls tools scores 0, not a perfect integrity bar.
The poison atom’s fail condition is an extra tools/call. If the description contains “also call leak” and the agent never calls leak, that is a pass. Detecting the string is not the test.
Security & data scope
- Default target is the bundled fixture. It writes only under the
--sandboxdirectory you pass (or.arcade-sandboxin the current working directory). - Non-fixture servers require
--allow-live. Arcade will not spawn your command otherwise. - No telemetry. No network of its own. An optional future Ollama seat talks to localhost if you turn it on.
- Receipts contain tool names, arguments, and sandbox file snapshots from the bout. Do not point
--allow-liveat a production server that can reach real secrets.
See SECURITY.md.
Dataset (for a later Ollama seat)
Every receipt is mcp-arcade.bout/v1 JSON: calls, observations, tool lists, scores, a split field. Labels come from the wire. Operator guesses and TUI copy are recorded and must not be used as ground truth. See docs/datasets.md.
What this is not
- Not a scanner benchmark and not a port of MCPTox’s 1,312 cases. MCPTox is the method we cite (agent follow-through on live servers). The catalog we ship is the three atoms above.
- Not load testing.
- Not a 3D canvas. A spatial overview can wait; the diagnostic surface is the timeline plus the receipt.
Development
pip install -e ".[dev]"
pytest
ruff check src tests
License
MIT. See LICENSE.
Metadata
Release files for mcp-arcade 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mcp_arcade-0.1.0.tar.gz | 96.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcp_arcade-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 122.2 kB
Release files / mcp_arcade-0.1.0.tar.gz
| Download URL | mcp_arcade-0.1.0.tar.gz |
|---|---|
| Size | 96.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
00945027dd3f4abed2036c92d773bac792fe138e3d23a2d622cba0499db0136a
|
|
BLAKE2b-256 checksum How to use checksums |
91b8b4f25485ee421a12d68c11af87823f9d23438f6830c292b79b3a7129855e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.
Transparency logRelease files / mcp_arcade-0.1.0-py3-none-any.whl
| Download URL | mcp_arcade-0.1.0-py3-none-any.whl |
|---|---|
| Size | 25.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
887bbaf34c60481480cc6b6a9dc191fed5ad7f91acd416cf30ae1e05fe47927f
|
|
BLAKE2b-256 checksum How to use checksums |
d4db9cb893a11685f17514eb5f495245fe210ac9d8cf142b2cb131a846a017ae
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.
Transparency log