diff --git a/samples/applications/azure-sql-mcp/.gitignore b/samples/applications/azure-sql-mcp/.gitignore
new file mode 100644
index 0000000000..6aab378106
--- /dev/null
+++ b/samples/applications/azure-sql-mcp/.gitignore
@@ -0,0 +1,3 @@
+.azure/
+dab-config.generated.json
+infra/main.json
diff --git a/samples/applications/azure-sql-mcp/README.md b/samples/applications/azure-sql-mcp/README.md
new file mode 100644
index 0000000000..6c3b4c9746
--- /dev/null
+++ b/samples/applications/azure-sql-mcp/README.md
@@ -0,0 +1,232 @@
+
+
+# Hosted MCP in Connector Namespace — Azure SQL Database
+
+This sample deploys a hosted Model Context Protocol (MCP) server in [Azure Connector Namespace](https://learn.microsoft.com/azure/logic-apps/connector-namespace/connector-namespace-hosted-mcp), backed by Azure SQL Database. It uses [Azure Developer CLI](https://learn.microsoft.com/azure/developer/azure-developer-cli/) (`azd`) and Bicep to provision the infrastructure, seed a sample `dbo.BlogPosts` table through a post-provision SQL script, and configure managed identity access. After deployment, MCP clients such as GitHub Copilot in Visual Studio Code can query the database through the hosted MCP server.
+
+### Contents
+
+[About this sample](#about-this-sample)
+[Before you begin](#before-you-begin)
+[Run this sample](#run-this-sample)
+[Sample details](#sample-details)
+[Clean up](#clean-up)
+[Related links](#related-links)
+
+
+
+## About this sample
+
+- **Applies to:** Azure SQL Database
+- **Key features:** Azure Connector Namespace, hosted MCP server, Data API builder, managed identity, Application Insights
+- **Workload:** AI agent data access
+- **Programming Language:** Bicep, PowerShell, Bash, JSON
+
+This sample deploys a hosted MCP server in [Azure Connector Namespace](https://learn.microsoft.com/azure/logic-apps/connector-namespace/connector-namespace-hosted-mcp). The server uses a [Data API builder](https://learn.microsoft.com/azure/data-api-builder/overview) configuration to expose an Azure SQL Database table through MCP tools. A post-provision SQL script creates and seeds the `dbo.BlogPosts` table with sample rows linking to Microsoft Learn and .NET Blog posts.
+
+
+
+## Before you begin
+
+To run this sample, you need the following prerequisites.
+
+**Software prerequisites:**
+
+1. [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) (`az`)
+1. [Azure Developer CLI](https://learn.microsoft.com/azure/developer/azure-developer-cli/install-azd) (`azd`)
+1. PowerShell 7+ on Windows, or Bash on Linux/macOS
+1. [Visual Studio Code](https://code.visualstudio.com/) with the [GitHub Copilot](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot) extension (to connect to the deployed MCP server)
+
+**Azure prerequisites:**
+
+1. An Azure subscription with permissions to create resource groups and resources.
+1. Permission to create Azure SQL Database, Application Insights, Log Analytics workspace, and Connector Namespace resources.
+1. Permission to create an Azure SQL Database Microsoft Entra ID administrator for the signed-in user.
+
+
+
+## Run this sample
+
+From this folder:
+
+```bash
+azd auth login
+azd init
+azd up
+```
+
+> **Cross-platform:** `azd up` works on Windows (runs the PowerShell post-provision hook), macOS, and Linux (runs the Bash post-provision hook). No additional tools are required beyond the prerequisites listed above. A standalone `deploy.ps1` script is also included as an alternative for PowerShell users.
+
+#### `azd init` prompts
+
+When you run `azd init` for the first time, it detects the existing `azure.yaml` and Bicep templates:
+
+1. **"How do you want to initialize your app?"** — Select **Use code in the current directory**.
+2. **"Confirm and continue initializing this app"** — Press **Enter** to confirm the detected services.
+3. **"Enter a new environment name"** — Pick any name, for example `mcp-dev`. This name is used as a prefix for Azure resource names.
+
+You only need to run `azd init` once. Subsequent deployments only require `azd up`.
+
+#### `azd up` prompts
+
+When you run `azd up`, you are prompted for:
+
+- **Azure Subscription:** Select the Azure subscription to deploy to.
+- **Azure location:** Choose a supported region (e.g. `eastasia`, `westcentralus`).
+- **`deployerLoginName` infrastructure parameter:** Enter your Azure sign-in email or user principal name, for example `user@contoso.com`. If you don't know the value, run the following command in a different terminal instance and use the result:
+
+ ```bash
+ az account show --query user.name -o tsv
+ ```
+- **`connectorNamespaceIdentityType` infrastructure parameter:** Enter `SystemAssigned` for the default Connector Namespace managed identity, or `UserAssigned` to create and attach a user-assigned managed identity.
+
+The `deployerLoginName` value is used to create the Azure SQL Database server with Microsoft Entra ID-only authentication and set you as the SQL admin.
+
+### Optional: use a user-assigned managed identity
+
+When `azd up` prompts for `connectorNamespaceIdentityType`, enter `UserAssigned` to test with a user-assigned managed identity.
+
+When set to `UserAssigned`, the template creates a user-assigned managed identity, attaches it to the Connector Namespace, passes its client ID to the hosted MCP server, and grants that identity access to Azure SQL Database.
+
+Choose the identity type before the first deployment. Connector Namespace doesn't allow changing attached user-assigned identities after the namespace is created. To switch between `SystemAssigned` and `UserAssigned`, create a new azd environment or run `azd down --purge` and deploy again.
+
+For more information about managed identity options in Azure Connector Namespace, see [Hosted MCP servers in Azure Connector Namespace](https://learn.microsoft.com/azure/logic-apps/connector-namespace/connector-namespace-hosted-mcp).
+
+### Connect from Visual Studio Code
+
+After `azd up` completes, the MCP endpoint URL is printed. Add it to VS Code using the UI. For full details, see the [VS Code MCP servers documentation](https://code.visualstudio.com/docs/copilot/chat/mcp-servers).
+
+1. In VS Code, open the Command Palette:
+ - Windows/Linux: Ctrl+Shift+P
+ - macOS: Cmd+Shift+P
+1. Run **MCP: Add Server**.
+1. Choose **HTTP** as the server type.
+1. Paste the MCP endpoint URL printed by `azd up`.
+1. Enter a server name, for example `sql-mcp`.
+1. Choose whether to save the server in user settings or workspace settings.
+1. Start the `sql-mcp` server when VS Code prompts you.
+
+VS Code prompts you to sign in with Microsoft.
+
+### Try it out
+
+Once the MCP server is connected in VS Code, open Copilot Chat (Agent mode) and try prompts like:
+
+- *"List the blog posts in the database."*
+- *"What tables are available?"*
+- *"Show me the blog post from the .NET Blog."*
+
+Copilot uses the MCP tools (`describe_entities`, `read_records`) exposed by Data API builder to query Azure SQL Database and return results.
+
+
+
+## Sample details
+
+### Architecture
+
+```mermaid
+graph TB
+ Client["VS Code / Copilot / MCP Client"]
+ Client -->|"MCP (HTTP + SSE)"| CN
+ subgraph CN["Connector Namespace"]
+ MCP["Hosted MCP Server\n(Data API builder)"]
+ end
+ MCP -->|"Managed Identity"| SQL[("Azure SQL Database")]
+```
+
+### Resources deployed
+
+| Resource | Purpose |
+|----------|---------|
+| **Resource Group** | Logical container for all deployed resources |
+| **Azure SQL Database logical server** | Microsoft Entra ID-only authentication, with you as the server admin |
+| **Azure SQL Database** | Basic SKU database with a seeded `dbo.BlogPosts` sample table used by the MCP server |
+| **SQL Firewall Rules** | Allows Azure services/resources, Azure Portal Query Editor, and your public IP for setup |
+| **Log Analytics Workspace** | Stores Application Insights telemetry |
+| **Application Insights** | Collects telemetry from the hosted MCP server |
+| **Connector Namespace** | Hosts MCP servers with system-assigned managed identity by default, or user-assigned managed identity when configured |
+| **Hosted MCP server** | Data API builder MCP server configuration deployed to the Connector Namespace |
+| **MCP Access Policy** | Grants you access to invoke MCP tools |
+
+Resource names use the pattern `--` where possible, for example `sql-mcp-dev-a1b2c3d4`. The suffix is deterministic for the subscription, environment name, and location so names are readable and stable across redeployments.
+
+### What `azd up` does
+
+| Step | Action |
+|------|--------|
+| **Provision** | Deploys Azure SQL Database, SQL firewall rules, Log Analytics, Application Insights, Connector Namespace, hosted MCP server, and MCP access policy. |
+| **Post-provision** | Allows your public IP through the SQL firewall, creates and seeds `dbo.BlogPosts`, creates the Connector Namespace managed identity SQL user, grants SQL permissions, generates `dab-config.generated.json`, and prints the MCP endpoint plus Azure Portal resource group link. |
+
+The hosted MCP server receives:
+
+- the included `dab-config.json` (the Data API builder configuration file) as `properties.hostedMcpServer.configuration.configFile`
+- the generated connection string as `SQL_CONNECTION_STRING`
+- the Application Insights connection string as `APPLICATIONINSIGHTS_CONNECTION_STRING`
+- `AZURE_CLIENT_ID` when the sample is configured to use a user-assigned managed identity
+
+No database or Application Insights connection strings are checked in.
+
+This sample includes a ready-to-use `dab-config.json`, the Data API builder configuration file that defines which database entities are exposed through MCP tools. If you want to create or customize a Data API builder configuration from scratch, install the DAB CLI and use it to generate a config file. For more information, see [Install the Data API builder CLI](https://learn.microsoft.com/azure/data-api-builder/command-line/install).
+
+For details about the hosted MCP server resource model and supported server types, see [Hosted MCP servers in Azure Connector Namespace](https://learn.microsoft.com/azure/logic-apps/connector-namespace/connector-namespace-hosted-mcp). For a walkthrough focused on the Azure SQL Database hosted MCP server, see [Hosted MCP server quickstart for SQL](https://learn.microsoft.com/azure/logic-apps/connector-namespace/hosted-mcp-quickstart?pivots=sql).
+
+### Inspect resources in Azure Portal
+
+After deployment, the post-provision output includes a link to the Azure resource group in the Azure Portal. Use that page to inspect the Azure SQL Database logical server, Application Insights resource, Log Analytics workspace, Connector Namespace, and hosted MCP server.
+
+To allow additional users to connect to the MCP server:
+
+1. Open the deployed **Connector Namespace** resource in the Azure Portal.
+1. Open the hosted MCP server configuration, for example `sql-mcp`.
+1. Add an access policy for each additional user or group that should be allowed to invoke the MCP server.
+
+### Sample data
+
+The post-provision hook creates and seeds `dbo.BlogPosts` with these entries:
+
+| Title | Source |
+|-------|--------|
+| Hosted MCP servers in Azure Connector Namespace | Microsoft Learn |
+| Durable Workflows in Microsoft Agent Framework | .NET Blog |
+
+### SQL firewall access
+
+The deployment configures two SQL firewall paths:
+
+| Rule | When | Purpose |
+|------|------|---------|
+| `AllowAzureServices` | During Bicep provisioning | Allows Azure services/resources, including Azure Portal Query Editor, to reach the SQL server. |
+| `AllowDeployerIp` | During post-provision | Detects your current public IP and allows your local machine to seed and query the database. |
+
+If SQL reports a different blocked client IP during post-provision, the script adds that IP and retries.
+
+
+
+## Clean up
+
+Using azd:
+
+```bash
+azd down --purge
+```
+
+Or with Azure CLI:
+
+```bash
+# Replace with your azd environment name.
+az group delete --name rg- --yes --no-wait
+
+# Optional: remove the subscription-scope deployment record.
+az deployment sub delete --name
+```
+
+
+
+## Related links
+
+- [Hosted MCP servers in Azure Connector Namespace](https://learn.microsoft.com/azure/logic-apps/connector-namespace/connector-namespace-hosted-mcp)
+- [Hosted MCP server quickstart for Azure SQL Database](https://learn.microsoft.com/azure/logic-apps/connector-namespace/hosted-mcp-quickstart?pivots=sql)
+- [Azure SQL Database MCP server support in Data API builder](https://learn.microsoft.com/azure/data-api-builder/mcp/overview)
+- [Install the Data API builder CLI](https://learn.microsoft.com/azure/data-api-builder/command-line/install)
+- [Connector Namespace overview](https://learn.microsoft.com/azure/logic-apps/connector-namespace/connector-namespace-overview)
+- [Azure Developer CLI](https://learn.microsoft.com/azure/developer/azure-developer-cli/)
diff --git a/samples/applications/azure-sql-mcp/azure.yaml b/samples/applications/azure-sql-mcp/azure.yaml
new file mode 100644
index 0000000000..75f2d5be47
--- /dev/null
+++ b/samples/applications/azure-sql-mcp/azure.yaml
@@ -0,0 +1,15 @@
+name: azure-sql-mcp
+metadata:
+ template: azure-sql-mcp
+hooks:
+ postprovision:
+ windows:
+ shell: pwsh
+ run: ./scripts/post-provision.ps1
+ interactive: true
+ continueOnError: false
+ posix:
+ shell: sh
+ run: ./scripts/post-provision.sh
+ interactive: true
+ continueOnError: false
diff --git a/samples/applications/azure-sql-mcp/dab-config.json b/samples/applications/azure-sql-mcp/dab-config.json
new file mode 100644
index 0000000000..58fd870adf
--- /dev/null
+++ b/samples/applications/azure-sql-mcp/dab-config.json
@@ -0,0 +1,64 @@
+{
+ "$schema": "https://github.com/Azure/data-api-builder/releases/download/v1.7.90/dab.draft.schema.json",
+ "data-source": {
+ "database-type": "mssql",
+ "connection-string": "@env('SQL_CONNECTION_STRING')",
+ "options": {
+ "set-session-context": false
+ }
+ },
+ "runtime": {
+ "rest": {
+ "enabled": false,
+ "path": "/api",
+ "request-body-strict": true
+ },
+ "graphql": {
+ "enabled": false,
+ "path": "/graphql",
+ "allow-introspection": true
+ },
+ "mcp": {
+ "enabled": true,
+ "path": "/mcp"
+ },
+ "host": {
+ "cors": {
+ "origins": [],
+ "allow-credentials": false
+ },
+ "authentication": {
+ "provider": "AppService"
+ },
+ "mode": "development"
+ }
+ },
+ "entities": {
+ "BlogPosts": {
+ "source": {
+ "object": "dbo.BlogPosts",
+ "type": "table"
+ },
+ "graphql": {
+ "enabled": true,
+ "type": {
+ "singular": "BlogPosts",
+ "plural": "BlogPosts"
+ }
+ },
+ "rest": {
+ "enabled": true
+ },
+ "permissions": [
+ {
+ "role": "anonymous",
+ "actions": [
+ {
+ "action": "*"
+ }
+ ]
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/applications/azure-sql-mcp/deploy.ps1 b/samples/applications/azure-sql-mcp/deploy.ps1
new file mode 100644
index 0000000000..9269551e6c
--- /dev/null
+++ b/samples/applications/azure-sql-mcp/deploy.ps1
@@ -0,0 +1,277 @@
+<#
+.SYNOPSIS
+ Deploy a Connector Namespace with a hosted Azure SQL Database MCP server.
+
+.DESCRIPTION
+ Standalone PowerShell deployment script (alternative to azd). Provisions
+ Azure SQL Database, Connector Namespace, hosted MCP server, seeds the
+ database, grants managed identity access, and prints the MCP endpoint URL
+ ready for VS Code.
+
+ Note: This script requires PowerShell 7+. For cross-platform deployment
+ without PowerShell, use 'azd up' instead — it runs the Bash post-provision
+ script on macOS/Linux automatically.
+
+.PARAMETER DabConfigPath
+ Path to the DAB configuration file. Defaults to dab-config.json in the project root.
+
+.PARAMETER EnvironmentName
+ Name for the deployment environment. Used to generate unique resource names.
+
+.PARAMETER Location
+ Azure region for SQL and general resources. Default: eastasia.
+
+.PARAMETER ConnectorNamespaceLocation
+ Azure region for the Connector Namespace. Must be a preview region.
+ Default: eastasia.
+
+.PARAMETER DatabaseName
+ Name of the SQL database. Default: mcpdb.
+
+.PARAMETER ConnectorNamespaceIdentityType
+ Managed identity type for the Connector Namespace. Default: SystemAssigned.
+ Use UserAssigned to create and attach a user-assigned managed identity.
+
+.EXAMPLE
+ .\deploy.ps1 -EnvironmentName mcp-dev
+ # Uses ./dab-config.json, deploys to eastasia
+
+.EXAMPLE
+ .\deploy.ps1 -EnvironmentName mcp-dev -DabConfigPath .\my-custom-dab.json -Location eastasia
+#>
+
+[CmdletBinding()]
+param(
+ [Parameter(Mandatory)]
+ [string]$EnvironmentName,
+
+ [string]$DabConfigPath,
+
+ [string]$Location = 'eastasia',
+
+ [string]$ConnectorNamespaceLocation = 'eastasia',
+
+ [string]$DatabaseName = 'mcpdb',
+
+ [ValidateSet('SystemAssigned', 'UserAssigned')]
+ [string]$ConnectorNamespaceIdentityType = 'SystemAssigned'
+)
+
+Set-StrictMode -Version Latest
+$ErrorActionPreference = 'Stop'
+
+$ProjectRoot = $PSScriptRoot
+
+# Resolve DAB config path
+if (-not $DabConfigPath) {
+ $DabConfigPath = Join-Path $ProjectRoot 'dab-config.json'
+}
+if (-not (Test-Path $DabConfigPath)) {
+ Write-Error "DAB config not found at: $DabConfigPath. Provide -DabConfigPath or place dab-config.json in the project root."
+ exit 1
+}
+$DabConfigPath = Resolve-Path $DabConfigPath
+Write-Host "Using DAB config: $DabConfigPath" -ForegroundColor Cyan
+
+# ── Step 1: Detect deployer identity ──────────────────────────────────────────
+
+Write-Host ""
+Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan
+Write-Host " Step 1/5: Detecting deployer identity" -ForegroundColor Cyan
+Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan
+
+$deployerLogin = az account show --query user.name -o tsv
+if (-not $deployerLogin) {
+ Write-Error "Not logged in. Run 'az login' first."
+ exit 1
+}
+Write-Host " Deployer: $deployerLogin" -ForegroundColor Green
+
+$deployerObjectId = az ad signed-in-user show --query id -o tsv
+Write-Host " Object ID: $deployerObjectId" -ForegroundColor Green
+
+$deployerIp = try { (Invoke-RestMethod -Uri 'https://api.ipify.org' -TimeoutSec 10) } catch { '' }
+if ($deployerIp) {
+ Write-Host " Public IP: $deployerIp" -ForegroundColor Green
+} else {
+ Write-Host " Public IP: (could not detect — SQL firewall rule skipped)" -ForegroundColor Yellow
+}
+
+# ── Step 2: Deploy Bicep ──────────────────────────────────────────────────────
+
+Write-Host ""
+Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan
+Write-Host " Step 2/5: Deploying infrastructure (Bicep)" -ForegroundColor Cyan
+Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan
+
+$bicepFile = Join-Path $ProjectRoot 'infra' 'main.bicep'
+if (-not (Test-Path $bicepFile)) {
+ Write-Error "Bicep file not found at: $bicepFile"
+ exit 1
+}
+
+# Copy DAB config to expected location for loadTextContent('../dab-config.json')
+$expectedDabPath = Join-Path $ProjectRoot 'dab-config.json'
+if ($DabConfigPath -ne (Resolve-Path $expectedDabPath -ErrorAction SilentlyContinue)) {
+ Write-Host " Copying DAB config to project root for Bicep..." -ForegroundColor Yellow
+ Copy-Item -Path $DabConfigPath -Destination $expectedDabPath -Force
+}
+
+Write-Host " Deploying to subscription..." -ForegroundColor Yellow
+
+$deployment = az deployment sub create `
+ --name "mcp-deploy-$EnvironmentName" `
+ --location $Location `
+ --template-file $bicepFile `
+ --parameters environmentName=$EnvironmentName `
+ location=$Location `
+ connectorNamespaceLocation=$ConnectorNamespaceLocation `
+ deployerLoginName=$deployerLogin `
+ deployerPrincipalId=$deployerObjectId `
+ deployerIpAddress=$deployerIp `
+ databaseName=$DatabaseName `
+ connectorNamespaceIdentityType=$ConnectorNamespaceIdentityType `
+ --query "properties.outputs" `
+ -o json 2>&1
+
+if ($LASTEXITCODE -ne 0) {
+ Write-Host $deployment -ForegroundColor Red
+ Write-Error "Bicep deployment failed."
+ exit 1
+}
+
+$outputs = $deployment | ConvertFrom-Json
+
+$sqlServerFqdn = $outputs.SQL_SERVER_FQDN.value
+$sqlDbName = $outputs.SQL_DATABASE_NAME.value
+$connectorNsName = $outputs.CONNECTOR_NAMESPACE_NAME.value
+$connectorNsSami = $outputs.CONNECTOR_NAMESPACE_PRINCIPAL_ID.value
+$sqlIdentityName = $outputs.SQL_IDENTITY_NAME.value
+$sqlIdentityPrincipal = $outputs.SQL_IDENTITY_PRINCIPAL_ID.value
+$mcpEndpointUrl = $outputs.MCP_ENDPOINT_URL.value
+$rgName = $outputs.RESOURCE_GROUP_NAME.value
+
+Write-Host " Deployment succeeded!" -ForegroundColor Green
+Write-Host " Resource Group: $rgName"
+Write-Host " SQL Server: $sqlServerFqdn"
+Write-Host " Connector Namespace: $connectorNsName"
+Write-Host " SQL MI User: $sqlIdentityName"
+Write-Host " SQL MI Principal ID: $sqlIdentityPrincipal"
+Write-Host " MCP Endpoint: $mcpEndpointUrl"
+
+# ── Step 3: Seed the database ─────────────────────────────────────────────────
+
+Write-Host ""
+Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan
+Write-Host " Step 3/5: Seeding the database" -ForegroundColor Cyan
+Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan
+
+$token = az account get-access-token --resource https://database.windows.net/ --query accessToken -o tsv
+
+$seedSql = @"
+IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'BlogPosts')
+BEGIN
+ CREATE TABLE dbo.BlogPosts (
+ Id int IDENTITY(1,1) PRIMARY KEY,
+ Title nvarchar(300) NOT NULL,
+ Url nvarchar(1000) NOT NULL,
+ Source nvarchar(100) NOT NULL
+ );
+END
+IF NOT EXISTS (SELECT 1 FROM dbo.BlogPosts WHERE Url = N'https://learn.microsoft.com/en-us/azure/logic-apps/connector-namespace/connector-namespace-hosted-mcp')
+BEGIN
+ INSERT INTO dbo.BlogPosts (Title, Url, Source)
+ VALUES (N'Hosted MCP servers in Azure Connector Namespace', N'https://learn.microsoft.com/en-us/azure/logic-apps/connector-namespace/connector-namespace-hosted-mcp', N'Microsoft Learn');
+END
+IF NOT EXISTS (SELECT 1 FROM dbo.BlogPosts WHERE Url = N'https://devblogs.microsoft.com/dotnet/durable-workflows-in-microsoft-agent-framework/')
+BEGIN
+ INSERT INTO dbo.BlogPosts (Title, Url, Source)
+ VALUES (N'Durable Workflows in Microsoft Agent Framework', N'https://devblogs.microsoft.com/dotnet/durable-workflows-in-microsoft-agent-framework/', N'.NET Blog');
+END
+PRINT 'BlogPosts table seeded.';
+"@
+
+$sqlSuccess = $false
+try {
+ Invoke-Sqlcmd -ServerInstance $sqlServerFqdn -Database $sqlDbName -AccessToken $token -Query $seedSql
+ Write-Host " Database seeded." -ForegroundColor Green
+ $sqlSuccess = $true
+} catch {
+ Write-Host " Invoke-Sqlcmd unavailable, trying sqlcmd CLI..." -ForegroundColor Yellow
+ try {
+ sqlcmd -S $sqlServerFqdn -d $sqlDbName -Q $seedSql --authentication-method=ActiveDirectoryDefault
+ Write-Host " Database seeded." -ForegroundColor Green
+ $sqlSuccess = $true
+ } catch {
+ Write-Host " Could not seed automatically." -ForegroundColor Red
+ }
+}
+
+# ── Step 4: Grant managed identity access ─────────────────────────────────────
+
+Write-Host ""
+Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan
+Write-Host " Step 4/5: Granting managed identity database access" -ForegroundColor Cyan
+Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan
+
+$grantSql = @"
+IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name = '$sqlIdentityName')
+BEGIN
+ CREATE USER [$sqlIdentityName] FROM EXTERNAL PROVIDER;
+END
+IF ISNULL(IS_ROLEMEMBER('db_datareader', '$sqlIdentityName'), 0) = 0
+ ALTER ROLE db_datareader ADD MEMBER [$sqlIdentityName];
+IF ISNULL(IS_ROLEMEMBER('db_datawriter', '$sqlIdentityName'), 0) = 0
+ ALTER ROLE db_datawriter ADD MEMBER [$sqlIdentityName];
+GRANT VIEW DEFINITION TO [$sqlIdentityName];
+IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name = '$sqlIdentityName')
+ THROW 51000, 'Connector Namespace managed identity SQL user was not created.', 1;
+IF ISNULL(IS_ROLEMEMBER('db_datareader', '$sqlIdentityName'), 0) <> 1
+ THROW 51001, 'Connector Namespace managed identity is not a member of db_datareader.', 1;
+IF ISNULL(IS_ROLEMEMBER('db_datawriter', '$sqlIdentityName'), 0) <> 1
+ THROW 51002, 'Connector Namespace managed identity is not a member of db_datawriter.', 1;
+PRINT 'Managed identity access granted.';
+"@
+
+if ($sqlSuccess) {
+ try {
+ Invoke-Sqlcmd -ServerInstance $sqlServerFqdn -Database $sqlDbName -AccessToken $token -Query $grantSql
+ Write-Host " Managed identity access granted." -ForegroundColor Green
+ } catch {
+ try {
+ sqlcmd -S $sqlServerFqdn -d $sqlDbName -Q $grantSql --authentication-method=ActiveDirectoryDefault
+ Write-Host " Managed identity access granted." -ForegroundColor Green
+ } catch {
+ $sqlSuccess = $false
+ }
+ }
+}
+
+if (-not $sqlSuccess) {
+ Write-Host ""
+ Write-Host " Run these SQL commands manually in Azure Portal Query Editor:" -ForegroundColor Yellow
+ Write-Host " (SQL Server → $sqlServerFqdn → Database → $sqlDbName → Query editor)" -ForegroundColor Yellow
+ Write-Host ""
+ Write-Host $seedSql -ForegroundColor White
+ Write-Host ""
+ Write-Host $grantSql -ForegroundColor White
+ Write-Host ""
+}
+
+# ── Step 5: Done ──────────────────────────────────────────────────────────────
+
+Write-Host ""
+Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan
+Write-Host " Step 5/5: Deployment Complete!" -ForegroundColor Cyan
+Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan
+Write-Host ""
+Write-Host " MCP Endpoint: $mcpEndpointUrl" -ForegroundColor Green
+$subscriptionId = az account show --query id -o tsv
+$resourceGroupUrl = "https://portal.azure.com/#@/resource/subscriptions/$subscriptionId/resourceGroups/$rgName/overview"
+Write-Host " Azure Portal: $resourceGroupUrl" -ForegroundColor Green
+Write-Host ""
+Write-Host " Use the MCP endpoint with any MCP client that supports HTTP transport." -ForegroundColor White
+Write-Host ""
+Write-Host " Clean up later with:" -ForegroundColor White
+Write-Host " az group delete --name $rgName --yes" -ForegroundColor Gray
+Write-Host ""
diff --git a/samples/applications/azure-sql-mcp/infra/main.bicep b/samples/applications/azure-sql-mcp/infra/main.bicep
new file mode 100644
index 0000000000..de344b7f8c
--- /dev/null
+++ b/samples/applications/azure-sql-mcp/infra/main.bicep
@@ -0,0 +1,207 @@
+targetScope = 'subscription'
+
+// ---------------------------------------------------------------------------
+// Parameters
+// ---------------------------------------------------------------------------
+
+@minLength(1)
+@maxLength(64)
+@description('Name of the environment (used to generate unique resource names).')
+param environmentName string
+
+@description('Primary location for SQL and other resources.')
+@metadata({
+ azd: {
+ type: 'location'
+ }
+})
+param location string
+
+@description('Location for the Connector Namespace. Preview regions: westcentralus, eastasia, centralus, northeurope.')
+param connectorNamespaceLocation string = location
+
+@description('Object ID of the deployer user. Used as Entra admin for SQL and for access policies.')
+@metadata({
+ azd: {
+ type: 'principalId'
+ }
+})
+param deployerPrincipalId string = deployer().objectId
+
+@description('Login name (email) of the deployer user for SQL Entra admin.')
+param deployerLoginName string
+
+@description('Name of the SQL Database to create.')
+param databaseName string = 'mcpdb'
+
+@description('Optional public IP address to allow through the SQL firewall. The azd post-provision hook also configures this for local setup.')
+param deployerIpAddress string = ''
+
+@allowed([
+ 'SystemAssigned'
+ 'UserAssigned'
+])
+@description('Managed identity type for the Connector Namespace and hosted SQL MCP server.')
+param connectorNamespaceIdentityType string
+
+// ---------------------------------------------------------------------------
+// Variables
+// ---------------------------------------------------------------------------
+
+var readableEnvironmentName = take(toLower(replace(replace(replace(environmentName, '_', '-'), '.', '-'), ' ', '-')), 40)
+var resourceToken = take(toLower(uniqueString(subscription().id, environmentName, location)), 8)
+var tags = { 'azd-env-name': environmentName }
+var resourceGroupName = 'rg-${readableEnvironmentName}'
+var sqlServerName = 'sql-${readableEnvironmentName}-${resourceToken}'
+var connectorNamespaceName = 'cn-${readableEnvironmentName}-${resourceToken}'
+var userAssignedIdentityName = 'id-${readableEnvironmentName}-${resourceToken}'
+var logAnalyticsWorkspaceName = 'log-${readableEnvironmentName}-${resourceToken}'
+var appInsightsName = 'appi-${readableEnvironmentName}-${resourceToken}'
+var useUserAssignedIdentity = connectorNamespaceIdentityType == 'UserAssigned'
+
+// Load the included DAB config and base64-encode it for the ARM API.
+var dabConfigBase64 = base64(loadTextContent('../dab-config.json'))
+
+// ---------------------------------------------------------------------------
+// Resource Group
+// ---------------------------------------------------------------------------
+
+resource rg 'Microsoft.Resources/resourceGroups@2024-03-01' = {
+ name: resourceGroupName
+ location: location
+ tags: tags
+}
+
+// ---------------------------------------------------------------------------
+// Azure SQL Server + Database
+// ---------------------------------------------------------------------------
+
+module sql './modules/sql.bicep' = {
+ scope: rg
+ name: 'sql-${resourceToken}'
+ params: {
+ sqlServerName: sqlServerName
+ databaseName: databaseName
+ location: location
+ tags: tags
+ entraAdminObjectId: deployerPrincipalId
+ entraAdminLogin: deployerLoginName
+ deployerIpAddress: deployerIpAddress
+ }
+}
+
+// ---------------------------------------------------------------------------
+// Application Insights
+// ---------------------------------------------------------------------------
+
+module appInsights './modules/appInsights.bicep' = {
+ scope: rg
+ name: 'appi-${resourceToken}'
+ params: {
+ workspaceName: logAnalyticsWorkspaceName
+ appInsightsName: appInsightsName
+ location: 'southcentralus' // TODO: revert to `location` after testing
+ tags: tags
+ }
+}
+
+// ---------------------------------------------------------------------------
+// Optional user-assigned managed identity
+// ---------------------------------------------------------------------------
+
+module userAssignedIdentity './modules/userAssignedIdentity.bicep' = if (useUserAssignedIdentity) {
+ scope: rg
+ name: 'id-${resourceToken}'
+ params: {
+ name: userAssignedIdentityName
+ location: location
+ tags: tags
+ }
+}
+
+// ---------------------------------------------------------------------------
+// Connector Namespace
+// ---------------------------------------------------------------------------
+
+module connectorNamespace './modules/connectorNamespace.bicep' = {
+ scope: rg
+ name: 'cn-${resourceToken}'
+ params: {
+ name: connectorNamespaceName
+ location: connectorNamespaceLocation
+ tags: tags
+ identityType: connectorNamespaceIdentityType
+ userAssignedIdentityResourceId: useUserAssignedIdentity ? userAssignedIdentity.outputs.id : ''
+ }
+}
+
+var managedIdentityClientId = useUserAssignedIdentity ? userAssignedIdentity.outputs.clientId : ''
+var sqlIdentityName = useUserAssignedIdentity ? userAssignedIdentity.outputs.name : connectorNamespace.outputs.name
+var sqlIdentityPrincipalId = useUserAssignedIdentity ? userAssignedIdentity.outputs.principalId : connectorNamespace.outputs.principalId
+var dabConnectionString = useUserAssignedIdentity
+ ? 'Server=${sql.outputs.sqlServerFqdn};Database=${databaseName};Authentication=Active Directory Managed Identity;User Id=${managedIdentityClientId};Encrypt=True;TrustServerCertificate=False;'
+ : 'Server=${sql.outputs.sqlServerFqdn};Database=${databaseName};Authentication=Active Directory Default;Encrypt=True;TrustServerCertificate=False;'
+
+// ---------------------------------------------------------------------------
+// Hosted SQL MCP Server + Access Policy
+// ---------------------------------------------------------------------------
+
+module hostedMcpServer './modules/hostedMcpServer.bicep' = {
+ scope: rg
+ name: 'mcp-${resourceToken}'
+ params: {
+ connectorNamespaceName: connectorNamespaceName
+ name: 'sql-mcp'
+ deployerPrincipalId: deployerPrincipalId
+ dabConfigBase64: dabConfigBase64
+ sqlConnectionString: dabConnectionString
+ applicationInsightsConnectionString: appInsights.outputs.connectionString
+ managedIdentityClientId: managedIdentityClientId
+ }
+ dependsOn: [
+ connectorNamespace
+ ]
+}
+
+// ---------------------------------------------------------------------------
+// Outputs
+// ---------------------------------------------------------------------------
+
+@description('The name of the resource group.')
+output RESOURCE_GROUP_NAME string = rg.name
+
+@description('The name of the SQL Server.')
+output SQL_SERVER_NAME string = sql.outputs.sqlServerName
+
+@description('The fully qualified domain name of the SQL Server.')
+output SQL_SERVER_FQDN string = sql.outputs.sqlServerFqdn
+
+@description('The name of the SQL Database.')
+output SQL_DATABASE_NAME string = sql.outputs.databaseName
+
+@description('The name of the Connector Namespace.')
+output CONNECTOR_NAMESPACE_NAME string = connectorNamespace.outputs.name
+
+@description('The principal ID of the Connector Namespace system-assigned managed identity. Empty when using user-assigned identity only.')
+output CONNECTOR_NAMESPACE_PRINCIPAL_ID string = connectorNamespace.outputs.principalId
+
+@description('The managed identity name granted access to Azure SQL.')
+output SQL_IDENTITY_NAME string = sqlIdentityName
+
+@description('The managed identity principal ID granted access to Azure SQL.')
+output SQL_IDENTITY_PRINCIPAL_ID string = sqlIdentityPrincipalId
+
+@description('The managed identity client ID used by the hosted MCP server. Empty when using system-assigned identity.')
+output SQL_IDENTITY_CLIENT_ID string = managedIdentityClientId
+
+@description('The name of the Application Insights resource.')
+output APPLICATIONINSIGHTS_NAME string = appInsights.outputs.appInsightsName
+
+@description('The name of the Log Analytics workspace backing Application Insights.')
+output LOG_ANALYTICS_WORKSPACE_NAME string = appInsights.outputs.workspaceName
+
+@description('Connection string for DAB config.')
+output DAB_CONNECTION_STRING string = dabConnectionString
+
+@description('MCP endpoint URL — point VS Code / MCP clients here.')
+output MCP_ENDPOINT_URL string = hostedMcpServer.outputs.mcpEndpointUrl
diff --git a/samples/applications/azure-sql-mcp/infra/main.parameters.json b/samples/applications/azure-sql-mcp/infra/main.parameters.json
new file mode 100644
index 0000000000..fa2e41ef88
--- /dev/null
+++ b/samples/applications/azure-sql-mcp/infra/main.parameters.json
@@ -0,0 +1,15 @@
+{
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "environmentName": {
+ "value": "${AZURE_ENV_NAME}"
+ },
+ "location": {
+ "value": "${AZURE_LOCATION}"
+ },
+ "deployerLoginName": {
+ "value": "${AZURE_DEPLOYER_LOGIN}"
+ }
+ }
+}
diff --git a/samples/applications/azure-sql-mcp/infra/modules/appInsights.bicep b/samples/applications/azure-sql-mcp/infra/modules/appInsights.bicep
new file mode 100644
index 0000000000..2c48cacf17
--- /dev/null
+++ b/samples/applications/azure-sql-mcp/infra/modules/appInsights.bicep
@@ -0,0 +1,47 @@
+@description('Name for the Log Analytics workspace backing Application Insights.')
+param workspaceName string
+
+@description('Name for the Application Insights resource.')
+param appInsightsName string
+
+@description('Location for monitoring resources.')
+param location string
+
+@description('Tags to apply to resources.')
+param tags object = {}
+
+resource workspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = {
+ name: workspaceName
+ location: location
+ tags: tags
+ properties: {
+ sku: {
+ name: 'PerGB2018'
+ }
+ retentionInDays: 30
+ publicNetworkAccessForIngestion: 'Enabled'
+ publicNetworkAccessForQuery: 'Enabled'
+ }
+}
+
+resource appInsights 'Microsoft.Insights/components@2020-02-02' = {
+ name: appInsightsName
+ location: location
+ tags: tags
+ kind: 'web'
+ properties: {
+ Application_Type: 'web'
+ WorkspaceResourceId: workspace.id
+ publicNetworkAccessForIngestion: 'Enabled'
+ publicNetworkAccessForQuery: 'Enabled'
+ }
+}
+
+@description('The name of the Log Analytics workspace.')
+output workspaceName string = workspace.name
+
+@description('The name of the Application Insights resource.')
+output appInsightsName string = appInsights.name
+
+@description('The Application Insights connection string.')
+output connectionString string = appInsights.properties.ConnectionString
diff --git a/samples/applications/azure-sql-mcp/infra/modules/connectorNamespace.bicep b/samples/applications/azure-sql-mcp/infra/modules/connectorNamespace.bicep
new file mode 100644
index 0000000000..242bdfee84
--- /dev/null
+++ b/samples/applications/azure-sql-mcp/infra/modules/connectorNamespace.bicep
@@ -0,0 +1,44 @@
+@description('Name for the Connector Namespace.')
+param name string
+
+@description('Location for the Connector Namespace. During preview, only select regions are supported: westcentralus, eastasia, centralus, northeurope.')
+param location string
+
+@description('Tags to apply to resources.')
+param tags object = {}
+
+@allowed([
+ 'SystemAssigned'
+ 'UserAssigned'
+])
+@description('Managed identity type for the Connector Namespace.')
+param identityType string = 'SystemAssigned'
+
+@description('Resource ID of the user-assigned managed identity to attach when identityType is UserAssigned.')
+param userAssignedIdentityResourceId string = ''
+
+var identityBlock = identityType == 'UserAssigned' ? {
+ type: 'UserAssigned'
+ userAssignedIdentities: {
+ '${userAssignedIdentityResourceId}': {}
+ }
+} : {
+ type: 'SystemAssigned'
+}
+
+resource connectorNamespace 'Microsoft.Web/connectorGateways@2026-05-01-preview' = {
+ name: name
+ location: location
+ tags: tags
+ identity: identityBlock
+ properties: {}
+}
+
+@description('The resource ID of the Connector Namespace.')
+output resourceId string = connectorNamespace.id
+
+@description('The name of the Connector Namespace.')
+output name string = connectorNamespace.name
+
+@description('The principal ID of the system-assigned managed identity. Empty when using user-assigned identity only.')
+output principalId string = identityType == 'SystemAssigned' ? connectorNamespace.identity.principalId : ''
diff --git a/samples/applications/azure-sql-mcp/infra/modules/hostedMcpServer.bicep b/samples/applications/azure-sql-mcp/infra/modules/hostedMcpServer.bicep
new file mode 100644
index 0000000000..f0950b1469
--- /dev/null
+++ b/samples/applications/azure-sql-mcp/infra/modules/hostedMcpServer.bicep
@@ -0,0 +1,82 @@
+@sys.description('Name of the parent Connector Namespace.')
+param connectorNamespaceName string
+
+@sys.description('Name for the MCP server config (2-64 chars).')
+@minLength(2)
+@maxLength(64)
+param name string
+
+@sys.description('Description shown to MCP clients.')
+param mcpServerDescription string = 'SQL MCP server bound to DAB config with managed identity.'
+
+@sys.description('Object ID of the deployer user to grant MCP access.')
+param deployerPrincipalId string
+
+@sys.description('Tenant ID for access policies.')
+param tenantId string = tenant().tenantId
+
+@sys.description('Base64-encoded DAB configuration file content.')
+param dabConfigBase64 string
+
+@secure()
+@sys.description('SQL connection string exposed to the hosted MCP server as SQL_CONNECTION_STRING.')
+param sqlConnectionString string
+
+@sys.description('Application Insights connection string exposed to the hosted MCP server as APPLICATIONINSIGHTS_CONNECTION_STRING.')
+param applicationInsightsConnectionString string
+
+@sys.description('Optional managed identity client ID exposed as AZURE_CLIENT_ID when using a user-assigned managed identity.')
+param managedIdentityClientId string = ''
+
+// Reference the existing Connector Namespace
+resource connectorNamespace 'Microsoft.Web/connectorGateways@2026-05-01-preview' existing = {
+ name: connectorNamespaceName
+}
+
+var hostedMcpConfiguration = union({
+ configFile: dabConfigBase64
+ SQL_CONNECTION_STRING: sqlConnectionString
+ APPLICATIONINSIGHTS_CONNECTION_STRING: applicationInsightsConnectionString
+}, empty(managedIdentityClientId) ? {} : {
+ AZURE_CLIENT_ID: managedIdentityClientId
+})
+
+// Hosted MCP Server — runs the curated mcp-sql container image with DAB config
+resource mcpServer 'Microsoft.Web/connectorGateways/mcpServerConfigs@2026-05-01-preview' = {
+ parent: connectorNamespace
+ name: name
+ kind: 'HostedMcpServer'
+ properties: {
+ description: mcpServerDescription
+ hostedMcpServer: {
+ hostedMcpServerId: 'mcp-sql'
+ configuration: hostedMcpConfiguration
+ }
+ }
+}
+
+// Grant the deployer access to invoke the MCP server tools.
+// The access-policy name must equal the principal's objectId.
+resource mcpAccessPolicy 'Microsoft.Web/connectorGateways/mcpServerConfigs/accessPolicies@2026-05-01-preview' = {
+ parent: mcpServer
+ name: deployerPrincipalId
+ properties: {
+ principal: {
+ type: 'ActiveDirectory'
+ identity: {
+ objectId: deployerPrincipalId
+ tenantId: tenantId
+ }
+ }
+ principalType: 'User'
+ }
+}
+
+@sys.description('Resource ID of the MCP server config.')
+output id string = mcpServer.id
+
+@sys.description('Name of the MCP server config.')
+output mcpServerName string = mcpServer.name
+
+@sys.description('MCP endpoint URL for clients to connect to.')
+output mcpEndpointUrl string = mcpServer.properties.mcpEndpointUrl
diff --git a/samples/applications/azure-sql-mcp/infra/modules/sql.bicep b/samples/applications/azure-sql-mcp/infra/modules/sql.bicep
new file mode 100644
index 0000000000..c345536b5e
--- /dev/null
+++ b/samples/applications/azure-sql-mcp/infra/modules/sql.bicep
@@ -0,0 +1,86 @@
+@description('Azure SQL Server name.')
+param sqlServerName string
+
+@description('Azure SQL Database name.')
+param databaseName string
+
+@description('Location for resources.')
+param location string
+
+@description('Tags to apply to resources.')
+param tags object = {}
+
+@description('Object ID of the Entra ID admin for the SQL Server.')
+param entraAdminObjectId string
+
+@description('Login name of the Entra ID admin (email or display name).')
+param entraAdminLogin string
+
+@description('Tenant ID for Entra ID authentication.')
+param tenantId string = tenant().tenantId
+
+@description('Public IP of the deployer for SQL firewall rule (allows post-provision scripts to connect). Leave empty to skip.')
+param deployerIpAddress string = ''
+
+resource sqlServer 'Microsoft.Sql/servers@2023-08-01-preview' = {
+ name: sqlServerName
+ location: location
+ tags: tags
+ properties: {
+ administrators: {
+ administratorType: 'ActiveDirectory'
+ azureADOnlyAuthentication: true
+ login: entraAdminLogin
+ sid: entraAdminObjectId
+ tenantId: tenantId
+ principalType: 'User'
+ }
+ minimalTlsVersion: '1.2'
+ publicNetworkAccess: 'Enabled'
+ }
+}
+
+// Allow Azure services to access the SQL Server
+resource firewallRuleAzure 'Microsoft.Sql/servers/firewallRules@2023-08-01-preview' = {
+ parent: sqlServer
+ name: 'AllowAzureServices'
+ properties: {
+ startIpAddress: '0.0.0.0'
+ endIpAddress: '0.0.0.0'
+ }
+}
+
+// Allow the deployer's IP to connect for post-provision seeding/granting
+resource firewallRuleDeployer 'Microsoft.Sql/servers/firewallRules@2023-08-01-preview' = if (!empty(deployerIpAddress)) {
+ parent: sqlServer
+ name: 'AllowDeployerIp'
+ properties: {
+ startIpAddress: deployerIpAddress
+ endIpAddress: deployerIpAddress
+ }
+}
+
+resource database 'Microsoft.Sql/servers/databases@2023-08-01-preview' = {
+ parent: sqlServer
+ name: databaseName
+ location: location
+ tags: tags
+ sku: {
+ name: 'Basic'
+ tier: 'Basic'
+ capacity: 5
+ }
+ properties: {
+ collation: 'SQL_Latin1_General_CP1_CI_AS'
+ maxSizeBytes: 2147483648
+ }
+}
+
+@description('The fully qualified domain name of the SQL Server.')
+output sqlServerFqdn string = sqlServer.properties.fullyQualifiedDomainName
+
+@description('The name of the SQL Server.')
+output sqlServerName string = sqlServer.name
+
+@description('The name of the SQL Database.')
+output databaseName string = database.name
diff --git a/samples/applications/azure-sql-mcp/infra/modules/userAssignedIdentity.bicep b/samples/applications/azure-sql-mcp/infra/modules/userAssignedIdentity.bicep
new file mode 100644
index 0000000000..4ced3d435b
--- /dev/null
+++ b/samples/applications/azure-sql-mcp/infra/modules/userAssignedIdentity.bicep
@@ -0,0 +1,26 @@
+@description('Name for the user-assigned managed identity.')
+param name string
+
+@description('Location for the user-assigned managed identity.')
+param location string
+
+@description('Tags to apply to resources.')
+param tags object = {}
+
+resource identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
+ name: name
+ location: location
+ tags: tags
+}
+
+@description('The resource ID of the user-assigned managed identity.')
+output id string = identity.id
+
+@description('The name of the user-assigned managed identity.')
+output name string = identity.name
+
+@description('The client ID of the user-assigned managed identity.')
+output clientId string = identity.properties.clientId
+
+@description('The principal ID of the user-assigned managed identity.')
+output principalId string = identity.properties.principalId
diff --git a/samples/applications/azure-sql-mcp/scripts/post-provision.ps1 b/samples/applications/azure-sql-mcp/scripts/post-provision.ps1
new file mode 100644
index 0000000000..ab1c98ab3d
--- /dev/null
+++ b/samples/applications/azure-sql-mcp/scripts/post-provision.ps1
@@ -0,0 +1,264 @@
+#!/usr/bin/env pwsh
+# post-provision.ps1 — Runs after `azd provision` to seed the database and
+# generate the DAB config file.
+
+Set-StrictMode -Version Latest
+$ErrorActionPreference = 'Stop'
+
+function Add-SqlFirewallRuleForIp {
+ param(
+ [Parameter(Mandatory)]
+ [string]$IpAddress,
+
+ [Parameter(Mandatory)]
+ [string]$RuleName
+ )
+
+ az sql server firewall-rule create `
+ --resource-group $resourceGroupName `
+ --server $sqlServerName `
+ --name $RuleName `
+ --start-ip-address $IpAddress `
+ --end-ip-address $IpAddress `
+ --only-show-errors | Out-Null
+}
+
+function Invoke-SqlcmdWithFirewallRetry {
+ param(
+ [Parameter(Mandatory)]
+ [string]$Query
+ )
+
+ $maxAttempts = 20
+ for ($attempt = 1; $attempt -le $maxAttempts; $attempt++) {
+ try {
+ Invoke-Sqlcmd -ServerInstance $sqlServerFqdn -Database $databaseName -AccessToken $token -Query $Query
+ return
+ } catch {
+ $message = $_.Exception.Message
+ if ($message -match "Client with IP address '([^']+)' is not allowed") {
+ $blockedIp = $Matches[1]
+ Write-Host " SQL reported blocked client IP $blockedIp; adding firewall rule and retrying ($attempt/$maxAttempts)..." -ForegroundColor Yellow
+ Add-SqlFirewallRuleForIp -IpAddress $blockedIp -RuleName 'AllowSqlClientIp'
+ Start-Sleep -Seconds 15
+ continue
+ }
+
+ throw
+ }
+ }
+
+ throw "Timed out waiting for SQL firewall rules to allow this client."
+}
+
+# Read outputs from azd
+$resourceGroupName = (azd env get-value RESOURCE_GROUP_NAME)
+$sqlServerName = (azd env get-value SQL_SERVER_NAME)
+$sqlServerFqdn = (azd env get-value SQL_SERVER_FQDN)
+$databaseName = (azd env get-value SQL_DATABASE_NAME)
+$connectorNsName = (azd env get-value CONNECTOR_NAMESPACE_NAME)
+$connectorNsPrincipal = (azd env get-value CONNECTOR_NAMESPACE_PRINCIPAL_ID)
+$sqlIdentityName = (azd env get-value SQL_IDENTITY_NAME)
+$sqlIdentityPrincipal = (azd env get-value SQL_IDENTITY_PRINCIPAL_ID)
+$dabConnectionString = (azd env get-value DAB_CONNECTION_STRING)
+
+if (-not $sqlIdentityName) {
+ $sqlIdentityName = $connectorNsName
+}
+if (-not $sqlIdentityPrincipal) {
+ $sqlIdentityPrincipal = $connectorNsPrincipal
+}
+
+Write-Host ""
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host " Post-Provision Setup" -ForegroundColor Cyan
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host ""
+Write-Host "SQL Server: $sqlServerFqdn"
+Write-Host "Database: $databaseName"
+Write-Host "Connector Namespace: $connectorNsName"
+Write-Host "Connector NS SAMI ID: $connectorNsPrincipal"
+Write-Host "SQL MI User: $sqlIdentityName"
+Write-Host "SQL MI Principal ID: $sqlIdentityPrincipal"
+Write-Host ""
+
+# --- Step 1: Allow this machine through the SQL firewall ---
+Write-Host "[1/4] Configuring SQL firewall for this machine..." -ForegroundColor Yellow
+try {
+ $detectedIps = @()
+ foreach ($uri in @('https://api.ipify.org', 'https://ifconfig.me/ip')) {
+ try {
+ $ip = (Invoke-RestMethod -Uri $uri -TimeoutSec 10)
+ if ($ip -and $ip -match '^\d{1,3}(\.\d{1,3}){3}$') {
+ $detectedIps += $ip
+ }
+ } catch {
+ Write-Host " Could not detect public IP from $uri." -ForegroundColor DarkYellow
+ }
+ }
+
+ $index = 0
+ foreach ($deployerIp in ($detectedIps | Select-Object -Unique)) {
+ $index++
+ $ruleName = if ($index -eq 1) { 'AllowDeployerIp' } else { "AllowDeployerIp$index" }
+ Add-SqlFirewallRuleForIp -IpAddress $deployerIp -RuleName $ruleName
+ Write-Host " Allowed public IP: $deployerIp" -ForegroundColor Green
+ }
+} catch {
+ Write-Host " WARNING: Could not detect or configure public IP. SQL commands may need to be run manually." -ForegroundColor Yellow
+}
+
+# --- Step 2: Get an access token for Azure SQL ---
+Write-Host "[2/4] Getting access token for Azure SQL..." -ForegroundColor Yellow
+$token = az account get-access-token --resource https://database.windows.net/ --query accessToken -o tsv
+if (-not $token) {
+ Write-Host "ERROR: Failed to get access token. Make sure you are logged in with 'az login'." -ForegroundColor Red
+ exit 1
+}
+
+# --- Step 3: Seed the database ---
+Write-Host "[3/4] Seeding the database with BlogPosts table..." -ForegroundColor Yellow
+
+$seedSql = @"
+IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'BlogPosts')
+BEGIN
+ CREATE TABLE dbo.BlogPosts (
+ Id int IDENTITY(1,1) PRIMARY KEY,
+ Title nvarchar(300) NOT NULL,
+ Url nvarchar(1000) NOT NULL,
+ Source nvarchar(100) NOT NULL
+ );
+END
+IF NOT EXISTS (SELECT 1 FROM dbo.BlogPosts WHERE Url = N'https://learn.microsoft.com/en-us/azure/logic-apps/connector-namespace/connector-namespace-hosted-mcp')
+BEGIN
+ INSERT INTO dbo.BlogPosts (Title, Url, Source)
+ VALUES (N'Hosted MCP servers in Azure Connector Namespace', N'https://learn.microsoft.com/en-us/azure/logic-apps/connector-namespace/connector-namespace-hosted-mcp', N'Microsoft Learn');
+END
+IF NOT EXISTS (SELECT 1 FROM dbo.BlogPosts WHERE Url = N'https://devblogs.microsoft.com/dotnet/durable-workflows-in-microsoft-agent-framework/')
+BEGIN
+ INSERT INTO dbo.BlogPosts (Title, Url, Source)
+ VALUES (N'Durable Workflows in Microsoft Agent Framework', N'https://devblogs.microsoft.com/dotnet/durable-workflows-in-microsoft-agent-framework/', N'.NET Blog');
+END
+PRINT 'BlogPosts table seeded.';
+"@
+
+$grantSql = @"
+IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name = '$sqlIdentityName')
+BEGIN
+ CREATE USER [$sqlIdentityName] FROM EXTERNAL PROVIDER;
+END
+IF ISNULL(IS_ROLEMEMBER('db_datareader', '$sqlIdentityName'), 0) = 0
+ ALTER ROLE db_datareader ADD MEMBER [$sqlIdentityName];
+IF ISNULL(IS_ROLEMEMBER('db_datawriter', '$sqlIdentityName'), 0) = 0
+ ALTER ROLE db_datawriter ADD MEMBER [$sqlIdentityName];
+GRANT VIEW DEFINITION TO [$sqlIdentityName];
+IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name = '$sqlIdentityName')
+ THROW 51000, 'Connector Namespace managed identity SQL user was not created.', 1;
+IF ISNULL(IS_ROLEMEMBER('db_datareader', '$sqlIdentityName'), 0) <> 1
+ THROW 51001, 'Connector Namespace managed identity is not a member of db_datareader.', 1;
+IF ISNULL(IS_ROLEMEMBER('db_datawriter', '$sqlIdentityName'), 0) <> 1
+ THROW 51002, 'Connector Namespace managed identity is not a member of db_datawriter.', 1;
+PRINT 'Granted managed identity access to database.';
+"@
+
+if (-not (Get-Command Invoke-Sqlcmd -ErrorAction SilentlyContinue)) {
+ Write-Host "ERROR: Invoke-Sqlcmd is required for automatic post-provision database setup." -ForegroundColor Red
+ Write-Host "Install the SqlServer PowerShell module or run the SQL commands manually in Azure Portal Query Editor." -ForegroundColor Red
+ exit 1
+}
+
+Invoke-SqlcmdWithFirewallRetry -Query $seedSql
+Write-Host " Database seeded successfully." -ForegroundColor Green
+
+Write-Host "[4/4] Granting managed identity access to database..." -ForegroundColor Yellow
+Invoke-SqlcmdWithFirewallRetry -Query $grantSql
+Write-Host " Managed identity access granted." -ForegroundColor Green
+
+# --- Generate DAB config ---
+Write-Host ""
+Write-Host "Generating dab-config.json..." -ForegroundColor Yellow
+
+$dabConfig = @{
+ '$schema' = 'https://github.com/Azure/data-api-builder/releases/download/v1.7.93/dab.draft.schema.json'
+ 'data-source' = @{
+ 'database-type' = 'mssql'
+ 'connection-string' = $dabConnectionString
+ 'options' = @{
+ 'set-session-context' = $false
+ }
+ }
+ 'runtime' = @{
+ 'rest' = @{
+ 'enabled' = $false
+ 'path' = '/api'
+ 'request-body-strict' = $true
+ }
+ 'graphql' = @{
+ 'enabled' = $false
+ 'path' = '/graphql'
+ 'allow-introspection' = $true
+ }
+ 'mcp' = @{
+ 'enabled' = $true
+ 'path' = '/mcp'
+ }
+ 'host' = @{
+ 'cors' = @{
+ 'origins' = @()
+ 'allow-credentials' = $false
+ }
+ 'authentication' = @{
+ 'provider' = 'AppService'
+ }
+ 'mode' = 'development'
+ }
+ }
+ 'entities' = @{
+ 'BlogPosts' = @{
+ 'source' = @{
+ 'object' = 'dbo.BlogPosts'
+ 'type' = 'table'
+ }
+ 'graphql' = @{
+ 'enabled' = $true
+ 'type' = @{
+ 'singular' = 'BlogPosts'
+ 'plural' = 'BlogPosts'
+ }
+ }
+ 'rest' = @{
+ 'enabled' = $true
+ }
+ 'permissions' = @(
+ @{
+ 'role' = 'anonymous'
+ 'actions' = @(
+ @{ 'action' = '*' }
+ )
+ }
+ )
+ }
+ }
+} | ConvertTo-Json -Depth 10
+
+$dabConfig | Set-Content -Path (Join-Path $PSScriptRoot '..' 'dab-config.generated.json') -Encoding utf8
+Write-Host " Created dab-config.generated.json" -ForegroundColor Green
+
+# --- Print MCP endpoint and portal link ---
+$mcpEndpointUrl = (azd env get-value MCP_ENDPOINT_URL)
+$subscriptionId = (azd env get-value AZURE_SUBSCRIPTION_ID)
+if (-not $subscriptionId) {
+ $subscriptionId = az account show --query id -o tsv
+}
+$resourceGroupUrl = "https://portal.azure.com/#@/resource/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/overview"
+
+Write-Host ""
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host " Deployment Complete!" -ForegroundColor Cyan
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host ""
+Write-Host "MCP Endpoint: $mcpEndpointUrl" -ForegroundColor Green
+Write-Host "Azure Portal: $resourceGroupUrl" -ForegroundColor Green
+Write-Host ""
+Write-Host "Use the MCP endpoint with any MCP client that supports HTTP transport." -ForegroundColor White
+Write-Host ""
diff --git a/samples/applications/azure-sql-mcp/scripts/post-provision.sh b/samples/applications/azure-sql-mcp/scripts/post-provision.sh
new file mode 100755
index 0000000000..046a4e0410
--- /dev/null
+++ b/samples/applications/azure-sql-mcp/scripts/post-provision.sh
@@ -0,0 +1,224 @@
+#!/usr/bin/env bash
+# post-provision.sh — Runs after `azd provision` to seed the database and
+# generate the DAB config file.
+
+set -euo pipefail
+
+add_sql_firewall_rule_for_ip() {
+ local ip_address="$1"
+ local rule_name="$2"
+
+ az sql server firewall-rule create \
+ --resource-group "$RESOURCE_GROUP_NAME" \
+ --server "$SQL_SERVER_NAME" \
+ --name "$rule_name" \
+ --start-ip-address "$ip_address" \
+ --end-ip-address "$ip_address" \
+ --only-show-errors >/dev/null
+}
+
+run_sqlcmd_with_firewall_retry() {
+ local query="$1"
+ local output
+ local max_attempts=20
+ local attempt=1
+
+ while [ "$attempt" -le "$max_attempts" ]; do
+ set +e
+ output=$(echo "$query" | sqlcmd -S "$SQL_SERVER_FQDN" -d "$DATABASE_NAME" -G 2>&1)
+ local exit_code=$?
+ set -e
+
+ if [ "$exit_code" -eq 0 ]; then
+ echo "$output"
+ return 0
+ fi
+
+ if [[ "$output" =~ Client\ with\ IP\ address\ \'([0-9.]+)\'\ is\ not\ allowed ]]; then
+ local blocked_ip="${BASH_REMATCH[1]}"
+ echo " SQL reported blocked client IP $blocked_ip; adding firewall rule and retrying ($attempt/$max_attempts)..."
+ add_sql_firewall_rule_for_ip "$blocked_ip" "AllowSqlClientIp"
+ sleep 15
+ attempt=$((attempt + 1))
+ continue
+ fi
+
+ echo "$output"
+ return "$exit_code"
+ done
+
+ echo "Timed out waiting for SQL firewall rules to allow this client."
+ return 1
+}
+
+# Read outputs from azd
+RESOURCE_GROUP_NAME=$(azd env get-value RESOURCE_GROUP_NAME)
+SQL_SERVER_NAME=$(azd env get-value SQL_SERVER_NAME)
+SQL_SERVER_FQDN=$(azd env get-value SQL_SERVER_FQDN)
+DATABASE_NAME=$(azd env get-value SQL_DATABASE_NAME)
+CONNECTOR_NS_NAME=$(azd env get-value CONNECTOR_NAMESPACE_NAME)
+CONNECTOR_NS_PRINCIPAL=$(azd env get-value CONNECTOR_NAMESPACE_PRINCIPAL_ID)
+SQL_IDENTITY_NAME=$(azd env get-value SQL_IDENTITY_NAME || true)
+SQL_IDENTITY_PRINCIPAL=$(azd env get-value SQL_IDENTITY_PRINCIPAL_ID || true)
+DAB_CONNECTION_STRING=$(azd env get-value DAB_CONNECTION_STRING)
+
+if [ -z "$SQL_IDENTITY_NAME" ]; then
+ SQL_IDENTITY_NAME="$CONNECTOR_NS_NAME"
+fi
+if [ -z "$SQL_IDENTITY_PRINCIPAL" ]; then
+ SQL_IDENTITY_PRINCIPAL="$CONNECTOR_NS_PRINCIPAL"
+fi
+
+echo ""
+echo "============================================================"
+echo " Post-Provision Setup"
+echo "============================================================"
+echo ""
+echo "SQL Server: $SQL_SERVER_FQDN"
+echo "Database: $DATABASE_NAME"
+echo "Connector Namespace: $CONNECTOR_NS_NAME"
+echo "Connector NS SAMI ID: $CONNECTOR_NS_PRINCIPAL"
+echo "SQL MI User: $SQL_IDENTITY_NAME"
+echo "SQL MI Principal ID: $SQL_IDENTITY_PRINCIPAL"
+echo ""
+
+# --- Step 1: Allow this machine through the SQL firewall ---
+echo "[1/4] Configuring SQL firewall for this machine..."
+DETECTED_IPS=()
+for IP_ENDPOINT in "https://api.ipify.org" "https://ifconfig.me/ip"; do
+ DETECTED_IP=$(curl -s --max-time 10 "$IP_ENDPOINT" || true)
+ if [[ "$DETECTED_IP" =~ ^[0-9]{1,3}(\.[0-9]{1,3}){3}$ ]]; then
+ DETECTED_IPS+=("$DETECTED_IP")
+ fi
+done
+
+if [ "${#DETECTED_IPS[@]}" -eq 0 ]; then
+ echo " WARNING: Could not detect public IP. SQL commands may need to be run manually."
+else
+ INDEX=0
+ printf "%s\n" "${DETECTED_IPS[@]}" | sort -u | while read -r DEPLOYER_IP; do
+ INDEX=$((INDEX + 1))
+ RULE_NAME="AllowDeployerIp"
+ if [ "$INDEX" -gt 1 ]; then
+ RULE_NAME="AllowDeployerIp$INDEX"
+ fi
+ add_sql_firewall_rule_for_ip "$DEPLOYER_IP" "$RULE_NAME"
+ echo " Allowed public IP: $DEPLOYER_IP"
+ done
+fi
+
+# --- Step 2: Get an access token for Azure SQL ---
+echo "[2/4] Getting access token for Azure SQL..."
+TOKEN=$(az account get-access-token --resource https://database.windows.net/ --query accessToken -o tsv)
+if [ -z "$TOKEN" ]; then
+ echo "ERROR: Failed to get access token. Make sure you are logged in with 'az login'."
+ exit 1
+fi
+
+# --- Step 3: Seed the database ---
+echo "[3/4] Seeding the database with BlogPosts table..."
+
+SEED_SQL="IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'BlogPosts')
+BEGIN
+ CREATE TABLE dbo.BlogPosts (
+ Id int IDENTITY(1,1) PRIMARY KEY,
+ Title nvarchar(300) NOT NULL,
+ Url nvarchar(1000) NOT NULL,
+ Source nvarchar(100) NOT NULL
+ );
+END;
+IF NOT EXISTS (SELECT 1 FROM dbo.BlogPosts WHERE Url = N'https://learn.microsoft.com/en-us/azure/logic-apps/connector-namespace/connector-namespace-hosted-mcp')
+BEGIN
+ INSERT INTO dbo.BlogPosts (Title, Url, Source)
+ VALUES (N'Hosted MCP servers in Azure Connector Namespace', N'https://learn.microsoft.com/en-us/azure/logic-apps/connector-namespace/connector-namespace-hosted-mcp', N'Microsoft Learn');
+END;
+IF NOT EXISTS (SELECT 1 FROM dbo.BlogPosts WHERE Url = N'https://devblogs.microsoft.com/dotnet/durable-workflows-in-microsoft-agent-framework/')
+BEGIN
+ INSERT INTO dbo.BlogPosts (Title, Url, Source)
+ VALUES (N'Durable Workflows in Microsoft Agent Framework', N'https://devblogs.microsoft.com/dotnet/durable-workflows-in-microsoft-agent-framework/', N'.NET Blog');
+END;"
+
+GRANT_SQL="IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name = '${SQL_IDENTITY_NAME}')
+BEGIN
+ CREATE USER [${SQL_IDENTITY_NAME}] FROM EXTERNAL PROVIDER;
+END;
+IF ISNULL(IS_ROLEMEMBER('db_datareader', '${SQL_IDENTITY_NAME}'), 0) = 0
+ ALTER ROLE db_datareader ADD MEMBER [${SQL_IDENTITY_NAME}];
+IF ISNULL(IS_ROLEMEMBER('db_datawriter', '${SQL_IDENTITY_NAME}'), 0) = 0
+ ALTER ROLE db_datawriter ADD MEMBER [${SQL_IDENTITY_NAME}];
+GRANT VIEW DEFINITION TO [${SQL_IDENTITY_NAME}];
+IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name = '${SQL_IDENTITY_NAME}')
+ THROW 51000, 'Connector Namespace managed identity SQL user was not created.', 1;
+IF ISNULL(IS_ROLEMEMBER('db_datareader', '${SQL_IDENTITY_NAME}'), 0) <> 1
+ THROW 51001, 'Connector Namespace managed identity is not a member of db_datareader.', 1;
+IF ISNULL(IS_ROLEMEMBER('db_datawriter', '${SQL_IDENTITY_NAME}'), 0) <> 1
+ THROW 51002, 'Connector Namespace managed identity is not a member of db_datawriter.', 1;"
+
+if command -v sqlcmd &> /dev/null; then
+ run_sqlcmd_with_firewall_retry "$SEED_SQL"
+ echo " Database seeded."
+ echo "[4/4] Granting managed identity access..."
+ run_sqlcmd_with_firewall_retry "$GRANT_SQL"
+ echo " Managed identity access granted."
+else
+ echo "WARNING: sqlcmd not found. Please run these SQL commands in the Azure Portal Query Editor:"
+ echo ""
+ echo "$SEED_SQL"
+ echo ""
+ echo "$GRANT_SQL"
+ exit 1
+fi
+
+# --- Generate DAB config ---
+echo ""
+echo "Generating dab-config.generated.json..."
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+cat > "$SCRIPT_DIR/../dab-config.generated.json" <$null
+if (-not $currentLogin) {
+ Write-Host "Detecting deployer login from Azure CLI..." -ForegroundColor Yellow
+ $login = az account show --query user.name -o tsv
+ if ($login) {
+ azd env set AZURE_DEPLOYER_LOGIN $login
+ Write-Host " Set AZURE_DEPLOYER_LOGIN=$login" -ForegroundColor Green
+ } else {
+ Write-Host "ERROR: Could not detect login. Run: azd env set AZURE_DEPLOYER_LOGIN your-email@example.com" -ForegroundColor Red
+ exit 1
+ }
+}
+
+# Auto-detect deployer public IP for SQL firewall
+$currentIp = azd env get-value AZURE_DEPLOYER_IP 2>$null
+if (-not $currentIp) {
+ Write-Host "Detecting deployer public IP..." -ForegroundColor Yellow
+ try {
+ $ip = (Invoke-RestMethod -Uri 'https://api.ipify.org' -TimeoutSec 10)
+ azd env set AZURE_DEPLOYER_IP $ip
+ Write-Host " Set AZURE_DEPLOYER_IP=$ip" -ForegroundColor Green
+ } catch {
+ Write-Host "WARNING: Could not detect public IP. SQL post-provision scripts may fail." -ForegroundColor Yellow
+ azd env set AZURE_DEPLOYER_IP ''
+ }
+}
diff --git a/samples/applications/azure-sql-mcp/scripts/pre-provision.sh b/samples/applications/azure-sql-mcp/scripts/pre-provision.sh
new file mode 100755
index 0000000000..510212acc1
--- /dev/null
+++ b/samples/applications/azure-sql-mcp/scripts/pre-provision.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+# pre-provision.sh — Auto-detect deployer login and public IP before provisioning.
+
+set -euo pipefail
+
+# Auto-detect deployer login (email) if not already set
+CURRENT_LOGIN=$(azd env get-value AZURE_DEPLOYER_LOGIN 2>/dev/null || true)
+if [ -z "$CURRENT_LOGIN" ]; then
+ echo "Detecting deployer login from Azure CLI..."
+ LOGIN=$(az account show --query user.name -o tsv)
+ if [ -n "$LOGIN" ]; then
+ azd env set AZURE_DEPLOYER_LOGIN "$LOGIN"
+ echo " Set AZURE_DEPLOYER_LOGIN=$LOGIN"
+ else
+ echo "ERROR: Could not detect login. Run: azd env set AZURE_DEPLOYER_LOGIN your-email@example.com"
+ exit 1
+ fi
+fi
+
+# Auto-detect deployer public IP for SQL firewall
+CURRENT_IP=$(azd env get-value AZURE_DEPLOYER_IP 2>/dev/null || true)
+if [ -z "$CURRENT_IP" ]; then
+ echo "Detecting deployer public IP..."
+ IP=$(curl -s --max-time 10 https://api.ipify.org || true)
+ if [ -n "$IP" ]; then
+ azd env set AZURE_DEPLOYER_IP "$IP"
+ echo " Set AZURE_DEPLOYER_IP=$IP"
+ else
+ echo "WARNING: Could not detect public IP. SQL post-provision scripts may fail."
+ azd env set AZURE_DEPLOYER_IP ""
+ fi
+fi