Skip to main content
Glama

Google Cloud MCP Server

by krzko
resources.ts7.19 kB
/** * Google Cloud IAM resources for MCP */ import { McpServer, ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js"; import { getProjectId } from "../../utils/auth.js"; import { GcpMcpError } from "../../utils/error.js"; import { getResourceManagerClient, formatIamPolicy, IamPolicy, } from "./types.js"; import { logger } from "../../utils/logger.js"; /** * Registers Google Cloud IAM resources with the MCP server * * @param server The MCP server instance */ export function registerIamResources(server: McpServer): void { // Register a resource for project IAM policy server.resource( "gcp-iam-project-policy", new ResourceTemplate("gcp-iam://{projectId}/policy", { list: undefined }), async (uri, { projectId }) => { try { const actualProjectId = Array.isArray(projectId) ? projectId[0] : projectId || (await getProjectId()); const resourceManager = getResourceManagerClient(); logger.debug(`Fetching IAM policy for project: ${actualProjectId}`); const [policy] = await resourceManager.getIamPolicy({ resource: `projects/${actualProjectId}`, options: { requestedPolicyVersion: 3, }, }); if (!policy) { throw new GcpMcpError( `No IAM policy found for project: ${actualProjectId}`, "NOT_FOUND", 404, ); } const formattedPolicy = formatIamPolicy(policy as IamPolicy); return { contents: [ { uri: uri.href, mimeType: "text/markdown", text: `# Project IAM Policy\n\nProject: ${actualProjectId}\n\n${formattedPolicy}`, }, ], }; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : "Unknown error"; logger.error(`Error fetching project IAM policy: ${errorMessage}`); throw new GcpMcpError( `Failed to fetch IAM policy for project: ${errorMessage}`, "INTERNAL_ERROR", 500, ); } }, ); // Register a resource for IAM policy analysis summary server.resource( "gcp-iam-policy-summary", new ResourceTemplate("gcp-iam://{projectId}/summary", { list: undefined }), async (uri, { projectId }) => { try { const actualProjectId = Array.isArray(projectId) ? projectId[0] : projectId || (await getProjectId()); const resourceManager = getResourceManagerClient(); logger.debug( `Generating IAM policy summary for project: ${actualProjectId}`, ); const [policy] = await resourceManager.getIamPolicy({ resource: `projects/${actualProjectId}`, options: { requestedPolicyVersion: 3, }, }); if (!policy || !policy.bindings) { return { contents: [ { uri: uri.href, mimeType: "text/markdown", text: `# IAM Policy Summary\n\nProject: ${actualProjectId}\n\n**No IAM policy found or no bindings configured.**`, }, ], }; } let summary = `# IAM Policy Summary\n\nProject: ${actualProjectId}\n\n`; // Count different types of members const memberTypes = { users: 0, serviceAccounts: 0, groups: 0, domains: 0, allUsers: 0, allAuthenticatedUsers: 0, other: 0, }; const roleCount = policy.bindings.length; let totalMembers = 0; const uniqueRoles = new Set<string>(); policy.bindings.forEach((binding) => { if (binding.role) uniqueRoles.add(binding.role); if (binding.members) { totalMembers += binding.members.length; binding.members.forEach((member) => { if (member.startsWith("user:")) memberTypes.users++; else if (member.startsWith("serviceAccount:")) memberTypes.serviceAccounts++; else if (member.startsWith("group:")) memberTypes.groups++; else if (member.startsWith("domain:")) memberTypes.domains++; else if (member === "allUsers") memberTypes.allUsers++; else if (member === "allAuthenticatedUsers") memberTypes.allAuthenticatedUsers++; else memberTypes.other++; }); } }); summary += `## Overview\n\n`; summary += `- **Total Role Bindings:** ${roleCount}\n`; summary += `- **Unique Roles:** ${uniqueRoles.size}\n`; summary += `- **Total Member Assignments:** ${totalMembers}\n`; summary += `- **Policy Version:** ${policy.version || 1}\n\n`; summary += `## Member Types\n\n`; if (memberTypes.users > 0) summary += `- **Users:** ${memberTypes.users}\n`; if (memberTypes.serviceAccounts > 0) summary += `- **Service Accounts:** ${memberTypes.serviceAccounts}\n`; if (memberTypes.groups > 0) summary += `- **Groups:** ${memberTypes.groups}\n`; if (memberTypes.domains > 0) summary += `- **Domains:** ${memberTypes.domains}\n`; if (memberTypes.allUsers > 0) summary += `- **All Users (Public):** ${memberTypes.allUsers} ⚠️\n`; if (memberTypes.allAuthenticatedUsers > 0) summary += `- **All Authenticated Users:** ${memberTypes.allAuthenticatedUsers} ⚠️\n`; if (memberTypes.other > 0) summary += `- **Other:** ${memberTypes.other}\n`; if (memberTypes.allUsers > 0 || memberTypes.allAuthenticatedUsers > 0) { summary += `\n⚠️ **Security Notice:** This project has public access configured. Review these bindings carefully.\n`; } // List the most common roles const roleCounts = new Map<string, number>(); policy.bindings.forEach((binding) => { if (binding.role && binding.members) { roleCounts.set( binding.role, (roleCounts.get(binding.role) || 0) + binding.members.length, ); } }); const topRoles = Array.from(roleCounts.entries()) .sort((a, b) => b[1] - a[1]) .slice(0, 10); if (topRoles.length > 0) { summary += `\n## Most Assigned Roles\n\n`; topRoles.forEach(([role, count]) => { summary += `- **${role}:** ${count} assignments\n`; }); } return { contents: [ { uri: uri.href, mimeType: "text/markdown", text: summary, }, ], }; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : "Unknown error"; logger.error(`Error generating IAM policy summary: ${errorMessage}`); throw new GcpMcpError( `Failed to generate IAM policy summary: ${errorMessage}`, "INTERNAL_ERROR", 500, ); } }, ); }

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/krzko/google-cloud-mcp'

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