Skip to main content
Glama
azure-manager.ts6 kB
import { z } from 'zod'; import { executeAzCommand, CommandResult } from '../lib/cli-executor.js'; import { sanitizeInput, generateCommandSummary, RiskLevel } from '../lib/safety.js'; import { createAuditContext } from '../lib/audit.js'; import { getOperatorInfo } from '../lib/config.js'; import { logger } from '../lib/logger.js'; export type PlanStatus = 'WAITING_FOR_CONFIRMATION' | 'EXECUTED' | 'FAILED' | 'REJECTED'; export const ManageAzureResourcesSchema = z.object({ command: z.string().describe('Azure CLI command to execute'), explanation: z.string().describe('Why this command was chosen'), execute_now: z.boolean().default(false).describe('If true, execute; if false, plan only'), }); export type ManageAzureResourcesInput = z.infer<typeof ManageAzureResourcesSchema>; export interface PlanResponse { proposed_command: string; risk_level: RiskLevel; summary: string; explanation: string; status: PlanStatus; warnings: string[]; next_steps: string; correlation_id?: string; operator?: { email?: string; name?: string }; } export interface ExecutionResponse { executed_command: string; status: PlanStatus; success: boolean; output?: unknown; raw_output?: string; error?: string; stderr?: string; error_analysis?: string; correlation_id: string; operator?: { email?: string; name?: string }; } const ERROR_PATTERNS = new Map<RegExp, string>([ [/ResourceNotFound|NotFound/, 'Resource not found. Verify name and resource group.'], [/ResourceGroup.*not found/i, 'Resource group not found. Create it first: az group create'], [/AADSTS|authentication|login/i, 'Auth issue. Run "az login" to authenticate.'], [/subscription.*not found/i, 'Subscription not found. List available: az account list'], [/AuthorizationFailed|does not have authorization/i, 'Permission denied. Check RBAC role assignments.'], [/QuotaExceeded|quota/i, 'Quota exceeded. Request increase or change region/SKU.'], [/InvalidParameter|BadRequest/i, 'Invalid parameter. Review command syntax.'], [/already exists|AlreadyExists|Conflict/i, 'Resource exists. Use different name or manage existing.'], ]); function analyzeError(stderr: string): string { for (const [pattern, suggestion] of ERROR_PATTERNS) { if (pattern.test(stderr)) return suggestion; } return 'Review error message and adjust parameters.'; } export async function handleManageAzureResources( input: ManageAzureResourcesInput ): Promise<PlanResponse | ExecutionResponse> { const { command, explanation, execute_now } = input; const operator = getOperatorInfo(); const validation = sanitizeInput(command); if (!validation.isValid) { logger.warn('Command validation failed', { command, error: validation.error }); return { proposed_command: command, risk_level: 'high', summary: 'Validation failed', explanation, status: 'REJECTED', warnings: [validation.error || 'Unknown error'], next_steps: 'Provide a valid Azure CLI command.', operator, }; } const cmd = validation.sanitizedCommand!; const risk = validation.riskLevel; const audit = createAuditContext(cmd, risk, execute_now ? 'execute' : 'plan'); if (!execute_now) { const summary = generateCommandSummary(cmd); const nextSteps = risk === 'high' ? '⚠️ HIGH RISK: Review carefully before execute_now=true' : 'Call again with execute_now=true to execute.'; logger.command('plan', cmd, 'success', { riskLevel: risk, correlationId: audit.correlationId }); return { proposed_command: cmd, risk_level: risk, summary, explanation, status: 'WAITING_FOR_CONFIRMATION', warnings: validation.warnings, next_steps: nextSteps, correlation_id: audit.correlationId, operator, }; } logger.info('Executing', { command: cmd, correlationId: audit.correlationId }); const result: CommandResult = await executeAzCommand(cmd, { applyScope: true, enableRetry: true }); if (result.success) { await audit.logSuccess(); logger.command('execute', cmd, 'success', { correlationId: audit.correlationId }); return { executed_command: cmd, status: 'EXECUTED', success: true, output: result.parsedOutput ?? result.stdout, raw_output: result.stdout, correlation_id: audit.correlationId, operator, }; } const analysis = analyzeError(result.stderr); await audit.logFailure(result.stderr); logger.command('execute', cmd, 'failure', { correlationId: audit.correlationId, error: result.stderr }); return { executed_command: cmd, status: 'FAILED', success: false, error: result.stderr || 'Execution failed', stderr: result.stderr, error_analysis: analysis, correlation_id: audit.correlationId, operator, }; } export const manageAzureResourcesTool = { name: 'manage_azure_resources', description: `Primary tool for all Azure operations via CLI. FLOW: 1) Call with execute_now=false for plan 2) Review risk 3) Call with execute_now=true to execute SAFETY: Commands validated for injection. Destructive ops flagged HIGH risk. AUDIT: All ops logged with operator email and correlation ID.`, inputSchema: { type: 'object', properties: { command: { type: 'string', description: 'Azure CLI command (e.g., "az aks create ...")' }, explanation: { type: 'string', description: 'Why this command was chosen' }, execute_now: { type: 'boolean', description: 'false: plan only, true: execute', default: false }, }, required: ['command', 'explanation'], }, };

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/vedantparmar12/Azure-_MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server