Extending a MCP/A2A Currency Agent with A2UI — Stable…
    Neura MarketNeura Market/Stable Diffusion
    ChatGPTChatGPTClaudeClaudeGeminiGeminiCursorCursorGrokGrokPerplexityPerplexityStable DiffusionStable Diffusion
    DeepSeekDeepSeekCoPilotCoPilotMidjourneyMidjourney
    View All Directories
    OverviewPromptsBlogVideosGuidesCoursesCommunityModelsLoRAsComfyUI WorkflowsTrending
    Stable DiffusionBlogExtending a MCP/A2A Currency Agent with A2UI
    Back to Blog
    Extending a MCP/A2A Currency Agent with A2UI
    agents

    Extending a MCP/A2A Currency Agent with A2UI

    xbill June 4, 2026
    0 views

    Building an Agent with A2A, MCP, ADK, and A2UI This tutorial aims to extend and test a...


    title: Extending a MCP/A2A Currency Agent with A2UI published: true series: A2A date: 2026-06-03 21:02:16 UTC tags: aiagent,googleadk,a2aprotocol,a2ui canonical_url: https://xbill999.medium.com/extending-a-mcp-a2a-currency-agent-with-a2ui-dc43ffdc2508

    Building an Agent with A2A, MCP, ADK, and A2UI

    This tutorial aims to extend and test a currency Agent using A2A and MCP protocols with the A2UI protocol for custom presentation.

    Reduce, Re-Use, Re-Cycle!

    This paper is a re-visiting of the original currency Agent Codelab:

    Getting Started with MCP, ADK and A2A | Google Codelabs

    and a GitHub Repo:

    GitHub - jackwotherspoon/currency-agent: A sample agent demonstrating A2A + ADK + MCP working together.

    In this updated version, the Antigravity CLI is used to add support for A2UI and extend the existing user interface.

    What is the A2A protocol?

    The Agent2Agent (A2A) protocol, an open communication standard for AI agents, was initially introduced by Google in April 2025. It is specifically engineered to facilitate seamless interoperability within multi-agent systems, enabling AI agents developed by diverse providers or built upon disparate AI agent frameworks to communicate and collaborate effectively.

    A good overview of the A2A protocol can be found here:

    A2A Protocol

    Language Support For the A2A Protocol

    The official ADK for Python, GO, and Java provide built-in support for working with the A2A protocol. For other programming languages like JS, Rust, and .NET — 3rd party libraries are available to add support for the protocol.

    The main source for A2A Language support is the GitHub repo:

    GitHub - a2aproject/A2A: An open protocol enabling communication and interoperability between opaque agentic applications.

    A2UI

    A2UI (Agent-to-User Interface) is an open-source protocol that allows AI agents to dynamically generate and stream rich, interactive user interfaces in real-time. [1, 2]

    Instead of an AI relying on pre-built screens or just returning plain text in a chat window, A2UI enables the agent to instantly build and display tailored components like interactive charts, date-pickers, or approval forms. [1, 2]

    What is A2UI? - A2UI

    More Word Salad Protocols — What about A2A-XYZ?

    This article provides a good overview of how the various protocols fit together:

    A2A, MCP, AG-UI, A2UI: The Essential 2026 AI Agent Protocol Stack

    Confused yet? But wait- there’s more!

    How Does A2UI Compare? - A2UI

    Antigravity CLI

    Antigravity CLI is the follow-on successor to Gemini CLI- the terminal driven, agent assisted coding tool.

    Full details on installing Antigravity CLI are here:

    Getting Started with Antigravity CLI

    Testing the Antigravity CLI Environment

    Once you have all the tools in place- you can test the startup of Antigravity CLI.

    You will need to authenticate with a Google Cloud Project or your Google Account:

    agy
    

    This will start the interface:

    Checking the Developer Environment

    Verify that all the prerequisite packages and compilers are installed — and clone the sample Github repo:

    git clone https://github.com/xbill9/currency-agent
    cd currency-agent
    

    Once you have your Google Cloud Project and preferred authentication method — run the init.sh script to validate the setup:

    xbill@penguin:~/currency-agent$ source init.sh
    
    [environment: Development]
    Updated property [core/project].
    ADC is valid.
    Environment setup
    GOOGLE_GENAI_USE_VERTEXAI=1
    GOOGLE_CLOUD_PROJECT=comglitn
    GOOGLE_CLOUD_LOCATION=us-central1
    IMAGEN_MODEL="imagen-3.0-fast-generate-001"
    GENAI_MODEL="gemini-2.5-flash"
    Cloud Login
      Credentialed Accounts
    ACTIVE ACCOUNT
    * [email protected]
    

    The set_env.sh script is provided to set common ADK environment variables:

    xbill@penguin:~/currency-agent$ source set_env.sh 
    Current Environment
    GOOGLE_GENAI_USE_VERTEXAI=false
    GOOGLE_CLOUD_PROJECT=comglitn
    GOOGLE_CLOUD_LOCATION=us-central1
    GENAI_MODEL="gemini-2.5-flash"
    
    Cloud Login
      Credentialed Accounts
    ACTIVE ACCOUNT
    * [email protected]
    
    To set the active account, run:
        $ gcloud config set account `ACCOUNT`
    
    ADK Version
    adk, version 2.1.0
    

    Debugging API Permission Errors

    If your application default credentials expires or your Google Cloud Authentication expires you will get an error. The workaround is to re-authenticate:

    gcloud auth login
    gcloud auth application-default login
    

    Another common error is that the environment variables are not set correctly. Go the the root directory and re-run the set_env.sh to set the variables:

    cd ~/currency-agent
    source set_env.sh
    

    A2A Debugging Tools -A2A Inspector

    The A2A Inspector is a standalone tool that provides low level visibility into the A2A protocol. The GitHub is available here:

    GitHub - a2aproject/a2a-inspector: Validation Tools for A2A Agents

    A summary of the features of the A2A inspector can be found here:

    A2A Protocol Documentation

    To install the A2A Inspector:

    cd ~
    git clone https://github.com/a2aproject/a2a-inspector
    

    Then follow the build instructions — you need uv , and a recent version of node :

    a2a-inspector/README.md at main · a2aproject/a2a-inspector

    Staring the A2A Inspector

    Once the A2A inspector has been installed- you can validate the installation by using this URL:

    http://127.0.0.1:5001/

    Local A2A Validation with A2A Inspector

    The local A2A agent is checked with the A2A Inspector:

    > which port is the a2a server listening on
    
    ● ListDir(/home/xbill/currency-agent) 
    ● Read(/home/xbill/currency-agent/GEMINI.md) 
    ● Read(/home/xbill/currency-agent/Makefile) (ctrl+o to expand)
    
      The A2A server is listening on port 10000 .
    
      This is configured when starting the service (e.g., via uvicorn currency_agent.agent:a2a_app --port 10000 ).
    
    

    and then the Agent card is retrieved:

    and the Agent skill cross checked:

    Antigravity CLI with MCP Connection

    The Master Agent starts a FastMCP server interface. This allows Antigravity CLI to be used as a MCP client:

    xbill@penguin:~/currency-agent/.agents$ more mcp_config.json 
    
        "currency_mcp": {
          "serverUrl": "http://localhost:8080/mcp"
        }
    
    

    The MCP tools can be reviewed:

    MCP Servers
    
    Plugins (~/.gemini/antigravity-cli/plugins)
       ✓ currency_mcp Tools: get_exchange_rate
    

    The MCP tool functionality can be checked with Antigravity:

    
    > what does get_exchange_rate do?
    
      I will search the repository to locate the definition of the get_exchange_rate tool.
    
    ● Search(Grep search) (ctrl+o to expand)
    
      I will view the definition of the get_exchange_rate tool in server.py.
    
    ● Read(/home/xbill/currency-agent/mcp-server/server.py) (ctrl+o to expand)
    
      The server.py tool is an MCP tool defined in server.py.
    
      ### What it does:
    
      It retrieves the currency exchange rate between two currencies for a specific date (or the latest date) using the
      free Frankfurter API https://www.frankfurter.dev/.
    
      ### Parameters:
    
      • currency_from ( str , default "USD" ): The source currency code (e.g. "USD" , "GBP" , "CAD" ).
      • currency_to ( str , default "EUR" ): The destination currency code to convert to (e.g. "EUR" , "JPY" , "AUD" 
      ).
      • currency_date ( str , default "latest" ): The date for the exchange rate query (formatted as YYYY-MM-DD or    
      "latest" ).
    
      ### Returns:
    
      It returns a Python dictionary containing the Frankfurter API response:
    
        {
          "amount": 1.0,
          "base": "USD",       
          "date": "2026-06-03",
          "rates": {      
            "EUR": 0.86103
          } 
        }
    
      If an HTTP request fails or returns an invalid response, it catches the error and returns a dictionary detailing the
      error (e.g., {"error": "API request failed: ..."} ).
    

    So What is all this Doing?

    All of the setup and configuration allows you to start debugging and visualizing Agent flows using the A2A protocol. The currency Agent has been validated using the A2A Inspector and the MCP interface via Antigravity CLI.

    The make help provides the main project targets:

    xbill@penguin:~/currency-agent$ make help
    Available commands:
      install - Install all project dependencies (including frontend and react UI)
      start - Start all services in background (MCP + Agent)
      stop - Stop all background services
      status - Check status of background services
      mcp - Start the MCP Server (foreground)
      agent - Start the A2A Agent Server (foreground)
      frontend - Build and start the FastAPI + Vanilla TS frontend server (port 8000)
      react-install - Install dependencies for React + CopilotKit UI
      react-ui - Start React Frontend UI (port 3000)
      react-agent - Start React Frontend Agent (port 8000)
      test-client - Run the A2A Client (test queries)
      e2e-test - Run end-to-end tests (alias for test-client)
      adktest - Run interactive ADK CLI for the agent
      test - Run all tests (pytest)
      frontend-test - Run frontend specific tests
      lint - Run linting checks (ruff)
      format - Auto-format code (ruff)
      clean - Remove caches and logs
      deploy - Deploy to Cloud Run using Cloud Build
      logs - Read logs from Cloud Run
      endpoint - Get the Cloud Run service endpoint
      remote-status - Check the status of the remote endpoint
    xbill@penguin:~/currency-agent$ 
    

    Building and Debugging

    The Makefile provides targets to build and manage the project:

    make install
    xbill@penguin:~/currency-agent$ make install
    Installing dependencies...
    uv sync
    Resolved 109 packages in 1ms
    Checked 105 packages in 0.60ms
    make frontend-install
    make[1]: Entering directory '/home/xbill/currency-agent'
    Installing frontend dependencies...
    cd frontend/frontend && npm install
    
    up to date, audited 16 packages in 606ms
    
    5 packages are looking for funding
      run `npm fund` for details
    
    1 moderate severity vulnerability
    
    To address all issues, run:
      npm audit fix
    
    Run `npm audit` for details.
    uv pip install -r frontend/requirements.txt
    Checked 14 packages in 7ms
    make[1]: Leaving directory '/home/xbill/currency-agent'
    make react-install
    make[1]: Entering directory '/home/xbill/currency-agent'
    Installing React frontend dependencies...
    cd frontend-react && npm install
    
    > [email protected] postinstall
    > npm run install:agent
    
    > [email protected] install:agent
    > ./scripts/setup-agent.sh || scripts\setup-agent.bat
    
    Resolved 127 packages in 0.53ms
    Checked 123 packages in 0.56ms
    
    up to date, audited 1195 packages in 2s
    
    232 packages are looking for funding
      run `npm fund` for details
    
    9 vulnerabilities (5 low, 3 moderate, 1 high)
    
    To address issues that do not require attention, run:
      npm audit fix
    
    To address all issues (including breaking changes), run:
      npm audit fix --force
    
    Run `npm audit` for details.
    make[1]: Leaving directory '/home/xbill/currency-agent'
    

    Lint:

    xbill@penguin:~/currency-agent$ make lint
    Running linting checks (ruff check + format)...
    uv run ruff check .
    All checks passed!
    uv run ruff format --check .
    20 files already formatted
    

    Test:

    xbill@penguin:~/currency-agent$ make test
    Running tests...
    make stop
    make[1]: Entering directory '/home/xbill/currency-agent'
    Stopping servers...
    make[1]: Leaving directory '/home/xbill/currency-agent'
    make start
    make[1]: Entering directory '/home/xbill/currency-agent'
    Starting MCP Server in background...
    Waiting for MCP Server to initialize...
    Starting A2A Agent Server in background...
    Services started. Logs: mcp.log, agent.log
    make[1]: Leaving directory '/home/xbill/currency-agent'
    uv run pytest
    ================================================== test session starts ===================================================
    platform linux -- Python 3.13.13, pytest-9.0.3, pluggy-1.6.0
    rootdir: /home/xbill/currency-agent
    configfile: pyproject.toml
    plugins: asyncio-1.3.0, anyio-4.10.0
    asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
    collected 15 items                                                                                                       
    
    frontend/tests/test_a2a_utils.py .. [13%]
    frontend/tests/test_api.py ... [33%]
    frontend/tests/test_auth.py ... [53%]
    frontend/tests/test_logging_config.py .. [66%]
    frontend/tests/test_utils.py ... [86%]
    frontend-react/scripts/test_copilot_endpoint.py s [93%]
    mcp-server/test_server.py . [100%]
    
    

    Time to Start some Currency Arbitrage!

    The servers are started:

    xbill@penguin:~/currency-agent$ make start
    Starting MCP Server in background...
    Waiting for MCP Server to initialize...
    Starting A2A Agent Server in background...
    Services started. Logs: mcp.log, agent.log
    xbill@penguin:~/currency-agent$ make status
    Checking status of background services...
      All backend and frontend services are currently active and running:
    
      • MCP Server: Running (Port 8080)
      • A2A Agent Server: Running (Port 10000)
      • Frontend Server: Running (Port 8000)
    

    and checked end-to-end:

    xbill@penguin:~/currency-agent$ make e2e-test
    Running A2A Client tests...
    uv run currency_agent/test_client.py
    /home/xbill/currency-agent/.venv/lib/python3.13/site-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.3 is exactly one major version older than the runtime version 6.31.1 at a2a.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
      warnings.warn(
    --- 🔄 Connecting to agent at http://127.0.0.1:10000... ---
    /home/xbill/currency-agent/currency_agent/test_client.py:136: DeprecationWarning: A2AClient is deprecated and will be removed in a future version. Use ClientFactory to create a client with a JSON-RPC transport.
      client = A2AClient(
    --- ✅ Connection successful. ---
    --- ✉️ Single Turn Request ---
    --- 📥 Single Turn Request Response ---
    {"id":"0921454b-23dc-4b11-99b0-8e505ce61df9","jsonrpc":"2.0","result":{"artifacts":[{"artifactId":"7d9d4434-d5af-4741-b191-05d939f1c049","parts":[{"data":{"version":"v0.9","updateComponents":{"surfaceId":"currency_agent","components":[{"id":"root","component":"Card","child":"conversion_display"},{"id":"conversion_display","component":"Column","children":["initial_amount","exchange_rate_text","converted_amount"]},{"id":"initial_amount","component":"Text","variant":"h3","text":"100 USD is equal to:"},{"id":"exchange_rate_text","component":"Text","variant":"body","text":"Exchange Rate (USD to CAD): 1 USD = 1.3857 CAD"},{"id":"converted_amount","component":"Text","variant":"h2","text":"138.57 CAD"}]}},"kind":"data","metadata":{"mimeType":"application/json+a2ui"}},{"kind":"text","text":"100 USD is 138.57 CAD."}]}],"contextId":"81d471d1-0a12-4470-b752-85904a0d8d6c","history":[{"contextId":"81d471d1-0a12-4470-b752-85904a0d8d6c","kind":"message","messageId":"be48a82bd4d34484983ed106cc7d3f33","parts":[{"kind":"text","text":"how much is 100 USD in CAD?"}],"role":"user","taskId":"52014164-6d93-430f-9ea6-ecbeea73ac62"},{"contextId":"81d471d1-0a12-4470-b752-85904a0d8d6c","kind":"message","messageId":"be48a82bd4d34484983ed106cc7d3f33","parts":[{"kind":"text","text":"how much is 100 USD in CAD?"}],"role":"user","taskId":"52014164-6d93-430f-9ea6-ecbeea73ac62"},{"kind":"message","messageId":"b9789b81-b159-4f2d-83c5-c7c2b1c90b2b","parts":[{"data":{"id":"adk-c26ec1aa-91f7-446e-8630-252c9d6c906d","args":{"currency_from":"USD","currency_to":"CAD"},"name":"get_exchange_rate"},"kind":"data","metadata":{"adk_type":"function_call","adk_thought_signature":"CoIDAQw51scWbt6KizGVX3bW32jTuvriziuNmeSevAkVV3/eDXpYNQO1yBaVslcacx5hm56GxgZeZ7clP+WhJyVWZEr7JI13gYj5Dn6lFAyo2JxmcTx3HKA4rsAI2TCtmCk54hmar7Nwx3pCKQ/25dFvQ2dmU3yJ0023JO9CB5MQyIMFe1kCG6wwspfYXsFCfK/n9EstWQNuKQC4bp1u9z8cEefx8vvXhyioAirZfCnFYTQye9SAqYBLoLue6rCpN7k1WNNKrbheiiBiuk9cuQTCChr6V9npWoE+IkV6rwYFaM1XNW9ecTdqShDehvagVYJjETGCi3VOIpotclNKhF14CI2fulDrgYiEhZGQvC2Hp9ozJWrb31kd/b94Y8FZ2MqgyWxCF7qmCUfEAQ4HGr+x92lLEWkapN35MNW4RmjJwieJsZwGqC+bzhxueD2oFYclviNzMqJsFgcgVS4JC9w00/nDIyxe3ketyRys/CbwasNdLHUlYjcWSLI7PoZXk7f3TZI="}}],"role":"agent"},{"kind":"message","messageId":"127d8a47-ca80-459e-933e-5d946d33da6a","parts":[{"data":{"id":"adk-c26ec1aa-91f7-446e-8630-252c9d6c906d","name":"get_exchange_rate","response":{"content":[{"type":"text","text":"{\"amount\":1.0,\"base\":\"USD\",\"date\":\"2026-06-03\",\"rates\":{\"CAD\":1.3857}}"}],"structuredContent":{"amount":1.0,"base":"USD","date":"2026-06-03","rates":{"CAD":1.3857}},"isError":false}},"kind":"data","metadata":{"adk_type":"function_response"}}],"role":"agent"},{"kind":"message","messageId":"f8313128-811e-43c1-9ad5-2463bc7ecd61","parts":[{"data":{"version":"v0.9","updateComponents":{"surfaceId":"currency_agent","components":[{"id":"root","component":"Card","child":"conversion_display"},{"id":"conversion_display","component":"Column","children":["initial_amount","exchange_rate_text","converted_amount"]},{"id":"initial_amount","component":"Text","variant":"h3","text":"100 USD is equal to:"},{"id":"exchange_rate_text","component":"Text","variant":"body","text":"Exchange Rate (USD to CAD): 1 USD = 1.3857 CAD"},{"id":"converted_amount","component":"Text","variant":"h2","text":"138.57 CAD"}]}},"kind":"data","metadata":{"mimeType":"application/json+a2ui"}},{"kind":"text","text":"100 USD is 138.57 CAD."}],"role":"agent"}],"id":"52014164-6d93-430f-9ea6-ecbeea73ac62","kind":"task","metadata":{"adk_app_name":"currency_agent","adk_user_id":"A2A_USER_81d471d1-0a12-4470-b752-85904a0d8d6c","adk_session_id":"81d471d1-0a12-4470-b752-85904a0d8d6c","adk_invocation_id":"e-800169b7-70f8-4a90-9613-c80d43152b4f","adk_author":"currency_agent","adk_event_id":"0e81d6c1-5b69-4969-bad7-6d14fe58e9ab","adk_usage_metadata":{"cacheTokensDetails":[{"modality":"TEXT","tokenCount":24060}],"cachedContentTokenCount":24060,"candidatesTokenCount":317,"promptTokenCount":24450,"promptTokensDetails":[{"modality":"TEXT","tokenCount":24450}],"thoughtsTokenCount":100,"totalTokenCount":24867},"adk_actions":{"stateDelta":{},"artifactDelta":{},"requestedAuthConfigs":{},"requestedToolConfirmations":{}}},"status":{"state":"completed","timestamp":"2026-06-03T19:31:49.955541+00:00"}}}
    
    --- ❔ Query Task ---
    --- 📥 Query Task Response ---
    {"id":"416f7448-0059-45aa-90c6-c90a96d021bc","jsonrpc":"2.0","result":{"artifacts":[{"artifactId":"7d9d4434-d5af-4741-b191-05d939f1c049","parts":[{"data":{"version":"v0.9","updateComponents":{"surfaceId":"currency_agent","components":[{"id":"root","component":"Card","child":"conversion_display"},{"id":"conversion_display","component":"Column","children":["initial_amount","exchange_rate_text","converted_amount"]},{"id":"initial_amount","component":"Text","variant":"h3","text":"100 USD is equal to:"},{"id":"exchange_rate_text","component":"Text","variant":"body","text":"Exchange Rate (USD to CAD): 1 USD = 1.3857 CAD"},{"id":"converted_amount","component":"Text","variant":"h2","text":"138.57 CAD"}]}},"kind":"data","metadata":{"mimeType":"application/json+a2ui"}},{"kind":"text","text":"100 USD is 138.57 CAD."}]}],"contextId":"81d471d1-0a12-4470-b752-85904a0d8d6c","history":[{"contextId":"81d471d1-0a12-4470-b752-85904a0d8d6c","kind":"message","messageId":"be48a82bd4d34484983ed106cc7d3f33","parts":[{"kind":"text","text":"how much is 100 USD in CAD?"}],"role":"user","taskId":"52014164-6d93-430f-9ea6-ecbeea73ac62"},{"contextId":"81d471d1-0a12-4470-b752-85904a0d8d6c","kind":"message","messageId":"be48a82bd4d34484983ed106cc7d3f33","parts":[{"kind":"text","text":"how much is 100 USD in CAD?"}],"role":"user","taskId":"52014164-6d93-430f-9ea6-ecbeea73ac62"},{"kind":"message","messageId":"b9789b81-b159-4f2d-83c5-c7c2b1c90b2b","parts":[{"data":{"id":"adk-c26ec1aa-91f7-446e-8630-252c9d6c906d","args":{"currency_from":"USD","currency_to":"CAD"},"name":"get_exchange_rate"},"kind":"data","metadata":{"adk_type":"function_call","adk_thought_signature":"CoIDAQw51scWbt6KizGVX3bW32jTuvriziuNmeSevAkVV3/eDXpYNQO1yBaVslcacx5hm56GxgZeZ7clP+WhJyVWZEr7JI13gYj5Dn6lFAyo2JxmcTx3HKA4rsAI2TCtmCk54hmar7Nwx3pCKQ/25dFvQ2dmU3yJ0023JO9CB5MQyIMFe1kCG6wwspfYXsFCfK/n9EstWQNuKQC4bp1u9z8cEefx8vvXhyioAirZfCnFYTQye9SAqYBLoLue6rCpN7k1WNNKrbheiiBiuk9cuQTCChr6V9npWoE+IkV6rwYFaM1XNW9ecTdqShDehvagVYJjETGCi3VOIpotclNKhF14CI2fulDrgYiEhZGQvC2Hp9ozJWrb31kd/b94Y8FZ2MqgyWxCF7qmCUfEAQ4HGr+x92lLEWkapN35MNW4RmjJwieJsZwGqC+bzhxueD2oFYclviNzMqJsFgcgVS4JC9w00/nDIyxe3ketyRys/CbwasNdLHUlYjcWSLI7PoZXk7f3TZI="}}],"role":"agent"},{"kind":"message","messageId":"127d8a47-ca80-459e-933e-5d946d33da6a","parts":[{"data":{"id":"adk-c26ec1aa-91f7-446e-8630-252c9d6c906d","name":"get_exchange_rate","response":{"content":[{"type":"text","text":"{\"amount\":1.0,\"base\":\"USD\",\"date\":\"2026-06-03\",\"rates\":{\"CAD\":1.3857}}"}],"structuredContent":{"amount":1.0,"base":"USD","date":"2026-06-03","rates":{"CAD":1.3857}},"isError":false}},"kind":"data","metadata":{"adk_type":"function_response"}}],"role":"agent"},{"kind":"message","messageId":"f8313128-811e-43c1-9ad5-2463bc7ecd61","parts":[{"data":{"version":"v0.9","updateComponents":{"surfaceId":"currency_agent","components":[{"id":"root","component":"Card","child":"conversion_display"},{"id":"conversion_display","component":"Column","children":["initial_amount","exchange_rate_text","converted_amount"]},{"id":"initial_amount","component":"Text","variant":"h3","text":"100 USD is equal to:"},{"id":"exchange_rate_text","component":"Text","variant":"body","text":"Exchange Rate (USD to CAD): 1 USD = 1.3857 CAD"},{"id":"converted_amount","component":"Text","variant":"h2","text":"138.57 CAD"}]}},"kind":"data","metadata":{"mimeType":"application/json+a2ui"}},{"kind":"text","text":"100 USD is 138.57 CAD."}],"role":"agent"}],"id":"52014164-6d93-430f-9ea6-ecbeea73ac62","kind":"task","metadata":{"adk_app_name":"currency_agent","adk_user_id":"A2A_USER_81d471d1-0a12-4470-b752-85904a0d8d6c","adk_session_id":"81d471d1-0a12-4470-b752-85904a0d8d6c","adk_invocation_id":"e-800169b7-70f8-4a90-9613-c80d43152b4f","adk_author":"currency_agent","adk_event_id":"0e81d6c1-5b69-4969-bad7-6d14fe58e9ab","adk_usage_metadata":{"cacheTokensDetails":[{"modality":"TEXT","tokenCount":24060}],"cachedContentTokenCount":24060,"candidatesTokenCount":317,"promptTokenCount":24450,"promptTokensDetails":[{"modality":"TEXT","tokenCount":24450}],"thoughtsTokenCount":100,"totalTokenCount":24867},"adk_actions":{"stateDelta":{},"artifactDelta":{},"requestedAuthConfigs":{},"requestedToolConfirmations":{}}},"status":{"state":"completed","timestamp":"2026-06-03T19:31:49.955541+00:00"}}}
    
    --- 📝 Multi-Turn Request ---
    --- 📥 Multi-Turn: First Turn Response ---
    {"id":"c17d3d20-d4c1-4b70-b2a3-1f56b30529f1","jsonrpc":"2.0","result":{"artifacts":[{"artifactId":"29c35c34-b8ea-4c29-9ce1-929b97ab3ca3","parts":[{"kind":"text","text":"What currency do you want to convert to?"}]}],"contextId":"a106129a-7692-4bd1-bd06-0e4f09a258af","history":[{"contextId":"a106129a-7692-4bd1-bd06-0e4f09a258af","kind":"message","messageId":"2b709153e93d4ca2b59349c4dba6f658","parts":[{"kind":"text","text":"how much is 100 USD?"}],"role":"user","taskId":"e7eb6014-f770-4b06-b7fb-1a1a12b3bfee"},{"contextId":"a106129a-7692-4bd1-bd06-0e4f09a258af","kind":"message","messageId":"2b709153e93d4ca2b59349c4dba6f658","parts":[{"kind":"text","text":"how much is 100 USD?"}],"role":"user","taskId":"e7eb6014-f770-4b06-b7fb-1a1a12b3bfee"},{"kind":"message","messageId":"45a99a3b-7395-4af5-af7a-c1452e1f53b1","parts":[{"kind":"text","text":"What currency do you want to convert to?"}],"role":"agent"}],"id":"e7eb6014-f770-4b06-b7fb-1a1a12b3bfee","kind":"task","metadata":{"adk_app_name":"currency_agent","adk_user_id":"A2A_USER_a106129a-7692-4bd1-bd06-0e4f09a258af","adk_session_id":"a106129a-7692-4bd1-bd06-0e4f09a258af","adk_invocation_id":"e-8041dafe-4319-42ed-89ef-0999dacf84a7","adk_author":"currency_agent","adk_event_id":"195fc334-df88-40ec-bf75-884ff395b671","adk_usage_metadata":{"candidatesTokenCount":9,"promptTokenCount":24309,"promptTokensDetails":[{"modality":"TEXT","tokenCount":24309}],"thoughtsTokenCount":61,"totalTokenCount":24379},"adk_actions":{"stateDelta":{},"artifactDelta":{},"requestedAuthConfigs":{},"requestedToolConfirmations":{}}},"status":{"state":"completed","timestamp":"2026-06-03T19:31:51.471602+00:00"}}}
    
    --- 🚀 First turn completed, no further input required for this test case. ---
    

    Start the Currency Session

    Once all the agents have been started — the web interface on port 8000 is connected with a standard web browser:

    The new A2UI tools are presented:

    Running the new A2UI tools — conversion card:

    Rates Table:

    Line Chart: 5 day trend:

    Multicurrency Wallet:

    What does the A2UI Code Look Like?

    The A2UI generated code follows a well defined format:

     To match the workspace's glassmorphic aesthetics, the agent typically wraps components inside a Card layout using  
      parentId relationships:
    
        {                                                                                                                  
          "version": "v0.9",
          "components": [
            {
              "id": "container_card",
              "type": "Card",
              "props": {
                "title": "📈 Historical exchange rates"
              }
            },
            {
              "id": "historical_line_chart",
              "type": "LineChart",
              "parentId": "container_card",
              "props": {
                "title": "USD / EUR Trend",
                "labels": ["Mon", "Tue", "Wed", "Thu", "Fri"],
                "values": [0.8558, 0.8577, 0.8573, 0.8583, 0.8610],
                "color": "#3b82f6"
              }
            }
          ]
        }
    
    

    How does this all Work?

    Antigravity CLI has the answer!

    > summarize how the currency project uses A2UI
    
    ▸ Thought for 3s, 422 tokens
      Analyzing A2UI Integration
      The Currency Agent uses Agent-to-UI (A2UI) to present structured information (like conversion rates, trend tables,
      and
      wallet balances) as interactive, premium UI cards instead of raw text. Here is how it is implemented across the
      project:
    
      ### 1. Agent Configuration & Generation (agent.py)
    
      • Schema Definition: Initializes agent.py with version 0.9 components (e.g., Card , Text , Table , Column ,
      Row ).
      • Prompt Injection: The schema manager generates a detailed system prompt instruction that details the catalog schema
      and provides examples. This instructs the LLM (agent.py) on how to output structured JSON wrapped inside <a2ui-
      json>...</a2ui-json> blocks.
      • Part Conversion: Integrates agent.py inside the A2A executor factory to process Gemini's output and format
      A2UI blocks during Agent-to-Agent (A2A) protocol exchanges.
    
      ### 2. Frontend Parser & Renderer (app.ts)
    
      • Response Parsing: The workspace frontend regex-searches all incoming chat messages for <a2ui-json> blocks.
      • Dynamic Rendering: Passes the JSON content to app.ts, which parses the tree of UI components and
      dynamically builds native HTML elements matching the catalog parameters.
      • Sandbox Demos: Implements sandbox controls that simulate agent responses to let developers preview A2UI components
      live in the web browser.
    
      ### 3. Visual Styling (style.css)
    
      • Defines CSS properties for .a2ui-card and .a2ui-block-container , styled with glassmorphic borders, neon mint
      green text, and premium dark-mode grids matching the theme.
    
    

    Phew. that's a lot! What else is there?

      ### How A2UI works in this Project
    
      Rather than running a bidirectional state synchronizer (like AG-UI), this project relies on a clean, declarative A2UI
      flow:
    
      1. Prompt Configuration: In agent.py, the agent is configured with the A2uiSchemaManager to append formatting
      rules and examples to the system prompt.
      2. Declarative Output: The LLM output contains UI components formatted in JSON, wrapped in <a2ui-json>...</a2ui-    
      json> blocks.
      3. A2A Integration: The agent.py extracts these blocks and converts them into A2A parts.
      4. Client-Side Rendering: The frontend browser client (app.ts) extracts the raw <a2ui-json> blocks via
      regex and calls its client-side rendering engine app.ts to map the JSON elements to styled HTML containers.
    

    Are you sure? How about a code review:

      Initiating Code Review
      Here is a detailed code review of how Agent-to-UI (A2UI) is used within this project.
      ──────
       A2UI Code Review: Currency Agent Ecosystem 
    
      ## 1. Backend Architecture & Integration (agent.py)
    
      The backend uses the Google ADK library and the official a2ui Python package to inject formatting rules into the
      model context and package UI components.
    
      ### Setup & Prompt Generation
      • Schema Definition: Initializes the A2uiSchemaManager with version 0.9 and selects the BasicCatalog .
      • System Prompt Injection:
        SYSTEM_INSTRUCTION = schema_manager.generate_system_prompt(                                                        
            role_description=( ... ),                                                                                      
            workflow_description="Use components to display structured currency conversions and rates.",                   
            ui_description="Use Card and Text components for displaying rates. Use Table components when presenting        
      multiple exchange rates or history.",                                                                                
            include_schema=True,                                                                                           
            include_examples=True,                                                                                         
            allowed_components=["Card", "Text", "Table"],                                                                  
        )                                                                                                                  
    
          • Review Verdict: Excellent practice. Rather than manually typing and maintaining JSON-schema rules or few-shot
          examples in a raw text string, the A2uiSchemaManager generates precise prompt instructions dynamically. Setting
          allowed_components limits the model's vocabulary and prevents hallucination of unsupported UI elements.
    
      ### Toolset & Part Conversion
    
      • UI Toolset: Equips the LlmAgent with a2ui_toolset ( SendA2uiToClientToolset ).
      • Part Converter Setup:
        def agent_executor_factory(runner):                                                                                
            config = A2aAgentExecutorConfig(                                                                               
                gen_ai_part_converter=A2uiPartConverter(                                                                   
                    selected_catalog, bypass_tool_check=True                                                               
                ).convert                                                                                                  
            )                                                                                                              
            return A2aAgentExecutor(runner=runner, config=config)                                                          
    
          • Review Verdict: By integrating the A2uiPartConverter directly into the A2aAgentExecutorConfig , any text
          responses returned by Gemini containing <a2ui-json> blocks are interceptable and mapped cleanly into structured
          data parts matching the A2A MIME standard ( application/json+a2ui ).
    
      ──────
      ## 2. Frontend Parser & Renderer (app.ts)
    
      The frontend receives the response, parses out the <a2ui-json> block, and recursively translates it to styled HTML
      components.
    
      ### Regex Extraction
    
      • Location: app.ts
        const a2uiRegex = /<a2ui-json>([\s\S]*?)<\/a2ui-json>/;                                                            
        const match = text.match(a2uiRegex);                                                                               
    
          • Review Verdict: The regex is simple, clean, and handles multi-line blocks. It strips the <a2ui-json> block
          from the text message so the user gets clean text alongside a structured component.
    
      ### DOM Generation Engine ( renderA2UI )
    
      • Location: app.ts
      • Schema Normalization: Parses the JSON and accommodates multiple layout formats (basic array, parsed.components ,  
      parsed.updateComponents.components , or parsed.message.components ).
      • Hierarchy Resolution: Resolves hierarchical relationships using parentId referencing, allowing nested elements:
        normalized.forEach((c: any) => {                                                                                   
            if (c.child) { ... }                                                                                           
            if (Array.isArray(c.children)) { ... }                                                                         
        });                                                                                                                
    
      • Security & XSS Prevention:
      Throughout the element building code (e.g. el.textContent = c.props.value or title.textContent = cardComp.props.  
      title ), the renderer uses textContent rather than innerHTML .
          • Review Verdict: Highly Secure. Directly mapping LLM output to innerHTML poses a serious Cross-Site Scripting
          (XSS) risk if the model produces malformed or malicious script tags. Using textContent ensures that strings are
          treated strictly as text.
    
      ### Visual Aesthetics
    
      • The components are styled using theme-consistent CSS variables (e.g., background = 'hsl(var(--bg-card))' , border
      = '1px solid hsl(var(--border-color))' ).
          • Review Verdict: Ensures that the A2UI elements match the surrounding dark mode/glassmorphism styling system
          seamlessly.
    
      ──────
      ## 3. Strengths & Best Practices Found
    
      1. Decoupled Architecture: The agent provides a declarative specification of the UI components ( what to render) and
      leaves the client browser in control of styling, positioning, and visual mapping ( how to render).
      2. Robust Fallbacks: The code handles cases where there is a parse failure by logging the error and falling back to
      raw text so that the conversation does not break.
      3. Recursive Column/Row Layouts: Incorporating parent-child rendering ( renderElement ) allows complex nested grids
      (e.g., wallet columns/rows) to render gracefully.
    
    

    Summary

    The goal of the demo/article was to enable A2UI presentation controls on a functional agent supporting common protocols like A2A and MCP.

    The currency agent was chosen as a starting point and new A2UI presentation objects were added to the user interface with Antigravity CLI.

    Finally- the updated A2UI project integration was summarized, and code reviewed with Antigravity CLI.

    Tags

    agentsgoogleadka2aprotocola2ui

    Comments

    More Blog

    View all
    Context bankruptcy: The case for strategic forgetting for AI Agentsai

    Context bankruptcy: The case for strategic forgetting for AI Agents

    Most of us have seen a coding agent fail to complete a task we know it can do. We just don't...

    J
    James O'Reilly
    Parallel Compliance Engine: Drive-to-Sheets Multi-Agent Orchestrationgooglecloud

    Parallel Compliance Engine: Drive-to-Sheets Multi-Agent Orchestration

    When building Generative AI applications, developers often encounter a massive bottleneck: sequential...

    A
    Aryan Irani
    Is It Ethical to Post and Ask About Circuits on Dev.to?discuss

    Is It Ethical to Post and Ask About Circuits on Dev.to?

    I’ve been thinking about sharing some electronic circuit posts on Dev.to — small circuits, DIY...

    C
    codebunny20
    The One-Click Exporter: AI Studio Antigravity, Probed to Its Limitsagents

    The One-Click Exporter: AI Studio Antigravity, Probed to Its Limits

    What nobody tells you about exporting your multi-agent prototype to a local workspace. Every...

    L
    leslysandra
    Guarding the till while autonomous data agents do the diggingagenticarchitect

    Guarding the till while autonomous data agents do the digging

    Autonomous agents are genuinely good at answering messy business questions. Give one an LLM and a set...

    S
    Sireesha Pulipati
    Return on Attention: Why AI Code Reviews Are Wearing Us Outai

    Return on Attention: Why AI Code Reviews Are Wearing Us Out

    PR volume went up, ticket quality didn't, and the gap got filled with LLMs on both sides of the review: bots reviewing, bots replying, bots occasionally arguing with bots about priorities that only existed in a teammate's head. Our CEO named the actual problem, and it's bigger than code review.

    C
    christine

    Stay up to date

    Get the latest Stable Diffusion prompts, rules, and resources delivered to your inbox weekly.

    Neura Market LogoNeura Market

    Discover the best AI prompts, plugins, and resources for Stable Diffusion and more.

    Content Types

    • Rules
    • Prompts
    • MCPs
    • Agents
    • Guides

    Platforms

    • ChatGPT Directory
    • Claude Directory
    • Gemini Directory
    • Cursor Directory
    • Grok Directory
    • Perplexity Directory
    • DeepSeek Directory
    • CoPilot Directory
    • Stable Diffusion Directory
    • Midjourney Directory
    • All Directories

    Resources

    • Blog
    • Documentation
    • Help Center
    • Marketplace

    Legal

    • Privacy Policy
    • Terms of Service

    © 2026 Neura Market. All rights reserved.

    |

    Not affiliated with any AI platform vendors.

    Ready-made automations for this

    Workflows from the Neura Market marketplace related to this Stable Diffusion resource

    • Automate Your Website Building with N8N: Unsubscribe Workflowmake · $6.62 · Related topic
    • Automated Currency Rate Update for Patient Management in Healthcaren8n · $16.09 · Related topic
    • Currency Exchange Estimatorn8n · $14.99 · Related topic
    • Currency Rate Monitor: Automate Your Financial Insightsn8n · $13.06 · Related topic
    Browse all workflows