Skip to main content
Glama
iceener

Google Calendar MCP Server

by iceener
registry.ts4.39 kB
/** * Shared tool registry - single source of truth for all tools. * Tools defined here work in both Node.js and Cloudflare Workers. */ import type { ZodObject, ZodRawShape } from 'zod'; import type { ToolContext, ToolResult } from './types.js'; // Re-export types for convenience export type { SharedToolDefinition, ToolContext, ToolResult } from './types.js'; export { defineTool } from './types.js'; /** * Simplified tool interface for the registry (type-erased for storage). */ export interface RegisteredTool { name: string; title?: string; description: string; inputSchema: ZodObject<ZodRawShape>; outputSchema?: ZodRawShape; annotations?: Record<string, unknown>; handler: (args: Record<string, unknown>, context: ToolContext) => Promise<ToolResult>; } import { checkAvailabilityTool } from './check-availability.js'; import { createEventTool } from './create-event.js'; import { deleteEventTool } from './delete-event.js'; // Import all tools import { listCalendarsTool } from './list-calendars.js'; import { respondToEventTool } from './respond-to-event.js'; import { searchEventsTool } from './search-events.js'; import { updateEventTool } from './update-event.js'; /** * All shared tools available in both runtimes. * Add new tools here to make them available everywhere. */ export const sharedTools: RegisteredTool[] = [ listCalendarsTool as unknown as RegisteredTool, searchEventsTool as unknown as RegisteredTool, checkAvailabilityTool as unknown as RegisteredTool, createEventTool as unknown as RegisteredTool, updateEventTool as unknown as RegisteredTool, deleteEventTool as unknown as RegisteredTool, respondToEventTool as unknown as RegisteredTool, ]; /** * Get a tool by name. */ export function getSharedTool(name: string): RegisteredTool | undefined { return sharedTools.find((t) => t.name === name); } /** * Get all tool names. */ export function getSharedToolNames(): string[] { return sharedTools.map((t) => t.name); } /** * Execute a shared tool by name. * Handles input validation, output validation, and error wrapping. * * Per MCP spec: When outputSchema is defined, structuredContent is required * (unless isError is true). The SDK validates this automatically for Node, * and we replicate that behavior here for Workers. */ export async function executeSharedTool( name: string, args: Record<string, unknown>, context: ToolContext, ): Promise<ToolResult> { const tool = getSharedTool(name); if (!tool) { return { content: [{ type: 'text', text: `Unknown tool: ${name}` }], isError: true, }; } try { // Check for cancellation before starting if (context.signal?.aborted) { return { content: [{ type: 'text', text: 'Operation was cancelled' }], isError: true, }; } // Validate input using Zod schema const parseResult = tool.inputSchema.safeParse(args); if (!parseResult.success) { const errors = parseResult.error.errors .map( (e: { path: (string | number)[]; message: string }) => `${e.path.join('.')}: ${e.message}`, ) .join(', '); return { content: [{ type: 'text', text: `Invalid input: ${errors}` }], isError: true, }; } const result = await tool.handler( parseResult.data as Record<string, unknown>, context, ); // Validate outputSchema compliance (per MCP spec) // When outputSchema is defined, structuredContent is required unless isError is true if (tool.outputSchema && !result.isError) { if (!result.structuredContent) { return { content: [ { type: 'text', text: 'Tool with outputSchema must return structuredContent (unless isError is true)', }, ], isError: true, }; } // Note: Full Zod validation of structuredContent against outputSchema // could be added here if needed for stricter compliance } return result; } catch (error) { // Check if this was an abort if (context.signal?.aborted) { return { content: [{ type: 'text', text: 'Operation was cancelled' }], isError: true, }; } return { content: [{ type: 'text', text: `Tool error: ${(error as Error).message}` }], isError: true, }; } }

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/iceener/google-calendar-streamable-mcp-server'

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