Blog Post

Microsoft Developer Community Blog
8 MIN READ

Genie in a Bot: Databricks AI/BI Meets Microsoft Teams

vikas_gautam's avatar
vikas_gautam
Icon for Microsoft rankMicrosoft
May 14, 2026

"What was our top campaign by ROI last quarter?" That's the question a marketing director typed into a Teams chat on a Tuesday morning — and got a SQL-backed, data-accurate answer in under ten seconds, without ever leaving the conversation. Behind that simple interaction lies a surprisingly complex engineering problem. We needed to connect three platforms — Microsoft Teams, Azure AI Foundry, and Databricks Genie — across private networks, through five authentication hops, while satisfying the security requirements of a regulated enterprise environment. The "obvious" approach (let AI Foundry call Databricks directly via server-side tooling) is a dead end the moment you lock down your network. And in regulated industries, locking down the network isn't optional — it's day one. This blog walks through how to solve it. I'll cover the use case, why private networking makes this harder than it looks, and the client-side Function Tool pattern I developed to make it all work — including the networking topology and authentication chain in detail.

The Use Case: Why Genie Needs to Live in Teams

Every organization has business users who need data answers — fast. Marketing managers want to know which campaign drove the most conversions last quarter. Finance teams need spend breakdowns by channel. Executives want real-time KPIs before a board meeting.

Databricks Genie (part of AI/BI) is a brilliant solution to this: it lets you ask natural-language questions against your Data Lakehouse and get SQL-backed answers instantly. No dashboards to navigate, no SQL to write, no tickets to the analytics team.

But there's a friction problem: Genie lives in the Databricks workspace. Your business users live in Microsoft Teams. Asking them to context-switch out of their primary collaboration tool, log into Databricks, navigate to a Genie Space, and type a question — that's a workflow that looks good in demos but dies in the field.
The real unlock is bringing Genie into Teams: a bot that business users can message directly, in the same place they chat with colleagues, and get instant, data-backed answers. No portal, no login, no context switch. 

This blog talks about exactly this integration. We will explore how to connect Microsoft Teams to a Databricks Genie Space via an Azure AI Foundry agent. Users ask natural-language questions about campaign data — spend, clicks, conversions, ROI, audience segments — and the system translates these into SQL queries executed against a Databricks SQL warehouse.

A user asks a question in Teams. The Bot Service relays it to our App Service, which uses an AI Foundry agent to reason over the question and queries Databricks Genie for SQL-backed data. The answer flows back the same path — arriving in the Teams chat within seconds.

But getting here was far from straightforward.

Why This Is Hard — Especially for Regulated Industries

If you're reading this and thinking "just connect the services together," you're in for a surprise. Private networking, multi-hop authentication requirements along with server-side tools problem makes it quite complicated. 

Here's why this problem is deceptively complex:

The Private Networking Requirement

In regulated industries — financial services, healthcare, government — you can't expose your AI Services resources to the public internet. Azure AI Foundry (the Cognitive Services / AI Services resource) must be locked down with:

  • defaultAction: Deny on the network ACL — blocking all traffic by default

  • Private Endpoints — the only way to reach the service is through your Virtual Network
  • No public network access — fully private deployment

These controls are baseline requirements for meeting SOC 2, HIPAA, PCI-DSS, and most enterprise security standards.

The MCP / Server-Side Tool Problem

Azure AI Foundry supports MCP (Model Context Protocol) — a server-side tool execution framework that lets your agent call external services (like Databricks Genie) seamlessly. When it works, it's powerful: you register a tool in the Foundry portal, and the platform handles authentication, execution, and response marshaling automatically. For deployments with public network access, this is the fastest path to a working agent — often just a few clicks.

However, in private-networked deployments, server-side tool execution faces a networking constraint.

Here's the problem: when you lock down your AI Services resource with defaultAction: Deny and private endpoints (as enterprise security policies require), the AI Services infrastructure has no outbound path to external services like Databricks. This isn't a bug in Foundry — it's an inherent trade-off of full network isolation. The same restriction applies to any Azure service calling out from a network-locked resource.

Microsoft is actively addressing this with newer features like Standard Agent Setup with dedicated MCP subnets, which give the agent infrastructure its own outbound-capable subnet within your VNet. As these capabilities mature and become generally available, the server-side MCP approach will work in private deployments too.

The Multi-Hop Authentication Challenge

Even once you solve the networking problem, you face a five-hop authentication chain:

  1. Teams → Bot Service: Bot Framework channel tokens
  2. Bot Service → App Service: User-Assigned Managed Identity (UAMI)
  3. App Service → AI Foundry: Managed Identity + Private Endpoint
  4. App Service → Entra ID: Token acquisition for Databricks resource
  5. Entra ID → Databricks: OAuth token federation (OIDC token exchange)

Each hop has its own identity model, token format, and failure modes. Getting one wrong means a silent 401 somewhere in the chain with no useful error message.

The Teams Bot Framework Constraint

Azure Bot Service adds its own constraints:

  • It requires a public HTTPS endpoint — you can't make the bot App Service fully private
  • It uses UAMI (User-Assigned Managed Identity) for passwordless authentication — not the simpler system-assigned MI
  • The Bot Framework SDK validates inbound channel tokens before your code even runs
  • You need both MicrosoftAppId and MICROSOFT_APP_ID (PascalCase and UPPER_SNAKE aliases) because different SDK layers read different env var names

Our Approach: Client-Side Function Tool Pattern

The challenges above - private networking, multi-hop authentication, Teams constraints - aren't individual problems to solve in isolation. They're interconnected design constraints that need a cohesive architectural answer. This could be solved if we introduce some component that can take the required actions while being in the same network as Databricks genie and follow instructions from the Foundry AI Agent. 

Reference Implementation

A complete, working implementation of the architecture described in this article is available as an open-source project:

github.com/vikasgautam18/foundry-genie

Azure AI Foundry excels at what it was built for - orchestrating large language models, managing conversation threads, and deciding when tools should be called. Databricks Genie excels at what it was built for - translating natural language into SQL and querying governed data. This new application in the middle will simply be the bridge between them. The diagram below explains this with a WebApp as the bridge. 

The diagram above shows the end-to-end execution path of a user query flowing from Microsoft Teams through a bot, into an orchestration layer, and finally into a data platform before returning a synthesized response. A Teams message is received by the Bot Service and forwarded to an App Service via POST /api/messages. The App Service validates the request using Bot Framework SDK's CloudAdapter and immediately initializes an AI Foundry thread to manage the interaction state, but importantly, this interaction stays within a private, service-to-service trust boundary, typically enforced via managed identity or private endpoints—no user-level credentials are propagated downstream. A detect step determines whether the input requires tool invocation, effectively acting as a lightweight router between pure LLM response generation and downstream system calls. Azure Bot Service requires a specific app registration (the MicrosoftAppId). With UAMI, the same managed identity serves as both the bot's app ID and the credential for calling AI Foundry. 

When the workflow requires data access, the App Service explicitly crosses into a new security boundary: Databricks. Instead of reusing upstream identity, the service acquires a scoped Databricks access token (often via OAuth, service principal, or managed identity federation). This token is short-lived and purpose-specific, limiting blast radius. The call to the Databricks Genie API initiates execution inside the data platform boundary, where the LLM translates intent into SQL and runs it against a SQL warehouse. Crucially, this isolates data-plane access from the application layer—App Service never directly queries the warehouse. 

The return path reinforces the separation of concerns. Databricks responses (SQL text, schema, and result sets) are treated as untrusted external input when re-entering the App Service boundary and are explicitly passed into AI Foundry as tool output. Within Foundry, the LLM operates inside its own controlled environment, synthesizing a response without gaining direct access to credentials or underlying systems. The App Service polls both Databricks and Foundry using their respective tokens, respecting independent authentication domains and time-bound sessions. Finally, the response is sent back through the Bot Service to Teams, completing a flow where each hop enforces validation, uses scoped credentials, and maintains strict isolation between user interaction, orchestration logic, AI reasoning, and data execution layers.

One of the most interesting hops from an authentication point-of-view is the App Service to Azure Databricks. There are three options available for you to implement: 

  1. PAT (Personal Access Token) approach uses a Databricks Personal Access Token - a long-lived bearer token issued to a user or service principal as the credential for every API/SQL call. These must be rotated manually, can't carry per-user identity (every call looks like the same principal), and a leaked PAT grants full workspace access until someone revokes it.
  2. M2M Mode (Machine-to-Machine OAuth a.k.a. workload identity federation) uses an OAuth 2.0 client-credentials flow between your app's managed identity and Databricks. Instead of carrying a static PAT, the app authenticates to a token endpoint with its credentials and receives a short-lived access token (usually ~1 hour) that it then uses as the Authorization: Bearer header for Databricks API/SQL calls. The token is refreshed automatically by the SDK when it expires. It does not carry per-user identity, though - every call to Databricks looks like the service principal, so row-level / Unity Catalog policies based on the end user won't apply.

  3. U2M Mode (User-to-Machine OAuth) uses an OAuth 2.0 authorization-code flow so that calls to Databricks are made as the actual end user, not as the application's service principal. The user signs in once (in Foundry Genie, via an Entra ID / Microsoft consent prompt surfaced in Teams or the web UI), the app receives an access token + refresh token scoped to that user's Databricks identity, and every subsequent SQL/Genie call carries those tokens. The access token is short-lived (~1 hour); the refresh token lets the app mint new ones silently in the background until the user revokes consent or the refresh token expires. 

    The most important property is identity propagation: when the app queries Databricks on behalf of a User1, Databricks sees User1 - so Unity Catalog row/column-level security, table grants, audit logs, and Genie Space permissions all evaluate against her entitlements. Two analysts asking the same question can legitimately get different answers (or one can get an "access denied") based on the data they're each allowed to see. 

    This comes at the cost of slightly higher operational complexity: you now have per-user tokens to store (Foundry Genie keeps them in Redis, keyed by Teams/AAD user ID, encrypted at rest), an interactive consent step the first time a user connects, and token refresh logic running in the background. 

Closing Thoughts: When “Just Ask the Question” Isn’t So Simple

The original ask was quite simple: let a marketing director ask, “What was our top campaign by ROI last quarter?” in Microsoft Teams and get a real, trustworthy answer. No dashboards. No exports. No side channels. Just a question and a response. But what we ended up building tells a very different story. Behind that single question sits a five-hop authentication chain spanning three platforms, a fully private network topology with multiple DNS zones, a per-user token store backed by Redis, and a deliberately enforced separation between AI reasoning and tool execution. None of that complexity is accidental. Every layer exists because regulated enterprise environments demand it. And that’s the first lesson worth calling out: enterprise-grade AI systems are shaped more by networking, identity, and governance than by prompts or models.

If you’re building something similar - a conversational interface over governed data, running inside a network-isolated environment, with per-user authorization - you’re not alone. The patterns here are reusable, and we hope they save you a few weeks of head-scratching. 

Updated Apr 25, 2026
Version 1.0
No CommentsBe the first to comment