Skip to content

Commit 7d6aa3b

Browse files
committed
Add Entra auth proxy
1 parent 1f69dee commit 7d6aa3b

22 files changed

+1399
-190
lines changed

.vscode/mcp.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"0.0.0.0:5678",
2828
"servers/basic_mcp_stdio.py"
2929
]
30-
},
30+
}
3131
},
3232
"inputs": []
33-
}
33+
}

AGENTS.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Instructions for coding agents
2+
3+
## Adding a new azd environment variable
4+
5+
An azd environment variable is stored by the azd CLI for each environment. It is passed to the "azd up" command and can configure both provisioning options and application settings.
6+
7+
When adding new azd environment variables, update these files:
8+
9+
1. **infra/main.parameters.json**: Add the new parameter mapping from azd env variable to Bicep parameter
10+
- Use format `${ENV_VAR_NAME}` for required values
11+
- Use format `${ENV_VAR_NAME=default}` for optional values with defaults
12+
- Example: `"useEntraProxy": { "value": "${USE_ENTRA_PROXY=false}" }`
13+
14+
2. **infra/main.bicep**: Add the Bicep parameter declaration at the top with `@description`
15+
- Use `@secure()` decorator for sensitive values like passwords/secrets
16+
- Example: `@description('Flag to enable feature X') param useFeatureX bool = false`
17+
18+
3. **infra/server.bicep** (or other module): If the variable needs to be passed to a container app:
19+
- Add a parameter to receive the value from main.bicep
20+
- Add the environment variable to the appropriate `env` array (e.g., `baseEnv`, or a conditional array)
21+
- For secrets, add to a secrets array and reference via `secretRef`
22+
23+
4. **infra/main.bicep**: Pass the parameter value to the module
24+
- Example: `featureXEnabled: useFeatureX ? someValue : ''`
25+
26+
5. **infra/write_env.sh** and **infra/write_env.ps1**: If the variable should be written to `.env` for local development:
27+
- Add a line to echo/write the value from `azd env get-value`
28+
- For conditional values, wrap in an if block to only write when populated
29+
30+
6. **infra/main.bicep outputs**: If the value needs to be stored back in azd env after provisioning:
31+
- Add an output (note: `@secure()` parameters cannot be outputs)

README.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ A demonstration project showcasing Model Context Protocol (MCP) implementations
1616
- [Deploy to Azure](#deploy-to-azure)
1717
- [Deploy to Azure with private networking](#deploy-to-azure-with-private-networking)
1818
- [Deploy to Azure with Keycloak authentication](#deploy-to-azure-with-keycloak-authentication)
19+
- [Deploy to Azure with Entra OAuth Proxy](#deploy-to-azure-with-entra-oauth-proxy)
1920

2021
## Getting started
2122

@@ -360,3 +361,83 @@ This project supports deploying with OAuth 2.0 authentication using Keycloak as
360361
| DCR | Open (anonymous) | Require initial access token | Any client can register without auth |
361362

362363
> **Note:** Keycloak must be publicly accessible because its URL is dynamically generated by Azure. Token issuer validation requires a known URL, but the mcproutes URL isn't available until after deployment. Using a custom domain would fix this.
364+
365+
---
366+
367+
## Deploy to Azure with Entra OAuth Proxy
368+
369+
This project supports deploying with Microsoft Entra ID (Azure AD) authentication using FastMCP's built-in Azure OAuth proxy. This is an alternative to Keycloak that uses Microsoft Entra with your Azure tenant for identity management.
370+
371+
### What gets deployed with Entra OAuth
372+
373+
| Component | Description |
374+
|-----------|-------------|
375+
| **Microsoft Entra App Registration** | Created automatically during provisioning with redirect URIs for local development, VS Code, and production |
376+
| **OAuth-protected MCP Server** | FastMCP with AzureProvider for OAuth authentication |
377+
| **CosmosDB OAuth Client Storage** | Persists OAuth client registrations across server restarts |
378+
379+
### Deployment steps for Entra OAuth
380+
381+
1. Enable Entra OAuth proxy:
382+
383+
```bash
384+
azd env set USE_FASTMCP_AUTH true
385+
```
386+
387+
2. Deploy to Azure:
388+
389+
```bash
390+
azd up
391+
```
392+
393+
During deployment:
394+
- **Preprovision hook**: Creates a Microsoft Entra App Registration with a client secret, and stores the credentials in azd environment variables
395+
- **Postprovision hook**: Updates the App Registration with the deployed server URL as an additional redirect URI
396+
397+
3. Verify deployment by checking the outputs:
398+
399+
```bash
400+
azd env get-value MCP_SERVER_URL
401+
azd env get-value FASTMCP_AUTH_AZURE_CLIENT_ID
402+
```
403+
404+
### Environment variables
405+
406+
The following environment variables are automatically set by the deployment hooks:
407+
408+
| Variable | Description |
409+
|----------|-------------|
410+
| `FASTMCP_AUTH_AZURE_CLIENT_ID` | The App Registration's client ID |
411+
| `FASTMCP_AUTH_AZURE_CLIENT_SECRET` | The App Registration's client secret |
412+
| `FASTMCP_AUTH_AZURE_TENANT_ID` | Your Azure tenant ID |
413+
414+
These are written to `.env` by the postprovision hook for local development.
415+
416+
### Testing locally
417+
418+
After deployment, you can test locally with OAuth enabled:
419+
420+
```bash
421+
# Run the MCP server
422+
cd servers && uvicorn deployed_mcp:app --host 0.0.0.0 --port 8000
423+
```
424+
425+
The server will use the Entra App Registration for OAuth and CosmosDB for client storage.
426+
427+
### Connecting VS Code MCP client
428+
429+
The App Registration includes redirect URIs for VS Code:
430+
431+
- `http://localhost:5173/oauth/callback` (VS Code extension localhost)
432+
- `http://localhost:5174/oauth/callback` (VS Code extension localhost alt port)
433+
- `https://vscode.dev/redirect` (VS Code web)
434+
435+
Configure your VS Code MCP client to use the deployed server URL with OAuth.
436+
437+
### Troubleshooting Entra OAuth
438+
439+
If you encounter issues with the OAuth flow in VS Code, you can reset the cached authentication state:
440+
441+
1. Open the Command Palette (`Cmd+Shift+P` on macOS, `Ctrl+Shift+P` on Windows/Linux)
442+
2. Run **"Authentication: Remove Dynamic Authentication Providers"**
443+
3. This clears any cached OAuth tokens and forces a fresh authentication flow

azure.yaml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,23 @@ services:
2929
path: ./agents/Dockerfile
3030
context: .
3131
hooks:
32+
preprovision:
33+
windows:
34+
shell: pwsh
35+
run: ./infra/auth_init.ps1
36+
interactive: true
37+
continueOnError: false
38+
posix:
39+
shell: sh
40+
run: ./infra/auth_init.sh
41+
interactive: true
42+
continueOnError: false
3243
postprovision:
3344
posix:
3445
shell: sh
35-
run: ./infra/write_env.sh
46+
run: ./infra/write_env.sh && ./infra/auth_update.sh
3647
continueOnError: true
3748
windows:
3849
shell: pwsh
39-
run: ./infra/write_env.ps1
50+
run: ./infra/write_env.ps1; ./infra/auth_update.ps1
4051
continueOnError: true

infra/auth_init.ps1

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Pre-provision hook to set up Azure/Entra ID app registration for FastMCP OAuth Proxy
2+
3+
# Check if USE_FASTMCP_AUTH is enabled
4+
$USE_FASTMCP_AUTH = azd env get-value USE_FASTMCP_AUTH 2>$null
5+
if ($USE_FASTMCP_AUTH -ne "true") {
6+
Write-Host "Skipping auth init (USE_FASTMCP_AUTH is not enabled)"
7+
exit 0
8+
}
9+
10+
Write-Host "Setting up Azure/Entra ID app registration for FastMCP OAuth Proxy..."
11+
python ./infra/fastmcp_auth_init.py

infra/auth_init.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
# Pre-provision hook to set up Azure/Entra ID app registration for FastMCP OAuth Proxy
3+
4+
# Check if USE_FASTMCP_AUTH is enabled
5+
USE_FASTMCP_AUTH=$(azd env get-value USE_FASTMCP_AUTH 2>/dev/null || echo "false")
6+
if [ "$USE_FASTMCP_AUTH" != "true" ]; then
7+
echo "Skipping auth init (USE_FASTMCP_AUTH is not enabled)"
8+
exit 0
9+
fi
10+
11+
echo "Setting up Azure/Entra ID app registration for FastMCP OAuth Proxy..."
12+
python ./infra/fastmcp_auth_init.py

infra/auth_update.ps1

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Post-provision hook to update Azure app registration redirect URIs with deployed server URL
2+
3+
# Check if USE_FASTMCP_AUTH is enabled
4+
$USE_FASTMCP_AUTH = azd env get-value USE_FASTMCP_AUTH 2>$null
5+
if ($USE_FASTMCP_AUTH -ne "true") {
6+
Write-Host "Skipping auth update (USE_FASTMCP_AUTH is not enabled)"
7+
exit 0
8+
}
9+
10+
Write-Host "Updating FastMCP auth redirect URIs with deployed server URL..."
11+
python ./infra/fastmcp_auth_update.py

infra/auth_update.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
# Post-provision hook to update Azure app registration redirect URIs with deployed server URL
3+
4+
# Check if USE_FASTMCP_AUTH is enabled
5+
USE_FASTMCP_AUTH=$(azd env get-value USE_FASTMCP_AUTH 2>/dev/null || echo "false")
6+
if [ "$USE_FASTMCP_AUTH" != "true" ]; then
7+
echo "Skipping auth update (USE_FASTMCP_AUTH is not enabled)"
8+
exit 0
9+
fi
10+
11+
echo "Updating FastMCP auth redirect URIs with deployed server URL..."
12+
python ./infra/fastmcp_auth_update.py

0 commit comments

Comments
 (0)