Skip to content

Commit d234dc4

Browse files
committed
refactor: apply Bicep best practices and fix token issuer mismatch
Bicep improvements: - Add @description() decorators to all parameters in aca.bicep, aca-noauth.bicep, keycloak.bicep, and http-routes.bicep - Remove redundant dependsOn in http-routes.bicep (implicit via existing) Token issuer fix: - Update write_env.sh and write_env.ps1 to use direct Keycloak URL for KEYCLOAK_REALM_URL instead of routed URL - Fixes 401 Unauthorized errors caused by issuer mismatch between token's iss claim and MCP server's expected issuer - Add MCP_SERVER_URL to env scripts for local agent testing
1 parent d6663a3 commit d234dc4

File tree

6 files changed

+84
-5
lines changed

6 files changed

+84
-5
lines changed

infra/aca-noauth.bicep

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,42 @@
11
// MCP Server WITHOUT Keycloak authentication (deployed_mcp.py)
2+
3+
@description('Name of the MCP server container app')
24
param name string
5+
6+
@description('Azure region for deployment')
37
param location string = resourceGroup().location
8+
9+
@description('Tags to apply to all resources')
410
param tags object = {}
511

12+
@description('User assigned identity name for ACR pull and Azure service access')
613
param identityName string
14+
15+
@description('Name of the Container Apps environment')
716
param containerAppsEnvironmentName string
17+
18+
@description('Name of the Azure Container Registry')
819
param containerRegistryName string
20+
21+
@description('Service name for azd tagging')
922
param serviceName string = 'mcpnoauth'
23+
24+
@description('Whether the container app already exists (for updates)')
1025
param exists bool
26+
27+
@description('Azure OpenAI deployment name')
1128
param openAiDeploymentName string
29+
30+
@description('Azure OpenAI endpoint URL')
1231
param openAiEndpoint string
32+
33+
@description('Cosmos DB account name')
1334
param cosmosDbAccount string
35+
36+
@description('Cosmos DB database name')
1437
param cosmosDbDatabase string
38+
39+
@description('Cosmos DB container name')
1540
param cosmosDbContainer string
1641

1742
resource mcpNoAuthIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {

infra/aca.bicep

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,49 @@
1+
@description('Name of the MCP server container app')
12
param name string
3+
4+
@description('Azure region for deployment')
25
param location string = resourceGroup().location
6+
7+
@description('Tags to apply to all resources')
38
param tags object = {}
49

10+
@description('User assigned identity name for ACR pull and Azure service access')
511
param identityName string
12+
13+
@description('Name of the Container Apps environment')
614
param containerAppsEnvironmentName string
15+
16+
@description('Name of the Azure Container Registry')
717
param containerRegistryName string
18+
19+
@description('Service name for azd tagging')
820
param serviceName string = 'aca'
21+
22+
@description('Whether the container app already exists (for updates)')
923
param exists bool
24+
25+
@description('Azure OpenAI deployment name')
1026
param openAiDeploymentName string
27+
28+
@description('Azure OpenAI endpoint URL')
1129
param openAiEndpoint string
30+
31+
@description('Cosmos DB account name')
1232
param cosmosDbAccount string
33+
34+
@description('Cosmos DB database name')
1335
param cosmosDbDatabase string
36+
37+
@description('Cosmos DB container name')
1438
param cosmosDbContainer string
1539

16-
// Keycloak authentication parameters
40+
@description('Keycloak realm URL for token validation')
1741
param keycloakRealmUrl string
42+
43+
@description('Base URL of the MCP server (for OAuth metadata)')
1844
param mcpServerBaseUrl string
45+
46+
@description('Expected audience claim in JWT tokens')
1947
param mcpServerAudience string = 'mcp-server'
2048

2149
resource acaIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {

infra/http-routes.bicep

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1+
@description('Name of the Container Apps environment')
12
param containerAppsEnvironmentName string
3+
4+
@description('Name of the MCP server container app')
25
param mcpServerAppName string
6+
7+
@description('Name of the Keycloak container app')
38
param keycloakAppName string
9+
10+
@description('Name for the HTTP route configuration')
411
param routeConfigName string = 'mcproutes'
512

613
resource containerEnv 'Microsoft.App/managedEnvironments@2024-10-02-preview' existing = {
@@ -63,10 +70,7 @@ resource httpRouteConfig 'Microsoft.App/managedEnvironments/httpRouteConfigs@202
6370
}
6471
]
6572
}
66-
dependsOn: [
67-
mcpServerApp
68-
keycloakApp
69-
]
73+
// Note: dependsOn not needed - 'existing' resources create implicit dependencies
7074
}
7175

7276
output fqdn string = httpRouteConfig.properties.fqdn

infra/keycloak.bicep

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
1+
@description('Name of the Keycloak container app')
12
param name string
3+
4+
@description('Azure region for deployment')
25
param location string = resourceGroup().location
6+
7+
@description('Tags to apply to all resources')
38
param tags object = {}
49

10+
@description('Name of the Container Apps environment')
511
param containerAppsEnvironmentName string
12+
13+
@description('Name of the Azure Container Registry')
614
param containerRegistryName string
15+
16+
@description('Service name for azd tagging')
717
param serviceName string = 'keycloak'
18+
19+
@description('Keycloak admin username')
820
param keycloakAdminUser string = 'admin'
21+
922
@secure()
23+
@description('Keycloak admin password')
1024
param keycloakAdminPassword string
25+
26+
@description('Whether the container app already exists (for updates)')
1127
param exists bool
1228

1329
@description('User assigned identity name for ACR pull')

infra/write_env.ps1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,7 @@ Add-Content -Path $ENV_FILE_PATH -Value "AZURE_TENANT_ID=$(azd env get-value AZU
1111
Add-Content -Path $ENV_FILE_PATH -Value "AZURE_COSMOSDB_ACCOUNT=$(azd env get-value AZURE_COSMOSDB_ACCOUNT)"
1212
Add-Content -Path $ENV_FILE_PATH -Value "AZURE_COSMOSDB_DATABASE=$(azd env get-value AZURE_COSMOSDB_DATABASE)"
1313
Add-Content -Path $ENV_FILE_PATH -Value "AZURE_COSMOSDB_CONTAINER=$(azd env get-value AZURE_COSMOSDB_CONTAINER)"
14+
# Use direct Keycloak URL for token requests (issuer must match what MCP server expects)
15+
Add-Content -Path $ENV_FILE_PATH -Value "KEYCLOAK_REALM_URL=$(azd env get-value KEYCLOAK_DIRECT_URL)/realms/mcp"
16+
Add-Content -Path $ENV_FILE_PATH -Value "MCP_SERVER_URL=$(azd env get-value MCP_SERVER_URL)/mcp"
1417
Add-Content -Path $ENV_FILE_PATH -Value "API_HOST=azure"

infra/write_env.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,7 @@ echo "AZURE_TENANT_ID=$(azd env get-value AZURE_TENANT_ID)" >> "$ENV_FILE_PATH"
1515
echo "AZURE_COSMOSDB_ACCOUNT=$(azd env get-value AZURE_COSMOSDB_ACCOUNT)" >> "$ENV_FILE_PATH"
1616
echo "AZURE_COSMOSDB_DATABASE=$(azd env get-value AZURE_COSMOSDB_DATABASE)" >> "$ENV_FILE_PATH"
1717
echo "AZURE_COSMOSDB_CONTAINER=$(azd env get-value AZURE_COSMOSDB_CONTAINER)" >> "$ENV_FILE_PATH"
18+
# Use direct Keycloak URL for token requests (issuer must match what MCP server expects)
19+
echo "KEYCLOAK_REALM_URL=$(azd env get-value KEYCLOAK_DIRECT_URL)/realms/mcp" >> "$ENV_FILE_PATH"
20+
echo "MCP_SERVER_URL=$(azd env get-value MCP_SERVER_URL)/mcp" >> "$ENV_FILE_PATH"
1821
echo "API_HOST=azure" >> "$ENV_FILE_PATH"

0 commit comments

Comments
 (0)