What happened?
Context: I found this while evaluating what the SDK can support, for an A2A server extension I am building for Quarkus LangChain4j. It started from a stalled PR by another contributor, who is not involved in this work. The goal is to land the extension in quarkus-langchain4j proper.
The JSON-RPC reference server documents tenant-prefixed routing and implements the extraction for it, but never registers a route that can match a tenant-prefixed path, so the documented behaviour is unreachable.
reference/jsonrpc/.../quarkus/A2AServerRoutes says in its class javadoc:
Tenant identification is extracted from the request path:
POST / → empty tenant
POST /tenant1 → tenant "tenant1"
POST /tenant1/ → tenant "tenant1" (trailing slash stripped)
and extractTenant(RoutingContext) implements exactly that. But setupRoutes registers only:
router.post("/")
router.get("/.well-known/agent-card.json")
In Vert.x a path that does not end in * is matched exactly, so POST /tenant1 never reaches the handler and extractTenant can only ever return the empty tenant.
The REST reference implementation does this correctly, with regex routes:
router.postWithRegex("^\\/(?<tenant>[^\\/]*\\/?)message:send$")
Reproduced empirically
A Quarkus application with a2a-java-sdk-reference-jsonrpc on the classpath, posting the same JSON-RPC body to each documented path:
| Request |
Observed |
Documented |
POST / |
200 |
empty tenant, OK |
POST /tenant1 |
405 Method Not Allowed |
tenant "tenant1" |
POST /tenant1/ |
405 Method Not Allowed |
tenant "tenant1" |
GET /tenant1/.well-known/agent-card.json |
404 |
n/a |
The 405 rather than 404 comes from another GET-only route matching the path; no POST route matches a tenant-prefixed path at all.
Why the tests do not catch it
A2AServerRoutesTest verifies tenant extraction by mocking the routing context:
when(mockRoutingContext.normalizedPath()).thenReturn("/tenant1");
That exercises the extraction in isolation but never goes through the router, so the missing route is invisible. No JSON-RPC test issues a real HTTP request to a tenant-prefixed path.
Impact
Per Multi-Tenancy and Multi-Agent Routing, the tenant field is one of the three sanctioned routing mechanisms. Today it works over REST but not over JSON-RPC, even though the JSON-RPC implementation documents it as supported, so an agent's routing behaviour depends on which transport a client happens to pick.
Suggested fix
Register the JSON-RPC endpoint with a tenant-capable route, mirroring what REST already does, and add a test that performs a real HTTP request to a tenant-prefixed path.
Happy to send a PR if you agree with the direction.
Verified against 1.2.0.Final
The javadoc, extractTenant and the two exact-match route registrations are all unchanged from 1.1.0.Final, where the table above was measured.
Relevant log output
$ curl -s -o /dev/null -w '%{http_code}\n' -X POST http://localhost:8080/ \
-H 'Content-Type: application/json' -H 'A2A-Version: 1.0' -d '{...}'
200
$ curl -s -o /dev/null -w '%{http_code}\n' -X POST http://localhost:8080/tenant1 \
-H 'Content-Type: application/json' -H 'A2A-Version: 1.0' -d '{...}'
405
$ curl -s -o /dev/null -w '%{http_code}\n' -X POST http://localhost:8080/tenant1/ \
-H 'Content-Type: application/json' -H 'A2A-Version: 1.0' -d '{...}'
405
Environment
- a2a-java
1.2.0.Final (measured on 1.1.0.Final; route registration unchanged)
- Quarkus 3.33.2
Code of Conduct
What happened?
Context: I found this while evaluating what the SDK can support, for an A2A server extension I am building for Quarkus LangChain4j. It started from a stalled PR by another contributor, who is not involved in this work. The goal is to land the extension in quarkus-langchain4j proper.
The JSON-RPC reference server documents tenant-prefixed routing and implements the extraction for it, but never registers a route that can match a tenant-prefixed path, so the documented behaviour is unreachable.
reference/jsonrpc/.../quarkus/A2AServerRoutessays in its class javadoc:and
extractTenant(RoutingContext)implements exactly that. ButsetupRoutesregisters only:In Vert.x a path that does not end in
*is matched exactly, soPOST /tenant1never reaches the handler andextractTenantcan only ever return the empty tenant.The REST reference implementation does this correctly, with regex routes:
Reproduced empirically
A Quarkus application with
a2a-java-sdk-reference-jsonrpcon the classpath, posting the same JSON-RPC body to each documented path:POST /POST /tenant1"tenant1"POST /tenant1/"tenant1"GET /tenant1/.well-known/agent-card.jsonThe 405 rather than 404 comes from another GET-only route matching the path; no POST route matches a tenant-prefixed path at all.
Why the tests do not catch it
A2AServerRoutesTestverifies tenant extraction by mocking the routing context:That exercises the extraction in isolation but never goes through the router, so the missing route is invisible. No JSON-RPC test issues a real HTTP request to a tenant-prefixed path.
Impact
Per Multi-Tenancy and Multi-Agent Routing, the
tenantfield is one of the three sanctioned routing mechanisms. Today it works over REST but not over JSON-RPC, even though the JSON-RPC implementation documents it as supported, so an agent's routing behaviour depends on which transport a client happens to pick.Suggested fix
Register the JSON-RPC endpoint with a tenant-capable route, mirroring what REST already does, and add a test that performs a real HTTP request to a tenant-prefixed path.
Happy to send a PR if you agree with the direction.
Verified against 1.2.0.Final
The javadoc,
extractTenantand the two exact-match route registrations are all unchanged from1.1.0.Final, where the table above was measured.Relevant log output
Environment
1.2.0.Final(measured on1.1.0.Final; route registration unchanged)Code of Conduct