Skip to content

Azure (MCP)

The Azure MCP server gives Holmes read-only access to any Azure API you permit via RBAC. This means Holmes can query VMs, AKS, SQL databases, Activity Log, Azure Monitor, networking, storage, and hundreds of other Azure services - limited only by the roles you assign.

Overview

The Azure MCP server runs as a pod in your Kubernetes cluster.

  • Helm users: The pod is deployed automatically when you enable the addon
  • CLI users: You deploy the pod manually to your cluster, then point Holmes at it

Note

Even when using Holmes CLI locally, the Azure MCP server must run in a Kubernetes cluster. Local-only deployment is not currently supported.

Configuration

For CLI usage, you need to deploy the Azure MCP server first, then configure Holmes to connect to it.

Step 1: Deploy the Azure MCP Server

Create a file named azure-mcp-deployment.yaml:

apiVersion: v1
kind: Namespace
metadata:
  name: holmes-mcp
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: azure-mcp-sa
  namespace: holmes-mcp
  labels:
    azure.workload.identity/use: "true"
  # For Workload Identity, add annotations:
  # annotations:
  #   azure.workload.identity/client-id: "YOUR_CLIENT_ID"
  #   azure.workload.identity/tenant-id: "YOUR_TENANT_ID"
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: azure-mcp-config
  namespace: holmes-mcp
data:
  AZURE_TENANT_ID: "YOUR_TENANT_ID"
  AZURE_SUBSCRIPTION_ID: "YOUR_SUBSCRIPTION_ID"
  AZ_AUTH_METHOD: "workload-identity"  # Options: workload-identity, managed-identity, service-principal
  READ_ONLY_MODE: "true"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: azure-mcp-server
  namespace: holmes-mcp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: azure-mcp-server
  template:
    metadata:
      labels:
        app: azure-mcp-server
        azure.workload.identity/use: "true"
    spec:
      serviceAccountName: azure-mcp-sa
      containers:
      - name: azure-mcp
        image: me-west1-docker.pkg.dev/robusta-development/development/azure-cli-mcp:1.0.1
        imagePullPolicy: IfNotPresent
        args:
          - "--transport"
          - "streamable-http"
          - "--host"
          - "0.0.0.0"
          - "--port"
          - "8000"
          - "--readonly"
        ports:
        - containerPort: 8000
          name: http
        env:
        - name: AZURE_TENANT_ID
          valueFrom:
            configMapKeyRef:
              name: azure-mcp-config
              key: AZURE_TENANT_ID
        - name: AZURE_SUBSCRIPTION_ID
          valueFrom:
            configMapKeyRef:
              name: azure-mcp-config
              key: AZURE_SUBSCRIPTION_ID
        - name: AZ_AUTH_METHOD
          valueFrom:
            configMapKeyRef:
              name: azure-mcp-config
              key: AZ_AUTH_METHOD
        - name: AZURE_CLIENT_ID
          value: "YOUR_CLIENT_ID"  # For workload identity or managed identity
        # For service principal authentication, add:
        # - name: AZURE_CLIENT_SECRET
        #   valueFrom:
        #     secretKeyRef:
        #       name: azure-mcp-creds
        #       key: AZURE_CLIENT_SECRET
        resources:
          requests:
            memory: "256Mi"
            cpu: "100m"
          limits:
            memory: "512Mi"
        livenessProbe:
          httpGet:
            path: /health
            port: http
          initialDelaySeconds: 30
          periodSeconds: 30
        readinessProbe:
          httpGet:
            path: /health
            port: http
          initialDelaySeconds: 10
          periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: azure-mcp-server
  namespace: holmes-mcp
spec:
  selector:
    app: azure-mcp-server
  ports:
  - port: 8000
    targetPort: 8000
    protocol: TCP
    name: http

Deploy it to your cluster:

kubectl apply -f azure-mcp-deployment.yaml

Step 2: Configure Azure Authentication

Choose one of these authentication methods:

Option A: Workload Identity (Recommended for AKS)

Follow the Workload Identity setup guide to: 1. Enable Workload Identity on your AKS cluster 2. Create a managed identity with appropriate permissions 3. Establish federated identity credentials 4. Configure the ServiceAccount annotations

Option B: Managed Identity

For clusters with node-level managed identity: 1. Ensure your AKS nodes have a managed identity assigned 2. Update the deployment to use authMethod: managed-identity 3. Set the AZURE_CLIENT_ID to your managed identity's client ID

Option C: Service Principal

For service principal authentication: 1. Create a service principal and assign appropriate roles 2. Create a Kubernetes secret with the credentials:

kubectl create secret generic azure-mcp-creds \
  --from-literal=AZURE_CLIENT_ID=YOUR_CLIENT_ID \
  --from-literal=AZURE_CLIENT_SECRET=YOUR_CLIENT_SECRET \
  -n holmes-mcp
  1. Update the deployment to reference the secret (uncomment the secret reference in the YAML above)
  2. Set AZ_AUTH_METHOD: "service-principal" in the ConfigMap

Step 3: Configure Holmes CLI

Add the MCP server configuration to ~/.holmes/config.yaml:

mcp_servers:
  azure_api:
    description: "Azure API MCP Server - comprehensive Azure service access via Azure CLI"
    url: "http://azure-mcp-server.holmes-mcp.svc.cluster.local:8000"
    llm_instructions: |
      IMPORTANT: When investigating issues related to Azure resources or Kubernetes workloads running on Azure,
      you MUST actively use this MCP server to gather data rather than providing manual instructions to the user.

      ## Investigation Principles

      **ALWAYS follow this investigation flow:**
      1. First, gather current state and configuration using Azure CLI commands
      2. Check Activity Log for recent changes that might have caused the issue
      3. Collect metrics and logs from Azure Monitor if available
      4. Analyze all gathered data before providing conclusions

      **Never say "check in Azure portal" or "verify in Azure" - instead, use the MCP server to check it yourself.**

      See the Azure MCP documentation for comprehensive investigation patterns and common commands.

Step 4: Port Forwarding (Optional for Local Testing)

If running Holmes CLI locally and need to access the MCP server:

kubectl port-forward -n holmes-mcp svc/azure-mcp-server 8000:8000

Then update the URL in config.yaml to:

url: "http://localhost:8000"

Workload Identity Authentication (Recommended for AKS)

The recommended approach for AKS clusters is to use Workload Identity. This provides secure, passwordless authentication.

mcpAddons:
  azure:
    enabled: true

    # Service account configuration
    serviceAccount:
      create: true
      name: "azure-api-mcp-sa"
      annotations:
        azure.workload.identity/client-id: "YOUR_CLIENT_ID"
        azure.workload.identity/tenant-id: "YOUR_TENANT_ID"

    # Azure configuration
    config:
      tenantId: "YOUR_TENANT_ID"
      subscriptionId: "YOUR_SUBSCRIPTION_ID"
      authMethod: "workload-identity"
      clientId: "YOUR_CLIENT_ID"
      readOnlyMode: true  # Recommended for safety

Setup Steps:

  1. Follow the Workload Identity setup guide
  2. Create a managed identity and assign Azure RBAC roles
  3. Configure federated identity credentials
  4. Deploy with the configuration above

Service Principal Authentication

For non-AKS clusters or if Workload Identity is not available:

mcpAddons:
  azure:
    enabled: true

    serviceAccount:
      create: true
      name: "azure-api-mcp-sa"

    config:
      tenantId: "YOUR_TENANT_ID"
      subscriptionId: "YOUR_SUBSCRIPTION_ID"
      authMethod: "service-principal"
      readOnlyMode: true

    # Reference to existing secret with credentials
    secretName: "azure-mcp-creds"

Create the secret before deploying:

kubectl create secret generic azure-mcp-creds \
  --from-literal=AZURE_CLIENT_ID=YOUR_CLIENT_ID \
  --from-literal=AZURE_CLIENT_SECRET=YOUR_CLIENT_SECRET \
  -n YOUR_NAMESPACE

Managed Identity Authentication

For AKS clusters with node-level managed identity:

mcpAddons:
  azure:
    enabled: true

    config:
      tenantId: "YOUR_TENANT_ID"
      subscriptionId: "YOUR_SUBSCRIPTION_ID"
      authMethod: "managed-identity"
      clientId: "YOUR_MANAGED_IDENTITY_CLIENT_ID"
      readOnlyMode: true

For additional configuration options (resources, network policy, node selectors, etc.), see the full chart values.

Then deploy or upgrade your Holmes installation:

helm upgrade --install holmes robusta/holmes -f values.yaml

Workload Identity Authentication (Recommended for AKS)

globalConfig:
  # Your existing Robusta configuration

# Add the Holmes MCP addon configuration
holmes:
  mcpAddons:
    azure:
      enabled: true

      # Service account configuration
      serviceAccount:
        create: true
        name: "azure-api-mcp-sa"
        annotations:
          azure.workload.identity/client-id: "YOUR_CLIENT_ID"
          azure.workload.identity/tenant-id: "YOUR_TENANT_ID"

      # Azure configuration
      config:
        tenantId: "YOUR_TENANT_ID"
        subscriptionId: "YOUR_SUBSCRIPTION_ID"
        authMethod: "workload-identity"
        clientId: "YOUR_CLIENT_ID"
        readOnlyMode: true

Service Principal Authentication

globalConfig:
  # Your existing Robusta configuration

holmes:
  mcpAddons:
    azure:
      enabled: true

      serviceAccount:
        create: true
        name: "azure-api-mcp-sa"

      config:
        tenantId: "YOUR_TENANT_ID"
        subscriptionId: "YOUR_SUBSCRIPTION_ID"
        authMethod: "service-principal"
        readOnlyMode: true

      secretName: "azure-mcp-creds"

Create the secret before deploying:

kubectl create secret generic azure-mcp-creds \
  --from-literal=AZURE_CLIENT_ID=YOUR_CLIENT_ID \
  --from-literal=AZURE_CLIENT_SECRET=YOUR_CLIENT_SECRET \
  -n YOUR_NAMESPACE

Managed Identity Authentication

globalConfig:
  # Your existing Robusta configuration

holmes:
  mcpAddons:
    azure:
      enabled: true

      config:
        tenantId: "YOUR_TENANT_ID"
        subscriptionId: "YOUR_SUBSCRIPTION_ID"
        authMethod: "managed-identity"
        clientId: "YOUR_MANAGED_IDENTITY_CLIENT_ID"
        readOnlyMode: true

For additional configuration options (resources, network policy, node selectors, etc.), see the full chart values.

Then deploy or upgrade your Robusta installation:

helm upgrade --install robusta robusta/robusta -f generated_values.yaml --set clusterName=YOUR_CLUSTER_NAME

IAM Configuration

Azure RBAC Roles

Assign roles based on what you want Holmes to investigate. At minimum, assign Reader on the subscription. For broader investigations, add more roles:

Role Purpose
Reader Read-only access to all resources (minimum)
Azure Kubernetes Service Cluster User Role kubectl access via az aks get-credentials
Log Analytics Reader Container Insights and Azure Monitor logs
Monitoring Reader Azure Monitor metrics
Cost Management Reader Cost analysis

Setup Script:

curl -O https://raw.githubusercontent.com/robusta-dev/holmes-mcp-integrations/master/servers/azure/setup-workload-identity.sh
bash setup-workload-identity.sh

This script will:

  1. Create a managed identity
  2. Assign appropriate RBAC roles
  3. Configure federated identity credentials
  4. Output the configuration values for your Helm chart

Manual Role Assignment:

# Assign Reader role to managed identity
az role assignment create \
  --assignee YOUR_CLIENT_ID \
  --role Reader \
  --scope /subscriptions/YOUR_SUBSCRIPTION_ID

# Assign Log Analytics Reader for monitoring
az role assignment create \
  --assignee YOUR_CLIENT_ID \
  --role "Log Analytics Reader" \
  --scope /subscriptions/YOUR_SUBSCRIPTION_ID

# Assign Cost Management Reader for cost analysis
az role assignment create \
  --assignee YOUR_CLIENT_ID \
  --role "Cost Management Reader" \
  --scope /subscriptions/YOUR_SUBSCRIPTION_ID

Multi-Subscription Access

Holmes can automatically discover and switch between subscriptions within the same tenant. Just ensure your identity has the appropriate roles in each subscription.

Example Usage

"Pods in namespace production can't reach Azure SQL database"
"Our ingress is showing TLS errors since yesterday"
"After AKS upgrade, some pods are failing to schedule"
"Applications intermittently can't connect to PostgreSQL since 2 PM"
"Our Azure costs increased 50% last week"

Testing the Connection

After deploying the Azure MCP server, verify it's working:

# Check pod status
kubectl get pods -n YOUR_NAMESPACE -l app.kubernetes.io/name=azure-mcp-server

# Check logs
kubectl logs -n YOUR_NAMESPACE -l app.kubernetes.io/name=azure-mcp-server

# Health check
kubectl port-forward -n YOUR_NAMESPACE svc/RELEASE_NAME-azure-mcp-server 8000:8000
curl http://localhost:8000/health

# Ask Holmes
holmes ask "Can you list all resource groups in my Azure subscription?"

Troubleshooting

Authentication Issues

Problem: Pod logs show authentication errors

Solutions:

  1. For Workload Identity: Verify federated identity credentials are configured correctly

    az identity federated-credential list \
      --identity-name YOUR_IDENTITY_NAME \
      --resource-group YOUR_RG
    

  2. For Service Principal: Verify secret exists and contains correct credentials

    kubectl get secret azure-mcp-creds -n YOUR_NAMESPACE -o yaml
    

  3. Check service account annotations

    kubectl get sa azure-api-mcp-sa -n YOUR_NAMESPACE -o yaml
    

Permission Errors

Problem: Holmes reports "AuthorizationFailed" or "Forbidden" errors

Solution: Verify RBAC role assignments

# Check role assignments for your managed identity or service principal
az role assignment list --assignee YOUR_CLIENT_ID --output table

Connection Timeouts

Problem: Holmes can't connect to the MCP server

Solutions:

  1. Verify the service is running

    kubectl get svc -n YOUR_NAMESPACE | grep azure-mcp
    

  2. Check network policy isn't blocking traffic

    kubectl get networkpolicy -n YOUR_NAMESPACE
    

  3. Test connectivity from Holmes pod

    kubectl exec -it HOLMES_POD -n YOUR_NAMESPACE -- \
      curl http://RELEASE_NAME-azure-mcp-server.YOUR_NAMESPACE.svc.cluster.local:8000/health
    

Subscription Access Issues

Problem: Can't query certain subscriptions

Solution: Verify your identity has access to all required subscriptions

# List accessible subscriptions
az account list --output table

# Check role assignments in specific subscription
az role assignment list \
  --assignee YOUR_CLIENT_ID \
  --subscription SUBSCRIPTION_ID

Additional Resources