Skip to content

Commit 6145eeb

Browse files
Craig ShoemakerCraig Shoemaker
authored andcommitted
verification updates
1 parent a66a5fb commit 6145eeb

7 files changed

Lines changed: 63 additions & 57 deletions

articles/container-apps/mcp-authentication.md

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Learn how to authenticate and authorize MCP servers on Azure Contai
55
ms.topic: how-to
66
ms.service: azure-container-apps
77
ms.collection: ce-skilling-ai-copilot
8-
ms.date: 02/18/2026
8+
ms.date: 02/19/2026
99
author: craigshoemaker
1010
ms.author: cshoe
1111
ms.reviewer: cshoe
@@ -21,7 +21,7 @@ This article explains how to authenticate and secure MCP servers running on Azur
2121
- [Azure CLI](/cli/azure/install-azure-cli) version 2.62.0 or later.
2222
- An existing container app or session pool. If you don't have one, see the [MCP server tutorials](mcp-overview.md).
2323

24-
## Authentication models at a glance
24+
## Authentication models overview
2525

2626
Azure Container Apps supports two authentication models for MCP servers. The following table summarizes the key differences.
2727

@@ -30,7 +30,7 @@ Azure Container Apps supports two authentication models for MCP servers. The fol
3030
| Auth mechanism | Container Apps built-in authentication with Microsoft Entra ID | API key via `x-ms-apikey` header |
3131
| Token type | OAuth 2.0 Bearer token | Opaque API key string |
3232
| Identity provider | Microsoft Entra ID | Azure Resource Manager |
33-
| Key/token rotation | Managed by Microsoft Entra ID | Regenerate the Azure Resource Manager API |
33+
| Key/token rotation | Managed by Microsoft Entra ID | Regenerate via Azure Resource Manager API |
3434
| Authorization scope | Configurable per application | Session pool level |
3535
| Transport encryption | TLS (Container Apps ingress) | TLS (Container Apps sessions endpoint) |
3636

@@ -95,7 +95,7 @@ When your MCP server requires a bearer token, configure token retrieval in your
9595
"servers": {
9696
"my-mcp-server": {
9797
"type": "http",
98-
"url": "https://<APP_NAME>.<REGION>.azurecontainerapps.io/mcp",
98+
"url": "https://<CONTAINER_APP_NAME>.<REGION>.azurecontainerapps.io/mcp",
9999
"headers": {
100100
"Authorization": "Bearer ${input:mcpBearerToken}"
101101
}
@@ -129,7 +129,7 @@ az containerapp ingress cors update \
129129
--max-age 3600
130130
```
131131

132-
Key headers to allow:
132+
The following headers are key to allow:
133133

134134
- `Content-Type`: required for JSON-RPC requests
135135
- `Authorization`: required for bearer token auth
@@ -138,7 +138,7 @@ Key headers to allow:
138138
> [!NOTE]
139139
> GitHub Copilot connects to remote MCP servers from the VS Code desktop app, not from a browser. CORS is only needed if you intend to support browser-based MCP clients or VS Code for the Web. The standalone tutorials use wildcard CORS origins for simplicity; for production, restrict to specific trusted origins as shown here.
140140
141-
### Security recommendations
141+
### Security recommendations for standalone MCP servers
142142

143143
Apply the following best practices to harden your standalone MCP server.
144144

@@ -150,15 +150,18 @@ Apply the following best practices to harden your standalone MCP server.
150150

151151
## Dynamic sessions with API key authentication
152152

153+
> [!IMPORTANT]
154+
> The platform-managed MCP server for dynamic sessions is in **preview**. The API version `2025-02-02-preview` and `mcpServerSettings` properties are subject to change.
155+
153156
The platform-managed MCP server in dynamic sessions uses API key authentication. The key is scoped to the session pool and grants access to all tools and sessions in the pool.
154157

155-
### Authentication flow
158+
### API key authentication flow
156159

157160
The following steps describe how API key authentication works for dynamic sessions.
158161

159162
1. The client sends a JSON-RPC request with the `x-ms-apikey` header.
160163
1. The session pool proxy validates the key against the Azure control plane.
161-
1. If the key is valid, the request is forwarded to the session. If not, a `401 Unauthorized` response is returned.
164+
1. If the key is valid, the request is forwarded to the session. If not, an authentication error is returned.
162165

163166
### Retrieve the API key
164167

@@ -171,9 +174,9 @@ API_KEY=$(az rest --method POST \
171174
--query "apiKey" -o tsv)
172175
```
173176

174-
### Key rotation and caching
177+
### Rotate and cache the API key
175178

176-
You can regenerate the API key at any time. The platform caches validation results, so previously valid keys might continue to work for several minutes after regeneration while the cache expires.
179+
You can regenerate the API key at any time. The platform caches validation results for up to five minutes, so previously valid keys might continue to work after regeneration until the cache expires.
177180

178181
To rotate the API key, call the `regenerateCredentials` action on the session pool:
179182

@@ -185,7 +188,7 @@ az rest --method POST \
185188

186189
After regeneration, retrieve the new key by using `fetchMCPServerCredentials` as shown earlier.
187190

188-
### Security recommendations
191+
### Security recommendations for dynamic sessions
189192

190193
Apply the following best practices to secure your dynamic sessions MCP deployment.
191194

@@ -195,7 +198,7 @@ Apply the following best practices to secure your dynamic sessions MCP deploymen
195198
- **Session lifetime**: Configure `coolDownPeriodInSeconds` to automatically destroy idle sessions. This setting limits the window of exposure if a session is compromised.
196199
- **Secret storage**: Store the API key in [Azure Key Vault](/azure/key-vault/general/overview) or [Container Apps secrets](/azure/container-apps/manage-secrets) rather than in code or configuration files.
197200

198-
## Authentication model comparison
201+
## Common authentication mismatches
199202

200203
A common mistake is using the API key header (`x-ms-apikey`) with a standalone container app, or using a bearer token with the sessions MCP endpoint. The following table shows what happens when you mix them up.
201204

articles/container-apps/mcp-choosing-azure-service.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ ms.topic: conceptual
66
ms.service: azure-container-apps
77
ms.collection: ce-skilling-ai-copilot
88
ms.custom: cross-service
9-
ms.date: 02/18/2026
9+
ms.date: 02/19/2026
1010
author: craigshoemaker
1111
ms.author: cshoe
1212
ms.reviewer: cshoe
@@ -37,7 +37,7 @@ Add an MCP endpoint to an existing or new web app. App Service supports code-bas
3737

3838
### Azure Functions
3939

40-
Map function triggers to MCP tools using the [Azure Functions MCP extension](/azure/azure-functions/scenario-custom-remote-mcp-server). Azure Functions is optimized for stateless, event-driven tool execution with per-invocation pricing.
40+
Map function triggers to MCP tools by using the [Azure Functions MCP extension](/azure/azure-functions/scenario-custom-remote-mcp-server). Azure Functions is optimized for stateless, event-driven tool execution with per-invocation pricing.
4141

4242
## Compare hosting options
4343

@@ -60,7 +60,7 @@ The following table summarizes the key differences between hosting options.
6060

6161
Use the following guidance to narrow your decision based on common workload patterns.
6262

63-
### Build a custom MCP server
63+
### Build a custom MCP server with Azure
6464

6565
**Recommended: Azure Container Apps (standalone) or Azure App Service**
6666

@@ -82,10 +82,11 @@ Tutorials:
8282

8383
Session pools with MCP enabled provide Hyper-V-isolated environments for running untrusted or LLM-generated code. The platform manages the MCP server, so you don't write or deploy server code. The built-in tools cover code execution scenarios without custom development:
8484

85-
- **Shell pools**: `launchShell`, `runShellCommandInRemoteEnvironment`
86-
- **Python pools**: `launchPythonEnvironment`, `runPythonCodeInRemoteEnvironment`
85+
- `launchShell`: Creates a new environment
86+
- `runShellCommandInRemoteEnvironment`: Executes shell commands
87+
- `runPythonCodeInRemoteEnvironment`: Executes Python code
8788

88-
Dynamic sessions maintain prewarmed instances, so there's no cold-start latency.
89+
Dynamic sessions maintain prewarmed instances, so you don't experience cold-start latency.
8990

9091
Tutorials:
9192

articles/container-apps/mcp-overview.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
---
2-
title: MCP servers on Azure Container Apps
3-
description: Learn how to host Model Context Protocol (MCP) servers on Azure Container Apps as standalone container apps or with platform-managed dynamic sessions.
2+
title: Host MCP servers on Azure Container Apps
3+
description: Learn how to host MCP servers on Azure Container Apps as standalone container apps or with dynamic sessions.
44
#customer intent: As a developer, I want to deploy an MCP server as a standalone container app so that I can expose custom tools and connect to backend services.
55
ms.topic: conceptual
66
ms.service: azure-container-apps
77
ms.collection: ce-skilling-ai-copilot
8-
ms.date: 02/18/2026
8+
ms.date: 02/19/2026
99
author: craigshoemaker
1010
ms.author: cshoe
1111
ms.reviewer: cshoe
1212
---
1313

14-
# MCP servers on Azure Container Apps
14+
# Host MCP servers on Azure Container Apps
1515

1616
[Model Context Protocol (MCP)](https://modelcontextprotocol.io/) is an open standard that connects AI applications to external data sources and tools. By using MCP, AI clients like GitHub Copilot can discover and invoke capabilities you expose, turning your APIs, databases, and business logic into tools an AI agent can use through natural language.
1717

@@ -80,13 +80,12 @@ In this model, the platform manages the MCP server. You don't write or deploy MC
8080

8181
| Tool | Description |
8282
|---|---|
83-
| `launchShell` | Creates a new shell environment and returns an `environmentId` |
84-
| `launchPythonEnvironment` | Creates a new Python environment and returns an `environmentId` |
83+
| `launchShell` | Creates a new environment and returns an `environmentId` |
8584
| `runShellCommandInRemoteEnvironment` | Executes a shell command in an existing environment |
8685
| `runPythonCodeInRemoteEnvironment` | Executes Python code in an existing environment |
8786

8887
> [!NOTE]
89-
> The available tools depend on the session pool's `containerType`. Shell pools expose `launchShell` and `runShellCommandInRemoteEnvironment`. Python pools expose `launchPythonEnvironment` and `runPythonCodeInRemoteEnvironment`.
88+
> The platform-managed MCP server exposes all three tools regardless of the session pool's `containerType`. Use `launchShell` to create an environment for both shell and Python pools.
9089
9190
### Request flow
9291

articles/container-apps/mcp-troubleshooting.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Diagnose and fix common issues with MCP servers on Azure Container
55
ms.topic: troubleshooting
66
ms.service: azure-container-apps
77
ms.collection: ce-skilling-ai-copilot
8-
ms.date: 02/18/2026
8+
ms.date: 02/19/2026
99
author: craigshoemaker
1010
ms.author: cshoe
1111
ms.reviewer: cshoe
@@ -111,7 +111,7 @@ The `id` must be a string or number. The `jsonrpc` field must be exactly `"2.0"`
111111

112112
### Transport mismatch
113113

114-
**Symptoms**: SSE client gets 404 or 405 errors; HTTP client gets unexpected `text/event-stream` content type.
114+
**Symptoms**: SSE client gets 404 or 405 errors. HTTP client gets unexpected `text/event-stream` content type.
115115

116116
MCP supports multiple transports. Ensure your client and server use the same transport.
117117

@@ -123,6 +123,9 @@ MCP supports multiple transports. Ensure your client and server use the same tra
123123

124124
Most modern MCP SDKs default to streamable HTTP. If you're connecting to a server that uses SSE (common with older examples), switch your client to SSE mode.
125125

126+
> [!NOTE]
127+
> The [Java tutorial](tutorial-mcp-server-java.md) uses the SSE transport (`WebMvcSseServerTransportProvider`) because the MCP Java SDK doesn't yet offer a stable streamable HTTP transport. When connecting from VS Code, select SSE and use `"type": "sse"` in `.vscode/mcp.json`.
128+
126129
## Deployment and scaling
127130

128131
Deployment issues prevent your container from starting or responding correctly. These problems typically relate to health probes, port configuration, or scaling settings.
@@ -221,15 +224,15 @@ Authentication problems typically happen when you use the wrong credential type
221224
1. Check that the Microsoft Entra app registration's `audience` matches the resource you requested.
222225
1. Verify the `--unauthenticated-client-action` setting. `Return401` blocks unauthenticated requests; `AllowAnonymous` lets them through.
223226

224-
### 401 Unauthorized: dynamic sessions MCP
227+
### Authentication error: dynamic sessions MCP
225228

226-
**Symptoms**: `401 Unauthorized` when calling the platform-managed MCP endpoint.
229+
**Symptoms**: Authentication error when calling the platform-managed MCP endpoint. The error might appear as an HTTP `401` response or as a JSON-RPC error message in the response body. The type of error depends on where in the request pipeline the failure occurs.
227230

228231
**Checklist**:
229232

230233
1. Verify the API key is sent via the `x-ms-apikey` header (not `Authorization`).
231234
1. Verify the key is from `fetchMCPServerCredentials`, not from a different API.
232-
1. If you recently regenerated the key, wait several minutes for the old key's cache to expire.
235+
1. If you recently regenerated the key, wait up to five minutes for the old key's cache to expire.
233236
1. Check that `mcpServerSettings.isMCPServerEnabled` is `true` on the session pool.
234237

235238
For more information, see the [authentication guide](mcp-authentication.md).
@@ -245,10 +248,10 @@ Issues in this section apply only to the platform-managed MCP server in [dynamic
245248
**Causes**:
246249

247250
- The session expired (exceeded `coolDownPeriodInSeconds`).
248-
- The `environmentId` wasn't extracted correctly from the `launchShell` or `launchPythonEnvironment` response.
251+
- The `environmentId` wasn't extracted correctly from the `launchShell` response.
249252
- You're using an environment ID from a different session pool.
250253

251-
**Solution**: Call `launchShell` or `launchPythonEnvironment` again to create a new environment.
254+
**Solution**: Call `launchShell` again to create a new environment.
252255

253256
### MCP not enabled on session pool
254257

articles/container-apps/sessions-tutorial-python-mcp.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Learn how to create a Python session pool with the platform-managed
55
ms.topic: tutorial
66
ms.service: azure-container-apps
77
ms.collection: ce-skilling-ai-copilot
8-
ms.date: 02/18/2026
8+
ms.date: 02/19/2026
99
author: craigshoemaker
1010
ms.author: cshoe
1111
ms.reviewer: cshoe
@@ -22,7 +22,7 @@ Unlike the [standalone MCP server tutorials](mcp-overview.md#standalone-containe
2222

2323
| Tool | Description |
2424
|------|-------------|
25-
| `launchPythonEnvironment` | Creates a new Python environment and returns an `environmentId` |
25+
| `launchShell` | Creates a new environment and returns an `environmentId` |
2626
| `runPythonCodeInRemoteEnvironment` | Executes Python code in an existing environment |
2727
| `runShellCommandInRemoteEnvironment` | Executes a shell command in an existing environment |
2828

@@ -184,7 +184,7 @@ Create a new Python environment:
184184
ENVIRONMENT_RESPONSE=$(curl -sS -X POST "$MCP_ENDPOINT" \
185185
-H "Content-Type: application/json" \
186186
-H "x-ms-apikey: $API_KEY" \
187-
-d '{ "jsonrpc": "2.0", "id": "2", "method": "tools/call", "params": { "name": "launchPythonEnvironment", "arguments": {} } }')
187+
-d '{ "jsonrpc": "2.0", "id": "2", "method": "tools/call", "params": { "name": "launchShell", "arguments": {} } }')
188188

189189
echo $ENVIRONMENT_RESPONSE
190190
```
@@ -197,7 +197,7 @@ echo $ENVIRONMENT_ID
197197
```
198198

199199
> [!NOTE]
200-
> The `launchPythonEnvironment` tool generates a unique environment identifier. The actual session is allocated "lazily". When you execute your first command, the session pool assigns a Hyper-V-isolated container to handle it.
200+
> The `launchShell` tool generates a unique environment identifier. The actual session is allocated "lazily". When you execute your first command, the session pool assigns a Hyper-V-isolated container to handle it.
201201
202202
## Execute Python commands
203203

0 commit comments

Comments
 (0)