Skip to main content
Glama

Google Cloud MCP Server

by krzko
mcp-protocol.test.ts9.86 kB
/** * MCP Protocol Compliance Tests * Tests adherence to Model Context Protocol specification 2025-06-18 */ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; // Import mocks first import '../mocks/google-cloud-mocks.js'; import { mockMcpServer } from '../mocks/google-cloud-mocks.js'; describe('MCP Protocol Compliance', () => { beforeEach(() => { vi.clearAllMocks(); }); afterEach(() => { vi.restoreAllMocks(); }); describe('Server Initialization', () => { it('should create MCP server with correct metadata', async () => { // This test verifies server creation matches MCP specification const { McpServer } = await import('@modelcontextprotocol/sdk/server/mcp.js'); expect(McpServer).toBeDefined(); expect(mockMcpServer).toBeDefined(); }); it('should support required capabilities', async () => { // Test that server declares required capabilities const capabilities = { prompts: {}, resources: {}, tools: {} }; expect(capabilities.prompts).toBeDefined(); expect(capabilities.resources).toBeDefined(); expect(capabilities.tools).toBeDefined(); }); }); describe('Tool Registration Compliance', () => { it('should register IAM tools with proper schema', async () => { const { registerIamTools } = await import('../../src/services/iam/tools.js'); registerIamTools(mockMcpServer as any); // Verify tools are registered with required fields const toolCalls = mockMcpServer.registerTool.mock.calls; toolCalls.forEach(call => { const [name, schema, handler] = call; expect(typeof name).toBe('string'); expect(schema).toHaveProperty('title'); expect(schema).toHaveProperty('description'); expect(schema).toHaveProperty('inputSchema'); expect(typeof handler).toBe('function'); }); }); it('should register billing tools with proper schema', async () => { vi.clearAllMocks(); const { registerBillingTools } = await import('../../src/services/billing/tools.js'); registerBillingTools(mockMcpServer as any); // Verify billing tools are registered with required fields const toolCalls = mockMcpServer.registerTool.mock.calls; expect(toolCalls.length).toBeGreaterThan(0); toolCalls.forEach(call => { const [name, schema, handler] = call; expect(typeof name).toBe('string'); expect(name).toMatch(/^gcp-billing-/); expect(schema).toHaveProperty('title'); expect(schema).toHaveProperty('description'); expect(schema).toHaveProperty('inputSchema'); expect(typeof handler).toBe('function'); }); }); it('should validate tool input schemas', async () => { const { registerIamTools } = await import('../../src/services/iam/tools.js'); registerIamTools(mockMcpServer as any); const toolCall = mockMcpServer.registerTool.mock.calls.find( call => call[0] === 'gcp-iam-get-project-policy' ); expect(toolCall).toBeDefined(); const schema = toolCall[1]; expect(schema.inputSchema).toBeDefined(); // Verify Zod schema structure if (schema.inputSchema.project) { expect(schema.inputSchema.project).toBeDefined(); } }); }); describe('Resource Registration Compliance', () => { it('should register IAM resources with proper templates', async () => { const { registerIamResources } = await import('../../src/services/iam/resources.js'); registerIamResources(mockMcpServer as any); // Verify resources are registered with MCP compliant structure expect(mockMcpServer.resource).toHaveBeenCalled(); const resourceCalls = mockMcpServer.resource.mock.calls; resourceCalls.forEach(call => { const [name, template, handler] = call; expect(typeof name).toBe('string'); expect(template).toBeDefined(); expect(typeof handler).toBe('function'); }); }); it('should register billing resources with proper templates', async () => { vi.clearAllMocks(); const { registerBillingResources } = await import('../../src/services/billing/resources.js'); registerBillingResources(mockMcpServer as any); // Verify billing resources are registered with MCP compliant structure expect(mockMcpServer.resource).toHaveBeenCalled(); const resourceCalls = mockMcpServer.resource.mock.calls; resourceCalls.forEach(call => { const [name, template, handler] = call; expect(typeof name).toBe('string'); expect(name).toMatch(/^gcp-billing-/); expect(template).toBeDefined(); expect(typeof handler).toBe('function'); }); }); }); describe('Response Format Compliance', () => { it('should return MCP-compliant IAM tool responses', async () => { const { registerIamTools } = await import('../../src/services/iam/tools.js'); registerIamTools(mockMcpServer as any); const toolCall = mockMcpServer.registerTool.mock.calls.find( call => call[0] === 'gcp-iam-test-project-permissions' ); const toolHandler = toolCall[2]; const result = await toolHandler({ permissions: ['test.permission'] }); // Verify MCP response structure expect(result).toHaveProperty('content'); expect(Array.isArray(result.content)).toBe(true); expect(result.content[0]).toHaveProperty('type'); expect(result.content[0]).toHaveProperty('text'); }); it('should return MCP-compliant billing tool responses', async () => { vi.clearAllMocks(); // Import and set up billing client mock const { mockBillingClient } = await import('../mocks/google-cloud-mocks.js'); const { createMockBillingAccount } = await import('../utils/test-helpers.js'); // Reset billing client mock for this test mockBillingClient.listBillingAccounts.mockResolvedValue([[createMockBillingAccount()], null]); const { registerBillingTools } = await import('../../src/services/billing/tools.js'); registerBillingTools(mockMcpServer as any); const toolCall = mockMcpServer.registerTool.mock.calls.find( call => call[0] === 'gcp-billing-list-accounts' ); const toolHandler = toolCall[2]; const result = await toolHandler({ pageSize: 10 }); // Verify MCP response structure expect(result).toHaveProperty('content'); expect(Array.isArray(result.content)).toBe(true); expect(result.content[0]).toHaveProperty('type'); expect(result.content[0]).toHaveProperty('text'); }); it('should handle errors in MCP-compliant format', async () => { const { registerIamTools } = await import('../../src/services/iam/tools.js'); // Mock error condition const { mockResourceManagerClient } = await import('../mocks/google-cloud-mocks.js'); mockResourceManagerClient.testIamPermissions.mockRejectedValue(new Error('Test error')); registerIamTools(mockMcpServer as any); const toolCall = mockMcpServer.registerTool.mock.calls.find( call => call[0] === 'gcp-iam-test-project-permissions' ); const toolHandler = toolCall[2]; const result = await toolHandler({ permissions: ['test.permission'] }); // Verify error response structure expect(result).toHaveProperty('content'); expect(result).toHaveProperty('isError'); expect(result.isError).toBe(true); }); }); describe('Security Best Practices Compliance', () => { it('should validate input parameters', async () => { const { registerIamTools } = await import('../../src/services/iam/tools.js'); registerIamTools(mockMcpServer as any); const toolCall = mockMcpServer.registerTool.mock.calls.find( call => call[0] === 'gcp-iam-test-resource-permissions' ); const toolHandler = toolCall[2]; // Test should handle invalid input gracefully try { await toolHandler({ resource: '', permissions: [] }); // Should not throw, but handle gracefully } catch (error) { // If it throws, it should be a handled error expect(error).toBeInstanceOf(Error); } }); it('should not expose sensitive information in errors', async () => { const { registerIamTools } = await import('../../src/services/iam/tools.js'); registerIamTools(mockMcpServer as any); const toolCall = mockMcpServer.registerTool.mock.calls.find( call => call[0] === 'gcp-iam-get-project-policy' ); const toolHandler = toolCall[2]; const result = await toolHandler({ project: 'test-project' }); // Verify no sensitive data in response const responseText = result.content[0].text; expect(responseText).not.toContain('password'); expect(responseText).not.toContain('secret'); expect(responseText).not.toContain('key'); }); }); describe('Transport Layer Compliance', () => { it('should support stdio transport', () => { const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js'); expect(StdioServerTransport).toBeDefined(); }); it('should handle UTF-8 encoding', () => { const testString = '🔐 IAM Policy Test ✅'; const encoded = Buffer.from(testString, 'utf-8'); const decoded = encoded.toString('utf-8'); expect(decoded).toBe(testString); }); }); });

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