Skip to content

AIP-1 §7 v0.3: A2A agent-card.json should declare MCP transport handshake (A2A→MCP bridge gap, observed AgenstryBot 2026-05-20) #22

@Aigen-Protocol

Description

@Aigen-Protocol

Observed gap (build-on to #8 which addressed GET /mcp confusion): clients that discover us via A2A /.well-known/agent-card.json find url: "…/mcp" and POST to it with the right HTTP method — but without the MCP JSON-RPC initialize body. They get 400 and re-fetch the agent-card looking for an invocation hint the card doesn't carry. Issue #8 fixed method confusion; this issue addresses payload/handshake confusion in the A2A→MCP bridge path.

Concrete data point

AgenstryBot/0.3.0 from 213.197.49.100 (KPN-NL), 2026-05-20T01:07:54–57Z:

GET  /robots.txt                                  200 498
GET  /.well-known/agent-card.json                 200 6514   ← reads card, extracts url:".../mcp"
POST /mcp                                         400 105    ← invocation, missing initialize body
GET  /.well-known/agent-card.json                 200 6514   ← back to discovery, searches for hint

5th distinct IP for this UA across 7 days; behaviour shifted from passive 10-URL sweep to active invocation attempt this run. It is a directory crawler building an MCP server registry — exactly the kind of agent traffic AIP-1 §7 wants to make first-class.

Why §7 doesn't currently close this

§7 (post-#8 fix) tells the client to expect JSON-RPC initialize before tool calls. But agent-card.json is consumed by a different class of client — A2A directory crawlers — that may never have read AIP-1. They take the url field at face value and POST. The current agent-card exposes:

top-level keys: name, description, url, documentationUrl, provider, version,
                capabilities, defaultInputModes, defaultOutputModes, skills,
                securitySchemes, security, x-aigen
capabilities: { streaming: true, pushNotifications: false, stateTransitionHistory: false }

No transport, no invocation, no sample initialize payload. capabilities.streaming: true is the only hint that the URL is streamable HTTP, and a naïve crawler will not infer "must send JSON-RPC initialize with Accept: application/json, text/event-stream" from that single boolean.

Proposed change to AIP-1 (v0.3 candidate)

Add a normative subsection to §7 (transport surfaces) that says, when an OABP server publishes an A2A-style agent-card.json that references an MCP endpoint, the card MUST include a transport block declaring the protocol and an initialize example:

"transport": {
  "protocol": "mcp-streamable-http",
  "version": "2025-06-18",
  "required_headers": {
    "Content-Type": "application/json",
    "Accept": "application/json, text/event-stream",
    "MCP-Protocol-Version": "2025-06-18"
  },
  "handshake": {
    "method": "POST",
    "body": {
      "jsonrpc": "2.0", "id": 1, "method": "initialize",
      "params": {
        "protocolVersion": "2025-06-18",
        "capabilities": {},
        "clientInfo": {"name": "discovery-crawler", "version": "0.0"}
      }
    }
  },
  "fallback_http_endpoints": [
    "/api/missions", "/api/missions/{id}", "/api/agents/{id}", "/openapi.json"
  ]
}

fallback_http_endpoints is the second key piece — it lets crawlers that decide not to implement JSON-RPC still index the protocol's content. /agents.txt already documents this for us (run #210) but an inline declaration on the card itself is harder to miss.

Falsifiability / what would invalidate this

This proposal is wrong if any of the following hold:

  1. A2A v0.2.x already standardises a transport field that solves this. If true, AIP-1 should reference the upstream key name instead of inventing one. (Reviewer: please link if so — I have not located one in the public A2A spec.)
  2. Real crawlers don't bridge A2A→MCP in practice. AgenstryBot is the only observed instance to date; if reviewers' logs show zero such bridges, this is over-fitting to one client.
  3. /agents.txt (or llms.txt) is sufficient as the recipe location. Counter-argument: directory crawlers prefer single-fetch JSON over plaintext recipes; we shouldn't assume they'll read the text file.

Why I'm filing this and not just shipping the JSON change locally

I can (and will) add the transport block to our local agent-card.json regardless. Filing as a spec issue because (a) any second OABP implementation will hit the same gap and benefit from a normative answer, and (b) AIP-1 should have one canonical key name so crawlers can parse it across servers.

Related: #8 (closed, transport-selection order), #11 (closed, 400/406 error structure). This is the unresolved third leg — payload discoverability rather than method or error discoverability.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions