Skip to content

MCP over HTTP

Core vx ships a per-workspace, process-private MCP server over stdio (vx mcp — see vx mcp (core)). The vx Cloud platform also exposes MCP over HTTP so an AI agent can read run history and analytics from a deployment, across every workspace in an org.

The self-hosted platform serves MCP at POST /mcp — dependency-free (JSON-RPC 2.0, protocol 2025-03-26, no SDK), behind the platform’s account/token auth and tenant-clamped by org and workspace. An AI agent points at your deployment with a minted vxc_ API token and reads the same metrics the dashboard shows (a workspace-scoped token is pinned to its workspace):

// Claude Code, pointing at your deployment
{
"mcpServers": {
"vx-team": {
"url": "https://vx.example.com/mcp",
"headers": { "Authorization": "Bearer vxc_..." }
}
}
}

The HTTP tools read from Postgres — the platform’s system of record — so they work even though the platform holds no workspace checkout or local cache.db:

ToolArgumentsWhat it answers
list_workspacesEvery workspace in the org: id, name, slug, last seen, run count
list_runsworkspace?, limit? (default 50, ≤500)Recent vx run invocations, newest first: command, branch/commit, CI, task/failed/hit counts, duration
get_runrunId, workspace?One run in full — the invocation header plus every per-task outcome (found: false for an unknown id)
run_trendsworkspace?, bucket? (hour|day, default hour), limit? (≤1000)Workspace-wide bucketed activity over time: run counts, failure counts, cache hits per bucket
cache_statsworkspace?Cache effectiveness: entries/bytes, last-24h runs + hits, local-vs-remote hit split
why_did_rerunrunId, taskId (project#task), workspace?Why the task re-executed — hash change vs the previous run + the per-component input diff
compare_runsrunId, workspace?Diff the run against its immediately-previous invocation: per-task duration/status/hash deltas + totals

Every tool takes an optional workspace argument (a workspace id from list_workspaces), defaulting to the org’s most-recently-seen workspace. A workspace-scoped token is pinned to its own workspace — the argument is ignored; an explicitly-named unknown workspace returns an isError result, never another tenant’s data, and every read is clamped to the token’s org.

Arguments are honoured or refused, never quietly reinterpreted. The bounds in the table above are enforced, not just advertised: a limit of the wrong type ("10", null, an array) or a non-finite one, and a bucket outside its enum, all come back as isError results naming the argument. A limit that is a real number but out of range still clamps to the stated bounds — the refusal is for values with no honest reading, so an agent never receives a confident answer to a question it did not ask.

Errors and batching: an unknown tool or missing required argument comes back as a JSON-RPC error / isError tool result with the message in the body. The endpoint accepts a single JSON-RPC message or a batch (an array); a POST containing only notifications is answered 202 with no body (the streamable-HTTP contract for non-streaming servers).

Mint the token under Admin → Tokens. See Self-hosting to deploy the platform, and the HTTP API reference for the raw /v1 routes behind these tools.

  • vx mcp (core, stdio) — per-developer, per-workspace, process-private; reads the local cache.db. No server, no auth.
  • POST /mcp (this page) — team-wide, org/workspace-clamped; reads Postgres on a deployment. Needs a vxc_ token.

See also: Dashboard — the same analytics as a UI.