mcp-app-harness
mcp-app-harness
A small, working reference implementation of the pattern behind an RL-training sandbox: take a real application, run it in a container, and expose it to an agent through a FastMCP server — with populate / snapshot / restore hooks so every episode starts from an identical, known state and any trajectory can be checkpointed and rewound.
It's deliberately tiny (a support-desk service + its MCP integration) so the seams are visible. Swap the demo app for any web/desktop app and the harness structure is unchanged.
┌────────────────┐ MCP tools/resources ┌────────────────────┐
│ Agent / RL │ ───────────────────────────────▶ │ FastMCP harness │
│ policy │ create_ticket, populate, │ (mcp_harness/) │
└────────────────┘ snapshot, restore, tickets://all └─────────┬──────────┘
│ HTTP (httpx)
▼
┌────────────────────┐
│ App under test │
│ FastAPI + SQLite │
│ (app/) │
└────────────────────┘Why this exists
Integrating an app into a sandbox has three hard parts, and this repo shows a clean answer to each:
Expose the app to an agent. Every product operation is a typed MCP tool (
mcp_harness/server.py) and live state is an MCP resource. Schemas come free from the type hints.Make state reproducible.
populate()seeds a deterministic baseline;snapshot()captures full state;restore()re-applies it.restore(snapshot(x)) == xis asserted in the tests (tests/test_hooks.py).Keep it testable locally. The HTTP client is transport-injectable, so the whole stack runs in-process over
httpx.ASGITransportin CI — no sockets, no flakiness — while production uses real HTTP unchanged.
Layout
Path | Role |
| The application under test — a FastAPI + SQLite support desk. Stands in for the third-party app you'd integrate. Ships an |
| The FastMCP server — product tools + lifecycle tools + resources. |
| Transport-injectable async HTTP client to the app. |
|
|
| Env-driven service configuration (12-factor). |
| Deterministic starting state for |
| pytest: app, hooks, and the MCP tools driven via FastMCP's in-memory client. |
| One image, two services (app + harness), healthcheck-ordered boot. |
Run it
Tests (fastest way to see it work):
uv venv --python 3.12 && source .venv/bin/activate
uv pip install -e ".[dev]"
pytest -qLocally, two processes:
# terminal 1 — the app under test
./scripts/run_app.sh # http://localhost:8080/health
# terminal 2 — an episode: populate → act → snapshot → reset → restore
./scripts/demo_episode.shThe MCP server:
python -m mcp_harness.server # stdio (embed in an agent runtime)
MCP_TRANSPORT=http python -m mcp_harness.server # HTTP transport on :9000In a sandbox (Docker):
docker compose up --build
# app → :8080 | MCP harness (HTTP) → :9000The MCP surface
Tools: create_ticket, list_tickets, get_ticket, assign_ticket, close_ticket,
populate, snapshot, restore.
Resources: tickets://all (live ticket list), health://app (liveness).
An agent's loop looks like: populate() → read tickets://all → call ticket tools →
snapshot() to checkpoint. An RL runner scores the resulting state and restore()s to
branch a new rollout.
Configuration (all via env — no code changes between environments)
Var | Default | Meaning |
|
| Where the harness reaches the app |
|
| SQLite path for the app ( |
|
|
|
|
| HTTP transport bind |
|
| Baseline for |
|
| Client timeout (short, so a wedged app fails fast) |
Adapting to a real app
app/ is the throwaway part. To integrate a real app:
Point
AppClient(or a subclass) at the app's actual API.Re-implement the three hooks against whatever state seam the app exposes — a DB volume snapshot, a
docker commit, an export/import endpoint, or a management command. The tool/resource layer and the tests don't change.
License
MIT.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/tachyurgy/mcp-app-harness'
If you have feedback or need assistance with the MCP directory API, please join our Discord server