Skip to content

MCP integration

The backend exposes an MCP server at /mcp, so an LLM client such as Claude Code or Cursor can browse runs and launch simulations directly. It is mounted inside the existing FastAPI app and protected by OAuth 2.0.

Requires OAUTH_ISSUER_URL, set to the public backend URL (e.g. http://localhost:8000). Without it the endpoint is not mounted.

Connecting

Click MCP on the runs page for copy-paste instructions, or configure manually.

Claude Code:

claude mcp add-json glossogen-runs '{"type":"http","url":"http://localhost:8000/mcp"}'

Cursor, in .cursor/mcp.json:

{
  "mcpServers": {
    "glossogen-runs": {
      "url": "http://localhost:8000/mcp"
    }
  }
}

No auth headers. The client discovers OAuth metadata at /mcp/.well-known/oauth-authorization-server and handles registration, authorization and token refresh on its own, using the authorization-code flow with PKCE and dynamic client registration.

Every token is bound to one group at consent time, so each tool call is scoped automatically:

  • Local mode auto-approves to the synthetic local group.
  • Multi-tenant mode parks the authorization request and redirects the browser to the frontend at /mcp-consent?request_id=..., where the user signs in and picks which organization to authorize. The page posts the choice back, the backend mints the code bound to that group_id, and redirects to the client's callback. The parking, the consent page and the code minting are platform code; the sign-in and the endpoint that verifies the posted session come from the installed identity provider.

Access tokens last an hour, refresh tokens thirty days. Token state lives in Postgres, or in memory in no-database local mode, where re-authenticating after a restart is the only consequence.

Tools

Tool Does
list_scenarios Available scenarios with their knobs presets, metrics and supported models
list_runs Paginated, filterable by scenario, model, fork status, run status and labels
get_run_metadata Agents, channels, configuration, evaluation summary, labels, and lineage: parent_run_id plus fork_source, replace_agent_source, fork_at_round_source and cross_run_replace_agent_source
list_derived_runs Every run derived from a parent, with derivation type, round boundaries and headline scores
get_run Full content with messages; opt-in reasoning, tool use, debug logs, system prompts
get_knobs_schema A scenario's knobs JSON Schema plus its preset names
get_knobs_preset One preset's payload
start_run Launch a simulation with scenario, model, provider and knobs
export_run_artifacts Download URL for a tar.gz bundle of the run directory
export_agent_thread One agent's thread as a drop-in Anthropic or OpenAI request body
export_agent_atif One agent as ATIF trajectories, one per generation of its seat

A run-start conversation usually goes: get_knobs_schema to see the fields and preset names, get_knobs_preset to load a baseline, then start_run with the model, provider and final knobs. start_run validates provider names and agent ids in model_overrides before launching, so a typo fails fast instead of producing a misconfigured run.

list_derived_runs reads the runs-index parent linkage, so it can return fewer runs than a grouping label that spans a whole experiment family.

From the CLI

The same OAuth flow gives the CLI a way to talk to a deployed, authenticated backend. It calls the existing REST endpoints. There is no separate upload feature on the server.

# One-time: sign in. Opens the browser to the consent page; the CLI's
# loopback server collects the code and writes ~/.glossogen/credentials.json (0600).
# It prints the group the token is bound to, which the file also records.
glossogen login --url https://your-backend.example.com

# Diff local runs against the remote and upload what is missing. Idempotent on
# run_id, so re-running is safe.
glossogen push-to-prod --label baseline --runs-dir ./runs

push-to-prod flags:

  • --scenario <name> (repeatable) restricts to specific scenarios.
  • --label <label> (repeatable, AND) requires every listed label.
  • --include-incomplete allows runs with no evaluation report. By default those are skipped, which is what keeps crashed runs out.
  • --dry-run prints the diff without sending bytes.
  • --concurrency N (default 1, clamped to 16) parallelizes uploads. Keep it small: each upload holds its bundle in memory.

For runs already on the remote whose local labels or report have since changed:

glossogen sync-metadata-to-prod --runs-dir ./runs

It PUTs local labels when they differ from the remote's, and the local evaluation report when its measurements differ from the remote copy's, treating local as the source of truth. It also PUTs every local label description the remote is missing or records differently, and leaves descriptions only the remote has alone. Same --scenario and --dry-run flags, though the glossary sync ignores --scenario because the glossary belongs to the group. --concurrency defaults to 4 (clamped to 8), higher than push-to-prod because the bodies are a label list and a JSON report rather than a bundle.

The identity middleware accepts an MCP OAuth bearer for /mcp/* tool calls and for /api/g/{slug}/... REST calls alike, so one token covers browsing in Claude Code, pushing bundles and syncing labels.