google-calendar-workspace-mcp-server 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +262 -0
  2. package/build/index.d.ts +2 -0
  3. package/build/index.integration-with-mock.d.ts +6 -0
  4. package/build/index.integration-with-mock.js +195 -0
  5. package/build/index.js +35 -0
  6. package/package.json +49 -0
  7. package/shared/calendar-client/lib/api-errors.d.ts +4 -0
  8. package/shared/calendar-client/lib/api-errors.js +25 -0
  9. package/shared/calendar-client/lib/create-event.d.ts +2 -0
  10. package/shared/calendar-client/lib/create-event.js +13 -0
  11. package/shared/calendar-client/lib/get-event.d.ts +2 -0
  12. package/shared/calendar-client/lib/get-event.js +9 -0
  13. package/shared/calendar-client/lib/list-calendars.d.ts +5 -0
  14. package/shared/calendar-client/lib/list-calendars.js +14 -0
  15. package/shared/calendar-client/lib/list-events.d.ts +10 -0
  16. package/shared/calendar-client/lib/list-events.js +24 -0
  17. package/shared/calendar-client/lib/query-freebusy.d.ts +2 -0
  18. package/shared/calendar-client/lib/query-freebusy.js +13 -0
  19. package/shared/index.d.ts +2 -0
  20. package/shared/index.js +2 -0
  21. package/shared/logging.d.ts +10 -0
  22. package/shared/logging.js +23 -0
  23. package/shared/server.d.ts +130 -0
  24. package/shared/server.js +132 -0
  25. package/shared/tools/create-event.d.ts +110 -0
  26. package/shared/tools/create-event.js +195 -0
  27. package/shared/tools/get-event.d.ts +44 -0
  28. package/shared/tools/get-event.js +154 -0
  29. package/shared/tools/list-calendars.d.ts +36 -0
  30. package/shared/tools/list-calendars.js +88 -0
  31. package/shared/tools/list-events.d.ts +79 -0
  32. package/shared/tools/list-events.js +176 -0
  33. package/shared/tools/query-freebusy.d.ts +61 -0
  34. package/shared/tools/query-freebusy.js +110 -0
  35. package/shared/tools.d.ts +3 -0
  36. package/shared/tools.js +41 -0
  37. package/shared/types.d.ts +111 -0
  38. package/shared/types.js +4 -0
@@ -0,0 +1,110 @@
1
+ import { z } from 'zod';
2
+ import { logError } from '../logging.js';
3
+ export const QueryFreebusySchema = z.object({
4
+ time_min: z
5
+ .string()
6
+ .describe('Start time for the query in RFC3339 format (e.g., "2024-01-01T00:00:00Z").'),
7
+ time_max: z
8
+ .string()
9
+ .describe('End time for the query in RFC3339 format (e.g., "2024-01-01T23:59:59Z").'),
10
+ calendar_ids: z
11
+ .array(z.string())
12
+ .min(1)
13
+ .describe('List of calendar IDs to check availability for. Use "primary" for the user\'s primary calendar.'),
14
+ timezone: z
15
+ .string()
16
+ .optional()
17
+ .describe('Time zone for the query (e.g., "America/New_York"). Optional.'),
18
+ });
19
+ export function queryFreebusyTool(server, clientFactory) {
20
+ return {
21
+ name: 'gcal_query_freebusy',
22
+ description: 'Queries free/busy information for one or more calendars within a specified time range. ' +
23
+ 'Returns time periods when calendars are busy (have events scheduled). ' +
24
+ 'Useful for finding available meeting times, checking if someone is free, or scheduling around existing events.',
25
+ inputSchema: {
26
+ type: 'object',
27
+ properties: {
28
+ time_min: {
29
+ type: 'string',
30
+ description: QueryFreebusySchema.shape.time_min.description,
31
+ },
32
+ time_max: {
33
+ type: 'string',
34
+ description: QueryFreebusySchema.shape.time_max.description,
35
+ },
36
+ calendar_ids: {
37
+ type: 'array',
38
+ items: { type: 'string' },
39
+ description: QueryFreebusySchema.shape.calendar_ids.description,
40
+ },
41
+ timezone: {
42
+ type: 'string',
43
+ description: QueryFreebusySchema.shape.timezone.description,
44
+ },
45
+ },
46
+ required: ['time_min', 'time_max', 'calendar_ids'],
47
+ },
48
+ handler: async (args) => {
49
+ try {
50
+ const parsed = QueryFreebusySchema.parse(args);
51
+ const client = clientFactory();
52
+ const request = {
53
+ timeMin: parsed.time_min,
54
+ timeMax: parsed.time_max,
55
+ items: parsed.calendar_ids.map((id) => ({ id })),
56
+ timeZone: parsed.timezone,
57
+ };
58
+ const result = await client.queryFreebusy(request);
59
+ let output = `# Free/Busy Information\n\n`;
60
+ output += `**Time Range:** ${new Date(result.timeMin).toLocaleString()} to ${new Date(result.timeMax).toLocaleString()}\n\n`;
61
+ for (const calendarId of parsed.calendar_ids) {
62
+ const calendarInfo = result.calendars[calendarId];
63
+ output += `## Calendar: ${calendarId}\n\n`;
64
+ if (calendarInfo.errors && calendarInfo.errors.length > 0) {
65
+ output += `**Errors:**\n`;
66
+ for (const error of calendarInfo.errors) {
67
+ output += `- ${error.domain}: ${error.reason}\n`;
68
+ }
69
+ output += '\n';
70
+ continue;
71
+ }
72
+ const busyPeriods = calendarInfo.busy || [];
73
+ if (busyPeriods.length === 0) {
74
+ output += `**Status:** Free for the entire time range\n\n`;
75
+ }
76
+ else {
77
+ output += `**Busy Periods:** ${busyPeriods.length}\n\n`;
78
+ for (const period of busyPeriods) {
79
+ const start = new Date(period.start).toLocaleString();
80
+ const end = new Date(period.end).toLocaleString();
81
+ output += `- ${start} to ${end}\n`;
82
+ }
83
+ output += '\n';
84
+ }
85
+ output += '---\n\n';
86
+ }
87
+ return {
88
+ content: [
89
+ {
90
+ type: 'text',
91
+ text: output,
92
+ },
93
+ ],
94
+ };
95
+ }
96
+ catch (error) {
97
+ logError('query-freebusy-tool', error);
98
+ return {
99
+ content: [
100
+ {
101
+ type: 'text',
102
+ text: `Error querying free/busy: ${error instanceof Error ? error.message : String(error)}`,
103
+ },
104
+ ],
105
+ isError: true,
106
+ };
107
+ }
108
+ },
109
+ };
110
+ }
@@ -0,0 +1,3 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import type { ClientFactory } from './server.js';
3
+ export declare function createRegisterTools(clientFactory: ClientFactory): (server: Server) => void;
@@ -0,0 +1,41 @@
1
+ import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
2
+ import { listEventsTool } from './tools/list-events.js';
3
+ import { getEventTool } from './tools/get-event.js';
4
+ import { createEventTool } from './tools/create-event.js';
5
+ import { listCalendarsTool } from './tools/list-calendars.js';
6
+ import { queryFreebusyTool } from './tools/query-freebusy.js';
7
+ const ALL_TOOLS = [
8
+ listEventsTool,
9
+ getEventTool,
10
+ createEventTool,
11
+ listCalendarsTool,
12
+ queryFreebusyTool,
13
+ ];
14
+ export function createRegisterTools(clientFactory) {
15
+ return (server) => {
16
+ const tools = ALL_TOOLS.map((factory) => factory(server, clientFactory));
17
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
18
+ tools: tools.map((tool) => ({
19
+ name: tool.name,
20
+ description: tool.description,
21
+ inputSchema: tool.inputSchema,
22
+ })),
23
+ }));
24
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
25
+ const { name, arguments: args } = request.params;
26
+ const tool = tools.find((t) => t.name === name);
27
+ if (!tool) {
28
+ return {
29
+ content: [
30
+ {
31
+ type: 'text',
32
+ text: `Unknown tool: ${name}`,
33
+ },
34
+ ],
35
+ isError: true,
36
+ };
37
+ }
38
+ return await tool.handler(args || {});
39
+ });
40
+ };
41
+ }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Google Calendar API type definitions
3
+ */
4
+ export interface CalendarEvent {
5
+ id: string;
6
+ status?: string;
7
+ htmlLink?: string;
8
+ created?: string;
9
+ updated?: string;
10
+ summary?: string;
11
+ description?: string;
12
+ location?: string;
13
+ start?: {
14
+ dateTime?: string;
15
+ date?: string;
16
+ timeZone?: string;
17
+ };
18
+ end?: {
19
+ dateTime?: string;
20
+ date?: string;
21
+ timeZone?: string;
22
+ };
23
+ attendees?: Array<{
24
+ email: string;
25
+ displayName?: string;
26
+ responseStatus?: string;
27
+ organizer?: boolean;
28
+ self?: boolean;
29
+ }>;
30
+ organizer?: {
31
+ email: string;
32
+ displayName?: string;
33
+ self?: boolean;
34
+ };
35
+ creator?: {
36
+ email: string;
37
+ displayName?: string;
38
+ self?: boolean;
39
+ };
40
+ recurrence?: string[];
41
+ recurringEventId?: string;
42
+ reminders?: {
43
+ useDefault: boolean;
44
+ overrides?: Array<{
45
+ method: string;
46
+ minutes: number;
47
+ }>;
48
+ };
49
+ transparency?: string;
50
+ visibility?: string;
51
+ colorId?: string;
52
+ iCalUID?: string;
53
+ sequence?: number;
54
+ }
55
+ export interface CalendarEventList {
56
+ kind: string;
57
+ etag: string;
58
+ summary: string;
59
+ updated: string;
60
+ timeZone: string;
61
+ accessRole: string;
62
+ items?: CalendarEvent[];
63
+ nextPageToken?: string;
64
+ nextSyncToken?: string;
65
+ }
66
+ export interface Calendar {
67
+ kind: string;
68
+ etag: string;
69
+ id: string;
70
+ summary: string;
71
+ description?: string;
72
+ location?: string;
73
+ timeZone: string;
74
+ selected?: boolean;
75
+ accessRole: string;
76
+ primary?: boolean;
77
+ backgroundColor?: string;
78
+ foregroundColor?: string;
79
+ }
80
+ export interface CalendarList {
81
+ kind: string;
82
+ etag: string;
83
+ items: Calendar[];
84
+ nextPageToken?: string;
85
+ nextSyncToken?: string;
86
+ }
87
+ export interface FreeBusyRequest {
88
+ timeMin: string;
89
+ timeMax: string;
90
+ items: Array<{
91
+ id: string;
92
+ }>;
93
+ timeZone?: string;
94
+ }
95
+ export interface FreeBusyResponse {
96
+ kind: string;
97
+ timeMin: string;
98
+ timeMax: string;
99
+ calendars: {
100
+ [calendarId: string]: {
101
+ busy: Array<{
102
+ start: string;
103
+ end: string;
104
+ }>;
105
+ errors?: Array<{
106
+ domain: string;
107
+ reason: string;
108
+ }>;
109
+ };
110
+ };
111
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Google Calendar API type definitions
3
+ */
4
+ export {};