Skip to main content
Glama

listAzureResourceGroups

Retrieve resource groups from your Azure subscription to manage cloud resources and organize infrastructure components effectively.

Instructions

List resource groups in a selected Azure subscription using MCP elicitation

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
subscriptionIdNoAzure subscription ID (will be elicited if not provided)

Implementation Reference

  • src/server.ts:435-598 (registration)
    Complete registration of the 'listAzureResourceGroups' MCP tool, including schema and inline handler function. The handler uses Azure CLI to list resource groups after eliciting subscription if needed.
    server.registerTool( "listAzureResourceGroups", { title: "List Azure Resource Groups", description: "List resource groups in a selected Azure subscription using MCP elicitation", inputSchema: { subscriptionId: z.string().optional().describe("Azure subscription ID (will be elicited if not provided)") } }, async ({ subscriptionId }, context) => { try { let targetSubscriptionId = subscriptionId; // If no subscription ID provided, use MCP elicitation to get it if (!targetSubscriptionId) { try { // Get available subscriptions first const subscriptionOptions = await getSubscriptionOptions(); if (subscriptionOptions.length === 0) { return { content: [{ type: "text", text: "❌ No Azure subscriptions found. Please run 'az login' first." }], isError: true }; } // Create elicitation request according to MCP spec const elicitationRequest = await server.server.elicitInput({ message: "Please select an Azure subscription to list resource groups from:", requestedSchema: { type: "object", properties: { subscriptionId: { type: "string", title: "Azure Subscription", description: "Select the subscription to use", enum: subscriptionOptions.map(sub => sub.id), enumNames: subscriptionOptions.map(sub => sub.label) } }, required: ["subscriptionId"] } }); // Handle elicitation response if (elicitationRequest.action === "accept" && elicitationRequest.content?.subscriptionId) { targetSubscriptionId = elicitationRequest.content.subscriptionId as string; } else if (elicitationRequest.action === "cancel") { return { content: [{ type: "text", text: "❌ Operation cancelled by user." }] }; } else if (elicitationRequest.action === "decline") { return { content: [{ type: "text", text: "❌ User declined to provide subscription information." }] }; } else { return { content: [{ type: "text", text: "❌ No subscription selected." }], isError: true }; } } catch (elicitationError: any) { return { content: [{ type: "text", text: `❌ Elicitation failed: ${elicitationError.message}\n\nPlease provide subscriptionId parameter directly.` }], isError: true }; } } // Now get resource groups using Azure CLI const { stdout, stderr } = await execAsync(`az group list --subscription "${targetSubscriptionId}" --output json`, { timeout: 30000, maxBuffer: 1024 * 1024 }); if (stderr) { return { content: [{ type: "text", text: `Azure CLI error: ${stderr}` }], isError: true }; } const resourceGroups = JSON.parse(stdout); if (!resourceGroups || resourceGroups.length === 0) { return { content: [{ type: "text", text: `📦 No resource groups found in the selected subscription.\n\n💡 Create one at: https://portal.azure.com` }] }; } // Get subscription name for display const { stdout: subStdout } = await execAsync(`az account show --subscription "${targetSubscriptionId}" --output json`); const subscriptionInfo = JSON.parse(subStdout); let result = `📦 Resource Groups in "${subscriptionInfo.name}" (${resourceGroups.length} found):\n\n`; resourceGroups.forEach((rg: any) => { const location = rg.location || 'Unknown'; const state = rg.properties?.provisioningState || 'Unknown'; const tags = rg.tags ? Object.keys(rg.tags).length : 0; result += `🏷️ ${rg.name}\n`; result += ` 📍 Location: ${location}\n`; result += ` 📊 State: ${state}\n`; result += ` 🏷️ Tags: ${tags} tag${tags !== 1 ? 's' : ''}\n`; if (rg.tags && Object.keys(rg.tags).length > 0) { const tagList = Object.entries(rg.tags).map(([k, v]) => `${k}=${v}`).slice(0, 3).join(', '); result += ` 🔖 ${tagList}${Object.keys(rg.tags).length > 3 ? '...' : ''}\n`; } result += `\n`; }); result += `💡 Subscription: ${subscriptionInfo.name}\n`; result += `🆔 Subscription ID: ${targetSubscriptionId}`; return { content: [{ type: "text", text: result }] }; } catch (err: any) { let errorMessage = `Failed to list resource groups: ${err.message}`; if (err.message.includes("az: command not found") || err.message.includes("'az' is not recognized")) { errorMessage += "\n\n🔧 Azure CLI is not installed. Please install it from: https://aka.ms/azure-cli"; } else if (err.message.includes("Please run 'az login'") || err.message.includes("not logged in")) { errorMessage += "\n\n🔐 Please authenticate first: az login"; } else if (err.message.includes("Subscription") && err.message.includes("not found")) { errorMessage += "\n\n🔍 Invalid subscription ID. Use listAzureSubscriptions to see available subscriptions."; } return { content: [{ type: "text", text: errorMessage }], isError: true }; } } );
  • The core handler function that executes the tool: elicits subscription ID if not provided using MCP, runs 'az group list', parses JSON, formats detailed output with locations, states, tags, and handles errors.
    async ({ subscriptionId }, context) => { try { let targetSubscriptionId = subscriptionId; // If no subscription ID provided, use MCP elicitation to get it if (!targetSubscriptionId) { try { // Get available subscriptions first const subscriptionOptions = await getSubscriptionOptions(); if (subscriptionOptions.length === 0) { return { content: [{ type: "text", text: "❌ No Azure subscriptions found. Please run 'az login' first." }], isError: true }; } // Create elicitation request according to MCP spec const elicitationRequest = await server.server.elicitInput({ message: "Please select an Azure subscription to list resource groups from:", requestedSchema: { type: "object", properties: { subscriptionId: { type: "string", title: "Azure Subscription", description: "Select the subscription to use", enum: subscriptionOptions.map(sub => sub.id), enumNames: subscriptionOptions.map(sub => sub.label) } }, required: ["subscriptionId"] } }); // Handle elicitation response if (elicitationRequest.action === "accept" && elicitationRequest.content?.subscriptionId) { targetSubscriptionId = elicitationRequest.content.subscriptionId as string; } else if (elicitationRequest.action === "cancel") { return { content: [{ type: "text", text: "❌ Operation cancelled by user." }] }; } else if (elicitationRequest.action === "decline") { return { content: [{ type: "text", text: "❌ User declined to provide subscription information." }] }; } else { return { content: [{ type: "text", text: "❌ No subscription selected." }], isError: true }; } } catch (elicitationError: any) { return { content: [{ type: "text", text: `❌ Elicitation failed: ${elicitationError.message}\n\nPlease provide subscriptionId parameter directly.` }], isError: true }; } } // Now get resource groups using Azure CLI const { stdout, stderr } = await execAsync(`az group list --subscription "${targetSubscriptionId}" --output json`, { timeout: 30000, maxBuffer: 1024 * 1024 }); if (stderr) { return { content: [{ type: "text", text: `Azure CLI error: ${stderr}` }], isError: true }; } const resourceGroups = JSON.parse(stdout); if (!resourceGroups || resourceGroups.length === 0) { return { content: [{ type: "text", text: `📦 No resource groups found in the selected subscription.\n\n💡 Create one at: https://portal.azure.com` }] }; } // Get subscription name for display const { stdout: subStdout } = await execAsync(`az account show --subscription "${targetSubscriptionId}" --output json`); const subscriptionInfo = JSON.parse(subStdout); let result = `📦 Resource Groups in "${subscriptionInfo.name}" (${resourceGroups.length} found):\n\n`; resourceGroups.forEach((rg: any) => { const location = rg.location || 'Unknown'; const state = rg.properties?.provisioningState || 'Unknown'; const tags = rg.tags ? Object.keys(rg.tags).length : 0; result += `🏷️ ${rg.name}\n`; result += ` 📍 Location: ${location}\n`; result += ` 📊 State: ${state}\n`; result += ` 🏷️ Tags: ${tags} tag${tags !== 1 ? 's' : ''}\n`; if (rg.tags && Object.keys(rg.tags).length > 0) { const tagList = Object.entries(rg.tags).map(([k, v]) => `${k}=${v}`).slice(0, 3).join(', '); result += ` 🔖 ${tagList}${Object.keys(rg.tags).length > 3 ? '...' : ''}\n`; } result += `\n`; }); result += `💡 Subscription: ${subscriptionInfo.name}\n`; result += `🆔 Subscription ID: ${targetSubscriptionId}`; return { content: [{ type: "text", text: result }] }; } catch (err: any) { let errorMessage = `Failed to list resource groups: ${err.message}`; if (err.message.includes("az: command not found") || err.message.includes("'az' is not recognized")) { errorMessage += "\n\n🔧 Azure CLI is not installed. Please install it from: https://aka.ms/azure-cli"; } else if (err.message.includes("Please run 'az login'") || err.message.includes("not logged in")) { errorMessage += "\n\n🔐 Please authenticate first: az login"; } else if (err.message.includes("Subscription") && err.message.includes("not found")) { errorMessage += "\n\n🔍 Invalid subscription ID. Use listAzureSubscriptions to see available subscriptions."; } return { content: [{ type: "text", text: errorMessage }], isError: true }; } }
  • Input schema using Zod for the tool, defining optional subscriptionId parameter.
    { title: "List Azure Resource Groups", description: "List resource groups in a selected Azure subscription using MCP elicitation", inputSchema: { subscriptionId: z.string().optional().describe("Azure subscription ID (will be elicited if not provided)") } },
  • Helper function to retrieve and format Azure subscriptions as typed options for use in MCP input elicitation enum.
    async function getSubscriptionOptions(): Promise<SubscriptionOption[]> { const { stdout } = await execAsync('az account list --output json', { timeout: 30000, maxBuffer: 1024 * 1024 }); const subscriptions = JSON.parse(stdout); return subscriptions.map((sub: any): SubscriptionOption => ({ id: sub.id, name: sub.name, label: `${sub.name}${sub.isDefault ? ' (ACTIVE)' : ''}`, isDefault: sub.isDefault })); }
  • TypeScript interface defining the shape of subscription options used in the helper and elicitation schema.
    interface SubscriptionOption { id: string; name: string; label: string; isDefault: boolean; }

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/ahemavathy/mcp'

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