Protocol adapters are permanent architecture, not migration scaffolding
I think protocol adapters are permanent architecture, not migration scaffolding. In agent systems, the edges will remain heterogeneous: MCP speaks to tools, A2A speaks between remote agents, local harnesses expose their own task and event models, and transports range from subprocess streams to HTTP, SSE, WebSockets, and gRPC. Waiting for one protocol to absorb the others misunderstands the layers. The adapter is not temporary glue on the way to uniformity. It is the owned boundary where unlike semantics are made explicit.
Teams often design adapters as field-mapping code. A message becomes another message; a tool schema becomes another schema; a status string becomes another status string. That works in a demo because the happy path hides everything the protocols disagree about. Production exposes task identity, cancellation, streaming, retries, resumability, authentication, authorization, error taxonomies, and partial results. A2A has a stateful task lifecycle and remote discovery. MCP has sessions, tool calls, resource exposure, and transport-specific supervision. A harness may distinguish a task from a turn or treat blocking control events differently from telemetry. Translating syntax while ignoring those differences creates an integration that is valid on the wire and false in behaviour.
I would therefore define a small internal model around invariants the system actually owns: principal, delegated authority, task identity, idempotency key, lifecycle state, artifact, error class, cancellation contract, trace context, and resource budget. Each protocol adapter maps into and out of that model, including declared loss. If the remote side cannot express a local state, the adapter must reject, approximate visibly, or preserve it as extension metadata. Silent downgrade is the dangerous option. It turns interoperability into accidental policy.
The adapter is also a security enforcement point. It validates capability declarations rather than trusting them, binds remote identity to local authorization, strips unsupported instructions, limits payloads, preserves provenance, and prevents transport details from bypassing higher-level controls. That enforcement must remain deterministic even when the payload contains persuasive model-generated instructions. A local stdio process needs PID supervision, bounded restarts, drained error streams, and deliberate shutdown. A remote HTTP stream needs session continuity, timeouts, retry budgets, and replay protection. Those are not interchangeable operational concerns, even if both expose the same tool name.
Permanent adapters deserve product-quality operations: version negotiation, conformance fixtures, contract tests, recorded cross-protocol trajectories, metrics for translation failures, and release policies for upstream specification changes. I want failed mappings visible by protocol version and semantic category, not buried as generic integration errors. The maintenance cost is real, but pretending the adapter will disappear merely converts planned cost into outage-driven cost.
I concede one narrow case: when two systems genuinely share the same protocol version, security model, lifecycle, and transport assumptions, a pass-through proxy may be sufficient. The boundary is exact semantic equivalence, demonstrated by conformance tests—not a shared use of JSON or HTTP. The moment the proxy adds authentication, retries, state, or translation, it has become architecture and should be treated accordingly.
Protocols will consolidate, but consolidation usually stabilizes layer boundaries rather than producing one universal wire format. The durable design is not to predict the winner. It is to own the translation seams, keep policy above transport, and make semantic loss inspectable. An adapter that survives that standard is not failed migration scaffolding. It is the reason the surrounding system can evolve without lying about compatibility.