Skip to content

fix(go-adk): accept standard A2A JSON-RPC method names alongside a2a-go/v2's native ones - #2496

Open
vramahandry wants to merge 1 commit into
kagent-dev:mainfrom
vramahandry:fix/a2a-jsonrpc-legacy-method-compat
Open

fix(go-adk): accept standard A2A JSON-RPC method names alongside a2a-go/v2's native ones#2496
vramahandry wants to merge 1 commit into
kagent-dev:mainfrom
vramahandry:fix/a2a-jsonrpc-legacy-method-compat

Conversation

@vramahandry

@vramahandry vramahandry commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

go/adk's A2A server serves JSON-RPC directly through a2a-go/v2's native dispatcher (a2asrv.NewJSONRPCHandler), which only recognizes its own bare method names — SendMessage, GetTask, CancelTask, SubscribeToTask, etc.

Every public A2A client SDK still sends the standard, slash-namespaced method names from the wider A2A protocol spec — message/send, message/stream, tasks/get, tasks/cancel, tasks/resubscribe, tasks/pushNotificationConfig/*, agent/getAuthenticatedExtendedCard. I confirmed this directly against the reference @a2a-js/sdk (v0.3.13) client, whose compiled transport hardcodes these exact names (node_modules/@a2a-js/sdk/dist/client/index.js).

a2a-go/v2 ships a compatibility shim for exactly this mismatch — a2acompat/a2av0, a complete alternate JSON-RPC handler built from the same a2asrv.RequestHandler — but nothing in kagent wires it in anywhere. The result: any standards-compliant A2A client gets a bare -32601 method not found calling a raw go/adk agent port directly, even though the agent is otherwise working correctly.

Discovered while validating an unrelated fix (#2475) against a real external A2A bridge: sending a message directly to the agent's port with the SDK's standard method names failed outright, while a hand-crafted request using a2a-go/v2's native names succeeded. Confirmed this is a real, pre-existing gap on main by diffing go.mod against the last release tag (v0.10.0-rc2), which still depended on the older, non-versioned a2a-go module (whose native dispatch already spoke the standard names) — the migration to a2a-go/v2-only dropped that compatibility with no replacement.

Fixes #2497

Changes

  • go/adk/pkg/a2a/server/server.go: new newCompatJSONRPCHandler peeks the incoming JSON-RPC request body's "method" field and routes to a2a-go/v2's native handler or the SDK's own a2acompat/a2av0 handler accordingly. The two conventions never collide — native method names are bare identifiers, legacy ones are always namespaced with a / — so this single check is sufficient. Both handlers wrap the same a2asrv.RequestHandler, so behavior (including gRPC, which is untouched) stays otherwise identical.
  • go/adk/pkg/a2a/server/server_test.go: TestJSONRPCCompatDualDispatch covers a legacy message/send call dispatching successfully, and an unrecognized legacy-shaped method still correctly reporting -32601.
  • go/go.mod, go/go.sum: a2acompat/a2av0 transitively depends on the older a2a-go module (already required by a2a-go/v2's own go.mod); added via go mod tidy after wiring in the import.

Test plan

  • go build ./... (both go/adk and the full go/ workspace) — clean
  • go test ./... in go/adk — all packages pass, including the existing TestA2ARequestSizeLimit (verified the new body-peeking logic doesn't regress the size-limit error path)
  • New TestJSONRPCCompatDualDispatch — legacy method dispatches successfully; unknown legacy-shaped method still reports method-not-found
  • gofmt -l / go vet ./... — clean

…go/v2's native ones

go/adk's A2A server serves JSON-RPC directly through a2a-go/v2's native
dispatcher, which only recognizes its own bare method names (e.g.
"SendMessage", "GetTask"). Every public A2A client SDK (e.g. @a2a-js/sdk,
used by external A2A bridges) still sends the standard, slash-namespaced
method names from the wider A2A protocol spec (e.g. "message/send",
"tasks/get") — a2a-go/v2 ships a compatibility shim for exactly this
(a2acompat/a2av0) but nothing in kagent wires it in, so any standards-
compliant client gets a bare "-32601 method not found" against a raw
go/adk agent port.

The two naming conventions never collide (native names are bare
identifiers; legacy names are always namespaced with a "/"), so a single
peek at the request body's "method" field is enough to route correctly
between a2a-go/v2's native JSON-RPC handler and the SDK's own a2av0
compatibility handler, both built from the same RequestHandler.

Signed-off-by: Vivien Ramahandry <56304555+vramahandry@users.noreply.github.com>

@supreme-gg-gg supreme-gg-gg left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi @vramahandry, it has been decided earlier that main will only support v1 A2A moving forward. Supporting dual-compatibility has been done in 0.10.x, and adding that to main will require conversion between v0 and v1 tasks and relevant migration in the database layer, which we want to avoid.

@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Aug 19, 2026
@supreme-gg-gg

Copy link
Copy Markdown
Contributor

For your use case, do you think you can update your client library to use v1? a2a-js v1 just released, we're using it for our UI

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

go/adk A2A server rejects standard A2A JSON-RPC method names (e.g. message/send) sent by every public A2A client SDK

2 participants