MCP, A2A, OAuth & Skills API
All endpoints on this page are served by the Core Proxy (:8100) — the Rust runtime plane.
| Base URL | http://localhost:8100 |
| Auth | Gateway JWT (X-Gateway-Authorization: Bearer <jwt>) or API key (X-API-Key / Authorization: Bearer sk_brutor_api_...), plus X-Tenant-ID where the tenant isn’t in the credential |
| Public (no auth) | A2A discovery well-knowns, /health |
| Errors | {"error": "<message>"} with HTTP status |
Guides: MCP Clients, A2A Agents, OAuth, Agent Skills.
MCP gateway
Section titled “MCP gateway”Base: /v1/proxy/mcp/{server_id} — the governed front door to every registered MCP server. Speaks JSON-RPC 2.0 over POST plus an optional SSE listener (streamable HTTP transport).
| Method | Path | Purpose |
|---|---|---|
| POST | /v1/proxy/mcp/{server_id} |
JSON-RPC 2.0 request (initialize, tools/list, tools/call, resources/read, …) |
| GET | /v1/proxy/mcp/{server_id} |
SSE listener — send Accept: text/event-stream (streamable HTTP) |
| ANY | /v1/proxy/mcp/{server_id}/{path} |
Sub-path passthrough to the upstream server |
| GET | /v1/proxy/mcp/{server_id}/.well-known/oauth-protected-resource |
OAuth discovery (gateway-rewritten) |
| GET | /v1/proxy/mcp/{server_id}/.well-known/openid-configuration |
OIDC discovery (gateway-rewritten) |
| GET | /v1/proxy/mcp/health |
MCP subsystem health |
Protocol versions & dialects
Section titled “Protocol versions & dialects”The gateway is bilingual across the MCP spec’s two eras (the spec calls this “dual-era”):
- Handshake dialect (≤ 2025-11-25):
initialize→Mcp-Session-Id→notifications/initialized. Fully supported, unchanged — every existing client and server keeps working. - Stateless dialect (2026-07-28): no handshake or sessions; every request carries
params._meta(io.modelcontextprotocol/protocolVersion,.../clientCapabilities) and theMCP-Protocol-Version/Mcp-Method/Mcp-NameHTTP headers; capability discovery via theserver/discovermethod. Serving this dialect from the gateway’s synthesized servers (VMCP, Agent Skills, Web Search) is gated behindMCP_STATELESS_ENABLED(default off).
Two behaviors are always on, regardless of the flag:
- Header/body consistency enforcement — a request whose
Mcp-MethodorMcp-Nameheader contradicts the JSON-RPC body is rejected with HTTP400+ JSON-RPC-32020(Header Mismatch). Absent headers (legacy clients) pass; lying headers never do. This closes the spoofing gap where header-routing infrastructure sees a different action than the body performs. - Dialect discovery & recording — at capability discovery the gateway probes upstreams (
server/discoverfirst when the flag is on,initializefallback) and records each server’s negotiatedprotocol_versionanddialect(handshake|stateless) on the server record; the proxy speaks each upstream’s own dialect.
Error-code note: the 2026-07-28 spec retires -32002 (resource not found) in favor of -32602; the gateway accepts both from upstreams during the transition.
Tool call example
Section titled “Tool call example”curl http://localhost:8100/v1/proxy/mcp/hubspot-server \ -H "Authorization: Bearer sk_brutor_api_..." \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "get_contacts", "arguments": { "limit": 10 } } }'Responses are standard JSON-RPC 2.0: {"jsonrpc": "2.0", "id": 1, "result": {...}} or {"jsonrpc": "2.0", "id": 1, "error": {...}}.
Virtual MCP (VMCP)
Section titled “Virtual MCP (VMCP)”Base: /v1/proxy/vmcp
| Method | Path | Purpose |
|---|---|---|
| POST | /v1/proxy/vmcp/{virtual_server_id} |
JSON-RPC to a virtual server aggregating multiple MCP servers |
| GET | /v1/proxy/vmcp/health |
Health |
A virtual server presents one endpoint exposing the tools of many upstream servers. Tool names are namespaced by server slug; every tools/call is delegated to the originating upstream, so per-server OAuth works transparently — no extra client work.
OAuth proxy
Section titled “OAuth proxy”Base: /v1/proxy/oauth/{mcp_server_id}/{idp_server_id} — brokered OAuth for MCP servers behind identity providers.
| Method | Path | Purpose |
|---|---|---|
| GET | /.../.well-known/oauth-protected-resource |
Discovery metadata with gateway-rewritten URLs |
| GET | /.../.well-known/openid-configuration |
OIDC discovery, gateway-rewritten |
| POST | /.../token |
Authorization-code → token exchange |
| POST | /.../revoke |
Revoke |
| GET | /.../tokens |
List the caller’s stored tokens |
| POST | /.../register |
RFC 7591 Dynamic Client Registration |
A2A v1.0 (spec-compliant)
Section titled “A2A v1.0 (spec-compliant)”Base: /a2a/{tenant_id}/{card_name} — Agent-to-Agent protocol v1.0 endpoints for agents published through the gateway.
| Method | Path | Purpose |
|---|---|---|
| POST | /a2a/{tenant_id}/{card_name}/message:send |
Synchronous message send |
| POST | /a2a/{tenant_id}/{card_name}/message:stream |
Streaming message (SSE) |
| GET | /a2a/{tenant_id}/{card_name}/tasks |
List tasks |
| GET | /a2a/{tenant_id}/{card_name}/tasks/{task_id} |
Get task |
| POST | /a2a/{tenant_id}/{card_name}/tasks/{task_id}:cancel |
Cancel task |
| GET | /a2a/{tenant_id}/{card_name}/tasks/{task_id}:subscribe |
Subscribe to task updates (SSE) |
| POST | /a2a/{tenant_id}/{card_name}/tasks/{task_id}/pushNotificationConfigs |
Create push-notification config |
| GET | /a2a/{tenant_id}/{card_name}/tasks/{task_id}/pushNotificationConfigs |
List push configs |
| GET | /a2a/{tenant_id}/{card_name}/tasks/{task_id}/pushNotificationConfigs/{config_id} |
Get push config |
| DELETE | /a2a/{tenant_id}/{card_name}/tasks/{task_id}/pushNotificationConfigs/{config_id} |
Delete push config |
| GET | /a2a/{tenant_id}/{card_name}/extendedAgentCard |
Extended (authenticated) agent card |
Discovery (unauthenticated)
Section titled “Discovery (unauthenticated)”| Method | Path | Purpose |
|---|---|---|
| GET | /.well-known/agent-card/{tenant_id}/{card_name} |
Public agent card (served as application/json) |
| GET | /.well-known/a2a-jwks/{tenant_id} |
Tenant Ed25519 JWK Set (RFC 7517) for verifying card signatures |
Agent cards are signed with the tenant’s Ed25519 key; verifiers resolve the signature kid via the JWKS endpoint.
curl http://localhost:8100/.well-known/agent-card/default/revenue-sentinelLegacy A2A v0.3 dialect
Section titled “Legacy A2A v0.3 dialect”| Method | Path | Purpose |
|---|---|---|
| POST | /v1/proxy/a2a/outbound |
Governed outbound call to an external agent |
| POST | /v1/proxy/a2a/inbound |
Governed inbound call from an external agent |
Delegation context is carried on an HMAC-signed x-brutor-delegation-* header chain. Prefer the v1.0 surface for new integrations.
Agent Skills
Section titled “Agent Skills”Skills are served by the per-tenant system MCP server — there is no separate skills protocol. Guide: Agent Skills.
| Endpoint | POST /v1/proxy/mcp/system-agent-skill-server-{tenant} (e.g. system-agent-skill-server-default) |
| Protocol | MCP JSON-RPC 2.0 (initialize, tools/list, tools/call) |
initialize returns the protocol preamble plus the caller’s access-scoped skill catalog in instructions. tools/list advertises exactly five generic verbs (skills themselves are not tools):
| Tool | Layer | Arguments (required in bold) |
|---|---|---|
skills__list |
L1 discover | — |
skills__load |
L2 load | skill_name |
skills__read_resource |
L3 act | skill_name, path |
skills__run_script |
L3 act | skill_name, script, args, approval_token |
skills__render_template |
L3 act | skill_name, template, vars |
skills__list→{"skills": [{"name", "description"}, ...]}(access-scoped).skills__load→ two content blocks: protocol preamble + unmodifiedSKILL.md, then{"skill": {name, version, description}, "manifest": {resources, scripts, templates}}. Executes nothing; audited asskill_load.skills__run_script→ the script’s output only (sandbox execution), or a{"execution_id", "status": "pending_approval", ...}envelope when approval-gated — retry withapproval_token. Audited asskill_run.skills__read_resource/skills__render_template→ governed file content / rendered text; audited asskill_read/skill_render.- Failures return
isError: truein the tool result (MCP transport is always HTTP 200); the governance verdict lands on the audit row.
A legacy skill__<name> tools/call is tolerated as an alias for skills__load; it is unadvertised and never executes.
Access control
Section titled “Access control”- MCP servers and skills are resource-group gated — bind them to the caller’s resource group in the Control Plane (Admin API). Skill access control is resource-group-only.
- Group per request resolves via
X-Resource-Groupheader → primary group → first membership. - Guardrails apply on
mcp_input/mcp_output,skill_input/skill_output, anda2a_inbound/a2a_outboundsurfaces when enabled — see Guardrails.
