google-tools-mcp 1.2.12 → 2.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/LICENSE +21 -21
- package/README.md +537 -276
- package/dist/cachedToolsList.js +52 -52
- package/dist/googleDocsApiHelpers.js +76 -12
- package/dist/helpers.js +572 -252
- package/dist/httpAuth.js +296 -0
- package/dist/index.js +162 -11
- package/dist/logger.js +87 -87
- package/dist/markdown-transformer/docsToMarkdown.js +128 -0
- package/dist/markdown-transformer/index.js +17 -7
- package/dist/markdown-transformer/markdownToDocs.js +185 -27
- package/dist/readTracker.js +136 -17
- package/dist/sessionContext.js +37 -0
- package/dist/setup.js +187 -9
- package/dist/tools/calendar/getBusy.js +64 -64
- package/dist/tools/calendar/getEvents.js +141 -141
- package/dist/tools/calendar/getFree.js +225 -225
- package/dist/tools/calendar/index.js +19 -19
- package/dist/tools/calendar/listCalendars.js +38 -38
- package/dist/tools/calendar/listRecurringInstances.js +83 -83
- package/dist/tools/calendar/manageCalendar.js +121 -121
- package/dist/tools/calendar/manageEvent.js +258 -258
- package/dist/tools/calendar/moveEvent.js +66 -66
- package/dist/tools/docs/addTab.js +10 -12
- package/dist/tools/docs/appendToGoogleDoc.js +9 -4
- package/dist/tools/docs/deleteRange.js +9 -4
- package/dist/tools/docs/findAndReplace.js +9 -4
- package/dist/tools/docs/formatting/applyParagraphStyle.js +4 -1
- package/dist/tools/docs/formatting/getFormatting.js +171 -171
- package/dist/tools/docs/insertImage.js +15 -2
- package/dist/tools/docs/insertPageBreak.js +4 -1
- package/dist/tools/docs/insertTable.js +4 -1
- package/dist/tools/docs/insertTableWithData.js +4 -1
- package/dist/tools/docs/modifyText.js +14 -4
- package/dist/tools/docs/modifyText.test.js +84 -84
- package/dist/tools/docs/readGoogleDoc.js +71 -11
- package/dist/tools/docs/renameTab.js +12 -14
- package/dist/tools/drafts.js +165 -165
- package/dist/tools/drive/createDocument.js +12 -0
- package/dist/tools/drive/downloadFile.js +268 -268
- package/dist/tools/drive/getFileInfo.js +48 -48
- package/dist/tools/drive/getFilePath.js +50 -50
- package/dist/tools/drive/listDriveFiles.js +112 -112
- package/dist/tools/drive/listSharedDrives.js +52 -52
- package/dist/tools/drive/listSharedWithMe.js +97 -97
- package/dist/tools/drive/uploadFile.js +111 -111
- package/dist/tools/extras/index.js +9 -9
- package/dist/tools/extras/readDriveFile.js +197 -196
- package/dist/tools/extras/readFile.js +84 -84
- package/dist/tools/extras/searchFileContents.js +81 -81
- package/dist/tools/forms/batchUpdateForm.js +81 -81
- package/dist/tools/forms/createForm.js +54 -54
- package/dist/tools/forms/getForm.js +118 -118
- package/dist/tools/forms/getFormResponse.js +45 -45
- package/dist/tools/forms/index.js +15 -15
- package/dist/tools/forms/listFormResponses.js +56 -56
- package/dist/tools/forms/setPublishSettings.js +59 -59
- package/dist/tools/gmail/drafts.js +165 -165
- package/dist/tools/gmail/labels.js +54 -83
- package/dist/tools/gmail/messages.js +444 -441
- package/dist/tools/gmail/settings.js +358 -528
- package/dist/tools/gmail/threads.js +286 -164
- package/dist/tools/index.js +511 -473
- package/dist/tools/labels.js +103 -103
- package/dist/tools/legacyAliases.js +426 -0
- package/dist/tools/maps/directions.js +72 -0
- package/dist/tools/maps/geocode.js +16 -0
- package/dist/tools/maps/index.js +15 -0
- package/dist/tools/maps/mapsClient.js +83 -0
- package/dist/tools/maps/placeDetails.js +16 -0
- package/dist/tools/maps/reverseGeocode.js +19 -0
- package/dist/tools/maps/searchNearby.js +54 -0
- package/dist/tools/maps/searchPlaces.js +24 -0
- package/dist/tools/messages.js +448 -448
- package/dist/tools/settings.js +528 -528
- package/dist/tools/slides/createPresentation.js +104 -104
- package/dist/tools/slides/createShape.js +92 -92
- package/dist/tools/slides/createTextBox.js +82 -82
- package/dist/tools/slides/deleteSlide.js +30 -30
- package/dist/tools/slides/duplicateSlide.js +37 -37
- package/dist/tools/slides/exportThumbnail.js +42 -42
- package/dist/tools/slides/formatParagraph.js +72 -72
- package/dist/tools/slides/formatText.js +84 -84
- package/dist/tools/slides/getPresentation.js +87 -87
- package/dist/tools/slides/index.js +33 -33
- package/dist/tools/slides/reorderSlides.js +41 -41
- package/dist/tools/slides/replaceAllText.js +46 -46
- package/dist/tools/slides/setBackground.js +58 -58
- package/dist/tools/slides/speakerNotes.js +102 -102
- package/dist/tools/slides/styleShape.js +111 -111
- package/dist/tools/slides/updatePresentation.js +128 -128
- package/dist/tools/threads.js +145 -145
- package/dist/tools/utils/appendMarkdownToGoogleDoc.js +30 -6
- package/dist/tools/utils/replaceDocumentWithMarkdown.js +71 -8
- package/dist/updateCheck.js +202 -0
- package/dist/workspace.js +122 -0
- package/package.json +82 -81
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
import { UserError } from 'fastmcp';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import { getCalendarClient } from '../../clients.js';
|
|
4
|
-
|
|
5
|
-
export function register(server) {
|
|
6
|
-
server.addTool({
|
|
7
|
-
name: '
|
|
8
|
-
description:
|
|
9
|
-
'Lists individual occurrences of a recurring event. Use this to find specific instances ' +
|
|
10
|
-
'you want to modify or cancel (e.g. "cancel next Tuesday\'s standup"). ' +
|
|
11
|
-
'Each instance has its own event ID that you can pass to
|
|
12
|
-
'By default only returns future instances (time_min defaults to now). To retrieve past instances, set time_min to a past date. ' +
|
|
13
|
-
'Note: all parameters use snake_case (event_id, time_min, time_max), not camelCase.',
|
|
14
|
-
parameters: z.object({
|
|
15
|
-
calendar_id: z
|
|
16
|
-
.string()
|
|
17
|
-
.optional()
|
|
18
|
-
.default('primary')
|
|
19
|
-
.describe('Calendar ID. Defaults to "primary".'),
|
|
20
|
-
event_id: z
|
|
21
|
-
.string()
|
|
22
|
-
.describe('The recurring event ID (the parent event, not an instance).'),
|
|
23
|
-
time_min: z
|
|
24
|
-
.string()
|
|
25
|
-
.optional()
|
|
26
|
-
.describe('Start of range in RFC3339 format. Defaults to now.'),
|
|
27
|
-
time_max: z
|
|
28
|
-
.string()
|
|
29
|
-
.optional()
|
|
30
|
-
.describe('End of range in RFC3339 format.'),
|
|
31
|
-
max_results: z
|
|
32
|
-
.number()
|
|
33
|
-
.optional()
|
|
34
|
-
.default(10)
|
|
35
|
-
.describe('Maximum number of instances to return. Defaults to 10.'),
|
|
36
|
-
}),
|
|
37
|
-
execute: async (args, { log }) => {
|
|
38
|
-
const calendar = await getCalendarClient();
|
|
39
|
-
log.info(`Listing instances of recurring event ${args.event_id}`);
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
const params = {
|
|
43
|
-
calendarId: args.calendar_id,
|
|
44
|
-
eventId: args.event_id,
|
|
45
|
-
maxResults: args.max_results,
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
if (args.time_min) params.timeMin = args.time_min;
|
|
49
|
-
else params.timeMin = new Date().toISOString();
|
|
50
|
-
|
|
51
|
-
if (args.time_max) params.timeMax = args.time_max;
|
|
52
|
-
|
|
53
|
-
const response = await calendar.events.instances(params);
|
|
54
|
-
const instances = response.data.items || [];
|
|
55
|
-
|
|
56
|
-
const results = instances.map((event) => ({
|
|
57
|
-
id: event.id,
|
|
58
|
-
summary: event.summary || '(No title)',
|
|
59
|
-
start: event.start?.dateTime || event.start?.date,
|
|
60
|
-
end: event.end?.dateTime || event.end?.date,
|
|
61
|
-
status: event.status,
|
|
62
|
-
recurringEventId: event.recurringEventId,
|
|
63
|
-
htmlLink: event.htmlLink,
|
|
64
|
-
}));
|
|
65
|
-
|
|
66
|
-
return JSON.stringify(results, null, 2);
|
|
67
|
-
} catch (error) {
|
|
68
|
-
log.error(`Error listing recurring instances: ${error.message || error}`);
|
|
69
|
-
if (error.code === 404)
|
|
70
|
-
throw new UserError(
|
|
71
|
-
'Recurring event not found. Check the event_id — it should be the parent recurring event ID.'
|
|
72
|
-
);
|
|
73
|
-
if (error.code === 400)
|
|
74
|
-
throw new UserError(
|
|
75
|
-
'The specified event_id does not appear to be a recurring event.'
|
|
76
|
-
);
|
|
77
|
-
throw new UserError(
|
|
78
|
-
`Failed to list recurring instances: ${error.message || 'Unknown error'}`
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
},
|
|
82
|
-
});
|
|
83
|
-
}
|
|
1
|
+
import { UserError } from 'fastmcp';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { getCalendarClient } from '../../clients.js';
|
|
4
|
+
|
|
5
|
+
export function register(server) {
|
|
6
|
+
server.addTool({
|
|
7
|
+
name: 'listRecurringEventInstances',
|
|
8
|
+
description:
|
|
9
|
+
'Lists individual occurrences of a recurring event. Use this to find specific instances ' +
|
|
10
|
+
'you want to modify or cancel (e.g. "cancel next Tuesday\'s standup"). ' +
|
|
11
|
+
'Each instance has its own event ID that you can pass to manageEvent. ' +
|
|
12
|
+
'By default only returns future instances (time_min defaults to now). To retrieve past instances, set time_min to a past date. ' +
|
|
13
|
+
'Note: all parameters use snake_case (event_id, time_min, time_max), not camelCase.',
|
|
14
|
+
parameters: z.object({
|
|
15
|
+
calendar_id: z
|
|
16
|
+
.string()
|
|
17
|
+
.optional()
|
|
18
|
+
.default('primary')
|
|
19
|
+
.describe('Calendar ID. Defaults to "primary".'),
|
|
20
|
+
event_id: z
|
|
21
|
+
.string()
|
|
22
|
+
.describe('The recurring event ID (the parent event, not an instance).'),
|
|
23
|
+
time_min: z
|
|
24
|
+
.string()
|
|
25
|
+
.optional()
|
|
26
|
+
.describe('Start of range in RFC3339 format. Defaults to now.'),
|
|
27
|
+
time_max: z
|
|
28
|
+
.string()
|
|
29
|
+
.optional()
|
|
30
|
+
.describe('End of range in RFC3339 format.'),
|
|
31
|
+
max_results: z
|
|
32
|
+
.number()
|
|
33
|
+
.optional()
|
|
34
|
+
.default(10)
|
|
35
|
+
.describe('Maximum number of instances to return. Defaults to 10.'),
|
|
36
|
+
}),
|
|
37
|
+
execute: async (args, { log }) => {
|
|
38
|
+
const calendar = await getCalendarClient();
|
|
39
|
+
log.info(`Listing instances of recurring event ${args.event_id}`);
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const params = {
|
|
43
|
+
calendarId: args.calendar_id,
|
|
44
|
+
eventId: args.event_id,
|
|
45
|
+
maxResults: args.max_results,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
if (args.time_min) params.timeMin = args.time_min;
|
|
49
|
+
else params.timeMin = new Date().toISOString();
|
|
50
|
+
|
|
51
|
+
if (args.time_max) params.timeMax = args.time_max;
|
|
52
|
+
|
|
53
|
+
const response = await calendar.events.instances(params);
|
|
54
|
+
const instances = response.data.items || [];
|
|
55
|
+
|
|
56
|
+
const results = instances.map((event) => ({
|
|
57
|
+
id: event.id,
|
|
58
|
+
summary: event.summary || '(No title)',
|
|
59
|
+
start: event.start?.dateTime || event.start?.date,
|
|
60
|
+
end: event.end?.dateTime || event.end?.date,
|
|
61
|
+
status: event.status,
|
|
62
|
+
recurringEventId: event.recurringEventId,
|
|
63
|
+
htmlLink: event.htmlLink,
|
|
64
|
+
}));
|
|
65
|
+
|
|
66
|
+
return JSON.stringify(results, null, 2);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
log.error(`Error listing recurring instances: ${error.message || error}`);
|
|
69
|
+
if (error.code === 404)
|
|
70
|
+
throw new UserError(
|
|
71
|
+
'Recurring event not found. Check the event_id — it should be the parent recurring event ID.'
|
|
72
|
+
);
|
|
73
|
+
if (error.code === 400)
|
|
74
|
+
throw new UserError(
|
|
75
|
+
'The specified event_id does not appear to be a recurring event.'
|
|
76
|
+
);
|
|
77
|
+
throw new UserError(
|
|
78
|
+
`Failed to list recurring instances: ${error.message || 'Unknown error'}`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
}
|
|
@@ -1,121 +1,121 @@
|
|
|
1
|
-
import { UserError } from 'fastmcp';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import { getCalendarClient } from '../../clients.js';
|
|
4
|
-
|
|
5
|
-
export function register(server) {
|
|
6
|
-
server.addTool({
|
|
7
|
-
name: '
|
|
8
|
-
description:
|
|
9
|
-
'Create, update, or delete a calendar. Use this to create project-specific calendars, ' +
|
|
10
|
-
'rename calendars, change timezone/description, or remove calendars you own.',
|
|
11
|
-
parameters: z.object({
|
|
12
|
-
action: z.enum(['create', 'update', 'delete']).describe('The operation to perform.'),
|
|
13
|
-
calendar_id: z
|
|
14
|
-
.string()
|
|
15
|
-
.optional()
|
|
16
|
-
.describe('Calendar ID — required for update and delete. Cannot delete primary calendar.'),
|
|
17
|
-
summary: z
|
|
18
|
-
.string()
|
|
19
|
-
.optional()
|
|
20
|
-
.describe('Calendar name/title. Required for create.'),
|
|
21
|
-
description: z
|
|
22
|
-
.string()
|
|
23
|
-
.optional()
|
|
24
|
-
.describe('Calendar description.'),
|
|
25
|
-
timezone: z
|
|
26
|
-
.string()
|
|
27
|
-
.optional()
|
|
28
|
-
.describe('Calendar timezone (e.g. "America/New_York").'),
|
|
29
|
-
}),
|
|
30
|
-
execute: async (args, { log }) => {
|
|
31
|
-
const calendar = await getCalendarClient();
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
if (args.action === 'create') {
|
|
35
|
-
if (!args.summary) throw new UserError('summary is required for create.');
|
|
36
|
-
log.info(`Creating calendar "${args.summary}"`);
|
|
37
|
-
|
|
38
|
-
const body = { summary: args.summary };
|
|
39
|
-
if (args.description) body.description = args.description;
|
|
40
|
-
if (args.timezone) body.timeZone = args.timezone;
|
|
41
|
-
|
|
42
|
-
const response = await calendar.calendars.insert({ requestBody: body });
|
|
43
|
-
return JSON.stringify(
|
|
44
|
-
{
|
|
45
|
-
success: true,
|
|
46
|
-
action: 'created',
|
|
47
|
-
id: response.data.id,
|
|
48
|
-
summary: response.data.summary,
|
|
49
|
-
timeZone: response.data.timeZone,
|
|
50
|
-
},
|
|
51
|
-
null,
|
|
52
|
-
2
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (args.action === 'update') {
|
|
57
|
-
if (!args.calendar_id) throw new UserError('calendar_id is required for update.');
|
|
58
|
-
log.info(`Updating calendar ${args.calendar_id}`);
|
|
59
|
-
|
|
60
|
-
// Fetch existing to preserve fields
|
|
61
|
-
const existing = await calendar.calendars.get({
|
|
62
|
-
calendarId: args.calendar_id,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
const body = {
|
|
66
|
-
summary: args.summary || existing.data.summary,
|
|
67
|
-
description:
|
|
68
|
-
args.description !== undefined
|
|
69
|
-
? args.description
|
|
70
|
-
: existing.data.description,
|
|
71
|
-
timeZone: args.timezone || existing.data.timeZone,
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
const response = await calendar.calendars.update({
|
|
75
|
-
calendarId: args.calendar_id,
|
|
76
|
-
requestBody: body,
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
return JSON.stringify(
|
|
80
|
-
{
|
|
81
|
-
success: true,
|
|
82
|
-
action: 'updated',
|
|
83
|
-
id: response.data.id,
|
|
84
|
-
summary: response.data.summary,
|
|
85
|
-
timeZone: response.data.timeZone,
|
|
86
|
-
},
|
|
87
|
-
null,
|
|
88
|
-
2
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (args.action === 'delete') {
|
|
93
|
-
if (!args.calendar_id) throw new UserError('calendar_id is required for delete.');
|
|
94
|
-
if (args.calendar_id === 'primary')
|
|
95
|
-
throw new UserError('Cannot delete the primary calendar.');
|
|
96
|
-
log.info(`Deleting calendar ${args.calendar_id}`);
|
|
97
|
-
|
|
98
|
-
await calendar.calendars.delete({ calendarId: args.calendar_id });
|
|
99
|
-
return JSON.stringify({
|
|
100
|
-
success: true,
|
|
101
|
-
action: 'deleted',
|
|
102
|
-
id: args.calendar_id,
|
|
103
|
-
message: `Calendar ${args.calendar_id} deleted.`,
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
throw new UserError(`Unknown action: ${args.action}`);
|
|
108
|
-
} catch (error) {
|
|
109
|
-
if (error instanceof UserError) throw error;
|
|
110
|
-
log.error(`Error in
|
|
111
|
-
if (error.code === 404)
|
|
112
|
-
throw new UserError('Calendar not found. Check the calendar_id.');
|
|
113
|
-
if (error.code === 403)
|
|
114
|
-
throw new UserError('Permission denied. You can only modify calendars you own.');
|
|
115
|
-
throw new UserError(
|
|
116
|
-
`Failed to ${args.action} calendar: ${error.message || 'Unknown error'}`
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
},
|
|
120
|
-
});
|
|
121
|
-
}
|
|
1
|
+
import { UserError } from 'fastmcp';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { getCalendarClient } from '../../clients.js';
|
|
4
|
+
|
|
5
|
+
export function register(server) {
|
|
6
|
+
server.addTool({
|
|
7
|
+
name: 'manageCalendar',
|
|
8
|
+
description:
|
|
9
|
+
'Create, update, or delete a calendar. Use this to create project-specific calendars, ' +
|
|
10
|
+
'rename calendars, change timezone/description, or remove calendars you own.',
|
|
11
|
+
parameters: z.object({
|
|
12
|
+
action: z.enum(['create', 'update', 'delete']).describe('The operation to perform.'),
|
|
13
|
+
calendar_id: z
|
|
14
|
+
.string()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe('Calendar ID — required for update and delete. Cannot delete primary calendar.'),
|
|
17
|
+
summary: z
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe('Calendar name/title. Required for create.'),
|
|
21
|
+
description: z
|
|
22
|
+
.string()
|
|
23
|
+
.optional()
|
|
24
|
+
.describe('Calendar description.'),
|
|
25
|
+
timezone: z
|
|
26
|
+
.string()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe('Calendar timezone (e.g. "America/New_York").'),
|
|
29
|
+
}),
|
|
30
|
+
execute: async (args, { log }) => {
|
|
31
|
+
const calendar = await getCalendarClient();
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
if (args.action === 'create') {
|
|
35
|
+
if (!args.summary) throw new UserError('summary is required for create.');
|
|
36
|
+
log.info(`Creating calendar "${args.summary}"`);
|
|
37
|
+
|
|
38
|
+
const body = { summary: args.summary };
|
|
39
|
+
if (args.description) body.description = args.description;
|
|
40
|
+
if (args.timezone) body.timeZone = args.timezone;
|
|
41
|
+
|
|
42
|
+
const response = await calendar.calendars.insert({ requestBody: body });
|
|
43
|
+
return JSON.stringify(
|
|
44
|
+
{
|
|
45
|
+
success: true,
|
|
46
|
+
action: 'created',
|
|
47
|
+
id: response.data.id,
|
|
48
|
+
summary: response.data.summary,
|
|
49
|
+
timeZone: response.data.timeZone,
|
|
50
|
+
},
|
|
51
|
+
null,
|
|
52
|
+
2
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (args.action === 'update') {
|
|
57
|
+
if (!args.calendar_id) throw new UserError('calendar_id is required for update.');
|
|
58
|
+
log.info(`Updating calendar ${args.calendar_id}`);
|
|
59
|
+
|
|
60
|
+
// Fetch existing to preserve fields
|
|
61
|
+
const existing = await calendar.calendars.get({
|
|
62
|
+
calendarId: args.calendar_id,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const body = {
|
|
66
|
+
summary: args.summary || existing.data.summary,
|
|
67
|
+
description:
|
|
68
|
+
args.description !== undefined
|
|
69
|
+
? args.description
|
|
70
|
+
: existing.data.description,
|
|
71
|
+
timeZone: args.timezone || existing.data.timeZone,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const response = await calendar.calendars.update({
|
|
75
|
+
calendarId: args.calendar_id,
|
|
76
|
+
requestBody: body,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
return JSON.stringify(
|
|
80
|
+
{
|
|
81
|
+
success: true,
|
|
82
|
+
action: 'updated',
|
|
83
|
+
id: response.data.id,
|
|
84
|
+
summary: response.data.summary,
|
|
85
|
+
timeZone: response.data.timeZone,
|
|
86
|
+
},
|
|
87
|
+
null,
|
|
88
|
+
2
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (args.action === 'delete') {
|
|
93
|
+
if (!args.calendar_id) throw new UserError('calendar_id is required for delete.');
|
|
94
|
+
if (args.calendar_id === 'primary')
|
|
95
|
+
throw new UserError('Cannot delete the primary calendar.');
|
|
96
|
+
log.info(`Deleting calendar ${args.calendar_id}`);
|
|
97
|
+
|
|
98
|
+
await calendar.calendars.delete({ calendarId: args.calendar_id });
|
|
99
|
+
return JSON.stringify({
|
|
100
|
+
success: true,
|
|
101
|
+
action: 'deleted',
|
|
102
|
+
id: args.calendar_id,
|
|
103
|
+
message: `Calendar ${args.calendar_id} deleted.`,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
throw new UserError(`Unknown action: ${args.action}`);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (error instanceof UserError) throw error;
|
|
110
|
+
log.error(`Error in manageCalendar (${args.action}): ${error.message || error}`);
|
|
111
|
+
if (error.code === 404)
|
|
112
|
+
throw new UserError('Calendar not found. Check the calendar_id.');
|
|
113
|
+
if (error.code === 403)
|
|
114
|
+
throw new UserError('Permission denied. You can only modify calendars you own.');
|
|
115
|
+
throw new UserError(
|
|
116
|
+
`Failed to ${args.action} calendar: ${error.message || 'Unknown error'}`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
}
|