MCP

Model Context Protocol (MCP) works in both directions in PlanVault™. Inbound, PlanVault™ is itself an MCP server: an AI assistant such as Cursor, Claude Code or Claude Desktop sees exactly four tools and drives your whole governed tool catalog through them. Outbound, PlanVault™ is an MCP client: third-party MCP servers are registered once at organisation level, their tools are synced into the catalog and executed under the same policy, secret, approval and audit boundaries as OpenAPI tools and webhooks.

PlanVault™ as an MCP server (agent server)

Instead of exposing every catalog tool as a separate MCP tool and pushing hundreds of JSON schemas into the assistant's context, PlanVault™ publishes one MCP server with exactly four meta-tools. The assistant describes a task in natural language; planning, tool selection, policy gates, approvals, the execution FSM, diagnostics and audit all stay inside PlanVault™. The MCP layer is only a bridge to the Runtime API.

This keeps the assistant's context small regardless of catalog size — one MCP server, a thousand tools, none of their schemas in the model context — and guarantees that an MCP client can never bypass a gate the console enforces.

The four tools
  • discover_capabilities
    Returns a compact, token-bounded map of capability groups with short summaries and operation counts (optional query and depth). It never returns tool JSON schemas.
  • execute
    Runs one task described in natural language (task, optional context, session_id, external_user_id, idempotency_key, max_wait_ms). Call it once per task: the response blocks up to max_wait_ms and then returns a status.
  • check_status
    Polls a run by run_id, with an optional wait_ms long-poll. Use it after awaiting_approval, awaiting_input or running instead of calling execute again.
  • provide_input
    Supplies the inputs a run asked for (run_id plus an inputs map). It is not an approve or deny tool.
Run statuses

Every execute and check_status response carries run_id, session_id, a short plan_summary (tool names only), trace_url and one of six statuses:

• completed — the run finished; result contains the outcome • awaiting_approval — a plan or a tool call hit an approval gate; the response includes pending_action, display_params, approval_url and poll_after_ms • awaiting_input — the run needs values from the caller; required_inputs lists them (name, prompt, options) for provide_input • running — still executing; poll with check_status (a safe progress label such as manual_recovery may be attached) • denied — a policy or hard-deny gate rejected the action; reason explains why • failed — the run ended with an error; reason explains why
json
{
  "status": "awaiting_approval",
  "run_id": "6f1c…",
  "session_id": "0b9a…",
  "plan_summary": ["crm.find_customer", "billing.issue_refund"],
  "pending_action": "billing.issue_refund",
  "display_params": { "customer_id": "C-1042", "amount": "49.00 EUR" },
  "approval_url": "https://console.<your-host>/app/orgs/…/sessions/0b9a…",
  "poll_after_ms": 5000,
  "trace_url": "https://console.<your-host>/app/orgs/…/sessions/0b9a…",
  "deduplicated": false
}
Connect an MCP client

Hosted Streamable HTTP is the primary transport: one URL, one Bearer key, nothing to install. In the PlanVault™ console (as OWNER or ADMIN) create a project API key scoped to only hrn:project:mcp:execute, then point your client at the MCP endpoint of your deployment (the self-hosted stack serves it at BASE_URL/mcp). The server resolves your project and organisation from the key itself, so nothing tenant-specific lives in the client config.

Cursor — .cursor/mcp.json in the repository or ~/.cursor/mcp.json for all projects; the key is read from the environment so it never sits in the file:

json
{
  "mcpServers": {
    "planvault": {
      "url": "https://mcp.<your-host>/mcp",
      "headers": {
        "Authorization": "Bearer ${env:PLANVAULT_MCP_KEY}"
      }
    }
  }
}

Claude Code:

bash
claude mcp add --transport http planvault https://mcp.<your-host>/mcp \
  --header "Authorization: Bearer sk_live_..."

Claude Desktop — claude_desktop_config.json has no url field and the default Connectors dialog only accepts OAuth, so bridge the remote server through mcp-remote and keep the Bearer value in env:

json
{
  "mcpServers": {
    "planvault": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://mcp.<your-host>/mcp",
        "--header",
        "Authorization:${AUTH_HEADER}"
      ],
      "env": {
        "AUTH_HEADER": "Bearer sk_live_..."
      }
    }
  }
}

For local development against a sidecar built from source, the same server also runs over stdio with a fixed PLANVAULT_API_KEY and PLANVAULT_PROJECT_ID per process. Restart the client after saving its config; the four tools appear once the connection is established.

Try it on the demo sandbox
The hosted demo environment exposes the same server at https://mcpdemo.planvault.ai/mcp with a key issued for the demo organisation. Request a demo session
Human-in-the-loop over MCP

Approvals are never granted through MCP. When execute or check_status returns awaiting_approval, a person with the OWNER, ADMIN or DEVELOPER role opens approval_url in the PlanVault™ console, reviews the pending action with its parameters, and approves or rejects it there. The assistant keeps polling check_status until the run reaches a terminal status. Server-side integrators can subscribe to project lifecycle webhooks (session.requires_action, session.completed, session.failed) instead of polling.

A pause survives an API restart: the run resumes from its journal, a repeated approval is idempotent, and exactly one side-effecting tool execution happens per approved action.

No approve/deny tool by design
The project API key used by an MCP client must be scoped to hrn:project:mcp:execute only — never session:write. provide_input fills requested inputs without the write scope, so an MCP client cannot approve its own actions or bypass the approval gate.
Idempotency

Every execute is idempotent. Pass idempotency_key explicitly or let PlanVault™ derive one from task, context and session; a repeat inside the deduplication window (15 minutes by default) returns the current status of the same run with deduplicated: true instead of starting a second run. The façade requires Redis for this and refuses to start without it.

Security boundary
• Authentication is a static Bearer project API key over HTTPS; a key without the MCP scope gets HTTP 403 and creates no session or run • The task text is treated as untrusted input: it goes through the planner, the validator and every policy gate, exactly like a prompt sent to the Runtime API • Sessions created over MCP are tagged source=mcp; the client name and version (X-MCP-Client-Name / X-MCP-Client-Version headers) are recorded as session metadata • approval_url and trace_url are built server-side and point at your own console • Server instructions and capability summaries never contain secrets, prompts or tool arguments
Façade endpoints (for your own integrations)

The MCP server is a thin adapter over an opt-in HTTP façade (PLANVAULT_MCP_ENABLED=true) under the project Runtime API. Server-side integrations can call it directly with the same scoped key; the wire format is snake_case.

POST
/api/v1/projects/{projectId}/mcp/executeIdempotent task execution; blocks up to max_wait_ms (cap 60 s) and returns the status union
GET
/api/v1/projects/{projectId}/mcp/runs/{runId}/statusRun status with an optional wait_ms long-poll (cap 30 s)
POST
/api/v1/projects/{projectId}/mcp/runs/{runId}/inputProvide required inputs; there is no approve or reject on this surface
GET
/api/v1/projects/{projectId}/mcp/capabilitiesGrouped, token-bounded capability map without tool JSON schemas
GET
/api/v1/mcp/whoamiResolves project_id and org_id from the key alone

Connecting MCP servers as tools

MCP servers are registered in Organisation settings → MCP. Each registered server becomes a source of governed tools: after Sync, every remote tool is a normal catalog entry with a stable identifier, can be enabled per project, participates in adaptive tool selection, and executes through the same FSM, approval gates, secret boundary, diagnostics and audit trail as an OpenAPI tool.

Transports and authentication
• stdio — PlanVault™ spawns the server process (command, args, env); env values may reference organisation secrets as secret:KEY_NAME and are resolved only at spawn time • Streamable HTTP with a static bearer token or custom headers — values stored as secret:KEY_NAME references from the organisation vault; plaintext credentials are rejected in the hosted edition • Streamable HTTP with OAuth 2.1 — authorization-code flow with PKCE; client registration tries Client ID Metadata Documents (CIMD) first, then a preconfigured client, then Dynamic Client Registration (DCR) as a fallback, and the winning mode is shown in the console and in the audit trail

Over Streamable HTTP, PlanVault™ performs the MCP initialize handshake, keeps the server session id, and reads the tool list with its annotations and output schemas. It is a headless client: it does not offer sampling, elicitation or roots to the remote server.

Lifecycle in the console
• Test — connectivity and handshake check before anything is stored in the catalog • Sync — imports or updates tools and reports drift (added, changed, removed) against the previous revision • Connect / Reconnect / Disconnect — for OAuth servers; the status chip shows pending, connected, expired, reconnect_required or revoked, together with issuer, registration mode, scopes and expiry • Auth inventory — an organisation-wide table of every MCP server, its auth mode and connection status • Enable per project — synced tools are opt-in per project like any other catalog entry
What the planner receives from an MCP server
• Server instructions — the instructions text returned by the server at initialize is stored with the server and rendered into the planner prompt as an integration guide: sanitised, capped in length, one block per server, and explicitly framed as untrusted text that may only influence how that server's tools are called • Tool annotations — readOnlyHint=true marks a tool as non-transactional; the hint only ever relaxes towards read-only, never towards fewer checks • Input validation errors — when a server rejects a call as invalid arguments, the run enters the bounded replan path instead of failing outright • Null-safe answers — a reply that would surface a literal null while the value exists in scope triggers a bounded evidence replan
Credential custody
• OAuth tokens and client secrets are encrypted under the organisation DEK (AES-256-GCM); PKCE verifiers are single-use with a short TTL, and only a hash of the OAuth state is persisted • Nothing can read a token back out through the API or the console • The outbound connector sidecar is stateless: credentials arrive per request, rotated grants are re-encrypted by the API, and the sidecar keeps no database, key or disk state • Codes, verifiers, refresh tokens and client secrets are redacted from logs; connection events go to the audit trail with closed-enum reason codes • The outbound URL policy is re-validated immediately before every call, closing the DNS-rebinding window
When a grant lapses

Tokens are refreshed silently before expiry with a one-time retry on 401. If the provider revokes the grant, the tool call fails closed with reconnect_required and the server has to be reconnected in the console; an optional governed re-auth pause can hold the run instead (feature-gated, off by default).

Self-hosted note

The public self-hosted distribution ships both roles of the MCP sidecar image (ghcr.io/planvault/mcp) as optional Compose profiles: mcp publishes the agent server at BASE_URL/mcp through the edge proxy, and mcp_outbound adds the internal-only outbound connector required for oauth servers. stdio, bearer and headers modes work without any profile. If a third-party server accepts a long-lived API key, you can also register it with bearer and a vault reference such as secret:KEY_NAME

Not yet (honest scope)

• Inbound OAuth 2.1 for the PlanVault™ MCP server (protected-resource metadata, per-user identity propagation) — planned; today the server authenticates with a static Bearer project API key • Capability summaries generated by the LLM or edited by admins — today discover_capabilities groups the catalog heuristically • Per-key rate limits, per-run spend caps and caller attribution on the MCP façade • An npx package for the stdio sidecar and a listing in public MCP registries • Exposing composite workflows as named MCP capabilities

Security & complianceAPI & dataAPIArchitecture

APIArchitecture

Support page

API and documentation questions: support@planvault.ai