[EPIC][A2A]: A2A Protocol v0.3.0 Full Compliance Implementation#3150
Draft
crivetimihai wants to merge 9 commits intomainfrom
Draft
[EPIC][A2A]: A2A Protocol v0.3.0 Full Compliance Implementation#3150crivetimihai wants to merge 9 commits intomainfrom
crivetimihai wants to merge 9 commits intomainfrom
Conversation
Signed-off-by: Jonathan Springer <jps@s390x.com>
Implement the foundation for A2A Protocol v1.0 RC1 migration: Proto & schemas: - Update a2a.proto with v1.0 Part restructuring (flat oneof), Message field rename (content -> parts), AgentCard with supported_interfaces, PascalCase RPC methods, tenant field, and blocking behavior - Add Pydantic schemas for tenant, icon_url, and server A2A config - Regenerate protobuf stubs DB & migrations: - Add A2AAgent.tenant, icon_url; Server A2A fields (a2a_enabled, etc.) - Add ServerInterface, A2AAgentAuth, ServerTaskMapping models - New migration 86d15e51b773 for A2A v1.0 tables and data migration - Fix duplicate alembic revision y8i9j0k1l2m3 (two files shared same ID) by renaming backfill_oauth_config to y8j9k0l1m2n3 and linearizing chain - Rebase a2a_v1 migration onto d9e0f1a2b3c4 for single head Service refactoring: - Extract shared A2A transport dispatch into a2a_dispatcher.py (resolve_a2a_auth, dispatch_a2a_transport, prepare_rpc_params, build_dispatch_headers) used by both a2a_service and tool_service - Move _get_team_name, _batch_get_team_names to BaseService - Unify _check_*_access into BaseService.check_item_access (static) - Remove duplicate _apply_visibility_filter from A2AAgentService - Update A2A_VERSION_HEADER from "0.3" to "1.0" - Add proto compat shim for a2a-sdk 0.3.x descriptor pool collision Bug fixes: - Fix A2A response serialization using str() instead of orjson.dumps(), which produced Python repr (None/False/single quotes) instead of valid JSON (null/false/double quotes) Architecture docs: - ADR-0041: A2A v1.0 RC1 migration strategy - ADR-0042: Virtual servers as multi-protocol endpoints - ADR-0043: Tenant vs team separation - A2A v1.0 architecture overview - Update multitenancy docs for tenant/team distinction Closes #2547 Signed-off-by: Jonathan Springer <jps@s390x.com>
- Add version-aware outbound dispatch: v0.3 agents receive v0.3 method names (slash-style) and kind-based Part format automatically based on their protocol_version field - Add MCPGATEWAY_A2A_V1_COMPAT_MODE config flag (default true) to gate acceptance of v0.3 inbound formats; when false, rejects legacy content field, kind discriminator, and slash-style methods - Add compat telemetry: structured DEBUG logs when v0.3 inbound normalization or outbound conversion paths are exercised - Migrate all internal service methods to v1.0 PascalCase (SendMessage, GetTask, ListTasks, etc.) — outbound conversion handles the translation for v0.3 agents - Update admin test payload builder to v1.0 format (no kind on parts, SendMessage method) - Extract A2A exception hierarchy into a2a_errors.py to break circular imports between a2a_service and a2a_dispatcher; re-export from a2a_service for backward compatibility - Mock _discover_agent_card in register_agent tests to eliminate 20-second network timeouts per test (~100s total savings) Closes #2547 Signed-off-by: Jonathan Springer <jps@s390x.com>
…hierarchy 102 new tests covering: - Backward compat: v0.3 ↔ v1.0 Part normalization roundtrip, method name mapping, compat mode gating (46 tests) - Dispatcher: prepare_rpc_params, dispatch_a2a_transport, build_dispatch_headers, dataclass defaults (37 tests) - Error hierarchy: exception inheritance, re-exports from a2a_service (19 tests) Signed-off-by: Jonathan Springer <jps@s390x.com>
…ndpoints
Implements Phase 1a/1b of the A2A v1.0 migration plan:
- A2AServerService: generates AgentCards from server metadata, routes
A2A requests to associated agents, manages server-level task mappings
via ServerTaskMapping, supports tenant precedence resolution
- a2a_server_router: mounts at /servers/{id}/a2a/* with REST endpoints
(message:send, message:stream, tasks, tasks/{id}, tasks/{id}:cancel),
JSON-RPC dispatcher, and agent card discovery (v1/card,
.well-known/agent-card.json)
- 35 unit tests covering agent card generation, request routing, task
mapping, tenant resolution, skill-based selection, and discovery
Signed-off-by: Jonathan Springer <jps@s390x.com>
- admin.js: remove v0.3 `kind` fields from message/parts, update JSON-RPC method `message/send` to `SendMessage`, update gRPC method - admin.html: show protocol version below agent type in dynamic table - admin-ui.test.js: update test assertions for v1.0 format Signed-off-by: Jonathan Springer <jps@s390x.com>
…ions - Security: delegate _base_url to get_base_url_with_protocol (SSRF fix) - Security: use server-derived team_id/owner_email in register_agent - Security: add access control to get_agent_by_name - Security: validate URL scheme for HTTP transports in dispatcher - Security: add identifier validation (_validate_a2a_identifier) - Correctness: replace get_for_update with direct SELECT in read paths - Correctness: remove db.close() on injected sessions - Correctness: add params dict validation in JSON-RPC dispatcher - Correctness: add db.commit() to _batch_get_team_names - Correctness: use agent_id instead of agent_name in ServerTaskMapping - Correctness: remap task IDs in list_tasks response - Correctness: filter by DbServer.enabled in server queries - Performance: set explicit httpx timeout for streaming connections - Robustness: add recursion depth limit to _extract_task_payloads - Robustness: redact JSON-RPC error data from client responses - Migration: use batch_alter_table for SQLite compat in downgrade - Migration: use .mappings().all() for named column access - Admin: remove server-side agentType formatting (JS handles it) - Docstrings: resolve ~300 DAR violations across 8 files (~87 functions) - Docstrings: remove 6 DAR per-file ignores from .flake8 (net reduction) - Imports: move re import and error re-exports to proper sections (E402) - Tests: add router tests (19), dispatcher auth tests (14), identifier validation tests (11), update ~35 existing test mocks Signed-off-by: Jonathan Springer <jps@s390x.com>
Resolve all blocking (B1-B3), major (M1-M11), and suggestion (S1-S4) issues identified in PR #3150 code review, spanning security, correctness, migration safety, and test coverage. Source fixes: - Fix route path collision: register a2a_server_router before server_router - Add JSON-RPC 2.0 version validation and gRPC config_name sanitization - Fix SSE error sanitization with auth_ctx.query_params_decrypted - Add agent_card_override allowlist to prevent unsafe card field injection - Add thread-safe singleton for A2AServerService with double-checked locking - Extract shared A2A error-to-HTTP mapping via global exception handlers - Replace serial agent card discovery and list_tasks with asyncio.gather - Remove _resolve_tenant dead code and fix circular import naming Migration fixes: - Add JSON serialization helper for raw SQL INSERT bind params - Fix nullable/server_default for timestamp columns across 3 tables - Add downgrade warning in no-op normalize migration Tests (+80 new): - Add security deny-path tests for a2a_server_router and main A2A routes - Add comprehensive _build_rest_request tests covering all 15 method branches - Add tests for stream_message, invoke_agent, team visibility, and agent lookup failure scenarios Signed-off-by: Jon Spriggs <github@jonspriggs.co.uk> Signed-off-by: Jonathan Springer <jps@s390x.com>
…est updates Rename alembic migrations to fix ordering, update A2A protobuf generated code, refine schemas and services for v1.0 protocol compliance, and expand test coverage for server router and service. Signed-off-by: Jonathan Springer <jps@s390x.com>
Open
3 tasks
Collaborator
|
Converting to a2a 1.0 via Rust. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR delivers full A2A Protocol v0.3.0 compliance in the gateway’s A2A stack, including:
a2a-jsonrpc,a2a-rest,a2a-grpc,rest-passthrough,custom),Closes #2547
What Was Implemented
1) A2A v0.3.0 operation coverage
Implemented canonical A2A operations end-to-end across router -> service -> transport:
message/sendmessage/streamtasks/listtasks/gettasks/canceltasks/subscribetasks/pushNotificationConfig/settasks/pushNotificationConfig/gettasks/pushNotificationConfig/listtasks/pushNotificationConfig/deleteagent/getCardNew/updated API routes in
mcpgateway/main.py:POST /a2a/{agent_name}/message/sendPOST /a2a/{agent_name}/message/streamGET /a2a/{agent_name}/tasksGET /a2a/{agent_name}/tasks/{task_id}POST /a2a/{agent_name}/tasks/{task_id}/cancelPOST /a2a/{agent_name}/tasks/{task_id}/subscribePOST /a2a/{agent_name}/tasks/{task_id}/pushNotificationConfigsGET /a2a/{agent_name}/tasks/{task_id}/pushNotificationConfigsGET /a2a/{agent_name}/tasks/{task_id}/pushNotificationConfigs/{config_id}DELETE /a2a/{agent_name}/tasks/{task_id}/pushNotificationConfigs/{config_id}GET /a2a/{agent_name}/cardAlso introduced
_get_a2a_invoke_context(...)to consistently deriveuser_id,user_email, and scopedtoken_teamsfor A2A invocation routes.2) Transport model normalization and strict dispatch
Added canonical transport normalization and alias handling in schemas and admin/UI:
a2a-jsonrpca2a-resta2a-grpcrest-passthroughcustomgeneric,jsonrpc,openai,anthropic,a2a, etc.)Key behavior change:
agent_type, not by endpoint trailing slash heuristics.This is implemented in:
mcpgateway/schemas.py(normalize_a2a_agent_type, validators in create/update/read models)mcpgateway/admin.pyandmcpgateway/static/admin.js(legacy alias normalization + display labels)mcpgateway/services/a2a_service.pyandmcpgateway/services/tool_service.py(runtime dispatch)3) A2A service enhancements (
mcpgateway/services/a2a_service.py)Major service improvements:
A2A_VERSION_HEADER = "0.3", code mapping for task/operation errors).parts[].kind, with compatibility from legacytype)./v1/...REST paths.grpcs://vsgrpc://),A2AAgentErrorwrapping for grpc failures.supportsAuthenticatedExtendedCardis enabled,preferredTransport,additionalInterfaces).send_message,stream_message,list_tasks,get_task,cancel_task,subscribe_task,set_task_push_notification_config,get_task_push_notification_config,list_task_push_notification_configs,delete_task_push_notification_config,get_agent_card._extract_task_payloads,_upsert_a2a_task) integrated into invoke flow.4) Tool integration behavior (
mcpgateway/services/tool_service.py)A2A tool invocation now aligns with same transport logic:
A2A-Version) when transport isa2a-rest,5) DB model + migrations
Added persisted A2A task storage:
A2ATaskinmcpgateway/db.pyA2AAgent->tasksNew migration 1:
mcpgateway/alembic/versions/x7h8i9j0k1l2_add_a2a_tasks_table.pya2a_taskstable and indexesNew migration 2:
mcpgateway/alembic/versions/y8i9j0k1l2m3_normalize_a2a_agent_type_values.pya2a_agents.agent_typevaluesdown_revisionpoints to previous new revision)6) gRPC protocol artifacts and generation pipeline
Added A2A protocol source and generated stubs:
mcpgateway/plugins/framework/external/grpc/proto/a2a.protomcpgateway/plugins/framework/external/grpc/proto/a2a_pb2.pymcpgateway/plugins/framework/external/grpc/proto/a2a_pb2.pyimcpgateway/plugins/framework/external/grpc/proto/a2a_pb2_grpc.pyUpdated plugin proto package loading:
mcpgateway/plugins/framework/external/grpc/proto/__init__.pyUpdated generation target in
Makefile:grpc-protonow generates stubs for bothplugin_service.protoanda2a.proto7) Admin UI and admin API improvements
mcpgateway/admin.py,mcpgateway/templates/admin.html,mcpgateway/static/admin.js:8) Schema updates
mcpgateway/schemas.py:normalize_a2a_agent_type(...),A2AAgentCreate,A2AAgentUpdate, andA2AAgentReadnow normalize types,a2a-jsonrpc.Tests Added / Updated
A2A service tests (
tests/unit/mcpgateway/services/test_a2a_service.py)Added broad coverage for:
A2A-Versionheader rules,parts.kindnormalization,Router/admin/schema/UI tests
tests/unit/mcpgateway/test_main.py: new tests for card and push-notification routes.tests/unit/mcpgateway/test_admin.py: new tests for admin type normalization, payload builders, and legacy handling.tests/unit/mcpgateway/test_schemas_validators_extra.py: alias normalization tests.tests/js/admin-ui.test.js: protocol helper tests (normalization, labels, payload preview shape, trailing slash warning behavior).Lint/Test/Validation Results
Executed and passing:
make doctest test1192 passed, 52 skipped12267 passed, 456 skipped, 5 warningsmake pylint flake810.00/10Additional Build/Tooling Changes
Makefiledoctest targets now ignore generated protobuf modules during doctest collection..flake8generated-protobuf per-file ignores were updated for regenerated stub formatting..flake8includes targetedDAR*per-file ignores for large modules touched in this PR (main.py,admin.py,schemas.py,a2a_service.py) to keep CI lint stable while preserving functional changes scope.Backward Compatibility / Behavior Notes
agent_typevalues continue to work, now normalized to canonical transport names.agent_type; endpoint trailing slash no longer toggles JSON-RPC behavior.A2A-Version: 0.3header.Files of Interest
mcpgateway/services/a2a_service.pymcpgateway/services/tool_service.pymcpgateway/main.pymcpgateway/admin.py,mcpgateway/static/admin.js,mcpgateway/templates/admin.htmlmcpgateway/db.pymcpgateway/schemas.pymcpgateway/alembic/versions/x7h8i9j0k1l2_add_a2a_tasks_table.pymcpgateway/alembic/versions/y8i9j0k1l2m3_normalize_a2a_agent_type_values.pymcpgateway/plugins/framework/external/grpc/proto/a2a.protomcpgateway/plugins/framework/external/grpc/proto/a2a_pb2.pymcpgateway/plugins/framework/external/grpc/proto/a2a_pb2.pyimcpgateway/plugins/framework/external/grpc/proto/a2a_pb2_grpc.py