From c9812a2f41041159df653d7a47cd325c36e31452 Mon Sep 17 00:00:00 2001 From: Rajesh Velicheti Date: Wed, 6 Aug 2025 12:47:25 -0700 Subject: [PATCH 01/15] Add agent card as a route in rest adapter --- src/a2a/server/apps/rest/rest_adapter.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/a2a/server/apps/rest/rest_adapter.py b/src/a2a/server/apps/rest/rest_adapter.py index 102349b9a..42dbb732f 100644 --- a/src/a2a/server/apps/rest/rest_adapter.py +++ b/src/a2a/server/apps/rest/rest_adapter.py @@ -93,6 +93,9 @@ async def handle_get_agent_card(self, request: Request) -> JSONResponse: Returns: A JSONResponse containing the agent card data. """ + if self.agent_card.supports_authenticated_extended_card: + return await self.handle_authenticated_agent_card(request) + # The public agent card is a direct serialization of the agent_card # provided at initialization. return JSONResponse( @@ -174,8 +177,7 @@ def routes(self) -> dict[tuple[str, str], Callable[[Request], Any]]: ('/v1/tasks', 'GET'): functools.partial( self._handle_request, self.handler.list_tasks ), + ('/v1/card', 'GET') : self.handle_get_agent_card, } - if self.agent_card.supports_authenticated_extended_card: - routes[('/v1/card', 'GET')] = self.handle_authenticated_agent_card return routes From 05b44d21452bff27ecd358d498ad72ec79053d69 Mon Sep 17 00:00:00 2001 From: Rajesh Velicheti Date: Wed, 6 Aug 2025 12:50:07 -0700 Subject: [PATCH 02/15] Update src/a2a/server/apps/rest/rest_adapter.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/a2a/server/apps/rest/rest_adapter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/a2a/server/apps/rest/rest_adapter.py b/src/a2a/server/apps/rest/rest_adapter.py index 42dbb732f..423256087 100644 --- a/src/a2a/server/apps/rest/rest_adapter.py +++ b/src/a2a/server/apps/rest/rest_adapter.py @@ -177,7 +177,7 @@ def routes(self) -> dict[tuple[str, str], Callable[[Request], Any]]: ('/v1/tasks', 'GET'): functools.partial( self._handle_request, self.handler.list_tasks ), - ('/v1/card', 'GET') : self.handle_get_agent_card, + ('/v1/card', 'GET'): self.handle_get_agent_card, } return routes From 12944c570675a00c12996116eaa9cfb7603c4b6f Mon Sep 17 00:00:00 2001 From: Rajesh Velicheti Date: Wed, 6 Aug 2025 12:59:45 -0700 Subject: [PATCH 03/15] Updated mypy failures --- src/a2a/server/apps/rest/rest_adapter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/a2a/server/apps/rest/rest_adapter.py b/src/a2a/server/apps/rest/rest_adapter.py index 423256087..33ac80a02 100644 --- a/src/a2a/server/apps/rest/rest_adapter.py +++ b/src/a2a/server/apps/rest/rest_adapter.py @@ -105,7 +105,7 @@ async def handle_get_agent_card(self, request: Request) -> JSONResponse: @rest_error_handler async def handle_authenticated_agent_card( self, request: Request - ) -> JSONResponse: + ) -> JSONResponse: # type: ignore[return-value] """Hook for per credential agent card response. If a dynamic card is needed based on the credentials provided in the request From 303faae9b4939e171f9bcdf498be48b96272b197 Mon Sep 17 00:00:00 2001 From: Rajesh Velicheti Date: Wed, 6 Aug 2025 13:03:20 -0700 Subject: [PATCH 04/15] Updated mypy failures --- src/a2a/server/apps/rest/rest_adapter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/a2a/server/apps/rest/rest_adapter.py b/src/a2a/server/apps/rest/rest_adapter.py index 33ac80a02..df3979953 100644 --- a/src/a2a/server/apps/rest/rest_adapter.py +++ b/src/a2a/server/apps/rest/rest_adapter.py @@ -105,7 +105,7 @@ async def handle_get_agent_card(self, request: Request) -> JSONResponse: @rest_error_handler async def handle_authenticated_agent_card( self, request: Request - ) -> JSONResponse: # type: ignore[return-value] + ) -> JSONResponse: # type: ignore[return-value] """Hook for per credential agent card response. If a dynamic card is needed based on the credentials provided in the request From 10e363353ef08166d368e40c54ed4b93fefb4086 Mon Sep 17 00:00:00 2001 From: Rajesh Velicheti Date: Wed, 6 Aug 2025 23:30:18 -0700 Subject: [PATCH 05/15] Updated mypy failures --- src/a2a/server/apps/rest/rest_adapter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/a2a/server/apps/rest/rest_adapter.py b/src/a2a/server/apps/rest/rest_adapter.py index df3979953..9dd6ebd68 100644 --- a/src/a2a/server/apps/rest/rest_adapter.py +++ b/src/a2a/server/apps/rest/rest_adapter.py @@ -105,7 +105,7 @@ async def handle_get_agent_card(self, request: Request) -> JSONResponse: @rest_error_handler async def handle_authenticated_agent_card( self, request: Request - ) -> JSONResponse: # type: ignore[return-value] + ) -> JSONResponse: """Hook for per credential agent card response. If a dynamic card is needed based on the credentials provided in the request @@ -124,7 +124,7 @@ async def handle_authenticated_agent_card( ) ) return JSONResponse( - self.agent_card.model_dump(mode='json', exclude_none=True) + content=self.agent_card.model_dump(mode='json', exclude_none=True) ) def routes(self) -> dict[tuple[str, str], Callable[[Request], Any]]: From 7cef6cb6551d73ea5900eb8eff28047c1363721c Mon Sep 17 00:00:00 2001 From: Rajesh Velicheti Date: Wed, 6 Aug 2025 23:44:13 -0700 Subject: [PATCH 06/15] Updated mypy failures --- src/a2a/server/apps/rest/rest_adapter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/a2a/server/apps/rest/rest_adapter.py b/src/a2a/server/apps/rest/rest_adapter.py index 9dd6ebd68..df0c3d0bb 100644 --- a/src/a2a/server/apps/rest/rest_adapter.py +++ b/src/a2a/server/apps/rest/rest_adapter.py @@ -94,7 +94,7 @@ async def handle_get_agent_card(self, request: Request) -> JSONResponse: A JSONResponse containing the agent card data. """ if self.agent_card.supports_authenticated_extended_card: - return await self.handle_authenticated_agent_card(request) + return await self.handle_authenticated_agent_card(request) # type: ignore[return-value] # The public agent card is a direct serialization of the agent_card # provided at initialization. @@ -124,7 +124,7 @@ async def handle_authenticated_agent_card( ) ) return JSONResponse( - content=self.agent_card.model_dump(mode='json', exclude_none=True) + self.agent_card.model_dump(mode='json', exclude_none=True) ) def routes(self) -> dict[tuple[str, str], Callable[[Request], Any]]: From 7530164490f2c2c804f3ddaadbb2107176af7047 Mon Sep 17 00:00:00 2001 From: Holt Skinner Date: Thu, 7 Aug 2025 15:47:40 +0100 Subject: [PATCH 07/15] formatting --- src/a2a/server/apps/rest/rest_adapter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/a2a/server/apps/rest/rest_adapter.py b/src/a2a/server/apps/rest/rest_adapter.py index df0c3d0bb..3a9310a36 100644 --- a/src/a2a/server/apps/rest/rest_adapter.py +++ b/src/a2a/server/apps/rest/rest_adapter.py @@ -94,7 +94,7 @@ async def handle_get_agent_card(self, request: Request) -> JSONResponse: A JSONResponse containing the agent card data. """ if self.agent_card.supports_authenticated_extended_card: - return await self.handle_authenticated_agent_card(request) # type: ignore[return-value] + return await self.handle_authenticated_agent_card(request) # type: ignore[return-value] # The public agent card is a direct serialization of the agent_card # provided at initialization. From 2c57faf3ec8ff826b0f2a06ac6be95ff16e791dd Mon Sep 17 00:00:00 2001 From: rajeshvelicheti Date: Mon, 11 Aug 2025 14:48:42 -0700 Subject: [PATCH 08/15] Updated agent card engpoints --- src/a2a/server/apps/rest/fastapi_app.py | 18 +++++- src/a2a/server/apps/rest/rest_adapter.py | 79 ++++++++++++++++++++---- 2 files changed, 85 insertions(+), 12 deletions(-) diff --git a/src/a2a/server/apps/rest/fastapi_app.py b/src/a2a/server/apps/rest/fastapi_app.py index e4092b12a..05c400085 100644 --- a/src/a2a/server/apps/rest/fastapi_app.py +++ b/src/a2a/server/apps/rest/fastapi_app.py @@ -1,11 +1,13 @@ import logging +from collections.abc import Callable from typing import Any from fastapi import APIRouter, FastAPI, Request, Response from a2a.server.apps.jsonrpc.jsonrpc_app import CallContextBuilder from a2a.server.apps.rest.rest_adapter import RESTAdapter +from a2a.server.context import ServerCallContext from a2a.server.request_handlers.request_handler import RequestHandler from a2a.types import AgentCard from a2a.utils.constants import AGENT_CARD_WELL_KNOWN_PATH @@ -22,11 +24,17 @@ class A2ARESTFastAPIApplication: (SSE). """ - def __init__( + def __init__( # noqa: PLR0913 self, agent_card: AgentCard, http_handler: RequestHandler, + extended_agent_card: AgentCard | None = None, context_builder: CallContextBuilder | None = None, + card_modifier: Callable[[AgentCard], AgentCard] | None = None, + extended_card_modifier: Callable[ + [AgentCard, ServerCallContext], AgentCard + ] + | None = None, ): """Initializes the A2ARESTFastAPIApplication. @@ -39,11 +47,19 @@ def __init__( context_builder: The CallContextBuilder used to construct the ServerCallContext passed to the http_handler. If None, no ServerCallContext is passed. + card_modifier: An optional callback to dynamically modify the public + agent card before it is served. + extended_card_modifier: An optional callback to dynamically modify + the extended agent card before it is served. It receives the + call context. """ self._adapter = RESTAdapter( agent_card=agent_card, http_handler=http_handler, + extended_agent_card=extended_agent_card, context_builder=context_builder, + card_modifier=card_modifier, + extended_card_modifier=extended_card_modifier, ) def build( diff --git a/src/a2a/server/apps/rest/rest_adapter.py b/src/a2a/server/apps/rest/rest_adapter.py index 3a9310a36..90e8f7fcd 100644 --- a/src/a2a/server/apps/rest/rest_adapter.py +++ b/src/a2a/server/apps/rest/rest_adapter.py @@ -33,11 +33,17 @@ class RESTAdapter: manages response generation including Server-Sent Events (SSE). """ - def __init__( + def __init__( # noqa: PLR0913 self, agent_card: AgentCard, http_handler: RequestHandler, + extended_agent_card: AgentCard | None = None, context_builder: CallContextBuilder | None = None, + card_modifier: Callable[[AgentCard], AgentCard] | None = None, + extended_card_modifier: Callable[ + [AgentCard, ServerCallContext], AgentCard + ] + | None = None, ): """Initializes the RESTApplication. @@ -45,14 +51,32 @@ def __init__( agent_card: The AgentCard describing the agent's capabilities. http_handler: The handler instance responsible for processing A2A requests via http. + extended_agent_card: An optional, distinct AgentCard to be served + at the authenticated extended card endpoint. context_builder: The CallContextBuilder used to construct the ServerCallContext passed to the http_handler. If None, no ServerCallContext is passed. + card_modifier: An optional callback to dynamically modify the public + agent card before it is served. + extended_card_modifier: An optional callback to dynamically modify + the extended agent card before it is served. It receives the + call context. """ self.agent_card = agent_card + self.extended_agent_card = extended_agent_card + self.card_modifier = card_modifier + self.extended_card_modifier = extended_card_modifier self.handler = RESTHandler( agent_card=agent_card, request_handler=http_handler ) + if ( + self.agent_card.supports_authenticated_extended_card + and self.extended_agent_card is None + and self.extended_card_modifier is None + ): + logger.error( + 'AgentCard.supports_authenticated_extended_card is True, but no extended_agent_card was provided. The /agent/authenticatedExtendedCard endpoint will return 404.' + ) self._context_builder = context_builder or DefaultCallContextBuilder() @rest_error_handler @@ -84,28 +108,33 @@ async def event_generator( ) @rest_error_handler - async def handle_get_agent_card(self, request: Request) -> JSONResponse: + async def handle_get_agent_card( + self, request: Request, call_context: ServerCallContext | None = None + ) -> JSONResponse | Response: """Handles GET requests for the agent card endpoint. Args: request: The incoming Starlette Request object. + call_context: ServerCallContext Returns: A JSONResponse containing the agent card data. """ - if self.agent_card.supports_authenticated_extended_card: - return await self.handle_authenticated_agent_card(request) # type: ignore[return-value] + card_to_serve = self.agent_card + if self.card_modifier: + card_to_serve = self.card_modifier(card_to_serve) - # The public agent card is a direct serialization of the agent_card - # provided at initialization. return JSONResponse( - self.agent_card.model_dump(mode='json', exclude_none=True) + card_to_serve.model_dump( + exclude_none=True, + by_alias=True, + ) ) @rest_error_handler async def handle_authenticated_agent_card( - self, request: Request - ) -> JSONResponse: + self, request: Request, call_context: ServerCallContext | None = None + ) -> JSONResponse | Response: """Hook for per credential agent card response. If a dynamic card is needed based on the credentials provided in the request @@ -113,6 +142,7 @@ async def handle_authenticated_agent_card( Args: request: The incoming Starlette Request object. + call_context: ServerCallContext Returns: A JSONResponse containing the authenticated card. @@ -123,8 +153,29 @@ async def handle_authenticated_agent_card( message='Authenticated card not supported' ) ) + card_to_serve = self.extended_agent_card + + if self.extended_card_modifier: + context = self._context_builder.build(request) + # If no base extended card is provided, pass the public card to the modifier + base_card = card_to_serve if card_to_serve else self.agent_card + card_to_serve = self.extended_card_modifier(base_card, context) + + if card_to_serve: + return JSONResponse( + card_to_serve.model_dump( + exclude_none=True, + by_alias=True, + ) + ) + # If supports_authenticated_extended_card is true, but no + # extended_agent_card was provided, and no modifier produced a card, + # return a 404. return JSONResponse( - self.agent_card.model_dump(mode='json', exclude_none=True) + { + 'error': 'Authenticated extended agent card is supported but not configured on the server.' + }, + status_code=404, ) def routes(self) -> dict[tuple[str, str], Callable[[Request], Any]]: @@ -177,7 +228,13 @@ def routes(self) -> dict[tuple[str, str], Callable[[Request], Any]]: ('/v1/tasks', 'GET'): functools.partial( self._handle_request, self.handler.list_tasks ), - ('/v1/card', 'GET'): self.handle_get_agent_card, + ('v1/well_known/agent_json', 'GET'): functools.partial( + self._handle_request, self.handle_get_agent_card + ), } + if self.agent_card.supports_authenticated_extended_card: + routes[('/v1/card', 'GET')] = functools.partial( + self._handle_request, self.handle_authenticated_agent_card + ) return routes From 47b4ac2240f94a1997e4e756163c6782d63eb75b Mon Sep 17 00:00:00 2001 From: rajeshvelicheti Date: Mon, 11 Aug 2025 18:55:34 -0700 Subject: [PATCH 09/15] Updated unit tests --- tests/integration/test_client_server_integration.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/integration/test_client_server_integration.py b/tests/integration/test_client_server_integration.py index 46907ee64..10722fea2 100644 --- a/tests/integration/test_client_server_integration.py +++ b/tests/integration/test_client_server_integration.py @@ -1,5 +1,4 @@ import asyncio - from collections.abc import AsyncGenerator from typing import NamedTuple from unittest.mock import ANY, AsyncMock @@ -8,7 +7,6 @@ import httpx import pytest import pytest_asyncio - from grpc.aio import Channel from a2a.client.transports import JsonRpcTransport, RestTransport @@ -38,7 +36,6 @@ TransportProtocol, ) - # --- Test Constants --- TASK_FROM_STREAM = Task( @@ -130,7 +127,7 @@ def agent_card() -> AgentCard: default_input_modes=['text/plain'], default_output_modes=['text/plain'], preferred_transport=TransportProtocol.jsonrpc, - supports_authenticated_extended_card=True, + supports_authenticated_extended_card=False, additional_interfaces=[ AgentInterface( transport=TransportProtocol.http_json, url='http://testserver' @@ -710,8 +707,6 @@ async def test_http_transport_get_card( ) transport = transport_setup.transport - # The transport starts with a minimal card, get_card() fetches the full one - transport.agent_card.supports_authenticated_extended_card = True result = await transport.get_card() assert result.name == agent_card.name From c1d6b008341fd43f5091ede3ea6d824b3fcba4d7 Mon Sep 17 00:00:00 2001 From: rajeshvelicheti Date: Mon, 11 Aug 2025 19:05:21 -0700 Subject: [PATCH 10/15] Updated comments on the test --- tests/integration/test_client_server_integration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/test_client_server_integration.py b/tests/integration/test_client_server_integration.py index 10722fea2..4f6037b3e 100644 --- a/tests/integration/test_client_server_integration.py +++ b/tests/integration/test_client_server_integration.py @@ -706,7 +706,7 @@ async def test_http_transport_get_card( transport_setup_fixture ) transport = transport_setup.transport - + # Get the base card. result = await transport.get_card() assert result.name == agent_card.name From 6ca3bee410dbc9d8e0458b45ce3fc5fe933fb966 Mon Sep 17 00:00:00 2001 From: rajeshvelicheti Date: Mon, 11 Aug 2025 20:15:35 -0700 Subject: [PATCH 11/15] Improve coverage --- src/a2a/server/apps/rest/rest_adapter.py | 18 +++++-------- .../test_client_server_integration.py | 27 +++++++++++++++++++ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/a2a/server/apps/rest/rest_adapter.py b/src/a2a/server/apps/rest/rest_adapter.py index 23a32a347..cda61420f 100644 --- a/src/a2a/server/apps/rest/rest_adapter.py +++ b/src/a2a/server/apps/rest/rest_adapter.py @@ -149,11 +149,9 @@ async def handle_get_agent_card( if self.card_modifier: card_to_serve = self.card_modifier(card_to_serve) - return JSONResponse( - card_to_serve.model_dump( - exclude_none=True, - by_alias=True, - ) + return card_to_serve.model_dump( + exclude_none=True, + by_alias=True, ) @rest_error_handler @@ -187,11 +185,9 @@ async def handle_authenticated_agent_card( card_to_serve = self.extended_card_modifier(base_card, context) if card_to_serve: - return JSONResponse( - card_to_serve.model_dump( - exclude_none=True, - by_alias=True, - ) + return card_to_serve.model_dump( + exclude_none=True, + by_alias=True, ) # If supports_authenticated_extended_card is true, but no # extended_agent_card was provided, and no modifier produced a card, @@ -253,7 +249,7 @@ def routes(self) -> dict[tuple[str, str], Callable[[Request], Any]]: ('/v1/tasks', 'GET'): functools.partial( self._handle_request, self.handler.list_tasks ), - ('v1/well_known/agent_json', 'GET'): functools.partial( + ('/v1/well_known/agent_json', 'GET'): functools.partial( self._handle_request, self.handle_get_agent_card ), } diff --git a/tests/integration/test_client_server_integration.py b/tests/integration/test_client_server_integration.py index 4f6037b3e..88d4d3d11 100644 --- a/tests/integration/test_client_server_integration.py +++ b/tests/integration/test_client_server_integration.py @@ -717,6 +717,33 @@ async def test_http_transport_get_card( await transport.close() +@pytest.mark.asyncio +async def test_http_transport_get_authenticated_card( + agent_card: AgentCard, + mock_request_handler: AsyncMock, +) -> None: + agent_card.supports_authenticated_extended_card = True + extended_agent_card = agent_card.model_copy(deep=True) + extended_agent_card.name = 'Extended Agent Card' + + app_builder = A2ARESTFastAPIApplication( + agent_card, + mock_request_handler, + extended_agent_card=extended_agent_card, + ) + app = app_builder.build() + httpx_client = httpx.AsyncClient(transport=httpx.ASGITransport(app=app)) + + transport = RestTransport(httpx_client=httpx_client, agent_card=agent_card) + result = await transport.get_card() + assert result.name == extended_agent_card.name + assert transport.agent_card.name == extended_agent_card.name + assert transport._needs_extended_card is False + + if hasattr(transport, 'close'): + await transport.close() + + @pytest.mark.asyncio async def test_grpc_transport_get_card( grpc_server_and_handler: tuple[str, AsyncMock], From b5bf26c1641148ebd1036fa9c209b750b42ecac6 Mon Sep 17 00:00:00 2001 From: rajeshvelicheti Date: Mon, 11 Aug 2025 20:18:49 -0700 Subject: [PATCH 12/15] Fix linter errors --- src/a2a/server/apps/rest/rest_adapter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/a2a/server/apps/rest/rest_adapter.py b/src/a2a/server/apps/rest/rest_adapter.py index cda61420f..7958f6e3e 100644 --- a/src/a2a/server/apps/rest/rest_adapter.py +++ b/src/a2a/server/apps/rest/rest_adapter.py @@ -135,7 +135,7 @@ async def event_generator( @rest_error_handler async def handle_get_agent_card( self, request: Request, call_context: ServerCallContext | None = None - ) -> JSONResponse | Response: + ) -> JSONResponse | Response | Any: """Handles GET requests for the agent card endpoint. Args: @@ -157,7 +157,7 @@ async def handle_get_agent_card( @rest_error_handler async def handle_authenticated_agent_card( self, request: Request, call_context: ServerCallContext | None = None - ) -> JSONResponse | Response: + ) -> JSONResponse | Response | Any: """Hook for per credential agent card response. If a dynamic card is needed based on the credentials provided in the request From bd476bca9658a71024cd37bb261e2f447eb7a090 Mon Sep 17 00:00:00 2001 From: rajeshvelicheti Date: Tue, 12 Aug 2025 15:40:32 -0700 Subject: [PATCH 13/15] Changes per review comments --- src/a2a/server/apps/rest/rest_adapter.py | 29 ++++++------------------ 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/src/a2a/server/apps/rest/rest_adapter.py b/src/a2a/server/apps/rest/rest_adapter.py index 7958f6e3e..91e6626ab 100644 --- a/src/a2a/server/apps/rest/rest_adapter.py +++ b/src/a2a/server/apps/rest/rest_adapter.py @@ -132,10 +132,9 @@ async def event_generator( event_generator(method(request, call_context)) ) - @rest_error_handler async def handle_get_agent_card( self, request: Request, call_context: ServerCallContext | None = None - ) -> JSONResponse | Response | Any: + ) -> dict[str, Any]: """Handles GET requests for the agent card endpoint. Args: @@ -149,15 +148,11 @@ async def handle_get_agent_card( if self.card_modifier: card_to_serve = self.card_modifier(card_to_serve) - return card_to_serve.model_dump( - exclude_none=True, - by_alias=True, - ) + return card_to_serve.model_dump(mode='json', exclude_none=True) - @rest_error_handler async def handle_authenticated_agent_card( self, request: Request, call_context: ServerCallContext | None = None - ) -> JSONResponse | Response | Any: + ) -> dict[str, Any]: """Hook for per credential agent card response. If a dynamic card is needed based on the credentials provided in the request @@ -178,26 +173,16 @@ async def handle_authenticated_agent_card( ) card_to_serve = self.extended_agent_card + if not card_to_serve: + card_to_serve = self.agent_card + if self.extended_card_modifier: context = self._context_builder.build(request) # If no base extended card is provided, pass the public card to the modifier base_card = card_to_serve if card_to_serve else self.agent_card card_to_serve = self.extended_card_modifier(base_card, context) - if card_to_serve: - return card_to_serve.model_dump( - exclude_none=True, - by_alias=True, - ) - # If supports_authenticated_extended_card is true, but no - # extended_agent_card was provided, and no modifier produced a card, - # return a 404. - return JSONResponse( - { - 'error': 'Authenticated extended agent card is supported but not configured on the server.' - }, - status_code=404, - ) + return card_to_serve.model_dump(mode='json', exclude_none=True) def routes(self) -> dict[tuple[str, str], Callable[[Request], Any]]: """Constructs a dictionary of API routes and their corresponding handlers. From 6310c5da113c21e52f0e88a499b8b6b98e02ff3f Mon Sep 17 00:00:00 2001 From: rajeshvelicheti Date: Tue, 12 Aug 2025 15:51:29 -0700 Subject: [PATCH 14/15] Changes per review comments --- src/a2a/server/apps/rest/rest_adapter.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/a2a/server/apps/rest/rest_adapter.py b/src/a2a/server/apps/rest/rest_adapter.py index 91e6626ab..0860825bf 100644 --- a/src/a2a/server/apps/rest/rest_adapter.py +++ b/src/a2a/server/apps/rest/rest_adapter.py @@ -234,9 +234,6 @@ def routes(self) -> dict[tuple[str, str], Callable[[Request], Any]]: ('/v1/tasks', 'GET'): functools.partial( self._handle_request, self.handler.list_tasks ), - ('/v1/well_known/agent_json', 'GET'): functools.partial( - self._handle_request, self.handle_get_agent_card - ), } if self.agent_card.supports_authenticated_extended_card: routes[('/v1/card', 'GET')] = functools.partial( From 726ed405a95463a777fe780f0d01ef98ab434ab2 Mon Sep 17 00:00:00 2001 From: rajeshvelicheti Date: Tue, 12 Aug 2025 16:12:35 -0700 Subject: [PATCH 15/15] Changes per review comments --- src/a2a/server/apps/rest/fastapi_app.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/a2a/server/apps/rest/fastapi_app.py b/src/a2a/server/apps/rest/fastapi_app.py index 31ab0dcf6..3ae5ad6fe 100644 --- a/src/a2a/server/apps/rest/fastapi_app.py +++ b/src/a2a/server/apps/rest/fastapi_app.py @@ -6,11 +6,13 @@ if TYPE_CHECKING: from fastapi import APIRouter, FastAPI, Request, Response + from fastapi.responses import JSONResponse _package_fastapi_installed = True else: try: from fastapi import APIRouter, FastAPI, Request, Response + from fastapi.responses import JSONResponse _package_fastapi_installed = True except ImportError: @@ -111,7 +113,8 @@ def build( @router.get(f'{rpc_url}{agent_card_url}') async def get_agent_card(request: Request) -> Response: - return await self._adapter.handle_get_agent_card(request) + card = await self._adapter.handle_get_agent_card(request) + return JSONResponse(card) app.include_router(router) return app