@node2flow/google-calendar-mcp 1.0.0

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.
package/src/types.ts ADDED
@@ -0,0 +1,317 @@
1
+ /**
2
+ * Google Calendar API v3 Types
3
+ */
4
+
5
+ // ========== DateTime ==========
6
+
7
+ export interface EventDateTime {
8
+ date?: string;
9
+ dateTime?: string;
10
+ timeZone?: string;
11
+ }
12
+
13
+ // ========== Event ==========
14
+
15
+ export interface Event {
16
+ kind?: string;
17
+ etag?: string;
18
+ id?: string;
19
+ status?: string;
20
+ htmlLink?: string;
21
+ created?: string;
22
+ updated?: string;
23
+ summary?: string;
24
+ description?: string;
25
+ location?: string;
26
+ colorId?: string;
27
+ creator?: EventPerson;
28
+ organizer?: EventPerson;
29
+ start?: EventDateTime;
30
+ end?: EventDateTime;
31
+ endTimeUnspecified?: boolean;
32
+ recurrence?: string[];
33
+ recurringEventId?: string;
34
+ originalStartTime?: EventDateTime;
35
+ transparency?: string;
36
+ visibility?: string;
37
+ iCalUID?: string;
38
+ sequence?: number;
39
+ attendees?: EventAttendee[];
40
+ attendeesOmitted?: boolean;
41
+ hangoutLink?: string;
42
+ conferenceData?: ConferenceData;
43
+ reminders?: EventReminders;
44
+ source?: EventSource;
45
+ attachments?: EventAttachment[];
46
+ eventType?: string;
47
+ }
48
+
49
+ export interface EventPerson {
50
+ id?: string;
51
+ email?: string;
52
+ displayName?: string;
53
+ self?: boolean;
54
+ }
55
+
56
+ export interface EventAttendee {
57
+ id?: string;
58
+ email?: string;
59
+ displayName?: string;
60
+ organizer?: boolean;
61
+ self?: boolean;
62
+ resource?: boolean;
63
+ optional?: boolean;
64
+ responseStatus?: string;
65
+ comment?: string;
66
+ additionalGuests?: number;
67
+ }
68
+
69
+ export interface ConferenceData {
70
+ createRequest?: ConferenceRequest;
71
+ entryPoints?: EntryPoint[];
72
+ conferenceSolution?: ConferenceSolution;
73
+ conferenceId?: string;
74
+ notes?: string;
75
+ }
76
+
77
+ export interface ConferenceRequest {
78
+ requestId?: string;
79
+ conferenceSolutionKey?: ConferenceSolutionKey;
80
+ status?: ConferenceRequestStatus;
81
+ }
82
+
83
+ export interface ConferenceSolutionKey {
84
+ type?: string;
85
+ }
86
+
87
+ export interface ConferenceRequestStatus {
88
+ statusCode?: string;
89
+ }
90
+
91
+ export interface EntryPoint {
92
+ entryPointType?: string;
93
+ uri?: string;
94
+ label?: string;
95
+ pin?: string;
96
+ accessCode?: string;
97
+ meetingCode?: string;
98
+ passcode?: string;
99
+ password?: string;
100
+ }
101
+
102
+ export interface ConferenceSolution {
103
+ key?: ConferenceSolutionKey;
104
+ name?: string;
105
+ iconUri?: string;
106
+ }
107
+
108
+ export interface EventReminders {
109
+ useDefault?: boolean;
110
+ overrides?: ReminderOverride[];
111
+ }
112
+
113
+ export interface ReminderOverride {
114
+ method?: string;
115
+ minutes?: number;
116
+ }
117
+
118
+ export interface EventSource {
119
+ url?: string;
120
+ title?: string;
121
+ }
122
+
123
+ export interface EventAttachment {
124
+ fileUrl?: string;
125
+ title?: string;
126
+ mimeType?: string;
127
+ iconLink?: string;
128
+ fileId?: string;
129
+ }
130
+
131
+ export interface EventList {
132
+ kind?: string;
133
+ etag?: string;
134
+ summary?: string;
135
+ description?: string;
136
+ updated?: string;
137
+ timeZone?: string;
138
+ accessRole?: string;
139
+ defaultReminders?: ReminderOverride[];
140
+ nextPageToken?: string;
141
+ nextSyncToken?: string;
142
+ items?: Event[];
143
+ }
144
+
145
+ // ========== CalendarList ==========
146
+
147
+ export interface CalendarListEntry {
148
+ kind?: string;
149
+ etag?: string;
150
+ id?: string;
151
+ summary?: string;
152
+ description?: string;
153
+ location?: string;
154
+ timeZone?: string;
155
+ summaryOverride?: string;
156
+ colorId?: string;
157
+ backgroundColor?: string;
158
+ foregroundColor?: string;
159
+ hidden?: boolean;
160
+ selected?: boolean;
161
+ accessRole?: string;
162
+ defaultReminders?: ReminderOverride[];
163
+ notificationSettings?: NotificationSettings;
164
+ primary?: boolean;
165
+ deleted?: boolean;
166
+ conferenceProperties?: ConferenceProperties;
167
+ }
168
+
169
+ export interface NotificationSettings {
170
+ notifications?: NotificationSetting[];
171
+ }
172
+
173
+ export interface NotificationSetting {
174
+ type?: string;
175
+ method?: string;
176
+ }
177
+
178
+ export interface ConferenceProperties {
179
+ allowedConferenceSolutionTypes?: string[];
180
+ }
181
+
182
+ export interface CalendarListList {
183
+ kind?: string;
184
+ etag?: string;
185
+ nextPageToken?: string;
186
+ nextSyncToken?: string;
187
+ items?: CalendarListEntry[];
188
+ }
189
+
190
+ // ========== Calendar ==========
191
+
192
+ export interface Calendar {
193
+ kind?: string;
194
+ etag?: string;
195
+ id?: string;
196
+ summary?: string;
197
+ description?: string;
198
+ location?: string;
199
+ timeZone?: string;
200
+ conferenceProperties?: ConferenceProperties;
201
+ }
202
+
203
+ // ========== ACL ==========
204
+
205
+ export interface AclRule {
206
+ kind?: string;
207
+ etag?: string;
208
+ id?: string;
209
+ scope?: AclScope;
210
+ role?: string;
211
+ }
212
+
213
+ export interface AclScope {
214
+ type?: string;
215
+ value?: string;
216
+ }
217
+
218
+ export interface AclList {
219
+ kind?: string;
220
+ etag?: string;
221
+ nextPageToken?: string;
222
+ nextSyncToken?: string;
223
+ items?: AclRule[];
224
+ }
225
+
226
+ // ========== FreeBusy ==========
227
+
228
+ export interface FreeBusyRequest {
229
+ timeMin: string;
230
+ timeMax: string;
231
+ timeZone?: string;
232
+ groupExpansionMax?: number;
233
+ calendarExpansionMax?: number;
234
+ items: FreeBusyRequestItem[];
235
+ }
236
+
237
+ export interface FreeBusyRequestItem {
238
+ id: string;
239
+ }
240
+
241
+ export interface FreeBusyResponse {
242
+ kind?: string;
243
+ timeMin?: string;
244
+ timeMax?: string;
245
+ groups?: Record<string, FreeBusyGroup>;
246
+ calendars?: Record<string, FreeBusyCalendar>;
247
+ }
248
+
249
+ export interface FreeBusyGroup {
250
+ errors?: ErrorEntry[];
251
+ calendars?: string[];
252
+ }
253
+
254
+ export interface FreeBusyCalendar {
255
+ errors?: ErrorEntry[];
256
+ busy?: TimePeriod[];
257
+ }
258
+
259
+ export interface ErrorEntry {
260
+ domain?: string;
261
+ reason?: string;
262
+ }
263
+
264
+ export interface TimePeriod {
265
+ start?: string;
266
+ end?: string;
267
+ }
268
+
269
+ // ========== Colors ==========
270
+
271
+ export interface Colors {
272
+ kind?: string;
273
+ updated?: string;
274
+ calendar?: Record<string, ColorDefinition>;
275
+ event?: Record<string, ColorDefinition>;
276
+ }
277
+
278
+ export interface ColorDefinition {
279
+ background?: string;
280
+ foreground?: string;
281
+ }
282
+
283
+ // ========== Settings ==========
284
+
285
+ export interface Setting {
286
+ kind?: string;
287
+ etag?: string;
288
+ id?: string;
289
+ value?: string;
290
+ }
291
+
292
+ export interface SettingsList {
293
+ kind?: string;
294
+ etag?: string;
295
+ nextPageToken?: string;
296
+ nextSyncToken?: string;
297
+ items?: Setting[];
298
+ }
299
+
300
+ // ========== Tool Definition ==========
301
+
302
+ export interface MCPToolDefinition {
303
+ name: string;
304
+ description: string;
305
+ inputSchema: {
306
+ type: 'object';
307
+ properties: Record<string, unknown>;
308
+ required?: string[];
309
+ };
310
+ annotations?: {
311
+ title?: string;
312
+ readOnlyHint?: boolean;
313
+ destructiveHint?: boolean;
314
+ idempotentHint?: boolean;
315
+ openWorldHint?: boolean;
316
+ };
317
+ }
package/src/worker.ts ADDED
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Cloudflare Worker entry — Stateless Streamable HTTP MCP
3
+ */
4
+
5
+ import {
6
+ WebStandardStreamableHTTPServerTransport,
7
+ } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
8
+
9
+ import { createServer } from './server.js';
10
+ import { TOOLS } from './tools.js';
11
+
12
+ function corsHeaders(): Record<string, string> {
13
+ return {
14
+ 'Access-Control-Allow-Origin': '*',
15
+ 'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',
16
+ 'Access-Control-Allow-Headers': 'Content-Type, mcp-session-id, Accept, mcp-protocol-version',
17
+ 'Access-Control-Expose-Headers': 'mcp-session-id',
18
+ };
19
+ }
20
+
21
+ function addCors(response: Response): Response {
22
+ const headers = new Headers(response.headers);
23
+ for (const [key, value] of Object.entries(corsHeaders())) {
24
+ headers.set(key, value);
25
+ }
26
+ return new Response(response.body, {
27
+ status: response.status,
28
+ statusText: response.statusText,
29
+ headers,
30
+ });
31
+ }
32
+
33
+ export default {
34
+ async fetch(request: Request): Promise<Response> {
35
+ const url = new URL(request.url);
36
+
37
+ if (request.method === 'OPTIONS') {
38
+ return new Response(null, { status: 204, headers: corsHeaders() });
39
+ }
40
+
41
+ if (url.pathname === '/' && request.method === 'GET') {
42
+ return addCors(Response.json({
43
+ name: 'google-calendar-mcp',
44
+ version: '1.0.0',
45
+ status: 'ok',
46
+ tools: TOOLS.length,
47
+ transport: 'streamable-http',
48
+ endpoints: { mcp: '/mcp' },
49
+ }));
50
+ }
51
+
52
+ if (url.pathname !== '/mcp') {
53
+ return addCors(new Response('Not Found', { status: 404 }));
54
+ }
55
+
56
+ if (request.method !== 'POST') {
57
+ return addCors(Response.json(
58
+ { jsonrpc: '2.0', error: { code: -32000, message: 'Method not allowed. Use POST.' }, id: null },
59
+ { status: 405 }
60
+ ));
61
+ }
62
+
63
+ const clientId = url.searchParams.get('GOOGLE_CLIENT_ID') || '';
64
+ const clientSecret = url.searchParams.get('GOOGLE_CLIENT_SECRET') || '';
65
+ const refreshToken = url.searchParams.get('GOOGLE_REFRESH_TOKEN') || '';
66
+ const config = clientId && clientSecret && refreshToken
67
+ ? { clientId, clientSecret, refreshToken }
68
+ : undefined;
69
+
70
+ try {
71
+ const transport = new WebStandardStreamableHTTPServerTransport({
72
+ sessionIdGenerator: undefined,
73
+ enableJsonResponse: true,
74
+ });
75
+
76
+ const server = createServer(config);
77
+ await server.connect(transport);
78
+
79
+ const response = await transport.handleRequest(request);
80
+ return addCors(response);
81
+ } catch (error: any) {
82
+ return addCors(Response.json(
83
+ { jsonrpc: '2.0', error: { code: -32603, message: error.message || 'Internal server error' }, id: null },
84
+ { status: 500 }
85
+ ));
86
+ }
87
+ },
88
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "Node16",
5
+ "moduleResolution": "Node16",
6
+ "outDir": "dist",
7
+ "rootDir": "src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "declaration": true,
13
+ "declarationMap": true,
14
+ "sourceMap": true
15
+ },
16
+ "include": ["src/**/*"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }
package/wrangler.toml ADDED
@@ -0,0 +1,14 @@
1
+ name = "google-calendar-mcp-community"
2
+ main = "src/worker.ts"
3
+ compatibility_date = "2025-01-01"
4
+ workers_dev = true
5
+
6
+ [[routes]]
7
+ pattern = "google-calendar-mcp-community.node2flow.net"
8
+ custom_domain = true
9
+
10
+ [placement]
11
+ mode = "smart"
12
+
13
+ [observability]
14
+ enabled = true