|  | 
|  | 1 | +@description('Name of the Container Apps Environment. Leave blank to create a new one.') | 
|  | 2 | +param containerAppEnvName string = '' | 
|  | 3 | + | 
|  | 4 | +@description('Location of resources') | 
|  | 5 | +param location string = resourceGroup().location | 
|  | 6 | + | 
|  | 7 | +@description('Name of the Container App') | 
|  | 8 | +param containerAppName string = 'mongo-mcp-server-app' | 
|  | 9 | + | 
|  | 10 | +@description('Docker image to deploy') | 
|  | 11 | +param containerImage string = 'mongodb/mongodb-mcp-server:latest' | 
|  | 12 | + | 
|  | 13 | +@description('Container CPU (vCPU) as string. Allowed: 0.25 - 2.0 in 0.25 increments') | 
|  | 14 | +@allowed([ | 
|  | 15 | +  '0.25' | 
|  | 16 | +  '0.5' | 
|  | 17 | +  '0.75' | 
|  | 18 | +  '1.0' | 
|  | 19 | +  '1.25' | 
|  | 20 | +  '1.5' | 
|  | 21 | +  '1.75' | 
|  | 22 | +  '2.0' | 
|  | 23 | +]) | 
|  | 24 | +param containerCpu string = '1.0' | 
|  | 25 | + | 
|  | 26 | +// Convert CPU string to number (Bicep lacks float type; json() parses to number) | 
|  | 27 | +var containerCpuNumber = json(containerCpu) | 
|  | 28 | + | 
|  | 29 | +@description('Container Memory (GB)') | 
|  | 30 | +@allowed([ | 
|  | 31 | +  '0.5Gi' | 
|  | 32 | +  '1Gi' | 
|  | 33 | +  '2Gi' | 
|  | 34 | +  '4Gi' | 
|  | 35 | +]) | 
|  | 36 | +param containerMemory string = '2Gi' | 
|  | 37 | + | 
|  | 38 | +@description('Container App Environment Variables') | 
|  | 39 | +param appEnvironmentVars object = { | 
|  | 40 | +  MDB_MCP_READ_ONLY: 'true' // set to 'false' to enable write operations | 
|  | 41 | +  MDB_MCP_HTTP_PORT: '8080' | 
|  | 42 | +  MDB_MCP_HTTP_HOST: '::' | 
|  | 43 | +  MDB_MCP_TRANSPORT: 'http' | 
|  | 44 | +  MDB_MCP_LOGGERS: 'disk,mcp,stderr' | 
|  | 45 | +  MDB_MCP_LOG_PATH: '/tmp/mongodb-mcp' | 
|  | 46 | +} | 
|  | 47 | + | 
|  | 48 | +@description('Authentication mode toggle for the Container App. NOAUTH disables platform auth; MicrosoftMIBasedAuth enables Azure AD auth and enforces 401 for unauthenticated requests.') | 
|  | 49 | +@allowed([ | 
|  | 50 | +  'NOAUTH' | 
|  | 51 | +  'MicrosoftMIBasedAuth' | 
|  | 52 | +]) | 
|  | 53 | +param authMode string = 'NOAUTH' | 
|  | 54 | + | 
|  | 55 | +@description('Azure AD Application (client) ID used when authMode is MicrosoftMIBasedAuth. Leave blank for NOAUTH.') | 
|  | 56 | +param authClientId string = '' | 
|  | 57 | + | 
|  | 58 | +@description('Issuer URL (OpenID issuer) when authMode is MicrosoftMIBasedAuth. Example: https://login.microsoftonline.com/<tenant-id>/v2.0 or https://sts.windows.net/<tenant-id>/v2.0') | 
|  | 59 | +param authIssuerUrl string = '' | 
|  | 60 | + | 
|  | 61 | +@description('Azure AD Tenant ID (GUID) used when authMode is MicrosoftMIBasedAuth. Provided separately to avoid hard-coded cloud endpoints in template logic.') | 
|  | 62 | +param authTenantId string = '' | 
|  | 63 | + | 
|  | 64 | +@description('Optional array of allowed client application IDs. If empty, all applications are allowed (not recommended).') | 
|  | 65 | +param authAllowedClientApps array = [] | 
|  | 66 | + | 
|  | 67 | +@secure() | 
|  | 68 | +@description('MongoDB Connection String') | 
|  | 69 | +param mdbConnectionString string | 
|  | 70 | + | 
|  | 71 | +// Create Container App Environment if not provided | 
|  | 72 | +resource containerAppEnv 'Microsoft.App/managedEnvironments@2024-02-02-preview' = if (empty(containerAppEnvName)) { | 
|  | 73 | +  name: 'mcp-env-${uniqueString(resourceGroup().id)}' | 
|  | 74 | +  location: location | 
|  | 75 | +  properties: {} | 
|  | 76 | +} | 
|  | 77 | + | 
|  | 78 | +// Get the Container App Environment resource ID (either existing or newly created) | 
|  | 79 | +var envResourceId = empty(containerAppEnvName)  | 
|  | 80 | +  ? containerAppEnv.id  | 
|  | 81 | +  : resourceId('Microsoft.App/managedEnvironments', containerAppEnvName) | 
|  | 82 | + | 
|  | 83 | +// Build environment variables array | 
|  | 84 | +var envVarsArray = [ | 
|  | 85 | +  for item in items(appEnvironmentVars): { | 
|  | 86 | +    name: item.key | 
|  | 87 | +    value: string(item.value) | 
|  | 88 | +  } | 
|  | 89 | +] | 
|  | 90 | + | 
|  | 91 | +// Additional environment variables injected when MicrosoftMIBasedAuth is enabled (merged after user-provided vars so user can override if desired) | 
|  | 92 | +var authEnvVars = authMode == 'MicrosoftMIBasedAuth' | 
|  | 93 | +  ? concat([ | 
|  | 94 | +      { | 
|  | 95 | +        name: 'MDB_MCP_HTTP_AUTH_MODE' | 
|  | 96 | +        value: 'azure-managed-identity' | 
|  | 97 | +      } | 
|  | 98 | +      { | 
|  | 99 | +        // Tenant ID of the Azure AD tenant | 
|  | 100 | +        name: 'MDB_MCP_AZURE_MANAGED_IDENTITY_TENANT_ID' | 
|  | 101 | +        value: authTenantId | 
|  | 102 | +      } | 
|  | 103 | +      { | 
|  | 104 | +        // Client ID of the Azure AD App representing your container app | 
|  | 105 | +        name: 'MDB_MCP_AZURE_MANAGED_IDENTITY_CLIENT_ID' | 
|  | 106 | +        value: authClientId | 
|  | 107 | +      } | 
|  | 108 | +    ], length(authAllowedClientApps) > 0 ? [ | 
|  | 109 | +      { | 
|  | 110 | +        // Comma-separated list of allowed Client App IDs for access | 
|  | 111 | +        // (only listed Client Apps are allowed if client apps specified) | 
|  | 112 | +        name: 'MDB_MCP_AZURE_MANAGED_IDENTITY_ALLOWED_APP_IDS' | 
|  | 113 | +        value: join(authAllowedClientApps, ',') | 
|  | 114 | +      } | 
|  | 115 | +    ] : []) | 
|  | 116 | +  : [ | 
|  | 117 | +      { | 
|  | 118 | +        name: 'MDB_MCP_HTTP_AUTH_MODE' | 
|  | 119 | +        value: 'none' | 
|  | 120 | +      } | 
|  | 121 | +    ] | 
|  | 122 | + | 
|  | 123 | +// Deploy Container App | 
|  | 124 | +resource containerApp 'Microsoft.App/containerApps@2024-02-02-preview' = { | 
|  | 125 | +  name: containerAppName | 
|  | 126 | +  location: location | 
|  | 127 | +  identity: { | 
|  | 128 | +    type: 'SystemAssigned' | 
|  | 129 | +  } | 
|  | 130 | +  properties: { | 
|  | 131 | +    managedEnvironmentId: envResourceId | 
|  | 132 | +    configuration: { | 
|  | 133 | +      ingress: { | 
|  | 134 | +        external: true | 
|  | 135 | +        targetPort: int(appEnvironmentVars.MDB_MCP_HTTP_PORT) | 
|  | 136 | +        transport: 'auto' | 
|  | 137 | +      } | 
|  | 138 | +      secrets: [ | 
|  | 139 | +        { | 
|  | 140 | +          name: 'mdb-mcp-connection-string' | 
|  | 141 | +          value: mdbConnectionString | 
|  | 142 | +        } | 
|  | 143 | +      ] | 
|  | 144 | +    } | 
|  | 145 | +    template: { | 
|  | 146 | +      containers: [ | 
|  | 147 | +        { | 
|  | 148 | +          name: 'mcpserver' | 
|  | 149 | +          image: containerImage | 
|  | 150 | +          resources: { | 
|  | 151 | +            cpu: containerCpuNumber | 
|  | 152 | +            memory: containerMemory | 
|  | 153 | +          } | 
|  | 154 | +          env: concat( | 
|  | 155 | +            envVarsArray, | 
|  | 156 | +            authEnvVars, | 
|  | 157 | +            [ | 
|  | 158 | +              { | 
|  | 159 | +                name: 'MDB_MCP_CONNECTION_STRING' | 
|  | 160 | +                secretRef: 'mdb-mcp-connection-string' | 
|  | 161 | +              } | 
|  | 162 | +            ] | 
|  | 163 | +          ) | 
|  | 164 | +        } | 
|  | 165 | +      ] | 
|  | 166 | +      scale: { | 
|  | 167 | +        minReplicas: 1 | 
|  | 168 | +        maxReplicas: 1 | 
|  | 169 | +        rules: [] // disables autoscaling | 
|  | 170 | +      } | 
|  | 171 | +    } | 
|  | 172 | +  } | 
|  | 173 | +} | 
|  | 174 | + | 
|  | 175 | +// Container App Authentication (child resource) - only deployed when MicrosoftMIBasedAuth selected | 
|  | 176 | +resource containerAppAuth 'Microsoft.App/containerApps/authConfigs@2024-10-02-preview' = if (authMode == 'MicrosoftMIBasedAuth') { | 
|  | 177 | +  name: 'current' | 
|  | 178 | +  parent: containerApp | 
|  | 179 | +  properties: { | 
|  | 180 | +    platform: { | 
|  | 181 | +      enabled: true | 
|  | 182 | +      // runtimeVersion optional | 
|  | 183 | +    } | 
|  | 184 | +    globalValidation: { | 
|  | 185 | +      unauthenticatedClientAction: 'Return401' | 
|  | 186 | +      redirectToProvider: 'azureActiveDirectory' | 
|  | 187 | +    } | 
|  | 188 | +    identityProviders: { | 
|  | 189 | +      azureActiveDirectory: { | 
|  | 190 | +        enabled: true | 
|  | 191 | +        registration: { | 
|  | 192 | +          clientId: authClientId | 
|  | 193 | +          openIdIssuer: authIssuerUrl | 
|  | 194 | +        } | 
|  | 195 | +        validation: { | 
|  | 196 | +          allowedAudiences: [ | 
|  | 197 | +            authClientId | 
|  | 198 | +          ] | 
|  | 199 | +          // defaultAuthorizationPolicy allows restriction to specific client applications | 
|  | 200 | +          defaultAuthorizationPolicy: length(authAllowedClientApps) > 0 ? { | 
|  | 201 | +            allowedApplications: authAllowedClientApps | 
|  | 202 | +          } : null | 
|  | 203 | +          jwtClaimChecks: length(authAllowedClientApps) > 0 ? { | 
|  | 204 | +            allowedClientApplications: authAllowedClientApps | 
|  | 205 | +          } : null | 
|  | 206 | +        } | 
|  | 207 | +      } | 
|  | 208 | +    } | 
|  | 209 | +  } | 
|  | 210 | +} | 
|  | 211 | + | 
|  | 212 | +output containerAppUrl string = containerApp.properties.configuration.ingress.fqdn | 
0 commit comments