Skip to main content
Glama

Google Calendar MCP

#!/bin/bash # Docker Testing Script for Google Calendar MCP Server # Tests Docker container functionality including stdio/HTTP modes and calendar integration set -e # Exit on any error # Configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" TEST_TIMEOUT=120 HTTP_PORT=3001 # Use different port to avoid conflicts CONTAINER_NAME="test-calendar-mcp" CONTAINER_NAME_STDIO="test-calendar-mcp-stdio" CONTAINER_NAME_HTTP="test-calendar-mcp-http" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Logging functions log_info() { echo -e "${BLUE}ℹ️ $1${NC}" } log_success() { echo -e "${GREEN}✅ $1${NC}" } log_warn() { echo -e "${YELLOW}⚠️ $1${NC}" } log_error() { echo -e "${RED}❌ $1${NC}" } # Cleanup function cleanup() { log_info "Cleaning up test containers..." # Stop and remove containers docker stop "$CONTAINER_NAME_STDIO" 2>/dev/null || true docker stop "$CONTAINER_NAME_HTTP" 2>/dev/null || true docker rm "$CONTAINER_NAME_STDIO" 2>/dev/null || true docker rm "$CONTAINER_NAME_HTTP" 2>/dev/null || true # Remove test network if it exists docker network rm mcp-test-network 2>/dev/null || true log_info "Cleanup completed" } # Trap to ensure cleanup on exit trap cleanup EXIT # Check prerequisites check_prerequisites() { log_info "Checking prerequisites..." # Check Docker if ! command -v docker &> /dev/null; then log_error "Docker is not installed" exit 1 fi # Check docker compose (modern command) if ! docker compose version &> /dev/null; then log_error "Docker Compose plugin is not installed" log_info "Please install Docker Compose plugin: https://docs.docker.com/compose/install/" exit 1 fi # Check OAuth credentials if [[ ! -f "$PROJECT_ROOT/gcp-oauth.keys.json" ]]; then log_error "OAuth credentials file not found: gcp-oauth.keys.json" log_info "Please download OAuth credentials from Google Cloud Console" exit 1 fi # Check environment variables for integration tests if [[ -z "$TEST_CALENDAR_ID" ]]; then log_warn "TEST_CALENDAR_ID not set - integration tests will be limited" fi log_success "Prerequisites check passed" } # Build Docker image build_image() { log_info "Building Docker image..." cd "$PROJECT_ROOT" docker build -t google-calendar-mcp:test . log_success "Docker image built successfully" } # Test container startup and basic functionality test_container_health() { local mode=$1 local container_name=$2 log_info "Testing $mode mode container health..." case $mode in "stdio") # Start stdio container with shell to keep it running docker run -d \ --name "$container_name" \ -v "$PROJECT_ROOT/gcp-oauth.keys.json:/app/gcp-oauth.keys.json:ro" \ -v mcp-test-tokens:/home/nodejs/.config/google-calendar-mcp \ -e NODE_ENV=test \ -e TRANSPORT=stdio \ --entrypoint=/bin/sh \ google-calendar-mcp:test -c "while true; do sleep 30; done" ;; "http") # Start HTTP container docker run -d \ --name "$container_name" \ -p "$HTTP_PORT:3000" \ -v "$PROJECT_ROOT/gcp-oauth.keys.json:/app/gcp-oauth.keys.json:ro" \ -v mcp-test-tokens:/home/nodejs/.config/google-calendar-mcp \ -e NODE_ENV=test \ -e TRANSPORT=http \ -e HOST=0.0.0.0 \ -e PORT=3000 \ google-calendar-mcp:test ;; esac # Wait for container to be ready log_info "Waiting for container to be ready..." sleep 5 # Check if container is running if ! docker ps | grep -q "$container_name"; then log_error "Container $container_name failed to start" docker logs "$container_name" return 1 fi log_success "$mode mode container is healthy" } # Test HTTP endpoint accessibility test_http_endpoints() { log_info "Testing HTTP endpoints..." # Wait for HTTP server to be ready for i in {1..30}; do if curl -s "http://localhost:$HTTP_PORT/health" > /dev/null 2>&1; then break fi sleep 1 if [[ $i -eq 30 ]]; then log_error "HTTP server failed to start within 30 seconds" docker logs "$CONTAINER_NAME_HTTP" return 1 fi done # Test health endpoint if ! curl -s "http://localhost:$HTTP_PORT/health" | grep -q "healthy"; then log_error "Health endpoint not responding correctly" return 1 fi # Test info endpoint if ! curl -s "http://localhost:$HTTP_PORT/info" > /dev/null; then log_error "Info endpoint not accessible" return 1 fi log_success "HTTP endpoints are accessible" } # Test MCP tool listing via Docker test_mcp_tools() { local container_name=$1 log_info "Testing MCP tool availability in container..." # Create a simple Node.js script to test MCP connection cat > "$PROJECT_ROOT/test-mcp-connection.js" << 'EOF' const { Client } = require("@modelcontextprotocol/sdk/client/index.js"); const { StdioClientTransport } = require("@modelcontextprotocol/sdk/client/stdio.js"); const { spawn } = require('child_process'); async function testMCPConnection() { const client = new Client({ name: "docker-test-client", version: "1.0.0" }, { capabilities: { tools: {} } }); try { // For stdio mode, exec into the container const transport = new StdioClientTransport({ command: 'docker', args: ['exec', '-i', process.argv[2], 'npm', 'start'], env: { ...process.env, NODE_ENV: 'test' } }); await client.connect(transport); const tools = await client.listTools(); console.log(`✅ Successfully connected to MCP server in container`); console.log(`📋 Available tools: ${tools.tools.length}`); // Test a simple tool call (list-calendars doesn't require auth setup) try { const result = await client.callTool({ name: 'list-calendars', arguments: {} }); console.log(`🔧 Tool execution test: SUCCESS`); } catch (toolError) { // Expected for auth issues in test environment console.log(`🔧 Tool execution test: ${toolError.message.includes('auth') ? 'AUTH_REQUIRED (expected)' : 'FAILED'}`); } await client.close(); process.exit(0); } catch (error) { console.error(`❌ MCP connection failed:`, error.message); process.exit(1); } } if (process.argv.length < 3) { console.error('Usage: node test-mcp-connection.js <container-name>'); process.exit(1); } testMCPConnection(); EOF # Run the MCP connection test if node "$PROJECT_ROOT/test-mcp-connection.js" "$container_name"; then log_success "MCP tools accessible via Docker" else log_error "MCP tools test failed" return 1 fi # Cleanup test file rm -f "$PROJECT_ROOT/test-mcp-connection.js" } # Test Docker Compose integration (simplified setup) test_docker_compose() { log_info "Testing Docker Compose integration..." cd "$PROJECT_ROOT" # Test stdio mode (default) docker compose up -d sleep 5 if ! docker compose ps | grep -q "calendar-mcp.*Up"; then log_error "Docker Compose stdio mode failed" docker compose logs calendar-mcp return 1 fi docker compose down # Test HTTP mode by temporarily modifying compose file log_info "Testing HTTP mode (requires manual setup)..." log_warn "HTTP mode test skipped - requires manual docker-compose.yml edit" log_info "To test HTTP mode manually:" log_info "1. Uncomment ports and environment sections in docker-compose.yml" log_info "2. Run: docker compose up -d" log_info "3. Test: curl http://localhost:3000/health" log_success "Docker Compose integration working" } # Test authentication setup (if credentials available) test_auth_setup() { log_info "Testing authentication setup in container..." # This will test if the auth command works (may fail due to interactive nature) if docker exec "$CONTAINER_NAME_STDIO" npm run auth --help > /dev/null 2>&1; then log_success "Auth command accessible in container" else log_warn "Auth command test inconclusive (expected for non-interactive environment)" fi # Test token file paths are accessible if docker exec "$CONTAINER_NAME_STDIO" ls -la /home/nodejs/.config/google-calendar-mcp/ > /dev/null 2>&1; then log_success "Token storage directory accessible" else log_error "Token storage directory not accessible" return 1 fi } # Run integration tests against Docker container (if environment supports it) test_calendar_integration() { if [[ -z "$TEST_CALENDAR_ID" || -z "$CLAUDE_API_KEY" ]]; then log_warn "Skipping calendar integration tests (missing TEST_CALENDAR_ID or CLAUDE_API_KEY)" return 0 fi log_info "Running calendar integration tests against Docker container..." # Use existing integration test but point it to Docker container cd "$PROJECT_ROOT" # Set environment to use Docker container export DOCKER_CONTAINER_NAME="$CONTAINER_NAME_STDIO" export USE_DOCKER_CONTAINER=true # Run subset of integration tests if timeout $TEST_TIMEOUT npm run test:integration -- --reporter=verbose --run docker 2>/dev/null; then log_success "Calendar integration tests passed" else log_warn "Calendar integration tests incomplete (may require manual auth)" fi } # Performance testing test_performance() { log_info "Running basic performance tests..." # Test HTTP response times local avg_response_time avg_response_time=$(curl -o /dev/null -s -w '%{time_total}\n' \ "http://localhost:$HTTP_PORT/health" \ "http://localhost:$HTTP_PORT/health" \ "http://localhost:$HTTP_PORT/health" | \ awk '{sum+=$1} END {print sum/NR}') echo "Average HTTP response time: ${avg_response_time}s" # Test container resource usage local memory_usage memory_usage=$(docker stats --no-stream --format "{{.MemUsage}}" "$CONTAINER_NAME_HTTP" | cut -d'/' -f1) echo "Container memory usage: $memory_usage" log_success "Performance tests completed" } # Main test execution main() { log_info "🐳 Starting Docker integration tests for Google Calendar MCP Server" # Cleanup any existing test containers cleanup # Run test suite check_prerequisites build_image # Test stdio mode test_container_health "stdio" "$CONTAINER_NAME_STDIO" test_mcp_tools "$CONTAINER_NAME_STDIO" test_auth_setup # Test HTTP mode test_container_health "http" "$CONTAINER_NAME_HTTP" test_http_endpoints test_performance # Test Docker Compose integration test_docker_compose # Test calendar integration (if environment supports it) test_calendar_integration log_success "🎉 All Docker tests completed successfully!" # Print summary echo "" echo "📋 Test Summary:" echo " ✅ Container Health (stdio & HTTP)" echo " ✅ MCP Tool Accessibility" echo " ✅ HTTP Endpoint Testing" echo " ✅ Docker Compose Integration" echo " ✅ Authentication Setup" echo " ✅ Performance Metrics" if [[ -n "$TEST_CALENDAR_ID" && -n "$CLAUDE_API_KEY" ]]; then echo " ✅ Calendar Integration" else echo " ⚠️ Calendar Integration (skipped - missing env vars)" fi } # Handle command line arguments case "${1:-}" in --help|-h) echo "Docker Testing Script for Google Calendar MCP Server" echo "" echo "Usage: $0 [options]" echo "" echo "Options:" echo " --help, -h Show this help message" echo " --quick Run only essential tests (faster)" echo " --integration Run full integration tests (requires auth)" echo "" echo "Environment Variables:" echo " TEST_CALENDAR_ID Calendar ID for integration tests" echo " CLAUDE_API_KEY Anthropic API key for Claude integration" echo " INVITEE_1, INVITEE_2 Email addresses for event testing" echo "" echo "Prerequisites:" echo " - Docker and Docker Compose plugin installed" echo " - gcp-oauth.keys.json file in project root" echo " - For integration tests: authenticated test account" exit 0 ;; --quick) log_info "Running quick Docker tests only..." check_prerequisites build_image test_container_health "stdio" "$CONTAINER_NAME_STDIO" test_container_health "http" "$CONTAINER_NAME_HTTP" test_http_endpoints test_docker_compose log_success "Quick tests completed!" ;; --integration) if [[ -z "$TEST_CALENDAR_ID" ]]; then log_error "--integration requires TEST_CALENDAR_ID environment variable" exit 1 fi main ;; "") main ;; *) log_error "Unknown option: $1" echo "Use --help for usage information" exit 1 ;; esac

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/nspady/google-calendar-mcp'

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