azure-billing-mcp-server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@azure-billing-mcp-servershow my costs by service for last month"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Azure Billing MCP Server
An MCP (Model Context Protocol) server that provides read-only access to Azure Cost Management and Billing APIs. It runs on Google Cloud Run and integrates with Gemini Enterprise as a custom AI connector, allowing users to query live Azure billing data through natural language.
Table of Contents
Related MCP server: Azure FinOps Elite
Overview
What It Does
This server exposes 11 read-only MCP tools that allow Gemini Enterprise (or any MCP-compatible AI client) to query live Azure billing data — cost breakdowns by service, resource group, or individual resource; daily spend trends; invoices; budgets; and detailed usage records.
Key Features
11 read-only tools covering Azure Cost Management and Billing APIs
Deployed on Google Cloud Run — serverless, auto-scaling, no infrastructure to manage
OAuth 2.0 via Microsoft Entra ID — users log in with their corporate Microsoft account
Audit logging — every request logs the caller's bearer token for traceability
Server-side service principal — all Azure calls use a fixed service account with least-privilege read-only access
Who Uses It
End users interact through Gemini Enterprise's AI chat interface. They ask natural-language questions about Azure spending (e.g. "What were our top 5 most expensive resources last month?"). The AI invokes the appropriate MCP tool and returns structured, readable data.
Architecture
User (Gemini Enterprise chat)
│
▼
Gemini Enterprise ──► Microsoft Entra ID OAuth
│ (login.microsoftonline.com)
│ Issues token scoped to: api://<client-id>/mcp.access
▼
Cloud Run MCP Server (IAM-gated: --no-allow-unauthenticated)
┌─────────────────────────────────────────────┐
│ BearerTokenMiddleware │
│ Captures bearer token for AUDIT LOG ONLY │
│ (token is NOT forwarded to Azure APIs) │
├─────────────────────────────────────────────┤
│ FastMCP → 11 MCP Tools │
├─────────────────────────────────────────────┤
│ AzureCostClient │
│ DefaultAzureCredential → service principal │
└─────────────────────────────────────────────┘
│
├──► Azure Cost Management API (cost queries, usage)
└──► Azure Billing API (invoices, periods, budgets)Two Separate Azure Identities
The system uses two completely separate Azure identities. This is intentional and important:
Identity | Purpose | Credentials used |
Billing service principal ( | Queries Azure Cost Management + Billing APIs |
|
Entra ID OAuth app ( | OAuth login screen for Gemini Enterprise users | Configured in Gemini Enterprise's data store form |
The bearer token that GE forwards with every request is scoped to api://<client-id>/mcp.access — this is the correct audience for this server, but the wrong audience for management.azure.com. It cannot be forwarded to Azure. All Azure API calls always use the server's own service principal credentials, regardless of who the caller is.
Request Flow
User sends a billing question in Gemini Enterprise
GE authenticates with Entra ID and receives an OAuth token
GE sends the MCP request to Cloud Run with
Authorization: Bearer <token>Cloud Run IAM verifies the caller is GE's own service account (
gcp-sa-discoveryengine)BearerTokenMiddlewarecaptures the token and logs its presence (audit only)The MCP tool calls
AzureCostClient, which authenticates to Azure usingDefaultAzureCredentialand the server's service principalAzure responds; the server returns structured JSON to GE
For detailed setup instructions, see SETUP.md.
Project Structure
azure-billing-mcp-server/
├── README.md # This file — main entry point
├── SETUP.md # Step-by-step Azure + GCP + Gemini Enterprise setup guide
│
├── docs/
│ ├── ARCHITECTURE.md # Detailed architecture and component documentation
│ ├── CONFIGURATION.md # All environment variables and configuration reference
│ ├── TROUBLESHOOTING.md # Common errors, symptoms, and fixes
│ └── MAINTENANCE.md # Ongoing maintenance procedures
│
├── server.py # All application code (MCP server, Azure client, 11 tools)
├── requirements.txt # Python dependencies
├── Dockerfile # Container image definition
├── deploy_cloudrun.sh # One-command deployment to Google Cloud Run
├── .env.example # Local development environment variable template
├── pyrightconfig.json # Pyright/Pylance type-checker config (development only)
└── Azure_Setup_Guide.docx # Azure setup reference documentKey Files
File | Purpose |
| All application logic. Contains |
| Builds the Docker image via Cloud Build, deploys to Cloud Run, grants IAM to Gemini Enterprise's service account. Fill in the variables at the top before running. |
| Uses |
| Complete step-by-step setup guide covering Azure Portal configuration, GCP Secret Manager, Cloud Run deployment, and Gemini Enterprise connection. Intended for engineers doing the initial setup. |
| Template for local development credentials. Copy to |
MCP Tools
All tools are read-only (readOnlyHint=True). The server never writes to Azure.
Cost Management Tools
Tool | Parameters | Description |
| — | List all Azure subscriptions the service principal can access. Call this first if the user hasn't specified a subscription. |
|
| General-purpose cost query. Full control over grouping (e.g. |
|
| Cost breakdown by Azure service (VM, Storage, Functions, etc.), sorted highest first. |
|
| Cost breakdown by resource group, sorted highest first. |
|
| Day-by-day cost time series sorted by date. |
|
| Top N most expensive individual resources (default: 10). |
Billing API Tools
Tool | Parameters | Description |
| — | List billing accounts accessible to the service principal. Call this first for invoice queries. |
|
| List recent billing periods, most recent first (default: 12). |
|
| List invoices for a billing account (default: 12). |
|
| Detailed line-item usage records for a date range (default: 100 records). |
|
| Budget limits and current spend vs limit for a subscription. |
Valid timeframe values: MonthToDate, BillingMonthToDate, TheLastMonth, TheLastBillingMonth, WeekToDate, Custom
When timeframe="Custom", both start_date and end_date are required in YYYY-MM-DD format.
Local Development
# 1. Create and activate a virtual environment
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# 2. Install dependencies
pip install -r requirements.txt
# 3. Configure credentials
cp .env.example .env
# Edit .env — fill in AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET
# 4. Start the server
python server.py
# Server starts at http://0.0.0.0:8080/mcpAlternative: Azure CLI authentication (no service principal needed locally)
az login
python server.py # DefaultAzureCredential picks up az login credentials automaticallyThe MCP endpoint is http://localhost:8080/mcp. You can connect any MCP-compatible client to this URL for local testing.
Deployment
See SETUP.md for complete step-by-step instructions. The high-level sequence is:
Prerequisites
gcloudCLI installed and authenticated (gcloud auth login)GCP project selected (
gcloud config set project <project-id>)Required GCP APIs enabled:
gcloud services enable run.googleapis.com secretmanager.googleapis.com discoveryengine.googleapis.com
Steps
Azure — Create the billing service principal (
azure-billing-mcp-reader), assignCost Management ReaderandBilling Readerroles (SETUP.md Steps 1–2)Azure — Create the OAuth app registration (
gemini-enterprise-mcp) with the custommcp.accessscope (SETUP.md Step 3)GCP — Store
AZURE_CLIENT_SECRETin GCP Secret Manager asAzure_secret_value(SETUP.md Step 4)GCP — Fill in
deploy_cloudrun.shvariables and runbash deploy_cloudrun.sh(SETUP.md Step 5)Gemini Enterprise — Create a Custom MCP data store pointing to the Cloud Run URL (SETUP.md Step 6)
Deploy Script Variables
Edit the top section of deploy_cloudrun.sh:
GCP_PROJECT="<your-gcp-project-id>"
GCP_REGION="asia-south1" # change if needed
SERVICE_NAME="<your-service-name>"
SECRET_NAME="Azure_secret_value" # must match the secret in GCP Secret Manager
COST_MGMT_TENANT_ID="<your-azure-tenant-id>"
COST_MGMT_CLIENT_ID="<your-azure-client-id>"Then run:
bash deploy_cloudrun.shThe script outputs the MCP Server URL on completion. Save this URL — it is needed for Gemini Enterprise configuration.
Verifying Deployment
After deployment:
Check Cloud Run console — service status should be Active
In Gemini Enterprise, click Reload custom actions — all 11 tools should appear with a green checkmark
Environment Variables
See docs/CONFIGURATION.md for full reference.
Variable | Required | Default | Purpose | Where to get it |
| Yes | — | Azure tenant ID for the billing service principal | Entra ID → App Registrations → Overview → Directory (tenant) ID |
| Yes | — | Application (client) ID of the billing service principal | Entra ID → App Registrations → Overview → Application (client) ID |
| Yes | — | Client secret for the billing service principal | Created in SETUP.md Step 1.3. In production, injected from GCP Secret Manager. |
| No |
| HTTP port the server listens on | N/A |
| No |
| Logging verbosity ( | N/A |
On Cloud Run: AZURE_TENANT_ID and AZURE_CLIENT_ID are passed as --set-env-vars; AZURE_CLIENT_SECRET is injected via --set-secrets from GCP Secret Manager. The .env file is for local development only.
Network Requirements
The server makes outbound HTTPS (port 443) calls to these endpoints:
Endpoint | Purpose |
| Azure token acquisition via |
| Azure Cost Management API and Billing API |
Inbound: Cloud Run handles TLS termination. The container listens on port 8080 internally. Access is restricted by Cloud Run IAM (--no-allow-unauthenticated) — no additional firewall rules are required.
No VPC peering, IP allowlisting, custom DNS, or proxy configuration is required for a standard Cloud Run deployment.
Security
Access Control Model
Cloud Run is deployed without public access (
--no-allow-unauthenticated)Only Gemini Enterprise's own Google service account (
service-<project-number>@gcp-sa-discoveryengine.iam.gserviceaccount.com) is grantedroles/run.invokerThe server does not perform JWT validation on incoming bearer tokens — token validation is Cloud Run IAM's responsibility
All Azure API calls use the server's own service principal credentials — callers cannot escalate or override which Azure identity is used
Secrets Management
Secret | Production location | Notes |
| GCP Secret Manager ( | Injected at deploy time via |
Entra ID OAuth app secret ( | Gemini Enterprise data store configuration | Used only by GE for the login flow — this server never sees it. |
Required Azure Roles
The billing service principal requires:
Role | Scope | Required for |
| Subscription | All cost query and usage tools |
| Subscription |
|
The service principal has no write permissions anywhere.
Subscription Type Requirement
Azure Cost Management and Billing APIs only work with paid commercial subscriptions:
Works | Does NOT work |
Pay-As-You-Go | Free Trial |
Enterprise Agreement (EA) | Visual Studio / Dev/Test |
Microsoft Customer Agreement (MCA) | CSP / Sponsored |
To upgrade: Azure Portal → Subscriptions → select subscription → Upgrade.
Gemini Enterprise Configuration
After deploying to Cloud Run, configure Gemini Enterprise:
Data Store Settings
In Gemini Enterprise Console → Data Stores → Create Data Store → Custom MCP Server:
Field | Value |
MCP Server URL |
|
Authorization URL |
|
Token URL |
|
Client ID | Application (client) ID of the |
Client Secret | Secret from |
Scopes |
|
Enable PKCE | Leave unchecked |
Required Redirect URIs (add in Entra ID App Registration → Authentication)
https://vertexaisearch.cloud.google.com/console/oauth/default_oauth.html
https://vertexaisearch.cloud.google.com/oauth-redirectMCP Agent Instructions
Paste this into the Gemini Enterprise agent instructions field:
You have access to Azure Cost Management and Billing tools for querying actual
Azure spend, invoices, budgets, and usage. All tools are read-only.
If the user doesn't specify a subscription, call list_subscriptions first.
For invoice queries, call get_billing_accounts first.
Default timeframe is "MonthToDate" unless the user asks for a different period.Troubleshooting
See docs/TROUBLESHOOTING.md for the full guide.
Symptom | Likely Cause | Fix |
| Wrong client secret in GE form | Use the |
| Cloud Run not starting | Check GCP Secret Manager IAM — the compute service account must have |
| Free Trial Azure subscription | Upgrade to Pay-As-You-Go |
| Missing | Assign |
Tools return empty | Service principal lacks subscription access | Assign roles using the service principal's Object ID (from Enterprise Applications), not the Application ID |
| GE service account missing invoker role | Re-run the IAM grant step in |
| Placeholder values left in deploy script | Fill in real |
| Cloud Run cannot read | Run the |
Maintenance
See docs/MAINTENANCE.md for full procedures.
Deploying a new version:
bash deploy_cloudrun.sh # rebuild image and redeployRotating the Azure client secret:
Create a new secret in Azure Portal (Entra ID → App Registrations →
azure-billing-mcp-reader→ Certificates & Secrets)Update the value in GCP Secret Manager:
Azure_secret_valueRedeploy:
bash deploy_cloudrun.sh
Viewing logs:
gcloud logging read "resource.type=cloud_run_revision AND resource.labels.service_name=azure-billing-mcp" \
--project <your-gcp-project-id> --limit 100 --format "table(timestamp, textPayload)"Known Limitations
Subscription type: Cost Management APIs do not work on Free Trial, Visual Studio, CSP, or sponsored subscriptions.
Pagination:
get_usage_detailsdefaults to 100 records (topparameter). Large date ranges may require multiple calls or a highertopvalue.No per-user Azure RBAC: All users share the service principal's access level. The bearer token is captured for audit logging only — there is no per-caller Azure identity switching.
Secret expiry: The
AZURE_CLIENT_SECREThas a finite validity (default: 12 months). When it expires, the server will stop authenticating to Azure. Set a calendar reminder to rotate it before expiry.Single region: The deploy script defaults to
asia-south1. Multi-region deployments require manual configuration.Read-only: No write operations are supported. The server cannot create budgets, modify resources, or take any action in Azure.
This server cannot be deployed
Maintenance
Related MCP Connectors
Hosted MCP server for LLM cost estimation, model comparison, and budget-aware routing.
Hosted MCP server for AWS cloud spend: service breakdowns, anomalies, savings and forecasts.
Hosted MCP server for Google Ads and LinkedIn Ads analysis.
Cloudflare Workers MCP server: ai-cost-optimizer
Related MCP Servers
- AlicenseAqualityBmaintenanceCloud cost management MCP server for Azure. Ask your AI about your cloud bill.1542 npm1MIT
- AlicenseNot gradedqualityDmaintenanceProduction-grade MCP server for enterprise Azure cost optimization, enabling spend anomaly detection, multi-tenant auditing, budget validation, and compliance-aware recommendations.1MIT
- AlicenseNot gradedqualityDmaintenanceAnalyzes Azure cloud costs, audits for waste, and provides budget insights via natural language through a secure local MCP server.2MIT
- FlicenseBqualityDmaintenanceAn MCP server that gives Claude live access to Azure pricing and cost data — retail prices, VM comparisons, reservation analysis, architecture estimates, and actual subscription spend.9-