Skip to main content
Glama

Google Calendar and Meet MCP Server

by INSIDE-HAIR
phase1-validation-complete.test.tsβ€’15.5 kB
/** * FASE 1 COMPLETADA: Tests para verificar que todas las 17 herramientas tienen validaciΓ³n Zod * Este test verifica que la Fase 1 de expansiΓ³n de validaciΓ³n se completΓ³ exitosamente */ import { describe, it, expect } from 'vitest'; import { ValidationSchemas, validateToolArgs } from '../src/validation/meetSchemas.js'; describe('FASE 1: ValidaciΓ³n Zod Completa - 17/17 Herramientas', () => { // Lista completa de las 21 herramientas del servidor const ALL_TOOLS = [ // Calendar API v3 (6 herramientas) 'calendar_v3_list_calendars', 'calendar_v3_list_events', 'calendar_v3_get_event', 'calendar_v3_create_event', 'calendar_v3_update_event', 'calendar_v3_delete_event', // Meet API v2 (15 herramientas) 'meet_v2_create_space', 'meet_v2_get_space', 'meet_v2_update_space', 'meet_v2_end_active_conference', 'meet_v2_list_conference_records', 'meet_v2_get_conference_record', 'meet_v2_list_recordings', 'meet_v2_get_recording', 'meet_v2_list_transcripts', 'meet_v2_get_transcript', 'meet_v2_list_transcript_entries', 'meet_v2_get_participant', 'meet_v2_list_participants', 'meet_v2_get_participant_session', 'meet_v2_list_participant_sessions' ]; describe('Schema Coverage Verification', () => { it('should have schemas for all 21 tools', () => { expect(ALL_TOOLS).toHaveLength(21); const schemasKeys = Object.keys(ValidationSchemas); expect(schemasKeys).toHaveLength(21); // Verificar que cada herramienta tiene su schema ALL_TOOLS.forEach(toolName => { expect(ValidationSchemas).toHaveProperty(toolName); expect(ValidationSchemas[toolName as keyof typeof ValidationSchemas]).toBeDefined(); }); }); it('should not have extra schemas beyond the 17 tools', () => { const schemasKeys = Object.keys(ValidationSchemas); const extraSchemas = schemasKeys.filter(key => !ALL_TOOLS.includes(key)); expect(extraSchemas).toHaveLength(0); }); }); describe('Calendar API v3 Validation (6 herramientas)', () => { it('calendar_v3_list_calendars - should validate empty args', () => { expect(() => validateToolArgs('calendar_v3_list_calendars', {})).not.toThrow(); }); it('calendar_v3_list_events - should validate with defaults', () => { const result = validateToolArgs('calendar_v3_list_events', {}); expect(result.max_results).toBe(10); expect(result.calendar_id).toBe('primary'); }); it('calendar_v3_list_events - should validate custom parameters', () => { const args = { max_results: 25, time_min: '2024-01-01T00:00:00Z', time_max: '2024-12-31T23:59:59Z', calendar_id: 'custom@example.com' }; const result = validateToolArgs('calendar_v3_list_events', args); expect(result.max_results).toBe(25); expect(result.time_min).toBe('2024-01-01T00:00:00Z'); }); it('calendar_v3_list_events - should reject invalid max_results', () => { expect(() => validateToolArgs('calendar_v3_list_events', { max_results: 0 })) .toThrow('Maximum results must be at least 1'); expect(() => validateToolArgs('calendar_v3_list_events', { max_results: 3000 })) .toThrow('Maximum results cannot exceed 2500'); }); it('calendar_v3_get_event - should require event_id', () => { expect(() => validateToolArgs('calendar_v3_get_event', {})) .toThrow('Required'); const result = validateToolArgs('calendar_v3_get_event', { event_id: 'test-event-123' }); expect(result.event_id).toBe('test-event-123'); }); it('calendar_v3_create_event - should validate complete event', () => { const eventData = { summary: 'Test Meeting', start_time: '2024-12-01T10:00:00Z', end_time: '2024-12-01T11:00:00Z', description: 'Test description', attendees: ['user@example.com', 'guest@example.com'], create_meet_conference: true, guest_can_invite_others: false }; const result = validateToolArgs('calendar_v3_create_event', eventData); expect(result.summary).toBe('Test Meeting'); expect(result.create_meet_conference).toBe(true); expect(result.guest_can_invite_others).toBe(false); expect(result.time_zone).toBe('UTC'); // default }); it('calendar_v3_create_event - should reject invalid times', () => { const eventData = { summary: 'Test Meeting', start_time: '2024-12-01T11:00:00Z', // End before start end_time: '2024-12-01T10:00:00Z', }; expect(() => validateToolArgs('calendar_v3_create_event', eventData)) .toThrow('End time must be after start time'); }); it('calendar_v3_update_event - should require event_id and validate optional fields', () => { expect(() => validateToolArgs('calendar_v3_update_event', {})) .toThrow('Required'); const updateData = { event_id: 'event-123', summary: 'Updated Meeting', start_time: '2024-12-01T10:00:00Z', end_time: '2024-12-01T11:00:00Z' }; const result = validateToolArgs('calendar_v3_update_event', updateData); expect(result.event_id).toBe('event-123'); expect(result.summary).toBe('Updated Meeting'); }); it('calendar_v3_delete_event - should require event_id', () => { expect(() => validateToolArgs('calendar_v3_delete_event', {})) .toThrow('Required'); const result = validateToolArgs('calendar_v3_delete_event', { event_id: 'delete-me-123' }); expect(result.event_id).toBe('delete-me-123'); }); }); describe('Meet API v2 Core Validation (5 herramientas principales)', () => { it('meet_v2_create_space - should validate with defaults', () => { const result = validateToolArgs('meet_v2_create_space', {}); expect(result.access_type).toBe('TRUSTED'); expect(result.enable_recording).toBe(false); expect(result.enable_transcription).toBe(false); expect(result.moderation_mode).toBe('OFF'); }); it('meet_v2_create_space - should validate custom configuration', () => { const config = { access_type: 'RESTRICTED', enable_recording: true, enable_transcription: true, enable_smart_notes: true, moderation_mode: 'ON', chat_restriction: 'HOSTS_ONLY', present_restriction: 'HOSTS_ONLY', default_join_as_viewer: true }; const result = validateToolArgs('meet_v2_create_space', config); expect(result.access_type).toBe('RESTRICTED'); expect(result.enable_recording).toBe(true); expect(result.enable_smart_notes).toBe(true); }); it('meet_v2_create_space - should enforce business logic rules', () => { // Recording + OPEN access should fail expect(() => validateToolArgs('meet_v2_create_space', { access_type: 'OPEN', enable_recording: true })).toThrow('Recording cannot be enabled for OPEN access meetings'); // Smart notes without transcription should fail expect(() => validateToolArgs('meet_v2_create_space', { enable_smart_notes: true, enable_transcription: false })).toThrow('Smart notes require transcription to be enabled'); }); it('meet_v2_get_space - should validate space name format', () => { expect(() => validateToolArgs('meet_v2_get_space', {})) .toThrow('Required'); expect(() => validateToolArgs('meet_v2_get_space', { space_name: 'invalid-format' })) .toThrow('Space name must be in format'); const result = validateToolArgs('meet_v2_get_space', { space_name: 'spaces/abc-defg-hij' }); expect(result.space_name).toBe('spaces/abc-defg-hij'); }); it('meet_v2_update_space - should validate space name and optional updates', () => { const updateData = { space_name: 'spaces/meeting-123', access_type: 'RESTRICTED', moderation_mode: 'ON' }; const result = validateToolArgs('meet_v2_update_space', updateData); expect(result.space_name).toBe('spaces/meeting-123'); expect(result.access_type).toBe('RESTRICTED'); }); it('meet_v2_list_conference_records - should validate page_size limits', () => { const result = validateToolArgs('meet_v2_list_conference_records', {}); expect(result.page_size).toBe(10); // default expect(() => validateToolArgs('meet_v2_list_conference_records', { page_size: 0 })) .toThrow('Page size must be at least 1'); expect(() => validateToolArgs('meet_v2_list_conference_records', { page_size: 100 })) .toThrow('Page size cannot exceed 50'); }); }); describe('Meet API v2 Advanced Validation (6 herramientas restantes)', () => { it('meet_v2_end_active_conference - should validate space name', () => { const result = validateToolArgs('meet_v2_end_active_conference', { space_name: 'spaces/end-this-meeting' }); expect(result.space_name).toBe('spaces/end-this-meeting'); }); it('meet_v2_get_conference_record - should validate conference record name format', () => { expect(() => validateToolArgs('meet_v2_get_conference_record', { conference_record_name: 'invalid-format' })).toThrow('Conference record name must be in format'); const result = validateToolArgs('meet_v2_get_conference_record', { conference_record_name: 'conferenceRecords/record-123' }); expect(result.conference_record_name).toBe('conferenceRecords/record-123'); }); it('meet_v2_list_recordings - should validate conference record name', () => { const result = validateToolArgs('meet_v2_list_recordings', { conference_record_name: 'conferenceRecords/with-recordings' }); expect(result.conference_record_name).toBe('conferenceRecords/with-recordings'); }); it('meet_v2_get_recording - should validate recording name format', () => { expect(() => validateToolArgs('meet_v2_get_recording', { recording_name: 'conferenceRecords/incomplete' })).toThrow('Recording name must be in format'); const result = validateToolArgs('meet_v2_get_recording', { recording_name: 'conferenceRecords/record-123/recordings/rec-456' }); expect(result.recording_name).toBe('conferenceRecords/record-123/recordings/rec-456'); }); it('meet_v2_list_transcripts - should validate conference record name', () => { const result = validateToolArgs('meet_v2_list_transcripts', { conference_record_name: 'conferenceRecords/with-transcripts' }); expect(result.conference_record_name).toBe('conferenceRecords/with-transcripts'); }); it('meet_v2_get_transcript - should validate transcript name format', () => { const result = validateToolArgs('meet_v2_get_transcript', { transcript_name: 'conferenceRecords/record-123/transcripts/trans-456' }); expect(result.transcript_name).toBe('conferenceRecords/record-123/transcripts/trans-456'); }); }); describe('Meet API v2 Participant Management (5 herramientas)', () => { it('meet_v2_list_transcript_entries - should validate transcript name and page_size', () => { const result = validateToolArgs('meet_v2_list_transcript_entries', { transcript_name: 'conferenceRecords/rec-123/transcripts/trans-456' }); expect(result.page_size).toBe(100); // default expect(() => validateToolArgs('meet_v2_list_transcript_entries', { transcript_name: 'conferenceRecords/rec-123/transcripts/trans-456', page_size: 1500 })).toThrow('Page size cannot exceed 1000'); }); it('meet_v2_get_participant - should validate participant name format', () => { const result = validateToolArgs('meet_v2_get_participant', { participant_name: 'conferenceRecords/rec-123/participants/part-456' }); expect(result.participant_name).toBe('conferenceRecords/rec-123/participants/part-456'); }); it('meet_v2_list_participants - should validate conference record and page_size', () => { const result = validateToolArgs('meet_v2_list_participants', { conference_record_name: 'conferenceRecords/with-participants' }); expect(result.page_size).toBe(10); // default expect(() => validateToolArgs('meet_v2_list_participants', { conference_record_name: 'conferenceRecords/with-participants', page_size: 150 })).toThrow('Page size cannot exceed 100'); }); it('meet_v2_get_participant_session - should validate session name format', () => { const sessionName = 'conferenceRecords/rec-123/participants/part-456/participantSessions/sess-789'; const result = validateToolArgs('meet_v2_get_participant_session', { participant_session_name: sessionName }); expect(result.participant_session_name).toBe(sessionName); }); it('meet_v2_list_participant_sessions - should validate participant name and page_size', () => { const result = validateToolArgs('meet_v2_list_participant_sessions', { participant_name: 'conferenceRecords/rec-123/participants/part-456' }); expect(result.page_size).toBe(10); // default }); }); describe('Error Handling Verification', () => { it('should provide helpful error messages for validation failures', () => { try { validateToolArgs('calendar_v3_create_event', { summary: '', // Empty title start_time: 'invalid-date', end_time: 'also-invalid' }); expect.fail('Should have thrown validation error'); } catch (error) { expect(error.message).toContain('❌ Validation failed for calendar_v3_create_event'); expect(error.message).toContain('Meeting title is required'); expect(error.message).toContain('Start time must be in ISO 8601 format'); expect(error.message).toContain('πŸ’‘ Tip: Check parameter format and required fields'); } }); it('should handle unknown tool names gracefully', () => { const result = validateToolArgs('unknown_tool', { any: 'data' }); expect(result).toEqual({ any: 'data' }); // Should return as-is for unknown tools }); }); describe('FASE 1 Success Metrics', () => { it('should achieve 100% validation coverage', () => { const totalTools = ALL_TOOLS.length; const validatedTools = Object.keys(ValidationSchemas).length; const coveragePercentage = (validatedTools / totalTools) * 100; expect(coveragePercentage).toBe(100); expect(validatedTools).toBe(21); }); it('should maintain backwards compatibility', () => { // All existing tools should still work with validateToolArgs const sampleValidations = [ ['calendar_v3_list_calendars', {}], ['calendar_v3_create_event', { summary: 'Test', start_time: '2024-12-01T10:00:00Z', end_time: '2024-12-01T11:00:00Z' }], ['meet_v2_create_space', {}], ['meet_v2_get_space', { space_name: 'spaces/test-123' }] ]; sampleValidations.forEach(([toolName, args]) => { expect(() => validateToolArgs(toolName as string, args)).not.toThrow(); }); }); }); });

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/INSIDE-HAIR/mcp-google-calendar-and-meet'

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