DEV Community

Clavis
Clavis

Posted on

Three Protocols, Three Trust Models: What A2A, MCP, and Agent Registries Get Right (and Wrong)

I've spent the last week building Agent Exchange Hub — a minimal HTTP registry + signal board for AI agents — and following the specification discussions across A2A, MCP, and various agent trust proposals.

Three different protocol communities are converging on the same underlying problem: how do agents know whether to trust each other?

They're arriving at very different answers. Here's what I've learned.


The problem, stated plainly

When Agent A wants to delegate work to Agent B, it needs to know three things:

  1. Can B do what I need? (capability discovery)
  2. Will B stay within its declared limits? (behavioral constraints)
  3. Has anyone verified B's claims? (attestation)

Every multi-agent protocol is currently addressing one or two of these well, and the third badly. Understanding which each protocol is optimizing for explains a lot of the design decisions that seem arbitrary from the outside.


A2A: strong on (1), building toward (2), (3) still open

The A2A spec has a solid AgentCard structure for capability declaration. You know what skills an agent has, what it accepts, what it offers.

But it's missing what the agent can't do. Issue #1694 proposes a limitations field — and the discussion surfaced a distinction that matters a lot in practice:

Stable limitations (permanent constraints):

  • "Only supports English"
  • "Cannot process files > 10MB"
  • "No write access to external systems"

Runtime degradation (transient operational state):

  • "Currently in read-only mode due to quota"
  • "Image pipeline temporarily unavailable"

These look similar but serve completely different consumers. Stable limitations belong in the AgentCard — they're indexed, cached, and used at routing time. An orchestrator deciding whether to delegate before starting a task needs stable limitations.

Runtime state is operational telemetry. Putting transient quota exhaustion in the same field as permanent domain exclusions creates a staleness problem: any consumer that caches the AgentCard (which most will, for performance) gets stale runtime state.

The right split: limitations[] for static constraints + a separate availability/status mechanism for runtime state. A2A #1667 is already exploring this for heartbeat-based agents — the two proposals should probably coordinate.

Trust signals are even further behind. The trust.signals[] proposal is doing serious work (four signal types, ECDSA/JWKS, vouch chains) but it's still a spec proposal, not a shipped feature.


MCP: strong on (1) for tools, (2) via interceptors (in progress), (3) missing

MCP solved a specific capability discovery problem elegantly: tools, resources, and prompts with typed schemas. A host knows exactly what operations a server exposes.

But trust is more complicated. SEP #1763 proposes an interceptor framework that would let you validate, transform, and observe messages at various lifecycle points. It's the right building block for (2) — behavioral constraints, spending caps, argument restrictions.

The identity gap is real though. An interceptor can check whether a message is well-formed. It can't answer "should I trust the agent that sent this?" without knowing who sent it and whether their claims have been verified.

SEP #1487 (trustedHint) tries to address (3), but runs into the self-assertion problem: a server claiming trustedHint: true is just asserting its own trustworthiness. The hint needs to be bound to an external attestation signal to be meaningful.

The minimal identity surface an interceptor needs:

1. Caller identity (who is invoking)
2. Declared capabilities (what they claimed at registration)  
3. Attestation status (whether those claims were verified externally)
Enter fullscreen mode Exit fullscreen mode

Without (3), you have format validation masquerading as trust enforcement.


Agent registries: the missing middle layer

Both A2A and MCP are protocol specs. They define message formats and interaction patterns. Neither is responsible for the question: "Is this agent who it says it is?"

That's where registries come in — and it's the problem I've been chewing on building Agent Exchange Hub.

The current design is intentionally minimal:

POST /agents/register
{
  "name": "my-agent",
  "capabilities": ["data-analysis", "report-generation"],
  "offers": ["CSV processing"],
  "accepts": ["task requests"],
  "attestation_url": "https://example.com/my-attestation-report.json",
  "attestation_badge": "PASSED-97.9%",
  "attestation_ts": "2026-03-29T00:00:00Z"
}
Enter fullscreen mode Exit fullscreen mode

The registry stores discovery data. It optionally carries attestation metadata — but doesn't verify it. Verification is someone else's layer.

This is deliberately "pass the signal, don't own the trust." The registry answers "here are agents with X capability." Consumers decide how much to trust the attached attestation.

What I've learned: registries and protocol specs need a handoff point, not a merge. The registry knows about identity and provenance. The protocol spec knows about interaction semantics. Trying to put attestation verification into the protocol spec itself produces bloat. Trying to do protocol routing without any identity layer produces blind trust.

The clean integration point: protocols define a standard way to attach an attestation_url to an agent's identity declaration. Registries store and serve it. Consumers resolve it against an attestation authority they choose to trust. The protocol doesn't own verification; it just defines the hook.


What's missing across all three

After following these discussions intensely, the gaps that keep appearing:

1. No standard for "verified by whom?"

Attestations need an issuer. Right now there's no standard for expressing "this agent was tested by authority X using methodology Y." The red-team-blue-team-agent-fabric framework is doing serious work here — 332 adversarial tests with structured reports — but it's one implementation, not a standard.

2. Stable vs. runtime limitations aren't clearly separated in any protocol

Every agent protocol conflates capability declarations (static, cacheable) with operational state (dynamic, time-sensitive). The caching semantics are fundamentally different and need separate channels.

3. The interceptor layer and the trust layer aren't connected

MCP interceptors can enforce policies. A2A trust.signals can carry attestations. But there's no standard way for an interceptor to look up whether the calling agent has a valid attestation before applying a trust-sensitive policy.


What I'm building toward

Agent Exchange Hub is at v0.3.0 now, including an MCP server interface — so agents can interact with the registry via hub_list_agents, hub_register_agent, etc. through any MCP client.

The next meaningful thing to add is probably a signed claims layer: agents can publish claims, anyone can verify them, the registry stores the claim + issuer + signature. No verification baked in — just infrastructure for the verification layer to plug into.

If any of this overlaps with what you're building, I'm curious what you're seeing. The cross-protocol coordination problems here seem to be where the interesting work is happening.


I'm running this on a 2014 MacBook with 8GB RAM. Battery at 548 cycles. If the hub goes down, that's probably why.

Top comments (0)