diff --git a/samples/agent/adk/mcp_app_proxy/agent.py b/samples/agent/adk/mcp_app_proxy/agent.py index ad0a94e42..ac06c6852 100644 --- a/samples/agent/adk/mcp_app_proxy/agent.py +++ b/samples/agent/adk/mcp_app_proxy/agent.py @@ -28,16 +28,17 @@ from google.adk.sessions import InMemorySessionService from google.genai import types from pydantic import PrivateAttr -from tools import get_calculator_app, calculate_via_mcp +from tools import get_calculator_app, calculate_via_mcp, get_pong_app_a2ui_json from agent_executor import get_a2ui_enabled, get_a2ui_catalog, get_a2ui_examples logger = logging.getLogger(__name__) ROLE_DESCRIPTION = """ -You are an expert A2UI Proxy Agent. Your primary function is to fetch the Calculator App and display it to the user. +You are an expert A2UI Proxy Agent. Your primary functions are to fetch the Calculator App or the Pong App and display it to the user. When the user asks for the calculator, you MUST call the `get_calculator_app` tool. +When the user asks for Pong, you MUST call the `get_pong_app_a2ui_json` tool. -IMPORTANT: Do NOT attempt to construct the JSON manually. The tool `get_calculator_app` handles it automatically. +IMPORTANT: Do NOT attempt to construct the JSON manually. The tools handle it automatically. When the user interacts with the calculator and issues a `calculate` action, you MUST call the `calculate_via_mcp` tool to perform the calculation via the remote MCP server. Return the resulting number directly as text to the user. """ @@ -45,6 +46,7 @@ WORKFLOW_DESCRIPTION = """ 1. **Analyze Request**: - If User asks for calculator: Call `get_calculator_app`. + - If User asks for Pong: Call `get_pong_app_a2ui_json`. - If User interacts with the calculator (ACTION: calculate): Extract 'operation', 'a', and 'b' from the event context and call `calculate_via_mcp`. Return the result to the user. """ @@ -134,7 +136,10 @@ def _build_agent_card(self) -> AgentCard: return AgentCard( name="MCP App Proxy Agent", - description="Provides access to MCP Apps like Calculator.", + description=( + "Provides access to MCP Apps and HTML demos, such as the Calculator and" + " Pong apps." + ), url=self.base_url, version="1.0.0", default_input_modes=McpAppProxyAgent.SUPPORTED_CONTENT_TYPES, @@ -147,7 +152,14 @@ def _build_agent_card(self) -> AgentCard: description="Opens the calculator app.", tags=["calculator", "app", "tool"], examples=["open calculator", "show calculator"], - ) + ), + AgentSkill( + id="open_pong", + name="Open Pong", + description="Opens Pong, a simple HTML game.", + tags=["html", "app", "demo", "tool"], + examples=["open pong", "show pong"], + ), ], ) @@ -182,7 +194,7 @@ def _build_llm_agent( name=self._agent_name, description="An agent that provides access to MCP Apps.", instruction=instruction, - tools=[get_calculator_app, calculate_via_mcp], + tools=[get_calculator_app, calculate_via_mcp, get_pong_app_a2ui_json], planner=BuiltInPlanner( thinking_config=types.ThinkingConfig( include_thoughts=True, diff --git a/samples/agent/adk/mcp_app_proxy/pong_app.html b/samples/agent/adk/mcp_app_proxy/pong_app.html new file mode 100644 index 000000000..21c98112b --- /dev/null +++ b/samples/agent/adk/mcp_app_proxy/pong_app.html @@ -0,0 +1,503 @@ + + + + + + + + Neon Pong - A2UI Demo + + + + + + +
+
+ +
+
+

NEON PONG

+
+
+ Player + 0 +
+
+ CPU + 0 +
+
+
+ +
+ +
+

NEON PONG

+ +
+ +
+ +
+ Move: W / S or Mouse +
+
+ + + + diff --git a/samples/agent/adk/mcp_app_proxy/tools.py b/samples/agent/adk/mcp_app_proxy/tools.py index d98072ac6..500b1f02a 100644 --- a/samples/agent/adk/mcp_app_proxy/tools.py +++ b/samples/agent/adk/mcp_app_proxy/tools.py @@ -108,3 +108,45 @@ async def calculate_via_mcp(operation: str, a: float, b: float): except Exception as e: logger.error(f"Error calling MCP calculate: {e} {traceback.format_exc()}") return f"Error connecting to MCP server: {e}" + + +async def get_pong_app_a2ui_json(tool_context: ToolContext): + """Fetches the Pong game app.""" + import os + + current_dir = os.path.dirname(os.path.abspath(__file__)) + html_file_path = os.path.join(current_dir, "pong_app.html") + + try: + with open(html_file_path, "r", encoding="utf-8") as f: + html_content = f.read() + except FileNotFoundError: + logger.error(f"Could not find {html_file_path}") + return {"error": "Could not find pong app HTML file."} + + encoded_html = "url_encoded:" + urllib.parse.quote(html_content) + messages = [ + { + "beginRendering": { + "surfaceId": "pong_surface", + "root": "pong_root", + }, + }, + { + "surfaceUpdate": { + "surfaceId": "pong_surface", + "components": [{ + "id": "pong_root", + "component": { + "McpApp": { + "content": {"literalString": encoded_html}, + "title": {"literalString": "Neon Pong"}, + "allowedTools": [], + } + }, + }], + }, + }, + ] + tool_context.actions.skip_summarization = True + return {"validated_a2ui_json": messages} diff --git a/samples/client/angular/projects/mcp_calculator/src/app/app.html b/samples/client/angular/projects/mcp_calculator/src/app/app.html index 66f19d83c..bdf5e9b3b 100644 --- a/samples/client/angular/projects/mcp_calculator/src/app/app.html +++ b/samples/client/angular/projects/mcp_calculator/src/app/app.html @@ -33,7 +33,11 @@
+