Skip to content

fix(server): register /.well-known/agent.json alias route in create_a2a_server#613

Merged
bokelley merged 2 commits intomainfrom
claude/issue-612-a2a-alias-route
May 10, 2026
Merged

fix(server): register /.well-known/agent.json alias route in create_a2a_server#613
bokelley merged 2 commits intomainfrom
claude/issue-612-a2a-alias-route

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

Closes #612

Summary

create_agent_card_routes() (a2a-sdk) registers exactly one route: /.well-known/agent-card.json. The 0.3 discovery alias /.well-known/agent.json was already present in _A2A_DISCOVERY_PATHS (auth middleware exempted it) but was never registered as a Starlette route — returning 404 or 503 at edge proxies. This broke @adcp/sdk CLI auto-detection of A2A transport, which probes the alias as a positive A2A signal.

Fix: Call create_agent_card_routes(agent_card=agent_card, card_url="/.well-known/agent.json") a second time in create_a2a_server(). Both paths serve identical agent-card JSON using independent handler closures — no redirect round-trip, no shared mutable state.

Also fixed:

  • Three tests that masked the bug by accepting 404 as valid (test_unified_mcp_a2a.py) or asserting only the canonical path (test_a2a_server.py)
  • New inverse coverage test (test_all_discovery_paths_are_registered_routes) asserting every path in _A2A_DISCOVERY_PATHS has a live Starlette route — this is the structural check that would have caught issue A2A: /.well-known/agent.json (0.3 alias) returns 404 — route not registered, breaking SDK auto-detection #612 at the point /.well-known/agent.json was added to the frozenset
  • Misleading comment in auth.py ("retained by enable_v0_3_compat=True") corrected to note the route is registered explicitly in create_a2a_server
  • A2ABearerAuthMiddleware docstring updated to mention both exempted paths
  • docs/handler-authoring.md corrected to name the canonical path (/.well-known/agent-card.json) with a parenthetical noting the 0.3 alias

Nits (not fixed in this PR):

  • test_a2a_server.py:349 uses startswith("/.well-known/agent-card") — could use AGENT_CARD_WELL_KNOWN_PATH constant for exactness

What was tested

ruff check src/           # All checks passed
pytest tests/test_a2a_server.py tests/test_unified_mcp_a2a.py tests/test_serve_auth_both.py -v
# 80 passed, 0 failed, 43 warnings

Pre-PR review

  • code-reviewer: approved — no blockers. Core fix is correct (create_agent_card_routes creates fresh independent closures per call; no shared state). Two issues addressed (auth docstring, test limitation comment). Noted that test_unified_mcp_a2a.py tightening from in (200, 404)== 200 is the right move.
  • ad-tech-protocol-expert: approved — no blockers. /.well-known/agent.json is confirmed as the intended 0.3 alias (already in _A2A_DISCOVERY_PATHS with intentional auth exemption). No canonicalization concern (neither well-known path appears in the serialized card body). Absence of Link: rel=canonical on alias response is consistent with all other A2A implementations and not required by the spec.

Triage-managed PR. This bot does not currently iterate on
review comments or PR conversation threads (only on the source
issue). To unblock:

  • Push fixup commits directly: gh pr checkout <num>
    fix → push.
  • Or re-trigger: comment /triage execute on the source
    issue.

See adcp#3121
for context.

Session: https://claude.ai/code/session_01JHq6DLPhFf2kQQpUkPtfZe


Generated by Claude Code

claude added 2 commits May 10, 2026 11:57
…2a_server

The 0.3 discovery alias was exempted from auth (auth.py _A2A_DISCOVERY_PATHS)
but never registered as a Starlette route, causing buyer SDKs that probe the
alias (including @adcp/sdk CLI auto-detection) to receive 404/503.

Adds a second create_agent_card_routes call with card_url="/.well-known/agent.json"
so both paths serve identical agent-card JSON without a redirect round-trip.
Also tightens three tests that masked the bug by accepting 404 as valid, fixes
the misleading auth comment, adds an inverse coverage check asserting all
_A2A_DISCOVERY_PATHS entries are registered routes, and corrects the docs path.

Closes #612

https://claude.ai/code/session_01JHq6DLPhFf2kQQpUkPtfZe
- Remove brand name from inline comment (use generic "A2A 0.3 buyer SDKs")
- Expand A2ABearerAuthMiddleware docstring to mention 0.3 alias path
- Add comment to inverse-drift-guard test noting it's structural-only

https://claude.ai/code/session_01JHq6DLPhFf2kQQpUkPtfZe
@bokelley
Copy link
Copy Markdown
Contributor Author

Pre-merge expert pass (fresh independent review)

  • code-reviewer: APPROVE — no blockers. Verified the inverse-coverage test (test_all_discovery_paths_are_registered_routes) catches the bug class structurally; verified no shared-state risk from calling create_agent_card_routes twice (fresh closures, no globals). Nit only: both routes' Route.name defaults to _get_agent_card; url_path_for would resolve to whichever Starlette finds first. Nothing in SDK uses url_path_for for this — theoretical, non-blocking.
  • security-reviewer: SAFE — no findings. Path was already auth-exempt; serving 200 instead of 404 doesn't expose anything new. Body is the static operator-authored agent card — no request-derived data, no per-tenant leakage. Exemption uses exact-set membership, not prefix match.
  • ad-tech-protocol-expert: APPROVE — duplicate handler is the right call (308 would corrupt buyer SDKs that probe path-suffix as a transport-version signal). One forward-looking caveat: alias is registered unconditionally; today enable_v0_3_compat=True is hardcoded so this is a no-op concern, but if the flag becomes user-configurable the alias registration should gate on it. Worth a TODO, not a block.

Admin-merging.

@bokelley bokelley merged commit 2989101 into main May 10, 2026
16 checks passed
@bokelley bokelley deleted the claude/issue-612-a2a-alias-route branch May 10, 2026 12:20
@bokelley
Copy link
Copy Markdown
Contributor Author

Acknowledged — thanks for the independent expert pass and the forward-looking caveat on the enable_v0_3_compat flag. The TODO on gating alias registration is noted; if that flag becomes user-configurable a follow-up issue would be the right place to track it.


Triaged by Claude Code. Session: https://claude.ai/code/session_01TJqAJYiwTZoGQVdL1cEpDP


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A2A: /.well-known/agent.json (0.3 alias) returns 404 — route not registered, breaking SDK auto-detection

2 participants