google-tools-mcp 1.2.11 → 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 +555 -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 +222 -21
- package/dist/markdown-transformer/index.js +19 -9
- package/dist/markdown-transformer/markdownToDocs.js +458 -28
- 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 +13 -1
- 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 +212 -206
- 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 +31 -7
- package/dist/tools/utils/replaceDocumentWithMarkdown.js +72 -9
- package/dist/updateCheck.js +202 -0
- package/dist/workspace.js +122 -0
- package/package.json +82 -80
|
@@ -1,165 +1,165 @@
|
|
|
1
|
-
// Gmail Draft tools
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import { UserError } from 'fastmcp';
|
|
4
|
-
import { getGmailClient } from '../../clients.js';
|
|
5
|
-
import { processMessagePart, constructRawMessage, constructRawMessageWithAttachments } from '../../helpers.js';
|
|
6
|
-
|
|
7
|
-
export function register(server) {
|
|
8
|
-
server.addTool({
|
|
9
|
-
name: '
|
|
10
|
-
description: 'Create a draft email in Gmail. Note the mechanics of the raw parameter.',
|
|
11
|
-
parameters: z.object({
|
|
12
|
-
raw: z.string().optional().describe("The entire email message in base64url encoded RFC 2822 format, ignores params.to, cc, bcc, subject, body, includeBodyHtml if provided"),
|
|
13
|
-
threadId: z.string().optional().describe("The thread ID to associate this draft with"),
|
|
14
|
-
to: z.array(z.string()).optional().describe("List of recipient email addresses"),
|
|
15
|
-
cc: z.array(z.string()).optional().describe("List of CC recipient email addresses"),
|
|
16
|
-
bcc: z.array(z.string()).optional().describe("List of BCC recipient email addresses"),
|
|
17
|
-
subject: z.string().optional().describe("The subject of the email"),
|
|
18
|
-
body: z.string().optional().describe("The body of the email. Supports plain text or HTML (auto-detected). Use HTML tags like <p>, <br>, <b> for formatted emails."),
|
|
19
|
-
attachments: z.array(z.object({
|
|
20
|
-
filename: z.string().describe("Attachment file name"),
|
|
21
|
-
mimeType: z.string().describe("MIME type of the attachment"),
|
|
22
|
-
base64Data: z.string().describe("Base64 encoded attachment data"),
|
|
23
|
-
})).optional().describe("File attachments to include"),
|
|
24
|
-
includeBodyHtml: z.boolean().optional().describe("Whether to include the parsed HTML in the return for each body"),
|
|
25
|
-
}),
|
|
26
|
-
execute: async (params, { log }) => {
|
|
27
|
-
const gmail = await getGmailClient();
|
|
28
|
-
let raw = params.raw;
|
|
29
|
-
if (!raw) {
|
|
30
|
-
if (params.attachments?.length) {
|
|
31
|
-
raw = await constructRawMessageWithAttachments(gmail, params);
|
|
32
|
-
} else {
|
|
33
|
-
raw = await constructRawMessage(gmail, params);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
const createParams = { userId: 'me', requestBody: { message: { raw } } };
|
|
37
|
-
if (params.threadId && createParams.requestBody?.message) {
|
|
38
|
-
createParams.requestBody.message.threadId = params.threadId;
|
|
39
|
-
}
|
|
40
|
-
const { data } = await gmail.users.drafts.create(createParams);
|
|
41
|
-
if (data.message?.payload) {
|
|
42
|
-
data.message.payload = processMessagePart(data.message.payload, params.includeBodyHtml);
|
|
43
|
-
}
|
|
44
|
-
return JSON.stringify(data);
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
server.addTool({
|
|
49
|
-
name: '
|
|
50
|
-
description: 'Update an existing draft\'s content. Replaces the draft message with new content.',
|
|
51
|
-
parameters: z.object({
|
|
52
|
-
id: z.string().describe("The ID of the draft to update"),
|
|
53
|
-
raw: z.string().optional().describe("The entire email message in base64url encoded RFC 2822 format, ignores other params if provided"),
|
|
54
|
-
threadId: z.string().optional().describe("The thread ID to associate this draft with"),
|
|
55
|
-
to: z.array(z.string()).optional().describe("List of recipient email addresses"),
|
|
56
|
-
cc: z.array(z.string()).optional().describe("List of CC recipient email addresses"),
|
|
57
|
-
bcc: z.array(z.string()).optional().describe("List of BCC recipient email addresses"),
|
|
58
|
-
subject: z.string().optional().describe("The subject of the email"),
|
|
59
|
-
body: z.string().optional().describe("The body of the email. Supports plain text or HTML (auto-detected). Use HTML tags like <p>, <br>, <b> for formatted emails."),
|
|
60
|
-
attachments: z.array(z.object({
|
|
61
|
-
filename: z.string().describe("Attachment file name"),
|
|
62
|
-
mimeType: z.string().describe("MIME type of the attachment"),
|
|
63
|
-
base64Data: z.string().describe("Base64 encoded attachment data"),
|
|
64
|
-
})).optional().describe("File attachments to include"),
|
|
65
|
-
includeBodyHtml: z.boolean().optional().describe("Whether to include the parsed HTML in the return for each body"),
|
|
66
|
-
}),
|
|
67
|
-
execute: async (params) => {
|
|
68
|
-
const gmail = await getGmailClient();
|
|
69
|
-
let raw = params.raw;
|
|
70
|
-
if (!raw) {
|
|
71
|
-
if (params.attachments?.length) {
|
|
72
|
-
raw = await constructRawMessageWithAttachments(gmail, params);
|
|
73
|
-
} else {
|
|
74
|
-
raw = await constructRawMessage(gmail, params);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
const updateParams = { userId: 'me', id: params.id, requestBody: { message: { raw } } };
|
|
78
|
-
if (params.threadId && updateParams.requestBody?.message) {
|
|
79
|
-
updateParams.requestBody.message.threadId = params.threadId;
|
|
80
|
-
}
|
|
81
|
-
const { data } = await gmail.users.drafts.update(updateParams);
|
|
82
|
-
if (data.message?.payload) {
|
|
83
|
-
data.message.payload = processMessagePart(data.message.payload, params.includeBodyHtml);
|
|
84
|
-
}
|
|
85
|
-
return JSON.stringify(data);
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
server.addTool({
|
|
90
|
-
name: '
|
|
91
|
-
description: 'Delete a draft',
|
|
92
|
-
parameters: z.object({
|
|
93
|
-
id: z.string().describe("The ID of the draft to delete"),
|
|
94
|
-
}),
|
|
95
|
-
execute: async (params) => {
|
|
96
|
-
const gmail = await getGmailClient();
|
|
97
|
-
const { data } = await gmail.users.drafts.delete({ userId: 'me', id: params.id });
|
|
98
|
-
return JSON.stringify(data || { success: true });
|
|
99
|
-
},
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
server.addTool({
|
|
103
|
-
name: '
|
|
104
|
-
description: 'Get a specific draft by ID',
|
|
105
|
-
parameters: z.object({
|
|
106
|
-
id: z.string().describe("The ID of the draft to retrieve"),
|
|
107
|
-
includeBodyHtml: z.boolean().optional().describe("Whether to include the parsed HTML in the return for each body"),
|
|
108
|
-
}),
|
|
109
|
-
execute: async (params) => {
|
|
110
|
-
const gmail = await getGmailClient();
|
|
111
|
-
const { data } = await gmail.users.drafts.get({ userId: 'me', id: params.id, format: 'full' });
|
|
112
|
-
if (data.message?.payload) {
|
|
113
|
-
data.message.payload = processMessagePart(data.message.payload, params.includeBodyHtml);
|
|
114
|
-
}
|
|
115
|
-
return JSON.stringify(data);
|
|
116
|
-
},
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
server.addTool({
|
|
120
|
-
name: '
|
|
121
|
-
description: 'List drafts in the user\'s mailbox',
|
|
122
|
-
parameters: z.object({
|
|
123
|
-
maxResults: z.number().optional().describe("Maximum number of drafts to return (1-500)"),
|
|
124
|
-
q: z.string().optional().describe("Only return drafts matching the specified query"),
|
|
125
|
-
includeSpamTrash: z.boolean().optional().describe("Include drafts from SPAM and TRASH"),
|
|
126
|
-
includeBodyHtml: z.boolean().optional().describe("Whether to include the parsed HTML in the return for each body"),
|
|
127
|
-
}),
|
|
128
|
-
execute: async (params) => {
|
|
129
|
-
const gmail = await getGmailClient();
|
|
130
|
-
let drafts = [];
|
|
131
|
-
const { data } = await gmail.users.drafts.list({ userId: 'me', ...params });
|
|
132
|
-
drafts.push(...(data.drafts || []));
|
|
133
|
-
let pageToken = data.nextPageToken;
|
|
134
|
-
while (pageToken) {
|
|
135
|
-
const { data: nextData } = await gmail.users.drafts.list({ userId: 'me', ...params, pageToken });
|
|
136
|
-
drafts.push(...(nextData.drafts || []));
|
|
137
|
-
pageToken = nextData.nextPageToken;
|
|
138
|
-
}
|
|
139
|
-
drafts = drafts.map(draft => {
|
|
140
|
-
if (draft.message?.payload) {
|
|
141
|
-
draft.message.payload = processMessagePart(draft.message.payload, params.includeBodyHtml);
|
|
142
|
-
}
|
|
143
|
-
return draft;
|
|
144
|
-
});
|
|
145
|
-
return JSON.stringify(drafts);
|
|
146
|
-
},
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
server.addTool({
|
|
150
|
-
name: '
|
|
151
|
-
description: 'Send an existing draft',
|
|
152
|
-
parameters: z.object({
|
|
153
|
-
id: z.string().describe("The ID of the draft to send"),
|
|
154
|
-
}),
|
|
155
|
-
execute: async (params) => {
|
|
156
|
-
const gmail = await getGmailClient();
|
|
157
|
-
try {
|
|
158
|
-
const { data } = await gmail.users.drafts.send({ userId: 'me', requestBody: { id: params.id } });
|
|
159
|
-
return JSON.stringify(data);
|
|
160
|
-
} catch (error) {
|
|
161
|
-
throw new UserError('Error sending draft, are you sure you have at least one recipient?');
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
|
-
});
|
|
165
|
-
}
|
|
1
|
+
// Gmail Draft tools
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { UserError } from 'fastmcp';
|
|
4
|
+
import { getGmailClient } from '../../clients.js';
|
|
5
|
+
import { processMessagePart, constructRawMessage, constructRawMessageWithAttachments } from '../../helpers.js';
|
|
6
|
+
|
|
7
|
+
export function register(server) {
|
|
8
|
+
server.addTool({
|
|
9
|
+
name: 'createDraft',
|
|
10
|
+
description: 'Create a draft email in Gmail. Note the mechanics of the raw parameter.',
|
|
11
|
+
parameters: z.object({
|
|
12
|
+
raw: z.string().optional().describe("The entire email message in base64url encoded RFC 2822 format, ignores params.to, cc, bcc, subject, body, includeBodyHtml if provided"),
|
|
13
|
+
threadId: z.string().optional().describe("The thread ID to associate this draft with"),
|
|
14
|
+
to: z.array(z.string()).optional().describe("List of recipient email addresses"),
|
|
15
|
+
cc: z.array(z.string()).optional().describe("List of CC recipient email addresses"),
|
|
16
|
+
bcc: z.array(z.string()).optional().describe("List of BCC recipient email addresses"),
|
|
17
|
+
subject: z.string().optional().describe("The subject of the email"),
|
|
18
|
+
body: z.string().optional().describe("The body of the email. Supports plain text or HTML (auto-detected). Use HTML tags like <p>, <br>, <b> for formatted emails."),
|
|
19
|
+
attachments: z.array(z.object({
|
|
20
|
+
filename: z.string().describe("Attachment file name"),
|
|
21
|
+
mimeType: z.string().describe("MIME type of the attachment"),
|
|
22
|
+
base64Data: z.string().describe("Base64 encoded attachment data"),
|
|
23
|
+
})).optional().describe("File attachments to include"),
|
|
24
|
+
includeBodyHtml: z.boolean().optional().describe("Whether to include the parsed HTML in the return for each body"),
|
|
25
|
+
}),
|
|
26
|
+
execute: async (params, { log }) => {
|
|
27
|
+
const gmail = await getGmailClient();
|
|
28
|
+
let raw = params.raw;
|
|
29
|
+
if (!raw) {
|
|
30
|
+
if (params.attachments?.length) {
|
|
31
|
+
raw = await constructRawMessageWithAttachments(gmail, params);
|
|
32
|
+
} else {
|
|
33
|
+
raw = await constructRawMessage(gmail, params);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const createParams = { userId: 'me', requestBody: { message: { raw } } };
|
|
37
|
+
if (params.threadId && createParams.requestBody?.message) {
|
|
38
|
+
createParams.requestBody.message.threadId = params.threadId;
|
|
39
|
+
}
|
|
40
|
+
const { data } = await gmail.users.drafts.create(createParams);
|
|
41
|
+
if (data.message?.payload) {
|
|
42
|
+
data.message.payload = processMessagePart(data.message.payload, params.includeBodyHtml);
|
|
43
|
+
}
|
|
44
|
+
return JSON.stringify(data);
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
server.addTool({
|
|
49
|
+
name: 'updateDraft',
|
|
50
|
+
description: 'Update an existing draft\'s content. Replaces the draft message with new content.',
|
|
51
|
+
parameters: z.object({
|
|
52
|
+
id: z.string().describe("The ID of the draft to update"),
|
|
53
|
+
raw: z.string().optional().describe("The entire email message in base64url encoded RFC 2822 format, ignores other params if provided"),
|
|
54
|
+
threadId: z.string().optional().describe("The thread ID to associate this draft with"),
|
|
55
|
+
to: z.array(z.string()).optional().describe("List of recipient email addresses"),
|
|
56
|
+
cc: z.array(z.string()).optional().describe("List of CC recipient email addresses"),
|
|
57
|
+
bcc: z.array(z.string()).optional().describe("List of BCC recipient email addresses"),
|
|
58
|
+
subject: z.string().optional().describe("The subject of the email"),
|
|
59
|
+
body: z.string().optional().describe("The body of the email. Supports plain text or HTML (auto-detected). Use HTML tags like <p>, <br>, <b> for formatted emails."),
|
|
60
|
+
attachments: z.array(z.object({
|
|
61
|
+
filename: z.string().describe("Attachment file name"),
|
|
62
|
+
mimeType: z.string().describe("MIME type of the attachment"),
|
|
63
|
+
base64Data: z.string().describe("Base64 encoded attachment data"),
|
|
64
|
+
})).optional().describe("File attachments to include"),
|
|
65
|
+
includeBodyHtml: z.boolean().optional().describe("Whether to include the parsed HTML in the return for each body"),
|
|
66
|
+
}),
|
|
67
|
+
execute: async (params) => {
|
|
68
|
+
const gmail = await getGmailClient();
|
|
69
|
+
let raw = params.raw;
|
|
70
|
+
if (!raw) {
|
|
71
|
+
if (params.attachments?.length) {
|
|
72
|
+
raw = await constructRawMessageWithAttachments(gmail, params);
|
|
73
|
+
} else {
|
|
74
|
+
raw = await constructRawMessage(gmail, params);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const updateParams = { userId: 'me', id: params.id, requestBody: { message: { raw } } };
|
|
78
|
+
if (params.threadId && updateParams.requestBody?.message) {
|
|
79
|
+
updateParams.requestBody.message.threadId = params.threadId;
|
|
80
|
+
}
|
|
81
|
+
const { data } = await gmail.users.drafts.update(updateParams);
|
|
82
|
+
if (data.message?.payload) {
|
|
83
|
+
data.message.payload = processMessagePart(data.message.payload, params.includeBodyHtml);
|
|
84
|
+
}
|
|
85
|
+
return JSON.stringify(data);
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
server.addTool({
|
|
90
|
+
name: 'deleteDraft',
|
|
91
|
+
description: 'Delete a draft',
|
|
92
|
+
parameters: z.object({
|
|
93
|
+
id: z.string().describe("The ID of the draft to delete"),
|
|
94
|
+
}),
|
|
95
|
+
execute: async (params) => {
|
|
96
|
+
const gmail = await getGmailClient();
|
|
97
|
+
const { data } = await gmail.users.drafts.delete({ userId: 'me', id: params.id });
|
|
98
|
+
return JSON.stringify(data || { success: true });
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
server.addTool({
|
|
103
|
+
name: 'getDraft',
|
|
104
|
+
description: 'Get a specific draft by ID',
|
|
105
|
+
parameters: z.object({
|
|
106
|
+
id: z.string().describe("The ID of the draft to retrieve"),
|
|
107
|
+
includeBodyHtml: z.boolean().optional().describe("Whether to include the parsed HTML in the return for each body"),
|
|
108
|
+
}),
|
|
109
|
+
execute: async (params) => {
|
|
110
|
+
const gmail = await getGmailClient();
|
|
111
|
+
const { data } = await gmail.users.drafts.get({ userId: 'me', id: params.id, format: 'full' });
|
|
112
|
+
if (data.message?.payload) {
|
|
113
|
+
data.message.payload = processMessagePart(data.message.payload, params.includeBodyHtml);
|
|
114
|
+
}
|
|
115
|
+
return JSON.stringify(data);
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
server.addTool({
|
|
120
|
+
name: 'listDrafts',
|
|
121
|
+
description: 'List drafts in the user\'s mailbox',
|
|
122
|
+
parameters: z.object({
|
|
123
|
+
maxResults: z.number().optional().describe("Maximum number of drafts to return (1-500)"),
|
|
124
|
+
q: z.string().optional().describe("Only return drafts matching the specified query"),
|
|
125
|
+
includeSpamTrash: z.boolean().optional().describe("Include drafts from SPAM and TRASH"),
|
|
126
|
+
includeBodyHtml: z.boolean().optional().describe("Whether to include the parsed HTML in the return for each body"),
|
|
127
|
+
}),
|
|
128
|
+
execute: async (params) => {
|
|
129
|
+
const gmail = await getGmailClient();
|
|
130
|
+
let drafts = [];
|
|
131
|
+
const { data } = await gmail.users.drafts.list({ userId: 'me', ...params });
|
|
132
|
+
drafts.push(...(data.drafts || []));
|
|
133
|
+
let pageToken = data.nextPageToken;
|
|
134
|
+
while (pageToken) {
|
|
135
|
+
const { data: nextData } = await gmail.users.drafts.list({ userId: 'me', ...params, pageToken });
|
|
136
|
+
drafts.push(...(nextData.drafts || []));
|
|
137
|
+
pageToken = nextData.nextPageToken;
|
|
138
|
+
}
|
|
139
|
+
drafts = drafts.map(draft => {
|
|
140
|
+
if (draft.message?.payload) {
|
|
141
|
+
draft.message.payload = processMessagePart(draft.message.payload, params.includeBodyHtml);
|
|
142
|
+
}
|
|
143
|
+
return draft;
|
|
144
|
+
});
|
|
145
|
+
return JSON.stringify(drafts);
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
server.addTool({
|
|
150
|
+
name: 'sendDraft',
|
|
151
|
+
description: 'Send an existing draft',
|
|
152
|
+
parameters: z.object({
|
|
153
|
+
id: z.string().describe("The ID of the draft to send"),
|
|
154
|
+
}),
|
|
155
|
+
execute: async (params) => {
|
|
156
|
+
const gmail = await getGmailClient();
|
|
157
|
+
try {
|
|
158
|
+
const { data } = await gmail.users.drafts.send({ userId: 'me', requestBody: { id: params.id } });
|
|
159
|
+
return JSON.stringify(data);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
throw new UserError('Error sending draft, are you sure you have at least one recipient?');
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
}
|
|
@@ -1,83 +1,54 @@
|
|
|
1
|
-
// Gmail Label tools
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
execute: async () => {
|
|
56
|
-
const gmail = await getGmailClient();
|
|
57
|
-
const { data } = await gmail.users.labels.list({ userId: 'me' });
|
|
58
|
-
return JSON.stringify(data);
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
server.addTool({
|
|
63
|
-
name: 'patch_label',
|
|
64
|
-
description: 'Patch an existing label (partial update)',
|
|
65
|
-
parameters: z.object({
|
|
66
|
-
id: z.string().describe("The ID of the label to patch"),
|
|
67
|
-
name: z.string().optional().describe("The display name of the label"),
|
|
68
|
-
messageListVisibility: z.enum(['show', 'hide']).optional().describe("Visibility of messages with this label"),
|
|
69
|
-
labelListVisibility: z.enum(['labelShow', 'labelShowIfUnread', 'labelHide']).optional().describe("Visibility of the label in the label list"),
|
|
70
|
-
color: z.object({
|
|
71
|
-
textColor: z.string().describe("The text color as hex string"),
|
|
72
|
-
backgroundColor: z.string().describe("The background color as hex string"),
|
|
73
|
-
}).optional().describe("The color settings for the label"),
|
|
74
|
-
}),
|
|
75
|
-
execute: async (params) => {
|
|
76
|
-
const { id, ...labelData } = params;
|
|
77
|
-
const gmail = await getGmailClient();
|
|
78
|
-
const { data } = await gmail.users.labels.patch({ userId: 'me', id, requestBody: labelData });
|
|
79
|
-
return JSON.stringify(data);
|
|
80
|
-
},
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
}
|
|
1
|
+
// Gmail Label tools — consolidated dispatch tool (issue #31/#32/#33).
|
|
2
|
+
// manageLabel replaces create/patch/delete/get/list_label(s).
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { UserError } from 'fastmcp';
|
|
5
|
+
import { getGmailClient } from '../../clients.js';
|
|
6
|
+
|
|
7
|
+
export function register(server) {
|
|
8
|
+
server.addTool({
|
|
9
|
+
name: 'manageLabel',
|
|
10
|
+
description:
|
|
11
|
+
'Manage Gmail labels. action: create | patch | delete | get | list. ' +
|
|
12
|
+
'create requires name. patch/delete/get require id.',
|
|
13
|
+
parameters: z.object({
|
|
14
|
+
action: z.enum(['create', 'patch', 'delete', 'get', 'list']).describe('The label operation to perform'),
|
|
15
|
+
id: z.string().optional().describe('The label ID (required for patch, delete, get)'),
|
|
16
|
+
name: z.string().optional().describe('The display name of the label (required for create)'),
|
|
17
|
+
messageListVisibility: z.enum(['show', 'hide']).optional().describe('Visibility of messages with this label in the message list'),
|
|
18
|
+
labelListVisibility: z.enum(['labelShow', 'labelShowIfUnread', 'labelHide']).optional().describe('Visibility of the label in the label list'),
|
|
19
|
+
color: z.object({
|
|
20
|
+
textColor: z.string().describe('The text color as hex string'),
|
|
21
|
+
backgroundColor: z.string().describe('The background color as hex string'),
|
|
22
|
+
}).optional().describe('The color settings for the label'),
|
|
23
|
+
}),
|
|
24
|
+
execute: async (params) => {
|
|
25
|
+
if (params.action === 'create' && !params.name) {
|
|
26
|
+
throw new UserError('manageLabel action="create" requires name.');
|
|
27
|
+
}
|
|
28
|
+
if (['patch', 'delete', 'get'].includes(params.action) && !params.id) {
|
|
29
|
+
throw new UserError(`manageLabel action="${params.action}" requires id.`);
|
|
30
|
+
}
|
|
31
|
+
const gmail = await getGmailClient();
|
|
32
|
+
const { action, id, ...labelData } = params;
|
|
33
|
+
let data;
|
|
34
|
+
switch (action) {
|
|
35
|
+
case 'create':
|
|
36
|
+
({ data } = await gmail.users.labels.create({ userId: 'me', requestBody: labelData }));
|
|
37
|
+
break;
|
|
38
|
+
case 'patch':
|
|
39
|
+
({ data } = await gmail.users.labels.patch({ userId: 'me', id, requestBody: labelData }));
|
|
40
|
+
break;
|
|
41
|
+
case 'delete':
|
|
42
|
+
({ data } = await gmail.users.labels.delete({ userId: 'me', id }));
|
|
43
|
+
break;
|
|
44
|
+
case 'get':
|
|
45
|
+
({ data } = await gmail.users.labels.get({ userId: 'me', id }));
|
|
46
|
+
break;
|
|
47
|
+
case 'list':
|
|
48
|
+
({ data } = await gmail.users.labels.list({ userId: 'me' }));
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
return JSON.stringify(data || { success: true });
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
}
|