cameronking4/mcp-azure-cloudshell
If you are the rightful owner of mcp-azure-cloudshell and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.
The MCP Azure Cloud Shell server allows developers to execute Azure CLI commands and bash scripts within the Azure Cloud Shell environment, providing seamless integration with Azure services.
MCP Azure Cloud Shell
A Model Context Protocol (MCP) server that enables developers to execute Azure CLI commands and bash scripts in your Azure Cloud Shell environment.
Quick Links
- Features - Available tools and capabilities
- Installation - Get started in 3 steps
- Usage - Stdio vs HTTP transport setup
- Next Steps - Production deployment and development recommendations
- How It Works - Technical deep dive with code references
- Cost & Billing - Pricing breakdown and what resources are created
- Troubleshooting - Common issues and solutions
Features
This MCP server provides programmatic access to Azure Cloud Shell through the following tools:
Tools
-
azure_cli - Execute Azure CLI commands
- Run any
az
command in your Azure environment - Example:
az account show
,az vm list
,az group list
- Run any
-
azure_shell - Execute bash shell commands
- Run general bash commands, git operations, or scripts
- Example:
ls -la
,git status
,pwd
,cat file.txt
-
azure_shell_reconnect - Force reconnection to Cloud Shell
- Use if the connection seems stale or commands are timing out
How It Works
The server connects to Azure Cloud Shell using the official Azure REST API:
- Authentication - Uses
DefaultAzureCredential
from@azure/identity
- Console Provisioning - Provisions a Cloud Shell console via Azure Management API
- Terminal Creation - Creates a bash terminal session
- WebSocket Connection - Establishes bidirectional communication for command execution
Prerequisites
Before using this server, you need:
- Azure Account with an active subscription
- Azure CLI installed locally (for authentication setup)
- Node.js 18+ installed
- Azure Cloud Shell resource provider registered in your subscription
Register Azure Cloud Shell Resource Provider
If this is your first time using Cloud Shell, register the resource provider:
az provider register --namespace Microsoft.CloudShell
Authentication Setup
The server uses DefaultAzureCredential
, which supports multiple authentication methods. Choose one:
Option 1: Azure CLI (Recommended for Development)
az login
This is the simplest method for local development. The server will automatically use your Azure CLI credentials.
Option 2: Environment Variables (Service Principal)
export AZURE_TENANT_ID="your-tenant-id"
export AZURE_CLIENT_ID="your-client-id"
export AZURE_CLIENT_SECRET="your-client-secret"
Option 3: Managed Identity (For Azure-hosted applications)
If running on Azure VMs, App Service, or Functions, managed identity will be used automatically.
Installation
- Navigate to the project directory:
cd mcp-azure-cloudshell
- Install dependencies:
npm install
- Build the server:
npm run build
Usage
This server supports two transport mechanisms. Choose the one that best fits your use case:
Transport Options
Transport | Best For | Pros | Cons |
---|---|---|---|
Stdio | Local development, Claude Code desktop | Low latency, simple setup | Single user, local only |
HTTP | Remote access, web apps, multiple users | Network accessible, scalable | Requires server management |
Option 1: Stdio Transport (Recommended for Claude Code)
Start the server:
npm start
Add to Claude Code using CLI:
claude mcp add --transport stdio azure-cloudshell -- node /path/to/mcp-azure-cloudshell/dist/index.js
Or manually configure in .mcp.json
(local) or ~/.config/claude/mcp.json
(global):
{
"mcpServers": {
"azure-cloudshell": {
"command": "node",
"args": ["/absolute/path/to/mcp-azure-cloudshell/dist/index.js"],
"transport": "stdio"
}
}
}
Option 2: HTTP Transport (For Remote/Web Access)
Start the HTTP server:
npm run start:http
The server starts on http://localhost:3000/mcp
by default. Use PORT=8080
to customize.
Configure in Claude Code (.mcp.json
):
{
"mcpServers": {
"azure-cloudshell-http": {
"url": "http://localhost:3000/mcp",
"transport": "http"
}
}
}
Test with curl:
# Initialize session
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc": "2.0", "method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "curl-client", "version": "1.0.0"}}, "id": 1}'
# List tools (use session ID from response)
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Mcp-Session-Id: YOUR-SESSION-ID" \
-d '{"jsonrpc": "2.0", "method": "tools/list", "params": {}, "id": 2}'
For detailed HTTP setup, deployment options, and troubleshooting, see .
Example Queries
After adding the server, you can ask Claude Code questions like:
- "What Azure subscription am I using?"
- "List all my resource groups"
- "Show me all VMs in the eastus region"
- "Create a new resource group called test-rg in westus2"
- "What's my current directory in Cloud Shell?"
- "Clone the repository https://github.com/example/repo into Cloud Shell"
Next Steps
Now that you have the server set up, here are some recommended next steps:
For Production Deployments (HTTP Transport)
-
Add Authentication: Implement Bearer token or API key validation
app.use((req, res, next) => { const authHeader = req.headers.authorization; if (!authHeader || !validateToken(authHeader)) { return res.status(401).json({ error: 'Unauthorized' }); } next(); });
-
Enable HTTPS: Use valid TLS certificates for secure communication
- Deploy behind a reverse proxy (nginx, Caddy)
- Use Let's Encrypt for free certificates
- Configure HTTPS redirect
-
Deploy to Cloud:
- Azure App Service:
az webapp up --name my-mcp-server --resource-group my-rg
- AWS Lambda: Use AWS Lambda Web Adapter with the HTTP server
- Docker: Build and deploy containerized version (see )
- Azure App Service:
-
Add Monitoring: Track usage, errors, and performance
- Application Insights (Azure)
- CloudWatch (AWS)
- Custom logging and metrics
-
Implement Rate Limiting: Prevent abuse with request throttling
npm install express-rate-limit
For Development
- Test with Azure Credentials: Ensure
az login
is configured and test actual command execution - Add Custom Tools: Extend the server with additional Azure-specific tools
- Improve Output Parsing: Enhance the
cleanOutput
method for better command result formatting - Add PowerShell Support: Modify terminal creation to support PowerShell in addition to bash
Learning More
- Read for detailed HTTP setup and deployment guides
- Explore Azure Cloud Shell REST API documentation
- Check out the Model Context Protocol specification
Project Structure
mcp-azure-cloudshell/
āāā src/
ā āāā index.ts # Main MCP server (stdio transport)
ā āāā http-server.ts # HTTP server (HTTP transport)
ā āāā cloudshell.ts # Azure Cloud Shell connection manager
āāā dist/ # Compiled JavaScript (generated)
āāā package.json # Dependencies and scripts
āāā tsconfig.json # TypeScript configuration
āāā README.md # This file
āāā HTTP-TRANSPORT.md # HTTP transport documentation
Development
Development Mode
Run TypeScript compiler in watch mode:
npm run dev
Build
npm run build
Start Server (for testing)
npm start
Architecture Details
How It Works Under the Hood
The MCP server establishes a connection to Azure Cloud Shell through a three-step process:
Step 1: Console Provisioning (cloudshell.ts:60-93)
PUT https://management.azure.com/providers/Microsoft.Portal/consoles/default
- Calls the Microsoft.Portal resource provider (not Microsoft.CloudShell!)
- Creates or retrieves an existing Cloud Shell console metadata object
- This is a FREE management resource with no compute/storage costs
- Returns a URI pointing to your Cloud Shell gateway
Step 2: Terminal Creation (cloudshell.ts:98-133)
POST https://{gateway-url}/terminals?cols=160&rows=40&shell=bash
- Creates a bash terminal session in your Cloud Shell environment
- Specifies terminal dimensions and shell type
- Returns a WebSocket URI and terminal ID for bidirectional communication
Step 3: WebSocket Connection (cloudshell.ts:138-177)
wss://{gateway-url}/terminals/{terminal-id}
- Opens a persistent WebSocket connection to the terminal
- All command input/output flows through this connection
- Commands are queued and output is buffered until completion
- Detects command completion by watching for shell prompts ($, #, >)
Command Execution Flow (cloudshell.ts:212-244)
- Command sent via WebSocket with newline (
command\n
) - Output accumulated in buffer as messages arrive
- Completion detected when prompt characters appear
- ANSI escape codes removed and output cleaned
- Echoed command line and final prompt stripped from result
Authentication Flow
āāāāāāāāāāāāāāāāāāā
ā DefaultAzure ā
ā Credential ā
āāāāāāāāāā¬āāāāāāāāā
ā
v
āāāāāāāāāāāāāāāāāāā
ā Azure ā
ā Management API ā
āāāāāāāāāā¬āāāāāāāāā
ā
v
āāāāāāāāāāāāāāāāāāā
ā Cloud Shell ā
ā Console ā
āāāāāāāāāā¬āāāāāāāāā
ā
v
āāāāāāāāāāāāāāāāāāā
ā Terminal ā
ā Session ā
āāāāāāāāāā¬āāāāāāāāā
ā
v
āāāāāāāāāāāāāāāāāāā
ā WebSocket ā
ā Connection ā
āāāāāāāāāāāāāāāāāāā
API Endpoints Used
-
Console Provisioning
PUT https://management.azure.com/providers/Microsoft.Portal/consoles/default?api-version=2020-04-01-preview
- Returns:
{ properties: { uri: "https://...", provisioningState: "Succeeded", osType: "linux" } }
-
Terminal Creation
POST https://{gateway-url}/terminals?cols=160&rows=40&shell=bash
- Returns:
{ id: "terminal-id", socketUri: "wss://..." }
-
WebSocket Connection
wss://{gateway-url}/terminals/{terminal-id}
- Protocol: Bidirectional text messages with terminal I/O
Code Architecture
index.ts (MCP Server)
import { AzureCloudShell } from "./cloudshell.js";
// Server maintains a singleton Cloud Shell instance
let cloudShell: AzureCloudShell | null = null;
// On first tool call, initialize connection
if (!cloudShell) {
cloudShell = new AzureCloudShell(credential);
await cloudShell.connect(); // Runs 3-step connection process
}
// Execute commands through the established connection
const result = await cloudShell.executeCommand(command, timeout);
The .js
extension in the import is required because:
- TypeScript compiles to ES modules (
"type": "module"
in package.json) - ES module imports must include file extensions
- At runtime, Node.js loads
dist/cloudshell.js
(the compiled output)
cloudshell.ts (Connection Manager)
export class AzureCloudShell {
private ws: WebSocket | null = null; // WebSocket connection
private commandQueue: Array<{...}> = []; // Queue for sequential commands
private outputBuffer: string = ""; // Accumulates command output
private isReady: boolean = false; // Connection state
async connect() {
await this.provisionConsole(); // Step 1: Get console URI
await this.createTerminal(); // Step 2: Create terminal
await this.connectWebSocket(); // Step 3: Open WebSocket
}
async executeCommand(command: string, timeout: number): Promise<string> {
// Send command via WebSocket
this.ws.send(`${command}\n`);
// Wait for completion (detected by prompt characters)
return new Promise((resolve, reject) => {
this.commandQueue.push({ command, resolve, reject, timeout });
});
}
private handleMessage(data: WebSocket.Data) {
// Accumulate output until prompt detected
this.outputBuffer += data.toString();
// Resolve pending command when prompt appears
if (message includes prompt characters) {
currentCommand.resolve(this.cleanOutput(this.outputBuffer));
}
}
}
Key design patterns:
- Singleton connection: One WebSocket per server instance
- Command queuing: Sequential execution prevents output interleaving
- Promise-based API: Clean async/await interface for callers
- Automatic cleanup: SIGINT/SIGTERM handlers disconnect gracefully
Command Execution
The server handles command execution with the following features:
- Timeout Support - Configurable timeout per command (default 30 seconds)
- Output Cleaning - Removes ANSI escape codes and terminal prompts
- Queue Management - Handles multiple commands sequentially
- Error Handling - Provides clear error messages for failures
Troubleshooting
Authentication Errors
Error: "Failed to get access token"
Solutions:
- Ensure you're logged in with Azure CLI:
az login
- Verify your service principal credentials if using environment variables
- Check that you have appropriate permissions in your Azure subscription
Connection Errors
Error: "Failed to provision console"
Solutions:
- Ensure Microsoft.CloudShell resource provider is registered
- Verify your subscription is active
- Check network connectivity to Azure
Command Timeout
Error: "Command timed out after 30000ms"
Solutions:
- Increase the timeout parameter in your command
- Check if the command is actually long-running
- Use the
azure_shell_reconnect
tool to refresh the connection
WebSocket Errors
Error: "WebSocket connection closed"
Solutions:
- Cloud Shell sessions timeout after 20 minutes of inactivity
- Use
azure_shell_reconnect
to establish a new connection - The server will automatically reconnect on the next command
Cost & Billing
What Resources Are Created?
This MCP server does NOT create VMs, sandboxes, or resource groups. It connects to Azure's existing Cloud Shell infrastructure using REST APIs.
Resource Providers Used
Microsoft.Portal Resource Provider
- Resource Type:
Microsoft.Portal/consoles
- Cost: FREE - Just metadata tracking your Cloud Shell session
- What it does: Creates a console object that references your Cloud Shell gateway
- Location: Management plane only, no compute/storage resources
Microsoft.CloudShell Resource Provider
- Resource Type: Registration only (
operations
) - Cost: FREE - Just API operation definitions
- What it does: Enables Cloud Shell APIs in your subscription
What Cloud Shell Actually Provisions (First Use Only)
When you use Cloud Shell for the first time, Azure automatically provisions:
1. Storage Account (~$0.05-0.10/month)
- Resource: Azure Files share (5 GB)
- Purpose: Persistent storage for your
$HOME
directory - Naming: Usually
cs<randomstring>
- Cost: ~$0.05-0.10/month for Standard LRS storage
- Lifecycle: Created once, persists across sessions
2. Container Instances (Mostly FREE)
- Resource: Temporary Linux container for your shell session
- Cost:
- First 20 hours/month: FREE
- After 20 hours:
$0.0013/second ($4.68/hour if continuously running)
- Lifecycle:
- Spins up on first command
- Auto-terminates after 20 minutes of inactivity
- No charges when not running
3. Network Egress (FREE within limits)
- Resource: WebSocket traffic and Azure API calls
- Cost: Typically covered by Azure free tier
- Volume: Minimal (just command I/O)
Cost Comparison
Scenario | Monthly Cost |
---|---|
Typical usage (< 20 hrs/month) | ~$0.05-0.10 (storage only) |
Heavy usage (40 hrs/month) | ~$0.10 + (20 hrs Ć $4.68) = ~$93.70 |
This MCP Server vs Azure Portal | Identical costs - uses same infrastructure |
Idle (no commands running) | ~$0.05-0.10 (storage only) |
Important Notes
- This server uses the same Cloud Shell environment you access via portal.azure.com
- No additional resources are created beyond standard Cloud Shell
- The 20-minute idle timeout prevents runaway costs
- Storage costs persist but are minimal
- First 20 hours/month of compute are completely FREE
Monitoring Costs
To check if Cloud Shell storage exists in your subscription:
az storage account list --query "[?tags.ms-resource-usage=='azure-cloud-shell']"
To view your Cloud Shell usage:
- Azure Portal ā Cost Management ā Cost Analysis
- Filter by service: "Azure Container Instances" and "Storage"
Limitations
- Session Timeout - Cloud Shell sessions timeout after 20 minutes of inactivity
- Single Session - Only one active session per server instance
- Output Parsing - Complex interactive commands may not work perfectly
- Rate Limiting - Azure API rate limits apply
- Free Tier Limit - 20 hours/month of free compute; additional hours billed at standard rates
Security Considerations
- Credential Security - Uses Azure's official credential chain
- No Credential Storage - Tokens are fetched on-demand
- API Scope - Limited to Azure Management API scope
- Command Execution - Commands run in your Cloud Shell environment with your permissions
Advanced Usage
Custom Timeout
// In Claude Code, specify longer timeout for slow commands
"List all resources with a 60 second timeout using azure_cli with command 'az resource list' and timeout 60"
Chaining Commands
# Use && to chain multiple commands
"Execute in azure_shell: cd /home && ls -la && pwd"
Working with Files
# Create and read files in Cloud Shell
"Create a file in Cloud Shell named test.txt with content 'Hello World'"
"Read the contents of test.txt in Cloud Shell"
API Reference
azure_cli Tool
Parameters:
command
(string, required) - Azure CLI command to executetimeout
(number, optional) - Timeout in seconds (default: 30)
Returns:
- Command output as text
azure_shell Tool
Parameters:
command
(string, required) - Bash command to executetimeout
(number, optional) - Timeout in seconds (default: 30)
Returns:
- Command output as text
azure_shell_reconnect Tool
Parameters:
- None
Returns:
- Success message
Contributing
To extend this server:
- Add New Tools - Define additional tools in
src/index.ts
- Enhance Output Parsing - Improve the
cleanOutput
method insrc/cloudshell.ts
- Add PowerShell Support - Modify terminal creation to use
pwsh
instead ofbash
- Implement Resources - Expose Azure resources as MCP resources
Resources
License
MIT
Acknowledgments
This server is built using:
@azure/identity
- Azure authentication@modelcontextprotocol/sdk
- MCP server frameworkws
- WebSocket client- Azure Cloud Shell REST API