I wanted one agent platform to speak four emerging protocols without building four separate memories of the same work. MCP exposes tools and resources, ACP connects editors to agents, A2A delegates work between agents, and AG-UI streams a run into an interface. Each solves a useful integration problem and arrives with its own names for sessions, tasks, status and history.
My first design carried a common language through the whole platform. Conversations, runs, workspaces, streams and identity would mean the same thing everywhere; the four external standards would become translations at the edge. On the diagram it looked admirably simple: one vocabulary, four adapters.
When I began wiring the services together, the abstraction became translation work. The model gateway, agent runtime and workspace service already had APIs which worked together, each with its own credentials, state and operational behaviour. Forcing the common protocol through them changed none of that; it only added another layer.
I removed that internal layer and kept the shared language at the product boundaries where several systems genuinely needed to agree. Inside a service with a well-owned API, the same abstraction had become bureaucracy.
One record underneath four protocols
After that reset, the common record became deliberately small. A thread preserves continuity, a turn marks one exchange, and a run represents the work accepted from that turn. Items, blocks, outputs and deliveries record what happened. Stream events carry increasing sequence numbers, so a reconnecting client can ask for everything after sequence N instead of trusting an adapter to reconstruct the past from its own cache.
Identity follows the same separation. A service authenticates as itself and carries the delegated caller independently, scoped to a tenant, user and sometimes one thread or run. A user id inside an ordinary method parameter is not identity; it is a string the caller supplied.
The specialist services keep their native APIs. Concepts belonging only to a model gateway or workspace service remain there, while fields needed solely by ACP or A2A stay with the relevant adapter. Something enters the shared record only when several products need it to carry the same meaning.
ACP provides the cleanest example. An ACP session is a thread in the common record, and the session id and thread id are the same string. There is no reconciliation table whose loss can orphan a conversation. session/prompt starts a turn, session status projects from turn status, and the adapter reads the event stream in pages using the platform’s sequence number as its cursor. Local state may make translation cheaper; it cannot become another account of events.
A2A requires more interpretation. A contextId maps to a thread, a task maps to a turn, and task state is calculated from the turn and its outputs. The adapter answers both the proto-style TASK_STATE_WORKING vocabulary and the newer working vocabulary. A monotonicity guard prevents a completed task from regressing after a stale read. If a turn has no structured output, its transcript becomes an artifact so the caller still receives something inspectable.
AG-UI is closer to transliteration. A turn start becomes RUN_STARTED; block deltas become TEXT_MESSAGE_CONTENT. The SSE event id is the platform sequence number, which lets Last-Event-ID serve as a real replay cursor. Replay and live subscription begin together after reconnect, then deduplicate by sequence where they meet.
MCP has the broadest surface but follows the same ownership rule. Registered capabilities appear with their schemas in tools/list; tools/call becomes a capability invocation carrying the caller’s own authorisation. Adding a capability does not require another hand-maintained registration in the adapter. Platform state can appear as resources, while mounted third-party servers retain namespaced tools.
A common record does not remove any of the translation. It lets the four adapters disagree about names and wire formats without each keeping its own account of what happened.
Put conformance in CI
An adapter can look elegant while misunderstanding the protocol it claims to implement, so the available upstream conformance tools run in CI. In an April run, MCP’s CLI returned:
Total: 39 passed, 0 failed
The same battery runs the A2A TCK, validates its live agent card and sends AG-UI events through the standard verifier. It also asserts that no call reaches the inference gateway. Listing a tool, translating task state or resuming an event stream should be deterministic; protocol compatibility cannot depend on a model interpreting what the standard meant.
The failed first design changed the questions I ask when another standard arrives. Do several products need this concept to mean the same thing? Which system already owns it? What must the adapter be able to forget without losing the work?
Conformance belongs in CI, where a protocol change can fail loudly. The other test is simpler: wipe the adapter’s disk and reconnect. If the conversation disappears with the cache, the adapter had quietly become another source of truth.