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/registerfor 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/agentsand/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 returnedsession_id./schemas/agent-configand/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 requireagents: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_skillandget_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_catalogandsearch_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 explicitpublish_*tools. - Studio AI:
generate_agent,generate_workflow,get_generation,answer_generation,cancel_generation,ask_about_agent,ask_about_workflow,update_agent, andupdate_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, andget_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.