Skip to content

Programmatic Access: REST API & MCP Server

Beyond the CLI, AOBench exposes its benchmark engine over two machine surfaces so other tools and agents can run tasks, score traces, and read results programmatically:

  • a REST API (FastAPI) β€” HTTP access for any language or client;
  • a FastMCP server β€” the same engine exposed as Model Context Protocol tools and resources, so an MCP client (an agent) can drive the benchmark directly.

Both are thin transports over one shared BenchmarkService faΓ§ade, so a run started over REST, over MCP, or from the CLI produces identical scores.

Each surface is an optional extra β€” install only what you need:

uv sync --extra rest      # REST API (fastapi + uvicorn)
uv sync --extra mcp       # FastMCP server
uv sync --extra rest --extra mcp --extra otel   # everything (list all together)

Install extras together

Per-extra uv sync is exclusive β€” uv sync --extra mcp will remove fastapi. To keep multiple surfaces installed, list every extra in one command as shown above.


REST API

Start the server

The simplest way is the CLI:

uv run aobench serve rest --host 0.0.0.0 --port 8000
# OpenAPI docs at http://localhost:8000/docs  (schema at /openapi.json, OpenAPI 3.1)

Or embed it β€” create_app() returns a standard FastAPI application:

# serve.py
import uvicorn
from aobench.server.rest.app import create_app

app = create_app()          # uses AOBENCH_BENCHMARK_ROOT / AOBENCH_OUTPUT_ROOT env
if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

Authentication

An API key maps to an HPC role. Configure keys via AOBENCH_API_KEYS as a comma-separated key:role list; pass the key in the X-API-Key header:

export AOBENCH_API_KEYS="prod-key-1:hpc_user,admin-key:admin"
export AOBENCH_RATE_LIMIT_PER_MIN=1000        # optional; default 10000

When AOBENCH_API_KEYS is unset, the API runs in open (dev) mode and every request resolves to the admin role β€” convenient locally, but always set keys in production. A request over the per-minute budget receives 429 Too Many Requests.

Endpoints

Method & path Purpose
GET /health Liveness probe (no auth)
POST /v1/runs?wait=true Run a task against an env synchronously; returns run_id + score
POST /v1/runs?wait=false Enqueue as a tracked job; returns a job record to poll
GET /v1/jobs/{job_id} Poll a job's state (queued/running/completed/failed)
GET /v1/jobs List submitted jobs
GET /v1/runs/{run_id} Run record (task count, aggregate score, hard-fails)
GET /v1/runs/{run_id}/trace?task_id= Full execution trace
GET /v1/runs/{run_id}/report?format=json Scorecard summary (json/summary/clear)
GET /v1/runs/{run_id}/events SSE stream: replays trace steps, then a done event
POST /v1/score Score a supplied trace against a task (no re-run)
POST /v1/compare Compare two runs (score delta)
POST /v1/robustness Run a task n times; mean/stdev + pass^k
GET /v1/tasks?split=&qcat=&role= List task specs
GET /v1/envs List environment bundles
GET /v1/datasets Versioned splits as datasets

Example

# run one task
curl -s -X POST "http://localhost:8000/v1/runs?wait=true" \
  -H "X-API-Key: admin-key" -H "Content-Type: application/json" \
  -d '{"task_id": "JOB_USR_001", "env_id": "env_01", "adapter": "direct_qa"}'
# β†’ {"run_id": "...", "status": "completed", "aggregate_score": 0.83, ...}

# read its scorecard
curl -s "http://localhost:8000/v1/runs/<run_id>/report?format=clear" \
  -H "X-API-Key: admin-key"

For long sweeps, submit with wait=false to get a job record immediately and poll GET /v1/jobs/{job_id} until its state is terminal. (Single-process job tracking works out of the box; a durable arq/Redis worker is a drop-in backend upgrade.)

Errors map to HTTP status codes: unknown task/env/run/job β†’ 404, locked split or forbidden role β†’ 403, adapter failure β†’ 502, bad report format β†’ 400.


MCP Server (FastMCP)

The FastMCP server exposes the same engine as MCP tools (actions) and resources (read-only catalog/results), targeting MCP spec 2025-11-25.

Start the server

Via the CLI:

uv run aobench serve mcp     # stdio transport

Or embed it:

from aobench.server.mcp import create_server

server = create_server()     # raises RuntimeError if the `mcp` extra is absent
server.run()                 # stdio transport by default

Tools

Tool Purpose
run_task(task_id, env_id, adapter="direct_qa", role=None, seed=None) Run a task; returns run_id + score
score_trace(task_id, trace) Score a captured trace without re-running
validate_benchmark() Loadable task/env counts (health check)
robustness(task_id, env_id, adapter="direct_qa", n=5) Repeat a run; score mean/stdev

Resources

Resource URI Contents
aobench://catalog/tasks All task specs with QCAT/role/split
aobench://catalog/tasks/{task_id} One task's metadata
aobench://catalog/envs All env bundles with manifest fingerprints
aobench://runs/{run_id}/report Scorecard summary for a run
aobench://runs/{run_id}/trace Full execution trace for a run

Authentication (HTTP transport)

For the HTTP transport, enable OAuth 2.1 resource-server auth by setting the JWKS environment variables; the server maps JWT claims to HPC roles:

export AOBENCH_MCP_JWKS_URI="https://issuer.example.com/.well-known/jwks.json"
export AOBENCH_MCP_ISSUER="https://issuer.example.com/"
export AOBENCH_MCP_AUDIENCE="aobench-mcp"

Over the local stdio transport (the default), no auth is required.

Drive it from a client

import asyncio, json
from fastmcp import Client
from aobench.server.mcp import create_server

async def main():
    async with Client(create_server()) as client:
        run = await client.call_tool(
            "run_task",
            {"task_id": "JOB_USR_001", "env_id": "env_01", "adapter": "direct_qa"},
        )
        run_id = run.data["run_id"]
        report = await client.read_resource(f"aobench://runs/{run_id}/report")
        print(json.loads(report[0].text))

asyncio.run(main())

Which surface should I use?

  • REST β€” integrate AOBench into a web app, dashboard, or any HTTP client; run large sweeps behind a stable API.
  • MCP β€” let an agent (Claude, or any MCP client) call the benchmark as native tools, or dogfood MCP tool-use itself.
  • CLI β€” interactive/local use and scripting (see the CLI reference).

All three route through the same faΓ§ade, so results are directly comparable.