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,141 +1,141 @@
|
|
|
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
|
-
'Retrieves events from a Google Calendar. Can get a single event by ID, or list events in a time range with optional search. ' +
|
|
10
|
-
'By default only returns future events (time_min defaults to now). To retrieve past events, set time_min to a past date (e.g. "2025-01-01T00:00:00Z"). ' +
|
|
11
|
-
'Use calendar_id to query another user\'s calendar (requires sharing) or "primary" for the authenticated user.',
|
|
12
|
-
parameters: z.object({
|
|
13
|
-
calendar_id: z
|
|
14
|
-
.string()
|
|
15
|
-
.optional()
|
|
16
|
-
.default('primary')
|
|
17
|
-
.describe('Calendar ID to query. Use "primary" for the main calendar, or an email address for a shared calendar.'),
|
|
18
|
-
event_id: z
|
|
19
|
-
.string()
|
|
20
|
-
.optional()
|
|
21
|
-
.describe('Specific event ID to retrieve. If provided, other filter params are ignored.'),
|
|
22
|
-
time_min: z
|
|
23
|
-
.string()
|
|
24
|
-
.optional()
|
|
25
|
-
.describe('Start of time range in RFC3339 format (e.g. "2025-01-01T00:00:00Z"). Defaults to now if not specified.'),
|
|
26
|
-
time_max: z
|
|
27
|
-
.string()
|
|
28
|
-
.optional()
|
|
29
|
-
.describe('End of time range in RFC3339 format (e.g. "2025-01-31T23:59:59Z").'),
|
|
30
|
-
max_results: z
|
|
31
|
-
.number()
|
|
32
|
-
.optional()
|
|
33
|
-
.default(25)
|
|
34
|
-
.describe('Maximum number of events to return (default 25, max 2500).'),
|
|
35
|
-
query: z
|
|
36
|
-
.string()
|
|
37
|
-
.optional()
|
|
38
|
-
.describe('Free-text search across event summary, description, location, attendees, etc.'),
|
|
39
|
-
detailed: z
|
|
40
|
-
.boolean()
|
|
41
|
-
.optional()
|
|
42
|
-
.default(false)
|
|
43
|
-
.describe('If true, includes attendees, attachments, conferencing details, and extended properties.'),
|
|
44
|
-
}),
|
|
45
|
-
execute: async (args, { log }) => {
|
|
46
|
-
const calendar = await getCalendarClient();
|
|
47
|
-
|
|
48
|
-
try {
|
|
49
|
-
// Single event fetch
|
|
50
|
-
if (args.event_id) {
|
|
51
|
-
log.info(`Getting event ${args.event_id} from calendar ${args.calendar_id}`);
|
|
52
|
-
const response = await calendar.events.get({
|
|
53
|
-
calendarId: args.calendar_id,
|
|
54
|
-
eventId: args.event_id,
|
|
55
|
-
});
|
|
56
|
-
return JSON.stringify(formatEvent(response.data, true), null, 2);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// List events
|
|
60
|
-
log.info(`Listing events from calendar ${args.calendar_id}`);
|
|
61
|
-
const params = {
|
|
62
|
-
calendarId: args.calendar_id,
|
|
63
|
-
maxResults: Math.min(args.max_results, 2500),
|
|
64
|
-
singleEvents: true,
|
|
65
|
-
orderBy: 'startTime',
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
if (args.time_min) params.timeMin = args.time_min;
|
|
69
|
-
else params.timeMin = new Date().toISOString();
|
|
70
|
-
|
|
71
|
-
if (args.time_max) params.timeMax = args.time_max;
|
|
72
|
-
if (args.query) params.q = args.query;
|
|
73
|
-
|
|
74
|
-
const response = await calendar.events.list(params);
|
|
75
|
-
const events = response.data.items || [];
|
|
76
|
-
|
|
77
|
-
return JSON.stringify(
|
|
78
|
-
events.map((e) => formatEvent(e, args.detailed)),
|
|
79
|
-
null,
|
|
80
|
-
2
|
|
81
|
-
);
|
|
82
|
-
} catch (error) {
|
|
83
|
-
log.error(`Error getting events: ${error.message || error}`);
|
|
84
|
-
if (error.code === 404)
|
|
85
|
-
throw new UserError('Calendar or event not found. Check the calendar_id or event_id.');
|
|
86
|
-
if (error.code === 403)
|
|
87
|
-
throw new UserError('Permission denied. The calendar may not be shared with you.');
|
|
88
|
-
throw new UserError(`Failed to get events: ${error.message || 'Unknown error'}`);
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function formatEvent(event, detailed) {
|
|
95
|
-
const result = {
|
|
96
|
-
id: event.id,
|
|
97
|
-
summary: event.summary || '(No title)',
|
|
98
|
-
start: event.start?.dateTime || event.start?.date || null,
|
|
99
|
-
end: event.end?.dateTime || event.end?.date || null,
|
|
100
|
-
status: event.status,
|
|
101
|
-
htmlLink: event.htmlLink,
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
if (event.location) result.location = event.location;
|
|
105
|
-
if (event.description) result.description = event.description;
|
|
106
|
-
if (event.recurringEventId) result.recurringEventId = event.recurringEventId;
|
|
107
|
-
|
|
108
|
-
if (detailed) {
|
|
109
|
-
if (event.attendees?.length) {
|
|
110
|
-
result.attendees = event.attendees.map((a) => ({
|
|
111
|
-
email: a.email,
|
|
112
|
-
displayName: a.displayName || null,
|
|
113
|
-
responseStatus: a.responseStatus,
|
|
114
|
-
organizer: a.organizer || false,
|
|
115
|
-
self: a.self || false,
|
|
116
|
-
}));
|
|
117
|
-
}
|
|
118
|
-
if (event.conferenceData) {
|
|
119
|
-
const entryPoints = event.conferenceData.entryPoints || [];
|
|
120
|
-
result.conferencing = entryPoints.map((ep) => ({
|
|
121
|
-
type: ep.entryPointType,
|
|
122
|
-
uri: ep.uri,
|
|
123
|
-
label: ep.label || null,
|
|
124
|
-
}));
|
|
125
|
-
}
|
|
126
|
-
if (event.attachments?.length) {
|
|
127
|
-
result.attachments = event.attachments.map((a) => ({
|
|
128
|
-
title: a.title,
|
|
129
|
-
fileUrl: a.fileUrl,
|
|
130
|
-
mimeType: a.mimeType,
|
|
131
|
-
}));
|
|
132
|
-
}
|
|
133
|
-
if (event.creator) result.creator = event.creator;
|
|
134
|
-
if (event.organizer) result.organizer = { email: event.organizer.email, displayName: event.organizer.displayName || null };
|
|
135
|
-
result.visibility = event.visibility || 'default';
|
|
136
|
-
result.transparency = event.transparency || 'opaque';
|
|
137
|
-
if (event.reminders) result.reminders = event.reminders;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return result;
|
|
141
|
-
}
|
|
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: 'getEvents',
|
|
8
|
+
description:
|
|
9
|
+
'Retrieves events from a Google Calendar. Can get a single event by ID, or list events in a time range with optional search. ' +
|
|
10
|
+
'By default only returns future events (time_min defaults to now). To retrieve past events, set time_min to a past date (e.g. "2025-01-01T00:00:00Z"). ' +
|
|
11
|
+
'Use calendar_id to query another user\'s calendar (requires sharing) or "primary" for the authenticated user.',
|
|
12
|
+
parameters: z.object({
|
|
13
|
+
calendar_id: z
|
|
14
|
+
.string()
|
|
15
|
+
.optional()
|
|
16
|
+
.default('primary')
|
|
17
|
+
.describe('Calendar ID to query. Use "primary" for the main calendar, or an email address for a shared calendar.'),
|
|
18
|
+
event_id: z
|
|
19
|
+
.string()
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Specific event ID to retrieve. If provided, other filter params are ignored.'),
|
|
22
|
+
time_min: z
|
|
23
|
+
.string()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe('Start of time range in RFC3339 format (e.g. "2025-01-01T00:00:00Z"). Defaults to now if not specified.'),
|
|
26
|
+
time_max: z
|
|
27
|
+
.string()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe('End of time range in RFC3339 format (e.g. "2025-01-31T23:59:59Z").'),
|
|
30
|
+
max_results: z
|
|
31
|
+
.number()
|
|
32
|
+
.optional()
|
|
33
|
+
.default(25)
|
|
34
|
+
.describe('Maximum number of events to return (default 25, max 2500).'),
|
|
35
|
+
query: z
|
|
36
|
+
.string()
|
|
37
|
+
.optional()
|
|
38
|
+
.describe('Free-text search across event summary, description, location, attendees, etc.'),
|
|
39
|
+
detailed: z
|
|
40
|
+
.boolean()
|
|
41
|
+
.optional()
|
|
42
|
+
.default(false)
|
|
43
|
+
.describe('If true, includes attendees, attachments, conferencing details, and extended properties.'),
|
|
44
|
+
}),
|
|
45
|
+
execute: async (args, { log }) => {
|
|
46
|
+
const calendar = await getCalendarClient();
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
// Single event fetch
|
|
50
|
+
if (args.event_id) {
|
|
51
|
+
log.info(`Getting event ${args.event_id} from calendar ${args.calendar_id}`);
|
|
52
|
+
const response = await calendar.events.get({
|
|
53
|
+
calendarId: args.calendar_id,
|
|
54
|
+
eventId: args.event_id,
|
|
55
|
+
});
|
|
56
|
+
return JSON.stringify(formatEvent(response.data, true), null, 2);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// List events
|
|
60
|
+
log.info(`Listing events from calendar ${args.calendar_id}`);
|
|
61
|
+
const params = {
|
|
62
|
+
calendarId: args.calendar_id,
|
|
63
|
+
maxResults: Math.min(args.max_results, 2500),
|
|
64
|
+
singleEvents: true,
|
|
65
|
+
orderBy: 'startTime',
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
if (args.time_min) params.timeMin = args.time_min;
|
|
69
|
+
else params.timeMin = new Date().toISOString();
|
|
70
|
+
|
|
71
|
+
if (args.time_max) params.timeMax = args.time_max;
|
|
72
|
+
if (args.query) params.q = args.query;
|
|
73
|
+
|
|
74
|
+
const response = await calendar.events.list(params);
|
|
75
|
+
const events = response.data.items || [];
|
|
76
|
+
|
|
77
|
+
return JSON.stringify(
|
|
78
|
+
events.map((e) => formatEvent(e, args.detailed)),
|
|
79
|
+
null,
|
|
80
|
+
2
|
|
81
|
+
);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
log.error(`Error getting events: ${error.message || error}`);
|
|
84
|
+
if (error.code === 404)
|
|
85
|
+
throw new UserError('Calendar or event not found. Check the calendar_id or event_id.');
|
|
86
|
+
if (error.code === 403)
|
|
87
|
+
throw new UserError('Permission denied. The calendar may not be shared with you.');
|
|
88
|
+
throw new UserError(`Failed to get events: ${error.message || 'Unknown error'}`);
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function formatEvent(event, detailed) {
|
|
95
|
+
const result = {
|
|
96
|
+
id: event.id,
|
|
97
|
+
summary: event.summary || '(No title)',
|
|
98
|
+
start: event.start?.dateTime || event.start?.date || null,
|
|
99
|
+
end: event.end?.dateTime || event.end?.date || null,
|
|
100
|
+
status: event.status,
|
|
101
|
+
htmlLink: event.htmlLink,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
if (event.location) result.location = event.location;
|
|
105
|
+
if (event.description) result.description = event.description;
|
|
106
|
+
if (event.recurringEventId) result.recurringEventId = event.recurringEventId;
|
|
107
|
+
|
|
108
|
+
if (detailed) {
|
|
109
|
+
if (event.attendees?.length) {
|
|
110
|
+
result.attendees = event.attendees.map((a) => ({
|
|
111
|
+
email: a.email,
|
|
112
|
+
displayName: a.displayName || null,
|
|
113
|
+
responseStatus: a.responseStatus,
|
|
114
|
+
organizer: a.organizer || false,
|
|
115
|
+
self: a.self || false,
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
if (event.conferenceData) {
|
|
119
|
+
const entryPoints = event.conferenceData.entryPoints || [];
|
|
120
|
+
result.conferencing = entryPoints.map((ep) => ({
|
|
121
|
+
type: ep.entryPointType,
|
|
122
|
+
uri: ep.uri,
|
|
123
|
+
label: ep.label || null,
|
|
124
|
+
}));
|
|
125
|
+
}
|
|
126
|
+
if (event.attachments?.length) {
|
|
127
|
+
result.attachments = event.attachments.map((a) => ({
|
|
128
|
+
title: a.title,
|
|
129
|
+
fileUrl: a.fileUrl,
|
|
130
|
+
mimeType: a.mimeType,
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
if (event.creator) result.creator = event.creator;
|
|
134
|
+
if (event.organizer) result.organizer = { email: event.organizer.email, displayName: event.organizer.displayName || null };
|
|
135
|
+
result.visibility = event.visibility || 'default';
|
|
136
|
+
result.transparency = event.transparency || 'opaque';
|
|
137
|
+
if (event.reminders) result.reminders = event.reminders;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return result;
|
|
141
|
+
}
|