Skip to content

Commit c251425

Browse files
committed
Adds a new Azure SQL MCP sample under samples/applications/azure-sql-mcp. The sample deploys a hosted mcp-sql server in Azure Connector Namespace backed by Azure SQL Database
Adds a new Azure SQL MCP sample under `samples/applications/azure-sql-mcp`. The sample deploys a hosted `mcp-sql` server in Azure Connector Namespace backed by Azure SQL Database, using `azd` and Bicep. ### What�s included - Provisions Azure SQL Database with a seeded `dbo.BlogPosts` table - Deploys Azure Connector Namespace and a hosted SQL MCP server - Configures Data API Builder through the included `dab-config.json` - Passes SQL and Application Insights connection strings as hosted MCP configuration values - Grants the Connector Namespace managed identity access to the SQL database - Adds Application Insights and Log Analytics for telemetry - Includes post-provision scripts for database seeding, firewall setup, and managed identity grants - Provides README instructions for deployment, VS Code MCP setup, Azure Portal inspection, cleanup, and related docs
1 parent 5a2492c commit c251425

16 files changed

Lines changed: 1639 additions & 0 deletions
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.azure/
2+
dab-config.generated.json
3+
infra/main.json
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
![](../../../media/solutions-microsoft-logo-small.png)
2+
3+
# Azure SQL MCP Server with Connector Namespace
4+
5+
Deploy a hosted Azure SQL Model Context Protocol (MCP) server to [Azure Connector Namespace](https://learn.microsoft.com/azure/logic-apps/connector-namespace/connector-namespace-hosted-mcp). The sample provisions Azure SQL Database, exposes a `BlogPost` table through Data API Builder MCP, and configures managed identity access so MCP clients such as GitHub Copilot in Visual Studio Code can query the database.
6+
7+
### Contents
8+
9+
[About this sample](#about-this-sample)<br/>
10+
[Before you begin](#before-you-begin)<br/>
11+
[Run this sample](#run-this-sample)<br/>
12+
[Sample details](#sample-details)<br/>
13+
[Clean up](#clean-up)<br/>
14+
[Related links](#related-links)<br/>
15+
16+
<a name=about-this-sample></a>
17+
18+
## About this sample
19+
20+
- **Applies to:** Azure SQL Database
21+
- **Key features:** Azure Connector Namespace, hosted MCP server, Data API Builder, managed identity, Application Insights
22+
- **Workload:** AI agent data access
23+
- **Programming Language:** Bicep, PowerShell, Bash, JSON
24+
25+
This sample deploys a hosted `mcp-sql` server in Azure Connector Namespace. The hosted MCP server uses Data API Builder configuration to expose a SQL table through MCP tools. The SQL database is seeded with a `dbo.BlogPost` table containing links to Microsoft Learn and .NET Blog posts. For more background, see [Hosted MCP servers in Azure Connector Namespace](https://learn.microsoft.com/azure/logic-apps/connector-namespace/connector-namespace-hosted-mcp).
26+
27+
<a name=before-you-begin></a>
28+
29+
## Before you begin
30+
31+
To run this sample, you need the following prerequisites.
32+
33+
**Software prerequisites:**
34+
35+
1. [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) (`az`)
36+
1. [Azure Developer CLI](https://learn.microsoft.com/azure/developer/azure-developer-cli/install-azd) (`azd`)
37+
1. PowerShell 7+ on Windows, or Bash on Linux/macOS
38+
39+
**Azure prerequisites:**
40+
41+
1. An Azure subscription with permissions to create resource groups and resources.
42+
1. Permission to create Azure SQL Database, Application Insights, Log Analytics workspace, and Connector Namespace resources.
43+
1. Permission to create an Azure SQL Microsoft Entra administrator for the signed-in user.
44+
45+
<a name=run-this-sample></a>
46+
47+
## Run this sample
48+
49+
From this folder:
50+
51+
```bash
52+
azd auth login
53+
azd init
54+
azd up
55+
```
56+
57+
#### `azd init` prompts
58+
59+
When you run `azd init` for the first time, it detects the existing `azure.yaml` and Bicep templates:
60+
61+
1. **"How do you want to initialize your app?"** — Select **Use code in the current directory**.
62+
2. **"Confirm and continue initializing this app"** — Press **Enter** to confirm the detected services.
63+
3. **"Enter a new environment name"** — Pick any name, for example `mcp-dev`. This name is used as a prefix for Azure resource names.
64+
65+
You only need to run `azd init` once. Subsequent deployments only require `azd up`.
66+
67+
#### `azd up` prompts
68+
69+
When you run `azd up`, you are prompted for:
70+
71+
- **Azure Subscription:** Select the Azure subscription to deploy to.
72+
- **Azure location:** Choose a supported region (e.g. `eastasia`, `westcentralus`).
73+
- **`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:
74+
75+
```bash
76+
az account show --query user.name -o tsv
77+
```
78+
- **`connectorNamespaceIdentityType` infrastructure parameter:** Enter `SystemAssigned` for the default Connector Namespace managed identity, or `UserAssigned` to create and attach a user-assigned managed identity.
79+
80+
The `deployerLoginName` value is used to create the Azure SQL server with Microsoft Entra-only authentication and set you as the SQL Entra admin.
81+
82+
### Optional: use a user-assigned managed identity
83+
84+
When `azd up` prompts for `connectorNamespaceIdentityType`, enter `UserAssigned` to test with a user-assigned managed identity.
85+
86+
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.
87+
88+
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.
89+
90+
### Connect from Visual Studio Code
91+
92+
After `azd up` completes, the MCP endpoint URL is printed. Add it to VS Code using the UI:
93+
94+
1. In VS Code, open the Command Palette:
95+
- Windows/Linux: <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>
96+
- macOS: <kbd>Cmd</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>
97+
1. Run **MCP: Add Server**.
98+
1. Choose **HTTP** as the server type.
99+
1. Paste the MCP endpoint URL printed by `azd up`.
100+
1. Enter a server name, for example `sql-mcp`.
101+
1. Choose whether to save the server in user settings or workspace settings.
102+
1. Start the `sql-mcp` server when VS Code prompts you.
103+
104+
VS Code prompts you to sign in with Microsoft. Then use Copilot Chat to query your database, for example: *"List the blog posts in the database."*
105+
106+
<a name=sample-details></a>
107+
108+
## Sample details
109+
110+
### Architecture
111+
112+
```
113+
┌─────────────────────────────────────┐
114+
│ Connector Namespace │
115+
│ (Microsoft.Web/connectorGateways) │
116+
│ │
117+
│ ┌───────────────────────────────┐ │
118+
│ │ Hosted SQL MCP Server │ │
119+
│ │ (Data API Builder) │ │
120+
│ │ │ │
121+
│ │ MI ───► Azure SQL DB │ │
122+
│ └───────────────────────────────┘ │
123+
└─────────────────────────────────────┘
124+
125+
│ MCP (HTTP + SSE)
126+
127+
VS Code / Copilot / MCP Client
128+
```
129+
130+
### Resources deployed
131+
132+
| Resource | Purpose |
133+
|----------|---------|
134+
| **Resource Group** | Container for all deployed resources |
135+
| **Azure SQL Server** | Entra-only auth, with you as SQL admin |
136+
| **Azure SQL Database** | Basic SKU database with a `BlogPost` sample table used by the MCP server |
137+
| **SQL Firewall Rules** | Allows Azure services/resources, Azure Portal Query Editor, and your public IP for setup |
138+
| **Log Analytics Workspace** | Stores Application Insights telemetry |
139+
| **Application Insights** | Collects telemetry from the hosted MCP server |
140+
| **Connector Namespace** | Hosts MCP servers with system-assigned managed identity by default, or user-assigned managed identity when configured |
141+
| **Hosted SQL MCP Server** | `mcp-sql` server config on the namespace |
142+
| **MCP Access Policy** | Grants you access to invoke MCP tools |
143+
144+
Resource names use the pattern `<type>-<environment-name>-<short-suffix>` 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.
145+
146+
### What `azd up` does
147+
148+
| Step | Action |
149+
|------|--------|
150+
| **Provision** | Deploys Azure SQL, SQL firewall rules, Log Analytics, Application Insights, Connector Namespace, hosted `mcp-sql`, and MCP access policy. |
151+
| **Post-provision** | Allows your public IP through the SQL firewall, creates and seeds `dbo.BlogPost`, 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. |
152+
153+
The hosted MCP server receives:
154+
155+
- the included `dab-config.json` as `properties.hostedMcpServer.configuration.configFile`
156+
- the generated SQL connection string as `SQL_CONNECTION_STRING`
157+
- the Application Insights connection string as `APPLICATIONINSIGHTS_CONNECTION_STRING`
158+
- `AZURE_CLIENT_ID` when the sample is configured to use a user-assigned managed identity
159+
160+
No SQL or Application Insights connection string is checked in.
161+
162+
This sample includes a ready-to-use `dab-config.json`. 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).
163+
164+
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 SQL hosted MCP server, see [Hosted MCP server quickstart for SQL](https://learn.microsoft.com/azure/logic-apps/connector-namespace/hosted-mcp-quickstart?pivots=sql).
165+
166+
### Inspect resources in Azure Portal
167+
168+
After deployment, the post-provision output includes a link to the Azure resource group in the Azure Portal. Use that page to inspect the SQL server, Application Insights resource, Log Analytics workspace, Connector Namespace, and hosted MCP server.
169+
170+
To allow additional users to connect to the MCP server:
171+
172+
1. Open the deployed **Connector Namespace** resource in the Azure Portal.
173+
1. Open the hosted MCP server configuration, for example `sql-mcp`.
174+
1. Add an access policy for each additional user or group that should be allowed to invoke the MCP server.
175+
176+
### Sample data
177+
178+
The post-provision hook creates and seeds `dbo.BlogPost` with these entries:
179+
180+
| Title | Source |
181+
|-------|--------|
182+
| Hosted MCP servers in Azure Connector Namespace | Microsoft Learn |
183+
| Durable Workflows in Microsoft Agent Framework | .NET Blog |
184+
185+
### SQL firewall access
186+
187+
The deployment configures two SQL firewall paths:
188+
189+
| Rule | When | Purpose |
190+
|------|------|---------|
191+
| `AllowAzureServices` | During Bicep provisioning | Allows Azure services/resources, including Azure Portal Query Editor, to reach the SQL server. |
192+
| `AllowDeployerIp` | During post-provision | Detects your current public IP and allows your local machine to seed and query the database. |
193+
194+
If SQL reports a different blocked client IP during post-provision, the script adds that IP and retries.
195+
196+
<a name=clean-up></a>
197+
198+
## Clean up
199+
200+
Using azd:
201+
202+
```bash
203+
azd down --purge
204+
```
205+
206+
Or with Azure CLI:
207+
208+
```bash
209+
# Replace <environment-name> with your azd environment name.
210+
az group delete --name rg-<environment-name> --yes --no-wait
211+
212+
# Optional: remove the subscription-scope deployment record.
213+
az deployment sub delete --name <environment-name>
214+
```
215+
216+
<a name=related-links></a>
217+
218+
## Related links
219+
220+
- [Hosted MCP servers in Azure Connector Namespace](https://learn.microsoft.com/azure/logic-apps/connector-namespace/connector-namespace-hosted-mcp)
221+
- [Hosted MCP server quickstart for SQL](https://learn.microsoft.com/azure/logic-apps/connector-namespace/hosted-mcp-quickstart?pivots=sql)
222+
- [Azure SQL MCP server support in Data API Builder](https://learn.microsoft.com/azure/data-api-builder/mcp/overview)
223+
- [Install the Data API Builder CLI](https://learn.microsoft.com/azure/data-api-builder/command-line/install)
224+
- [Connector Namespace overview](https://learn.microsoft.com/azure/logic-apps/connector-namespace/connector-namespace-overview)
225+
- [Azure Developer CLI](https://learn.microsoft.com/azure/developer/azure-developer-cli/)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
name: azure-sql-mcp
2+
metadata:
3+
template: azure-sql-mcp
4+
hooks:
5+
postprovision:
6+
windows:
7+
shell: pwsh
8+
run: ./scripts/post-provision.ps1
9+
interactive: true
10+
continueOnError: false
11+
posix:
12+
shell: bash
13+
run: ./scripts/post-provision.sh
14+
interactive: true
15+
continueOnError: false
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"$schema": "https://github.com/Azure/data-api-builder/releases/download/v1.7.90/dab.draft.schema.json",
3+
"data-source": {
4+
"database-type": "mssql",
5+
"connection-string": "@env('SQL_CONNECTION_STRING')",
6+
"options": {
7+
"set-session-context": false
8+
}
9+
},
10+
"runtime": {
11+
"rest": {
12+
"enabled": false,
13+
"path": "/api",
14+
"request-body-strict": true
15+
},
16+
"graphql": {
17+
"enabled": false,
18+
"path": "/graphql",
19+
"allow-introspection": true
20+
},
21+
"mcp": {
22+
"enabled": true,
23+
"path": "/mcp"
24+
},
25+
"host": {
26+
"cors": {
27+
"origins": [],
28+
"allow-credentials": false
29+
},
30+
"authentication": {
31+
"provider": "AppService"
32+
},
33+
"mode": "development"
34+
}
35+
},
36+
"entities": {
37+
"BlogPost": {
38+
"source": {
39+
"object": "dbo.BlogPost",
40+
"type": "table"
41+
},
42+
"graphql": {
43+
"enabled": true,
44+
"type": {
45+
"singular": "BlogPost",
46+
"plural": "BlogPosts"
47+
}
48+
},
49+
"rest": {
50+
"enabled": true
51+
},
52+
"permissions": [
53+
{
54+
"role": "anonymous",
55+
"actions": [
56+
{
57+
"action": "*"
58+
}
59+
]
60+
}
61+
]
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)