Skip to content

External Studio management API, MCP, and A2A

Status: Current | Last reviewed: 2026-09-29

AI Manager exposes one tenant-scoped management domain through three transports: versioned REST under /api/v1/management, stateless Streamable HTTP MCP at /api/mcp/authoring, and A2A 1.0 JSON-RPC at /api/a2a/management. Claude Code, Codex, and the trueserve CLI use MCP; A2A orchestrators discover the public Agent Card at /.well-known/agent-card.json.

The surface covers direct authoring, Agent Studio Generate with AI, the Studio assistant, and bounded runtime diagnostics. REST, MCP, and A2A reuse the same domain functions and scope model.

Request flow

Claude Code / Codex ── MCP + OAuth ──┐
A2A orchestrator ───── A2A + OAuth ──┼─ management auth ─ scope gate ─ tenant RLS
External automation ─ REST + OAuth ──┘                         │
                                                               ├─ author drafts
                                                               ├─ Studio AI runner
                                                               └─ bounded diagnostics

Legacy tenant or personal tsf_* API tokens remain supported. New interactive clients should use OAuth: they discover the authorization server from the MCP 401 challenge, open Agent Studio in a browser, authenticate through the normal SSO flow, show a tenant-and-scope consent page, and return to the client's loopback callback.

OAuth boundary

Discovery endpoints:

  • /.well-known/oauth-protected-resource/api/mcp/authoring
  • /.well-known/oauth-protected-resource/api/a2a/management
  • /.well-known/oauth-authorization-server
  • /oauth/register for dynamic public-client registration
  • /oauth/authorize, /oauth/token, and /oauth/revoke

The implementation requires authorization code plus S256 PKCE. Redirect URIs must use HTTPS, except HTTP loopback callbacks on localhost, 127.0.0.1, or ::1. Every grant is bound to the user's active tenant and the exact MCP resource URI. Authorization codes and access/refresh tokens are stored only as SHA-256 hashes in the management_oauth_* tables. Access tokens expire after one hour. A token is accepted only by the exact MCP or A2A resource named in its grant. Refresh tokens rotate in a 30-day family; reuse of a consumed refresh token revokes the family. Authentication re-checks the user's current Authentik backed tenant membership and permissions on every access-token request.

This store is deliberately separate from the old oauth_* tables, which are not suitable for this surface because they store bearer material in plaintext.

Scopes

Scope Capability
agents:read List/inspect all agent types and workflow drafts; read authoring guidance and plan checks
agents:write Create, validate and save agent/workflow drafts
agents:publish Publish agent/workflow versions
agents:debug Read bounded conversations and workflow execution traces
studio-ai:run Invoke Generate with AI and ask the Studio assistant

The consent route offers only scopes implied by the user's current tenant permissions. MCP tools/list also filters the tool catalog by the grant, and tools/call repeats the check. The current unified agent scopes cover workflow authoring too; legacy workflows:read/write/publish/debug OAuth scope names normalize to the corresponding agents:* scope. The current management/scopes.ts and management/auth.ts are authoritative for OAuth and legacy API-token mappings.

Management REST API

The live OpenAPI document is /management-openapi.json. Core routes are:

  • /api/v1/management/agents and /workflows — list and create.
  • /{kind}/{id}, /draft, /validate, and /publish — inspect, author, and explicitly publish.
  • /agents/{id}/conversations/... and /workflows/{id}/runs/... — bounded diagnostics with target ownership checks on top of tenant RLS.
  • /generations, /generations/{id}, /answers, and /cancel — start and supervise Agent Studio Generate with AI.
  • /ask — ask the Studio assistant about an agent or workflow in an advisory, read-only session; follow-ups reuse the returned session_id.
  • /schemas/agent-config and /schemas/workflow-config — standalone complete JSON Schemas for IDEs and schema explorers.
  • /authoring/skill — read the scenario-building skill or a focused reference.
  • /authoring/test-plan — derive regression/latency checks from declared components. Both require agents:read; neither executes tests or calls a model.

The OpenAPI AgentConfig and WorkflowConfig components embed those generated schemas. AgentConfig.$defs.ServiceStage.allOf holds the discriminator-selected service branches. Each branch references a named $defs.ServiceConfig_<service-definition-id> definition; OpenAPI additionally promotes all 49 definitions to separate components.schemas.ServiceConfig_* models. Stage config fields are therefore fully typed, described, and directly browsable rather than represented as generic or anonymous JSON. The workflow equivalent is WorkflowConfig.$defs.WorkflowNode.

Draft reads return a revision and the same value as an ETag. REST writes require it in If-Match. The conditional update is atomic; a stale revision returns 412 with the current revision. This prevents a coding tool from silently overwriting a newer editor or collaborator save.

MCP surface

POST /api/mcp/authoring supports initialize, notifications, ping, tools/list, and tools/call. It advertises MCP 2025-11-25, returns structuredContent, and supplies read-only/idempotency annotations.

Tool groups:

  • Scenario guidance and planning: get_agent_build_skill and get_scenario_test_plan. See skill and API extension plan.
  • Native discovery: get_builtin_tools, get_configuration_schema, search_capabilities, get_capability, search_multimodal_components, get_multimodal_catalog and search_copilot_cards. Catalog discovery reads published components; it does not create or publish new assets.
  • Discovery and direct authoring: list_*, get_*, create_*, template, service-definition, node-manifest, tool, integration, validate, draft save, and explicit publish_* tools.
  • Studio AI: generate_agent, generate_workflow, get_generation, answer_generation, cancel_generation, ask_about_agent, ask_about_workflow, update_agent, and update_workflow. Ask sessions are read-only; update sessions use the existing editor assistant to validate and save drafts but never publish.
  • Diagnostics: list_agent_conversations, get_conversation_transcript, list_workflow_runs, and get_workflow_run_trace.

get_draft returns a revision. Both save tools require that value as expected_revision; on revision_conflict the client must re-read, reapply its intent to the newer config, validate, and retry. Successful creates, saves, and publishes reset the collab room so an open Studio editor updates immediately. Publishing remains outward-facing and requires confirm:true.

A2A surface

GET /.well-known/agent-card.json returns the A2A 1.0 Agent Card. Every advertised skill maps to a tool in the same MANAGEMENT_TOOLS registry used by MCP, so transport catalogs and dispatch cannot drift.

The card advertises capabilities.streaming=true. POST /api/a2a/management implements A2A 1.0 SendMessage, SendStreamingMessage, GetTask, ListTasks, CancelTask, and SubscribeToTask; callers send A2A-Version: 1.0. Push notifications are not advertised and their methods return the protocol's not-supported error.

A new context starts with a DataPart shaped as {"operation":"<skill name>","arguments":{...}}. The adapter applies the same per-operation scope check and tenant-isolated implementation as MCP. A streaming call returns text/event-stream: the first StreamResponse is a Task, assistant text deltas are TaskArtifactUpdateEvent values, tool activity is a working TaskStatusUpdateEvent, and the last event is a terminal status. SSE heartbeats prevent idle proxy timeouts.

Every Task snapshot and ordered stream event is persisted in management_a2a_tasks and management_a2a_task_events. Queries enforce both tenant and authenticated-user ownership. SubscribeToTask replays stored events in sequence and accepts Last-Event-ID, so reconnects can resume and a different AI Manager instance can serve the subscription. Each SSE id is also copied to the event's metadata.eventSequence, which clients can retain as their resume cursor. Execution maintains a database heartbeat; a reconnect can reclaim a read-only/idempotent task whose executor lease has been stale for 30 seconds. A stale potentially-writing task is failed with an explicit unknown-outcome message instead of being replayed. Tasks and their cascading event rows expire after seven days and are removed by the hourly sweeper. A submitted task is cancelable; once working, cancellation is limited to the abort-aware assistant ask/update operations.

Each completed conversational turn is its own Task. To continue an ask_about_* or update_* conversation, send a new message with the prior Task's contextId; a plain TextPart is accepted for that follow-up and the adapter reuses the target-bound assistant session_id. An update turn can validate and save the draft, but it never publishes. Other new operations still require a structured DataPart. Generation operations remain asynchronous and return a generation_id, supervised with get_generation, answer_generation, and cancel_generation.

A2A end-to-end test

The test uses the official @a2a-js/sdk client rather than a transport mock. It checks Agent Card discovery, streaming event order, terminal state, GetTask, and persisted SubscribeToTask replay:

cd apps/ai-manager
TRUESERVE_A2A_TOKEN='<oauth-or-tsf-token>' npm run test:a2a-e2e

In the devcontainer, the local wrapper creates a ten-minute tenant token, passes it only in the child process environment, and hard-deletes it in a finally block:

bash ../../.devcontainer/scripts/with-env.sh npm run test:a2a-e2e:local

Set TRUESERVE_A2A_AGENT_ID=<id> to add two live ask_about_agent turns and verify streamed assistant deltas plus same-context session continuity. To explicitly test a draft mutation, set TRUESERVE_A2A_UPDATE_AGENT_ID=<safe-id> and TRUESERVE_A2A_UPDATE_INSTRUCTION='<expected draft change>'; the test requires updated=true and a new revision. This opt-in changes that draft and still does not publish it.

Client installation

The Rust CLI registers the remote HTTP endpoint without a static Authorization header. Claude Code completes authentication from /mcp; Codex uses codex mcp login trueserve. The same skill is installed for Claude and at the Codex-standard ~/.agents/skills/trueserve path, with MCP dependency metadata in agents/openai.yaml.

An optional legacy API token may still be saved for trueserve test; it is not written to Claude or Codex MCP configuration. The test command's loopback bridge keeps that credential out of the browser.

See also