mcp-azure-cloudshell

cameronking4/mcp-azure-cloudshell

3.2

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.

Tools
3
Resources
0
Prompts
0

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

This MCP server provides programmatic access to Azure Cloud Shell through the following tools:

Tools

  1. azure_cli - Execute Azure CLI commands

    • Run any az command in your Azure environment
    • Example: az account show, az vm list, az group list
  2. azure_shell - Execute bash shell commands

    • Run general bash commands, git operations, or scripts
    • Example: ls -la, git status, pwd, cat file.txt
  3. 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:

  1. Authentication - Uses DefaultAzureCredential from @azure/identity
  2. Console Provisioning - Provisions a Cloud Shell console via Azure Management API
  3. Terminal Creation - Creates a bash terminal session
  4. WebSocket Connection - Establishes bidirectional communication for command execution

Prerequisites

Before using this server, you need:

  1. Azure Account with an active subscription
  2. Azure CLI installed locally (for authentication setup)
  3. Node.js 18+ installed
  4. 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

  1. Navigate to the project directory:
cd mcp-azure-cloudshell
  1. Install dependencies:
npm install
  1. Build the server:
npm run build

Usage

This server supports two transport mechanisms. Choose the one that best fits your use case:

Transport Options

TransportBest ForProsCons
StdioLocal development, Claude Code desktopLow latency, simple setupSingle user, local only
HTTPRemote access, web apps, multiple usersNetwork accessible, scalableRequires 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)

  1. 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();
    });
    
  2. 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
  3. 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 )
  4. Add Monitoring: Track usage, errors, and performance

    • Application Insights (Azure)
    • CloudWatch (AWS)
    • Custom logging and metrics
  5. Implement Rate Limiting: Prevent abuse with request throttling

    npm install express-rate-limit
    

For Development

  1. Test with Azure Credentials: Ensure az login is configured and test actual command execution
  2. Add Custom Tools: Extend the server with additional Azure-specific tools
  3. Improve Output Parsing: Enhance the cleanOutput method for better command result formatting
  4. Add PowerShell Support: Modify terminal creation to support PowerShell in addition to bash

Learning More

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)
  1. Command sent via WebSocket with newline (command\n)
  2. Output accumulated in buffer as messages arrive
  3. Completion detected when prompt characters appear
  4. ANSI escape codes removed and output cleaned
  5. 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

  1. 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" } }
  2. Terminal Creation

    • POST https://{gateway-url}/terminals?cols=160&rows=40&shell=bash
    • Returns: { id: "terminal-id", socketUri: "wss://..." }
  3. 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

ScenarioMonthly 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 PortalIdentical 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

  1. Session Timeout - Cloud Shell sessions timeout after 20 minutes of inactivity
  2. Single Session - Only one active session per server instance
  3. Output Parsing - Complex interactive commands may not work perfectly
  4. Rate Limiting - Azure API rate limits apply
  5. Free Tier Limit - 20 hours/month of free compute; additional hours billed at standard rates

Security Considerations

  1. Credential Security - Uses Azure's official credential chain
  2. No Credential Storage - Tokens are fetched on-demand
  3. API Scope - Limited to Azure Management API scope
  4. 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 execute
  • timeout (number, optional) - Timeout in seconds (default: 30)

Returns:

  • Command output as text

azure_shell Tool

Parameters:

  • command (string, required) - Bash command to execute
  • timeout (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:

  1. Add New Tools - Define additional tools in src/index.ts
  2. Enhance Output Parsing - Improve the cleanOutput method in src/cloudshell.ts
  3. Add PowerShell Support - Modify terminal creation to use pwsh instead of bash
  4. 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 framework
  • ws - WebSocket client
  • Azure Cloud Shell REST API