<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>article How to Deploy Agent-to-Agent (A2A) Protocol on Databricks Apps?-&amp;gt; End-to-End Guide in Technical Blog</title>
    <link>https://community.databricks.com/t5/technical-blog/how-to-deploy-agent-to-agent-a2a-protocol-on-databricks-apps-gt/ba-p/134213</link>
    <description>&lt;P&gt;&lt;SPAN&gt;Modern AI systems rarely live alone. They collaborate. Google’s &lt;/SPAN&gt;&lt;STRONG&gt;Agent-to-Agent (A2A)&lt;/STRONG&gt;&lt;SPAN&gt; protocol gives agents a common language (JSON-RPC over HTTP/S, with streaming via SSE) plus a discovery mechanism (the &lt;/SPAN&gt;&lt;STRONG&gt;Agent Card&lt;/STRONG&gt;&lt;SPAN&gt;) so they can find and work with each other securely.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Databricks Apps&lt;/STRONG&gt;&lt;SPAN&gt; let you ship secure, serverless AI apps &lt;/SPAN&gt;&lt;I&gt;&lt;SPAN&gt;inside&lt;/SPAN&gt;&lt;/I&gt;&lt;SPAN&gt; your Databricks workspace—no extra infra, integrated with Unity Catalog, SQL, Model Serving, OAuth and more. That’s perfect territory for hosting interoperable A2A agents where data governance and latency matter.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;In this post, you’ll deploy a production-style A2A server as a Databricks App. The example agent (“&lt;/SPAN&gt;&lt;STRONG&gt;CurrencyAgent&lt;/STRONG&gt;&lt;SPAN&gt;”) uses &lt;/SPAN&gt;&lt;STRONG&gt;LangGraph&lt;/STRONG&gt;&lt;SPAN&gt; tools + a Databricks&lt;/SPAN&gt;&lt;SPAN&gt;&amp;nbsp;LLM endpoint to answer FX questions—then exposes itself as an A2A service with streaming updates and optional push notifications.&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2&gt;&lt;SPAN&gt;What you’ll build&lt;/SPAN&gt;&lt;/H2&gt;
&lt;UL&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;A LangGraph-powered agent with a simple tool (get_exchange_rate via the Frankfurter API). &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;An &lt;/SPAN&gt;&lt;STRONG&gt;A2A Server&lt;/STRONG&gt;&lt;SPAN&gt; (Starlette/ASGI) that publishes an &lt;/SPAN&gt;&lt;STRONG&gt;Agent Card&lt;/STRONG&gt;&lt;SPAN&gt; and implements streaming (message/stream) and task artifacts. &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;A &lt;/SPAN&gt;&lt;STRONG&gt;Databricks App&lt;/STRONG&gt;&lt;SPAN&gt; (serverless) with a clean app.yaml, OAuth-friendly /api routing, and secrets handled safely.&lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;&lt;SPAN&gt;Architecture (at a glance)&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Mahavir_Teraiya_0-1759929370525.png" style="width: 999px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/20568i78DDF6902337E56E/image-size/large?v=v2&amp;amp;px=999" role="button" title="Mahavir_Teraiya_0-1759929370525.png" alt="Mahavir_Teraiya_0-1759929370525.png" /&gt;&lt;/span&gt;&lt;/P&gt;
&lt;H3&gt;&lt;SPAN&gt;Why A2A + Databricks Apps?&lt;/SPAN&gt;&lt;/H3&gt;
&lt;P&gt;&lt;SPAN&gt;A2A standardizes inter-agent comms (HTTP + JSON-RPC + SSE) and discovery (Agent Card). Databricks Apps provide governed hosting, OAuth integration and serverless scale so you can safely place agents next to your data and models.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2&gt;&lt;SPAN&gt;Prerequisites&lt;/SPAN&gt;&lt;/H2&gt;
&lt;UL&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;A Databricks workspace with &lt;/SPAN&gt;&lt;STRONG&gt;Apps&lt;/STRONG&gt;&lt;SPAN&gt; enabled and permission to deploy apps. &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;A &lt;/SPAN&gt;&lt;STRONG&gt;Model Serving&lt;/STRONG&gt;&lt;SPAN&gt; endpoint (e.g., Foundation Models API or your own) accessible via the&lt;/SPAN&gt;&lt;SPAN&gt;&amp;nbsp;interface. &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;(Recommended) OAuth setup for the app’s service principal and/or secrets configured via &lt;/SPAN&gt;&lt;STRONG&gt;Databricks Secrets&lt;/STRONG&gt;&lt;SPAN&gt;—don’t hardcode tokens. &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;Basic familiarity with the &lt;/SPAN&gt;&lt;STRONG&gt;Apps Cookbook&lt;/STRONG&gt;&lt;SPAN&gt; (FastAPI/ASGI patterns, /api route requirements, and deployment flow).&lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;&lt;SPAN&gt;Project layout&lt;/SPAN&gt;&lt;/H2&gt;
&lt;LI-CODE lang="markup"&gt;app/
  agent.py              # LangGraph agent using Databricks-hosted LLM
  agent_executor.py     # A2A AgentExecutor wiring (streaming + artifacts)
  server.py             # Starlette app exposing A2A endpoints + Agent Card
test.py                 # Notebook/REPL client using A2A SDK
app.yaml                # Databricks App config (command + env)
requirements.txt        # a2a-sdk[http-server], langgraph, httpx, uvicorn, etc.&lt;/LI-CODE&gt;
&lt;P&gt;&lt;SPAN&gt;The &lt;/SPAN&gt;&lt;STRONG&gt;A2A SDK&lt;/STRONG&gt;&lt;SPAN&gt; (a2a-sdk) provides server/client primitives, Agent Card types, event queues, push notifications, and JSON-RPC methods.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H1&gt;&lt;STRONG&gt;Step 1 — Implement the agent (LangGraph + ChatDatabricks)&lt;/STRONG&gt;&lt;/H1&gt;
&lt;P class="p3"&gt;&lt;SPAN class="s2"&gt;&lt;STRONG&gt;Goal:&lt;/STRONG&gt;&lt;/SPAN&gt; Build a small ReAct agent that calls a currency API tool and returns a &lt;SPAN class="s2"&gt;&lt;STRONG&gt;stable, typed&lt;/STRONG&gt;&lt;/SPAN&gt; (Pydantic) response you can safely consume downstream.&lt;/P&gt;
&lt;P class="p4"&gt;&lt;STRONG&gt;Key points:&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;P class="p1"&gt;Use &lt;SPAN class="s1"&gt;&lt;STRONG&gt;ChatDatabricks&lt;/STRONG&gt;&lt;/SPAN&gt; (LangChain on Databricks) and point it at your &lt;SPAN class="s1"&gt;&lt;STRONG&gt;Model Serving endpoint&lt;/STRONG&gt;&lt;/SPAN&gt; by name.&lt;/P&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;P class="p1"&gt;&lt;SPAN class="s1"&gt;Bind your tools and enable &lt;/SPAN&gt;&lt;SPAN class="s2"&gt;&lt;STRONG&gt;structured output&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;SPAN class="s1"&gt; with &lt;/SPAN&gt;response_format=(..., ResponseFormat)&lt;SPAN class="s1"&gt;.&lt;/SPAN&gt;&lt;/P&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;P class="p1"&gt;&lt;SPAN class="s1"&gt;Read the validated object from &lt;/SPAN&gt;state.values["structured_response"]&lt;SPAN class="s1"&gt;.&lt;/SPAN&gt;&lt;/P&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;P class="p1"&gt;&lt;SPAN class="s1"&gt;&lt;STRONG&gt;Auth:&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;SPAN class="s2"&gt; set &lt;/SPAN&gt;&lt;SPAN class="s1"&gt;&lt;STRONG&gt;either&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;SPAN class="s2"&gt; PAT (&lt;/SPAN&gt;DATABRICKS_TOKEN&lt;SPAN class="s2"&gt;) &lt;/SPAN&gt;&lt;SPAN class="s1"&gt;&lt;STRONG&gt;or&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;SPAN class="s2"&gt; OAuth (&lt;/SPAN&gt;DATABRICKS_CLIENT_ID&lt;SPAN class="s2"&gt; + &lt;/SPAN&gt;DATABRICKS_CLIENT_SECRET&lt;SPAN class="s2"&gt;) — not both.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class="p2"&gt;(Optional helper below auto-picks one if both are present.)&lt;/P&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;P class="p1"&gt;Frankfurter is a free, open-source currency API tracking ECB reference rates.&lt;/P&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;LI-CODE lang="python"&gt;# app/agent.py (excerpt)

import os, httpx, json, logging
from typing import Literal
from pydantic import BaseModel
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
from databricks_langchain import ChatDatabricks

log = logging.getLogger(__name__)

# --- Tool --------------------------------------------------------------------
@tool
def get_exchange_rate(currency_from: str="USD",
                      currency_to: str="EUR",
                      currency_date: str="latest"):
    """Use this to get current exchange rate."""
    r = httpx.get(
        f"https://api.frankfurter.app/{currency_date}",
        params={"from": currency_from, "to": currency_to},
        timeout=15.0,
    )
    r.raise_for_status()
    data = r.json()
    if "rates" not in data:
        return {"error": "Invalid API response format."}
    return data

# --- Structured response schema ----------------------------------------------
class ResponseFormat(BaseModel):
    status: Literal["input_required", "completed", "error"] = "input_required"
    message: str

# --- Optional: guard against PAT+OAuth at once (pick one) --------------------
def _prefer_single_databricks_auth():
    pat = bool(os.getenv("DATABRICKS_TOKEN"))
    oauth = bool(os.getenv("DATABRICKS_CLIENT_ID") and os.getenv("DATABRICKS_CLIENT_SECRET"))
    if pat and oauth:
        prefer = (os.getenv("DBX_AUTH_PREFERENCE") or "pat").lower()
        if prefer == "oauth":
            os.environ.pop("DATABRICKS_TOKEN", None)
            log.warning("Both PAT and OAuth found; preferring OAuth (unset DATABRICKS_TOKEN).")
        else:
            os.environ.pop("DATABRICKS_CLIENT_ID", None)
            os.environ.pop("DATABRICKS_CLIENT_SECRET", None)
            log.warning("Both PAT and OAuth found; preferring PAT (unset CLIENT_ID/SECRET).")

# --- LLM factory --------------------------------------------------------------
def _build_dbx_llm() -&amp;gt; ChatDatabricks:
    _prefer_single_databricks_auth()  # harmless if only one method is set
    endpoint = os.getenv("DBX_LLM_ENDPOINT")  # e.g., "databricks-dbrx-instruct" or your custom endpoint
    if not endpoint:
        raise RuntimeError("Missing required env var: DBX_LLM_ENDPOINT")

    # ChatDatabricks uses your Databricks workspace auth (PAT or OAuth).
    # When running outside a workspace, also set DATABRICKS_HOST.
    return ChatDatabricks(
        endpoint=endpoint,
        temperature=0.0,
        max_tokens=256,
        # Optional: smoothes tool-calling streams for some models
        disable_streaming="tool_calling",
    )

# --- Agent -------------------------------------------------------------------
class CurrencyAgent:
    SYSTEM_INSTRUCTION = (
        "You are a specialized assistant for currency conversions. "
        "Use the 'get_exchange_rate' tool to answer currency exchange questions. "
        "If asked about anything else, politely refuse."
    )

    def __init__(self):
        llm = _build_dbx_llm()
        tools = [get_exchange_rate]

        self.graph = create_react_agent(
            llm.bind_tools(tools),
            tools=tools,
            prompt=self.SYSTEM_INSTRUCTION,
            response_format=(
                "Set status to input_required, completed, or error as appropriate.",
                ResponseFormat,
            ),
        )&lt;/LI-CODE&gt;
&lt;P&gt;&lt;SPAN&gt;Frankfurter is a free, open-source currency API tracking ECB reference rates.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;LangGraph supports &lt;/SPAN&gt;&lt;STRONG&gt;structured responses&lt;/STRONG&gt;&lt;SPAN&gt; via response_format, which you read from state.values["structured_response"].&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;Databricks &lt;/SPAN&gt;&lt;STRONG&gt;Model Serving&lt;/STRONG&gt;&lt;SPAN&gt; exposes a unified&lt;/SPAN&gt;&lt;SPAN&gt;&amp;nbsp;API, which lets you use standard Chat clients in this case ChatDatabricks.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2&gt;&lt;SPAN&gt;Step 2 — Wire the agent to the A2A runtime&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN&gt;app/agent_executor.py bridges A2A’s &lt;/SPAN&gt;&lt;STRONG&gt;JSON-RPC&lt;/STRONG&gt;&lt;SPAN&gt; calls to your agent:&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;Accept a message, create/update a &lt;/SPAN&gt;&lt;STRONG&gt;Task&lt;/STRONG&gt;&lt;SPAN&gt;, stream &lt;/SPAN&gt;&lt;STRONG&gt;status&lt;/STRONG&gt;&lt;SPAN&gt; (working / input_required), and emit a final &lt;/SPAN&gt;&lt;STRONG&gt;artifact&lt;/STRONG&gt;&lt;SPAN&gt;.&lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;A2A uses an event queue to buffer updates for streaming via &lt;/SPAN&gt;&lt;STRONG&gt;SSE&lt;/STRONG&gt;&lt;SPAN&gt;.&lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;LI-CODE lang="python"&gt;# app/agent_executor.py (excerpt)

from a2a.server.agent_execution import AgentExecutor, RequestContext
from a2a.server.events import EventQueue
from a2a.server.tasks import TaskUpdater
from a2a.types import TaskState, Part, TextPart
from a2a.utils import new_agent_text_message, new_task
from app.agent import CurrencyAgent

class CurrencyAgentExecutor(AgentExecutor):

    def __init__(self): self.agent = CurrencyAgent()

    async def execute(self, context: RequestContext, event_queue: EventQueue) -&amp;gt; None:
        query = context.get_user_input()
        task = context.current_task or new_task(context.message)
        await event_queue.enqueue_event(task)
        updater = TaskUpdater(event_queue, task.id, task.context_id)

        async for item in self.agent.stream(query, task.context_id):
            if item["require_user_input"]:
                await updater.update_status(
                    TaskState.input_required,
                    new_agent_text_message(item["content"], task.context_id, task.id),
                    final=True,
                )

                break

            elif not item["is_task_complete"]:
                await updater.update_status(
                    TaskState.working,
                    new_agent_text_message(item["content"], task.context_id, task.id),
                )

            else:
                await updater.add_artifact([Part(root=TextPart(text=item["content"]))], name="conversion_result")
                await updater.complete()
                break&lt;/LI-CODE&gt;
&lt;P&gt;&lt;SPAN&gt;In A2A, streaming is done with SSE; clients receive a sequence of JSON-RPC responses until the task completes.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2&gt;&lt;SPAN&gt;Step 3 — Expose an Agent Card + JSON-RPC endpoints (Starlette)&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN&gt;Publish capabilities and skills so other agents can discover and call yours:&lt;/SPAN&gt;&lt;/P&gt;
&lt;LI-CODE lang="python"&gt;# app/server.py (excerpt)

import httpx, logging
from a2a.server.apps import A2AStarletteApplication
from a2a.server.request_handlers import DefaultRequestHandler
from a2a.server.tasks import InMemoryTaskStore, InMemoryPushNotificationConfigStore, BasePushNotificationSender
from a2a.types import AgentCapabilities, AgentCard, AgentSkill
from app.agent import CurrencyAgent
from app.agent_executor import CurrencyAgentExecutor

def build_asgi_app():
    capabilities = AgentCapabilities(streaming=True, push_notifications=True)
    skill = AgentSkill(
        id="convert_currency",
        name="Currency Exchange Rates Tool",
        description="Helps with exchange values between various currencies",
        tags=["currency conversion", "currency exchange"],
        examples=["What is exchange rate between USD and GBP?"],
    )

    agent_card = AgentCard(
        name="Currency Agent",
        description="Helps with exchange rates for currencies",
        url="/",  # important in Databricks Apps: relative path behind reverse proxy
        version="1.0.0",
        default_input_modes=CurrencyAgent.SUPPORTED_CONTENT_TYPES,
        default_output_modes=CurrencyAgent.SUPPORTED_CONTENT_TYPES,
        capabilities=capabilities,
        skills=[skill],
    )

    httpx_client = httpx.AsyncClient()

    push_store = InMemoryPushNotificationConfigStore()

    push_sender = BasePushNotificationSender(httpx_client=httpx_client, config_store=push_store)

    request_handler = DefaultRequestHandler(
        agent_executor=CurrencyAgentExecutor(),
        task_store=InMemoryTaskStore(),
        push_config_store=push_store,
        push_sender=push_sender,
    )

    server = A2AStarletteApplication(agent_card=agent_card, http_handler=request_handler)

    app = server.build()

    async def _close_httpx(): await httpx_client.aclose()

    app.add_event_handler("shutdown", _close_httpx)

    return app

app = build_asgi_app()&lt;/LI-CODE&gt;
&lt;P&gt;&lt;SPAN&gt;The &lt;/SPAN&gt;&lt;STRONG&gt;Agent Card&lt;/STRONG&gt;&lt;SPAN&gt; advertises identity, capabilities (e.g., streaming, pushNotifications), skills, and how to authenticate. Clients usually fetch it from a well-known path under your base URL.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2&gt;&lt;SPAN&gt;Step 4 — Package as a Databricks App&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN&gt;Create app.yaml to define how your server starts and how env vars flow in. &lt;/SPAN&gt;&lt;STRONG&gt;Never&lt;/STRONG&gt;&lt;SPAN&gt; hardcode secrets—use &lt;/SPAN&gt;&lt;STRONG&gt;App resources&lt;/STRONG&gt;&lt;SPAN&gt; + valueFrom or Databricks Secrets so Databricks injects them as environment variables at runtime.&lt;/SPAN&gt;&lt;/P&gt;
&lt;LI-CODE lang="python"&gt;# app.yaml

command: ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]

env:
  # Workspace URL &amp;amp; endpoint name can be plain values (non-secret).

  - name: DATABRICKS_WORKSPACE_URL
    value: "https://&amp;lt;your-workspace&amp;gt;.cloud.databricks.com"

  - name: DBX_LLM_ENDPOINT
    value: "&amp;lt;your-serving-endpoint&amp;gt;"

  # Token is secret: reference an App resource key you configured in the UI.
  # For production, prefer OAuth with the app’s service principal.

  - name: DATABRICKS_TOKEN
    valueFrom: dbx_llm_token   # &amp;lt;-- this key is defined in App resources (Secret)&lt;/LI-CODE&gt;
&lt;P&gt;&lt;STRONG&gt;Notes&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;Databricks Apps require &lt;/SPAN&gt;&lt;STRONG&gt;OAuth Bearer&lt;/STRONG&gt;&lt;SPAN&gt; auth on routes under /api for token-protected endpoints. If you expose any API routes for external clients, mount them under /api/*. &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;You can add secrets/resources in the &lt;/SPAN&gt;&lt;STRONG&gt;Apps UI&lt;/STRONG&gt;&lt;SPAN&gt; and then map them into env via valueFrom. &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;For &lt;/SPAN&gt;&lt;STRONG&gt;Foundation Models&lt;/STRONG&gt;&lt;SPAN&gt; or &lt;/SPAN&gt;&lt;STRONG&gt;route-optimized Serving&lt;/STRONG&gt;&lt;SPAN&gt; endpoints, use &lt;/SPAN&gt;&lt;STRONG&gt;OAuth tokens&lt;/STRONG&gt;&lt;SPAN&gt; (service principal) rather than PATs. &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;&lt;SPAN&gt;Step 5 — Install dependencies&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN&gt;Your requirements.txt should include:&lt;/SPAN&gt;&lt;/P&gt;
&lt;LI-CODE lang="python"&gt;uvicorn
fastapi
httpx
langgraph
databricks_langchain
a2a-sdk[http-server]&amp;gt;=0.3.0&lt;/LI-CODE&gt;
&lt;P&gt;&lt;SPAN&gt;The official &lt;/SPAN&gt;&lt;STRONG&gt;A2A SDK&lt;/STRONG&gt;&lt;SPAN&gt; is published on PyPI as a2a-sdk (extras: [http-server], [grpc], [telemetry]).&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2&gt;&lt;SPAN&gt;Step 6 — Deploy &amp;amp; run on Databricks Apps&lt;/SPAN&gt;&lt;/H2&gt;
&lt;OL&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Create App&lt;/STRONG&gt;&lt;SPAN&gt; → &lt;/SPAN&gt;&lt;I&gt;&lt;SPAN&gt;Custom&lt;/SPAN&gt;&lt;/I&gt;&lt;SPAN&gt; → point to your repo (or Git folder).&lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;Add an &lt;/SPAN&gt;&lt;STRONG&gt;App resource&lt;/STRONG&gt;&lt;SPAN&gt; for your secret (e.g., dbx_llm_token) and grant least-privilege access. Map it to DATABRICKS_TOKEN via valueFrom in app.yaml. &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;Click &lt;/SPAN&gt;&lt;STRONG&gt;Deploy&lt;/STRONG&gt;&lt;SPAN&gt;; the platform starts your app with the uvicorn command you specified. &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;Open the app URL; the &lt;/SPAN&gt;&lt;STRONG&gt;Agent Card&lt;/STRONG&gt;&lt;SPAN&gt; will be served at the well-known path the SDK exposes (or at / depending on your framework wiring).&lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;(Optional) Validate the /api routes with a Bearer token as described in the cookbook.&lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;&lt;SPAN&gt;Databricks Apps run behind a reverse proxy with platform-managed networking—avoid assumptions about request origin and keep your base URLs &lt;/SPAN&gt;&lt;STRONG&gt;relative&lt;/STRONG&gt;&lt;SPAN&gt;.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2&gt;&lt;SPAN&gt;Step 7 — Test the agent with the A2A client (from a notebook or local)&lt;/SPAN&gt;&lt;/H2&gt;
&lt;LI-CODE lang="python"&gt;# test.py (excerpt): call your app via A2A client

import json, logging, httpx
from uuid import uuid4
from a2a.client import A2ACardResolver, A2AClient
from a2a.types import MessageSendParams, SendMessageRequest

BASE_URL = "https://&amp;lt;your-app-url&amp;gt;"

async def chat_once(text: str):

    async with httpx.AsyncClient(timeout=60.0) as httpx_client:
        resolver = A2ACardResolver(httpx_client=httpx_client, base_url=BASE_URL)
        card = await resolver.get_agent_card()
        client = A2AClient(httpx_client=httpx_client, agent_card=card)
        req = SendMessageRequest(id=str(uuid4()),
                                 params=MessageSendParams(message={"role":"user",
                                                                   "parts":[{"kind":"text","text":text}]}))

        resp = await client.send_message(req)

        print(json.dumps(resp.model_dump(mode="json"), indent=2))

# e.g.
# await chat_once("USD to EUR today?")&lt;/LI-CODE&gt;
&lt;P&gt;&lt;SPAN&gt;The SDK exposes both non-streaming and streaming calls, plus push-notification configuration APIs.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2&gt;&lt;SPAN&gt;Security, auth, and secrets (read this!)&lt;/SPAN&gt;&lt;/H2&gt;
&lt;UL&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Never&lt;/STRONG&gt;&lt;SPAN&gt; commit tokens to source control. Use &lt;/SPAN&gt;&lt;STRONG&gt;App secrets/resources&lt;/STRONG&gt;&lt;SPAN&gt; to inject env vars at runtime; map them via valueFrom in app.yaml. &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;Prefer &lt;/SPAN&gt;&lt;STRONG&gt;OAuth&lt;/STRONG&gt;&lt;SPAN&gt; (service principal) for production access to Model Serving, especially on &lt;/SPAN&gt;&lt;STRONG&gt;route-optimized&lt;/STRONG&gt;&lt;SPAN&gt; or FM endpoints. &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt;Databricks Apps use &lt;/SPAN&gt;&lt;STRONG&gt;OAuth2&lt;/STRONG&gt;&lt;SPAN&gt; for user access; secure machine-to-machine calls to your app should target /api/* and send a Bearer token. &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;&lt;SPAN&gt;Troubleshooting&lt;/SPAN&gt;&lt;/H2&gt;
&lt;UL&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;401/403 from Model Serving&lt;/STRONG&gt;&lt;STRONG&gt;&lt;BR /&gt;&lt;/STRONG&gt;&lt;STRONG&gt;&lt;BR /&gt;&lt;/STRONG&gt;&lt;SPAN&gt; Check the token type (PAT vs OAuth) and the app service principal’s permissions (CAN QUERY on the serving endpoint). Route-optimized endpoints require OAuth. &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Your /api endpoints work locally but 401 in the app&lt;/STRONG&gt;&lt;STRONG&gt;&lt;BR /&gt;&lt;/STRONG&gt;&lt;STRONG&gt;&lt;BR /&gt;&lt;/STRONG&gt;&lt;SPAN&gt; Databricks Apps enforce Bearer auth on /api/*. Generate a workspace OAuth token (CLI) and include it in the Authorization: Bearer &amp;lt;token&amp;gt; header. &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Agent discovery fails&lt;/STRONG&gt;&lt;STRONG&gt;&lt;BR /&gt;&lt;/STRONG&gt;&lt;STRONG&gt;&lt;BR /&gt;&lt;/STRONG&gt;&lt;SPAN&gt; Verify the Agent Card URL served by your app (well-known path) and ensure the url in the card uses a &lt;/SPAN&gt;&lt;STRONG&gt;relative&lt;/STRONG&gt;&lt;SPAN&gt; base when running behind the Databricks proxy. &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Streaming isn’t streaming&lt;/STRONG&gt;&lt;STRONG&gt;&lt;BR /&gt;&lt;/STRONG&gt;&lt;STRONG&gt;&lt;BR /&gt;&lt;/STRONG&gt;&lt;SPAN&gt; Confirm you’re calling the &lt;/SPAN&gt;&lt;STRONG&gt;streaming&lt;/STRONG&gt;&lt;SPAN&gt; method and the server responds with Content-Type: text/event-stream as specified by A2A’s SSE flow. &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;&lt;SPAN&gt;Going deeper&lt;/SPAN&gt;&lt;/H2&gt;
&lt;UL&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Push notifications&lt;/STRONG&gt;&lt;SPAN&gt;: Configure webhooks via the SDK when clients can’t hold SSE streams (mobile, serverless). Use the SDK’s set_task_callback / get_task_callback methods. &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;More frameworks&lt;/STRONG&gt;&lt;SPAN&gt;: Databricks Apps support Streamlit, Dash, Flask, &lt;/SPAN&gt;&lt;STRONG&gt;FastAPI&lt;/STRONG&gt;&lt;SPAN&gt;, and more—see the Apps Cookbook for recipes (auth, Lakehouse access, CI/CD). &lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Agent design&lt;/STRONG&gt;&lt;SPAN&gt;: LangGraph response_format + Pydantic models keep outputs predictable when multiple agents collaborate downstream.&lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;&lt;SPAN&gt;Appendix — Minimal &lt;/SPAN&gt;&lt;A href="http://server.py" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;server.py&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; + app.yaml templates&lt;/SPAN&gt;&lt;/H2&gt;
&lt;LI-CODE lang="python"&gt;# server.py (minimal)

from a2a.server.apps import A2AStarletteApplication
from a2a.server.request_handlers import DefaultRequestHandler
from a2a.server.tasks import InMemoryTaskStore, InMemoryPushNotificationConfigStore, BasePushNotificationSender
from a2a.types import AgentCapabilities, AgentCard
import httpx
from app.agent_executor import CurrencyAgentExecutor
from app.agent import CurrencyAgent

def build_asgi_app():
    card = AgentCard(
        name="Currency Agent",
        description="Exchange rates over A2A",
        url="/",
        version="1.0.0",
        capabilities=AgentCapabilities(streaming=True, push_notifications=True),
        default_input_modes=CurrencyAgent.SUPPORTED_CONTENT_TYPES,
        default_output_modes=CurrencyAgent.SUPPORTED_CONTENT_TYPES,
    )

    httpx_client = httpx.AsyncClient()

    request_handler = DefaultRequestHandler(
        agent_executor=CurrencyAgentExecutor(),
        task_store=InMemoryTaskStore(),
        push_config_store=InMemoryPushNotificationConfigStore(),
        push_sender=BasePushNotificationSender(httpx_client=httpx_client),
    )

    return A2AStarletteApplication(agent_card=card, http_handler=request_handler).build()

app = build_asgi_app()

# app.yaml (minimal, secrets via valueFrom)

command: ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]

env:
  - name: DATABRICKS_WORKSPACE_URL
    value: "https://&amp;lt;your-workspace&amp;gt;.cloud.databricks.com"

  - name: DBX_LLM_ENDPOINT
    value: "&amp;lt;your-serving-endpoint&amp;gt;"

  - name: DATABRICKS_TOKEN
    valueFrom: dbx_llm_token&lt;/LI-CODE&gt;
&lt;H2&gt;&lt;SPAN&gt;References&lt;/SPAN&gt;&lt;/H2&gt;
&lt;UL&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;A2A overview &amp;amp; principles&lt;/STRONG&gt;&lt;SPAN&gt; (Google Developers Blog) — open protocol for agent interoperability.&lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;A2A spec &amp;amp; SDK&lt;/STRONG&gt;&lt;SPAN&gt; — JSON-RPC + SSE streaming, Python SDK, push config APIs.&lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Databricks Apps&lt;/STRONG&gt;&lt;SPAN&gt; — serverless hosting, platform integration, OAuth model, best practices.&lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Model Serving&lt;/STRONG&gt;&lt;SPAN&gt; — unified API for FMs and custom endpoints.&lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Apps Cookbook&lt;/STRONG&gt;&lt;SPAN&gt; — FastAPI /api auth, local/external connections, deployment steps.&lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Frankfurter API&lt;/STRONG&gt;&lt;SPAN&gt; — free ECB reference rates for examples.&lt;/SPAN&gt;&lt;SPAN&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;&lt;SPAN&gt;Wrap-up&lt;/SPAN&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN&gt;With A2A providing the interoperability fabric and Databricks Apps providing a secure, serverless runtime next to your governed data and models, you can &lt;/SPAN&gt;&lt;STRONG&gt;stand up enterprise-ready agents quickly&lt;/STRONG&gt;&lt;SPAN&gt;—and &lt;/SPAN&gt;&lt;I&gt;&lt;SPAN&gt;connect&lt;/SPAN&gt;&lt;/I&gt;&lt;SPAN&gt; them to the rest of your agent ecosystem when you’re ready. Swap the currency tool for your business tools, wire in push notifications, and you’ve got a production pattern you can reuse across many agents.&lt;/SPAN&gt;&lt;/P&gt;</description>
    <pubDate>Tue, 21 Oct 2025 11:45:43 GMT</pubDate>
    <dc:creator>Mahavir_Teraiya</dc:creator>
    <dc:date>2025-10-21T11:45:43Z</dc:date>
    <item>
      <title>How to Deploy Agent-to-Agent (A2A) Protocol on Databricks Apps?-&gt; End-to-End Guide</title>
      <link>https://community.databricks.com/t5/technical-blog/how-to-deploy-agent-to-agent-a2a-protocol-on-databricks-apps-gt/ba-p/134213</link>
      <description>&lt;P&gt;&lt;SPAN&gt;Modern AI systems rarely live alone. They collaborate. Google’s &lt;/SPAN&gt;&lt;STRONG&gt;Agent-to-Agent (A2A)&lt;/STRONG&gt;&lt;SPAN&gt; protocol gives agents a common language (JSON-RPC over HTTP/S, with streaming via SSE) plus a discovery mechanism (the &lt;/SPAN&gt;&lt;STRONG&gt;Agent Card&lt;/STRONG&gt;&lt;SPAN&gt;) so they can find and work with each other securely.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Databricks Apps&lt;/STRONG&gt;&lt;SPAN&gt; let you ship secure, serverless AI apps &lt;/SPAN&gt;&lt;I&gt;&lt;SPAN&gt;inside&lt;/SPAN&gt;&lt;/I&gt;&lt;SPAN&gt; your Databricks workspace—no extra infra, integrated with Unity Catalog, SQL, Model Serving, OAuth and more. That’s perfect territory for hosting interoperable A2A agents where data governance and latency matter.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;In this post, you’ll deploy a production-style A2A server as a Databricks App. The example agent (“&lt;/SPAN&gt;&lt;STRONG&gt;CurrencyAgent&lt;/STRONG&gt;&lt;SPAN&gt;”) uses &lt;/SPAN&gt;&lt;STRONG&gt;LangGraph&lt;/STRONG&gt;&lt;SPAN&gt; tools + a Databricks&lt;/SPAN&gt;&lt;SPAN&gt;&amp;nbsp;LLM endpoint to answer FX questions—then exposes itself as an A2A service with streaming updates and optional push notifications. &lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Tue, 21 Oct 2025 11:45:43 GMT</pubDate>
      <guid>https://community.databricks.com/t5/technical-blog/how-to-deploy-agent-to-agent-a2a-protocol-on-databricks-apps-gt/ba-p/134213</guid>
      <dc:creator>Mahavir_Teraiya</dc:creator>
      <dc:date>2025-10-21T11:45:43Z</dc:date>
    </item>
    <item>
      <title>Re: How to Deploy Agent-to-Agent (A2A) Protocol on Databricks Apps?-&gt; End-to-End Guide</title>
      <link>https://community.databricks.com/t5/technical-blog/how-to-deploy-agent-to-agent-a2a-protocol-on-databricks-apps-gt/bc-p/139715#M836</link>
      <description>&lt;P&gt;&lt;STRONG&gt;Subject: 302 Authentication Errors on Agent Discovery Endpoint&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;Hi, thanks for the great tutorial! I successfully deployed the A2A Currency Agent on &lt;STRONG&gt;Azure Databricks Apps, but I'm getting 302 redirects when trying to test it programmatically from a Databricks notebook.&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Issue: All endpoints return 302 redirects requiring OAuth login:&lt;/STRONG&gt;&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;/.well-known/agent-card.json → 302 redirect&lt;/LI&gt;&lt;LI&gt;Even when using WorkspaceClient().config.authenticate() headers&lt;/LI&gt;&lt;LI&gt;Even when using service principal Bearer tokens&lt;/LI&gt;&lt;LI&gt;The agent card JSON is visible via browser when logged into Databricks, but I can't send messages programmatically&lt;P&gt;&lt;STRONG&gt;Questions:&lt;/STRONG&gt;&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;Should the agent card be publicly accessible per A2A protocol?&lt;/LI&gt;&lt;LI&gt;How do you authenticate to A2A endpoints from Databricks notebooks?&lt;/LI&gt;&lt;LI&gt;The tutorial's test code (Step 7) doesn't show authentication - how is this supposed to work?&lt;P&gt;Any guidance on how to properly test the agent would be appreciated!&lt;/P&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;</description>
      <pubDate>Wed, 19 Nov 2025 19:03:41 GMT</pubDate>
      <guid>https://community.databricks.com/t5/technical-blog/how-to-deploy-agent-to-agent-a2a-protocol-on-databricks-apps-gt/bc-p/139715#M836</guid>
      <dc:creator>159937</dc:creator>
      <dc:date>2025-11-19T19:03:41Z</dc:date>
    </item>
  </channel>
</rss>

