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.
Files changed (97) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +537 -276
  3. package/dist/cachedToolsList.js +52 -52
  4. package/dist/googleDocsApiHelpers.js +76 -12
  5. package/dist/helpers.js +572 -252
  6. package/dist/httpAuth.js +296 -0
  7. package/dist/index.js +162 -11
  8. package/dist/logger.js +87 -87
  9. package/dist/markdown-transformer/docsToMarkdown.js +128 -0
  10. package/dist/markdown-transformer/index.js +17 -7
  11. package/dist/markdown-transformer/markdownToDocs.js +185 -27
  12. package/dist/readTracker.js +136 -17
  13. package/dist/sessionContext.js +37 -0
  14. package/dist/setup.js +187 -9
  15. package/dist/tools/calendar/getBusy.js +64 -64
  16. package/dist/tools/calendar/getEvents.js +141 -141
  17. package/dist/tools/calendar/getFree.js +225 -225
  18. package/dist/tools/calendar/index.js +19 -19
  19. package/dist/tools/calendar/listCalendars.js +38 -38
  20. package/dist/tools/calendar/listRecurringInstances.js +83 -83
  21. package/dist/tools/calendar/manageCalendar.js +121 -121
  22. package/dist/tools/calendar/manageEvent.js +258 -258
  23. package/dist/tools/calendar/moveEvent.js +66 -66
  24. package/dist/tools/docs/addTab.js +10 -12
  25. package/dist/tools/docs/appendToGoogleDoc.js +9 -4
  26. package/dist/tools/docs/deleteRange.js +9 -4
  27. package/dist/tools/docs/findAndReplace.js +9 -4
  28. package/dist/tools/docs/formatting/applyParagraphStyle.js +4 -1
  29. package/dist/tools/docs/formatting/getFormatting.js +171 -171
  30. package/dist/tools/docs/insertImage.js +15 -2
  31. package/dist/tools/docs/insertPageBreak.js +4 -1
  32. package/dist/tools/docs/insertTable.js +4 -1
  33. package/dist/tools/docs/insertTableWithData.js +4 -1
  34. package/dist/tools/docs/modifyText.js +14 -4
  35. package/dist/tools/docs/modifyText.test.js +84 -84
  36. package/dist/tools/docs/readGoogleDoc.js +71 -11
  37. package/dist/tools/docs/renameTab.js +12 -14
  38. package/dist/tools/drafts.js +165 -165
  39. package/dist/tools/drive/createDocument.js +12 -0
  40. package/dist/tools/drive/downloadFile.js +268 -268
  41. package/dist/tools/drive/getFileInfo.js +48 -48
  42. package/dist/tools/drive/getFilePath.js +50 -50
  43. package/dist/tools/drive/listDriveFiles.js +112 -112
  44. package/dist/tools/drive/listSharedDrives.js +52 -52
  45. package/dist/tools/drive/listSharedWithMe.js +97 -97
  46. package/dist/tools/drive/uploadFile.js +111 -111
  47. package/dist/tools/extras/index.js +9 -9
  48. package/dist/tools/extras/readDriveFile.js +197 -196
  49. package/dist/tools/extras/readFile.js +84 -84
  50. package/dist/tools/extras/searchFileContents.js +81 -81
  51. package/dist/tools/forms/batchUpdateForm.js +81 -81
  52. package/dist/tools/forms/createForm.js +54 -54
  53. package/dist/tools/forms/getForm.js +118 -118
  54. package/dist/tools/forms/getFormResponse.js +45 -45
  55. package/dist/tools/forms/index.js +15 -15
  56. package/dist/tools/forms/listFormResponses.js +56 -56
  57. package/dist/tools/forms/setPublishSettings.js +59 -59
  58. package/dist/tools/gmail/drafts.js +165 -165
  59. package/dist/tools/gmail/labels.js +54 -83
  60. package/dist/tools/gmail/messages.js +444 -441
  61. package/dist/tools/gmail/settings.js +358 -528
  62. package/dist/tools/gmail/threads.js +286 -164
  63. package/dist/tools/index.js +511 -473
  64. package/dist/tools/labels.js +103 -103
  65. package/dist/tools/legacyAliases.js +426 -0
  66. package/dist/tools/maps/directions.js +72 -0
  67. package/dist/tools/maps/geocode.js +16 -0
  68. package/dist/tools/maps/index.js +15 -0
  69. package/dist/tools/maps/mapsClient.js +83 -0
  70. package/dist/tools/maps/placeDetails.js +16 -0
  71. package/dist/tools/maps/reverseGeocode.js +19 -0
  72. package/dist/tools/maps/searchNearby.js +54 -0
  73. package/dist/tools/maps/searchPlaces.js +24 -0
  74. package/dist/tools/messages.js +448 -448
  75. package/dist/tools/settings.js +528 -528
  76. package/dist/tools/slides/createPresentation.js +104 -104
  77. package/dist/tools/slides/createShape.js +92 -92
  78. package/dist/tools/slides/createTextBox.js +82 -82
  79. package/dist/tools/slides/deleteSlide.js +30 -30
  80. package/dist/tools/slides/duplicateSlide.js +37 -37
  81. package/dist/tools/slides/exportThumbnail.js +42 -42
  82. package/dist/tools/slides/formatParagraph.js +72 -72
  83. package/dist/tools/slides/formatText.js +84 -84
  84. package/dist/tools/slides/getPresentation.js +87 -87
  85. package/dist/tools/slides/index.js +33 -33
  86. package/dist/tools/slides/reorderSlides.js +41 -41
  87. package/dist/tools/slides/replaceAllText.js +46 -46
  88. package/dist/tools/slides/setBackground.js +58 -58
  89. package/dist/tools/slides/speakerNotes.js +102 -102
  90. package/dist/tools/slides/styleShape.js +111 -111
  91. package/dist/tools/slides/updatePresentation.js +128 -128
  92. package/dist/tools/threads.js +145 -145
  93. package/dist/tools/utils/appendMarkdownToGoogleDoc.js +30 -6
  94. package/dist/tools/utils/replaceDocumentWithMarkdown.js +71 -8
  95. package/dist/updateCheck.js +202 -0
  96. package/dist/workspace.js +122 -0
  97. package/package.json +82 -81
@@ -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: 'create_draft',
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: 'update_draft',
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: 'delete_draft',
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: 'get_draft',
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: 'list_drafts',
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: 'send_draft',
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
- import { z } from 'zod';
3
- import { getGmailClient } from '../../clients.js';
4
-
5
- export function register(server) {
6
- server.addTool({
7
- name: 'create_label',
8
- description: 'Create a new label',
9
- parameters: z.object({
10
- name: z.string().describe("The display name of the label"),
11
- messageListVisibility: z.enum(['show', 'hide']).optional().describe("Visibility of messages with this label in the message list"),
12
- labelListVisibility: z.enum(['labelShow', 'labelShowIfUnread', 'labelHide']).optional().describe("Visibility of the label in the label list"),
13
- color: z.object({
14
- textColor: z.string().describe("The text color as hex string"),
15
- backgroundColor: z.string().describe("The background color as hex string"),
16
- }).optional().describe("The color settings for the label"),
17
- }),
18
- execute: async (params) => {
19
- const gmail = await getGmailClient();
20
- const { data } = await gmail.users.labels.create({ userId: 'me', requestBody: params });
21
- return JSON.stringify(data);
22
- },
23
- });
24
-
25
- server.addTool({
26
- name: 'delete_label',
27
- description: 'Delete a label',
28
- parameters: z.object({
29
- id: z.string().describe("The ID of the label to delete"),
30
- }),
31
- execute: async (params) => {
32
- const gmail = await getGmailClient();
33
- const { data } = await gmail.users.labels.delete({ userId: 'me', id: params.id });
34
- return JSON.stringify(data || { success: true });
35
- },
36
- });
37
-
38
- server.addTool({
39
- name: 'get_label',
40
- description: 'Get a specific label by ID',
41
- parameters: z.object({
42
- id: z.string().describe("The ID of the label to retrieve"),
43
- }),
44
- execute: async (params) => {
45
- const gmail = await getGmailClient();
46
- const { data } = await gmail.users.labels.get({ userId: 'me', id: params.id });
47
- return JSON.stringify(data);
48
- },
49
- });
50
-
51
- server.addTool({
52
- name: 'list_labels',
53
- description: 'List all labels in the user\'s mailbox',
54
- parameters: z.object({}),
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
+ }