This directory contains infrastructure-as-code templates and scripts for deploying the MCP Gateway to Azure.
There are two ways to deploy the MCP Gateway infrastructure:
Use the PowerShell deployment script for better control and separation of concerns. This approach:
Prerequisites:
az login)Basic Usage:
.\deployment\Deploy-McpGateway.ps1 -SubscriptionId "<subscription-id>" -TenantId "<tenant-id>" -ResourceGroupName "rg-mcpgateway-dev" -ResourceLabel "mcpdev" -ClientId "<your-entra-client-id>" -Stage Infrastructure
Run examples from the repository root. Use a lowercase alphanumeric ResourceLabel, even when the resource group name contains hyphens. Configure HTTPS before sending bearer tokens; without certificate parameters the template exposes an HTTP listener intended only for infrastructure bring-up.
Advanced Usage:
# Deploy to a specific region with a custom resource label
.\deployment\Deploy-McpGateway.ps1 `
-ResourceGroupName "rg-mcpgateway-prod" `
-ClientId "<your-entra-client-id>" `
-ResourceLabel "mcpprod" `
-Location "westus2"
# Deploy with private endpoints enabled
.\deployment\Deploy-McpGateway.ps1 `
-ResourceGroupName "rg-mcpgateway-secure" `
-ClientId "<your-entra-client-id>" `
-ResourceLabel "mcpsecure" `
-EnablePrivateEndpoints
Parameters:
| Parameter | Required | Description |
|---|---|---|
ResourceGroupName |
Yes | Name of the Azure resource group (created if doesn’t exist) |
ClientId |
Yes | Entra ID client ID for authentication |
ResourceLabel |
No | Alphanumeric suffix for resource naming (3-30 chars). Defaults to resource group name |
Location |
No | Azure region for deployment. Default: westus3 |
EnablePrivateEndpoints |
No | Create a Cosmos DB private endpoint and DNS link, and disable its public access; does not configure private ACR access |
SubscriptionId, TenantId |
No | Select the subscription and verify its tenant; specify both for repeatable deployments |
Stage |
No | Infrastructure, Kubernetes, or All (default) |
DeploymentName |
No | ARM deployment name reused to read outputs; default mcpgateway |
GatewayImage, ToolGatewayImage |
No | Exact first-party image references; supply your tested tags or digests rather than relying on default latest images |
NodeCount, NodeVmSize |
No | Default: two Standard_D4ds_v5 nodes; size a separate test deployment explicitly |
AcrSku |
No | Basic, Standard (default), or Premium |
CosmosServerless |
No | Enable serverless on a new test account; not an in-place conversion |
SecureParametersFile |
No | Path to an ARM parameter file with secure TLS certificate values; keep outside source control |
KubernetesTemplatePath |
No | Defaults to the checked-out deployment/k8s/cloud-deployment-template.yml |
KubernetesNamespace |
No | Infrastructure namespace, default adapter; the Kubernetes stage reuses the namespace in the infrastructure outputs |
Set -KubernetesNamespace mcp-gateway during the infrastructure stage to use a non-default namespace. The namespace is shared by workload-identity subjects, Kubernetes resources, secret lookup, and gateway runtime settings. The Kubernetes stage reads the recorded namespace automatically and rejects conflicting overrides. Changing it requires an infrastructure update and does not move existing workloads or data.
Provide tlsCertificateData (base64-encoded PFX) and tlsCertificatePassword as secure parameters through SecureParametersFile. Use a certificate valid for the public FQDN. Protect the parameter file and never commit or print its contents.
Use the same subscription, tenant, resource label, client ID, and deployment name for both stages:
what-if using your selected sizing and secure parameters.-Stage Infrastructure to provision AKS, ACR, storage, and ingress.-Stage Kubernetes with -GatewayImage and -ToolGatewayImage. The script reads the local manifest and preserves an existing gateway secret in the deployment namespace or generates one when absent. An empty stored secret or failed lookup stops deployment; repair the secret or access before retrying.publicOrigin, pod readiness, image digests, and authenticated MCP requests. Both clients and adapters must support MCP 2026-07-28.For a new short-lived test deployment only, -NodeCount 1 -NodeVmSize Standard_D4as_v5 -AcrSku Basic -CosmosServerless reduces the default footprint, subject to current regional capacity and AKS requirements. Application Gateway still has a base charge. See end-to-end testing for validation commands.
Deploy infrastructure directly using Bicep, then use the PowerShell Kubernetes stage with the same deployment name and exact image references. The examples disable the embedded script so image publishing can happen before pod creation.
The embedded-script path includes the checked-out manifest when Bicep is compiled.
Supply compatible gatewayImage and toolGatewayImage references, and use
kubernetesNamespace for a non-default namespace. The script preserves an existing
gateway secret or generates and stores one on first deployment. The optional
gatewaySecret secure parameter must match an existing secret when supplied;
secret rotation is a separate, coordinated operation. Empty stored secrets and
failed Kubernetes commands stop deployment without replacing credentials.
# Create resource group
az group create --name rg-mcpgateway-dev --location eastus
# Deploy using Bicep
az deployment group create \
--name mcpgateway-deployment \
--resource-group rg-mcpgateway-dev \
--template-file deployment/infra/azure-deployment.bicep \
--parameters clientId=<your-entra-client-id> resourceLabel=mcpdev enableKubernetesDeploymentScript=false
With additional parameters:
az deployment group create \
--name mcpgateway-deployment \
--resource-group rg-mcpgateway-dev \
--template-file deployment/infra/azure-deployment.bicep \
--parameters \
clientId=<your-entra-client-id> \
resourceLabel=mcpdev \
location=westus2 \
enablePrivateEndpoints=true \
enableKubernetesDeploymentScript=false
Disable embedded Kubernetes deployment script:
az deployment group create \
--name mcpgateway-deployment \
--resource-group rg-mcpgateway-dev \
--template-file deployment/infra/azure-deployment.bicep \
--parameters \
clientId=<your-entra-client-id> \
enableKubernetesDeploymentScript=false
The deployment creates the following Azure resources:
The template requests public network access by default. Organization policy may override it; check effective settings. Use HTTPS and Entra authentication for gateway traffic. ACR anonymous pull and admin access are disabled; Cosmos local key authentication is disabled.
Enable with -EnablePrivateEndpoints flag:
After successful deployment:
https://<public-ip-dns-label>.<region>.cloudapp.azure.com
adapter with the configured namespace when using a non-default value.
kubectl get pods -n adapter
kubectl logs -n adapter -l app=mcpgateway
Prerequisites not met:
az --versionaz loginDeployment failures:
Kubernetes deployment issues:
az aks show -g <rg-name> -n <aks-name>az aks command invoke -g <rg-name> -n <aks-name> --command "kubectl get pods -A"Template validation errors:
az deployment group validate \
--resource-group <rg-name> \
--template-file deployment/infra/azure-deployment.bicep \
--parameters clientId=<your-client-id>
Deployment script failures:
To remove all deployed resources:
# Delete the entire resource group
az group delete --name rg-mcpgateway-dev --yes --no-wait
If you previously deployed using the embedded Bicep deployment script:
enableKubernetesDeploymentScript parameter .\deployment\Deploy-McpGateway.ps1 -ResourceGroupName <existing-rg> -ClientId <client-id> -ResourceLabel <existing-label>
┌─────────────────────────────────────────────────────────────┐
│ Internet │
└────────────────────────┬────────────────────────────────────┘
│
┌────▼─────┐
│ Public IP│
└────┬─────┘
│
┌────────▼──────────┐
│ Application │
│ Gateway │
└────────┬──────────┘
│
┌────────────────┼────────────────┐
│ │
┌───────▼────────┐ ┌────────▼────────┐
│ │ │ │
│ AKS Cluster │──────────────│ ACR │
│ │ │ (Images) │
└───────┬────────┘ └─────────────────┘
│
│ Workload Identity
│
┌───────▼────────┐ ┌─────────────────┐
│ │ │ │
│ Cosmos DB │ │ App Insights │
│ (State) │ │ (Monitoring) │
└────────────────┘ └─────────────────┘