Skip to content

MCP Blueprint (Azure)
Deployment & Configuration Best Practices - Overview

This blueprint supports running the MCP server in multiple ways.

Table of contents

What this repo deploys

Standard configuration contract (env vars)

Required (any deployment)
  • PORT
  • Container Apps / App Service: typically 8000
  • Functions: typically 80 (fronted by Functions runtime)
Data + Search (when enabled)
  • COSMOS_ENDPOINT
  • COSMOS_KEY (optional)
  • If set, the server uses key-based auth.
  • If not set, the server uses Managed Identity / DefaultAzureCredential.
  • COSMOS_DATABASE
  • COSMOS_CONTAINER

  • SEARCH_ENDPOINT

  • SEARCH_ADMIN_KEY (optional)
  • If set, the server uses admin key via AzureKeyCredential.
  • If not set, the server uses Managed Identity / DefaultAzureCredential.
  • SEARCH_INDEX_NAME
Microsoft Foundry (Azure AI Foundry) (when enabled)

This repo treats Foundry (Azure AI Foundry) as the model endpoint. The runtime uses an OpenAI-compatible API surface, so configuration uses OPENAI_* env vars, with FOUNDRY_* supported as aliases. Learn more: https://learn.microsoft.com/azure/foundry/what-is-foundry

  • OPENAI_ENDPOINT (preferred) or FOUNDRY_ENDPOINT (alias)
  • OPENAI_API_KEY (optional) or FOUNDRY_API_KEY (alias)
  • If set and not equal to managed_identity, the server uses key-based auth.
  • Otherwise, the server uses Managed Identity / DefaultAzureCredential (AAD token provider).
Common
  • AZURE_KEY_VAULT_URI (recommended in Azure)
  • APPLICATIONINSIGHTS_CONNECTION_STRING (recommended)
  • SELECTED_INDUSTRY (used to keep infra + data consistent)

  • MCP_API_KEY (optional)

  • If set, requests to POST /mcp must include this value in the header specified by MCP_API_KEY_HEADER.
  • MCP_API_KEY_HEADER (optional, default: x-api-key)
  • MCP_ALLOWED_ORIGINS (optional)
  • Comma-separated allowlist for the Origin header (DNS rebinding protection). If unset and an Origin header is present, the request is rejected.

Secrets best practices

  • Use Azure Key Vault for secrets (COSMOS_KEY, SEARCH_ADMIN_KEY, OPENAI_API_KEY).
  • Prefer Managed Identity to access Key Vault (no secrets in repo).
  • Keep “non-secret config” (e.g., COSMOS_DATABASE, SEARCH_INDEX_NAME) as plain app settings.

Observability best practices

  • Emit structured logs and avoid logging request bodies that may contain PII.
  • In production, enable:
  • Application Insights (APPLICATIONINSIGHTS_CONNECTION_STRING)
  • Log Analytics (Container Apps environment)

Deployment options

Option A (recommended): Terraform + Azure Container Apps (zero-touch)

This is the only path in this repo that is currently end-to-end automated via Terraform.

  1. Configure terraform-infrastructure/terraform.tfvars
  2. selected_industry
  3. mcp_deployment_type = "container-app"
  4. Deploy:
  5. az login
  6. cd terraform-infrastructure
  7. terraform init
  8. terraform apply -auto-approve

Note

  • The container image is built in Azure using ACR Tasks (az acr build).
  • The Container App is configured with Key Vault-backed secrets.
Option B: Terraform provisions infra, then deploy code separately (Functions)

Terraform can provision the Function App + Key Vault + dependent services, but code deployment is best done via CI/CD (or your preferred release process).

  • Set mcp_deployment_type = "function" in terraform.tfvars.
  • Deploy code using one of:
  • GitHub Actions / Azure DevOps (recommended)
  • Manual publish (requires Azure Functions Core Tools): func azure functionapp publish <name> --python
Option C: Terraform provisions infra, then deploy code separately (App Service)
  • Set mcp_deployment_type = "app-service" in terraform.tfvars.
  • Deploy code using CI/CD or your chosen packaging method.

Data modeling & Cosmos DB best practices (when using Cosmos)

  • Choose partition keys that match your access patterns (high-cardinality; avoid hotspots).
  • Model to minimize cross-partition queries.
  • Keep items under the 2 MB item limit.
  • Capture Cosmos SDK diagnostics for latency spikes and unexpected status codes.
  • Handle 429 with backoff/retry.

Validation

  • Health endpoint: GET /health
  • MCP Streamable (recommended for Copilot Studio):
  • POST /mcp (JSON-RPC: initialize, tools/list, tools/call, ...)
  • Legacy HTTP endpoints (kept for backward compatibility):
  • GET /mcp/tools
  • GET /mcp/resources
  • GET /mcp/prompts
  • POST /mcp/execute

Tip

You can also run the built-in validator: scripts/validate-mcp.py

Common pitfalls (and how this blueprint avoids them)

  • Hard-coded Cosmos/Search names → Terraform + server now read these from the selected industry template and env vars.
  • Key vs Managed Identity mismatch → server supports both, based on presence of key env vars.
  • "Supports Functions/App Service" but breaks at apply time → Terraform automation is scoped to Container Apps; other options are provision-only unless you add a deployment pipeline.