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.
Files changed (97) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +555 -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 +222 -21
  10. package/dist/markdown-transformer/index.js +19 -9
  11. package/dist/markdown-transformer/markdownToDocs.js +458 -28
  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 +13 -1
  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 +212 -206
  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 +31 -7
  94. package/dist/tools/utils/replaceDocumentWithMarkdown.js +72 -9
  95. package/dist/updateCheck.js +202 -0
  96. package/dist/workspace.js +122 -0
  97. package/package.json +82 -80
@@ -1,111 +1,111 @@
1
- import { UserError } from 'fastmcp';
2
- import { z } from 'zod';
3
- import { getSlidesClient } from '../../clients.js';
4
-
5
- export function register(server) {
6
- server.addTool({
7
- name: 'styleSlidesShape',
8
- description:
9
- 'Style a shape in Google Slides: set background color, outline color/weight/dash style.',
10
- parameters: z.object({
11
- presentationId: z.string().describe('Presentation ID'),
12
- objectId: z.string().describe('Shape object ID'),
13
- backgroundColor: z
14
- .object({
15
- red: z.number().min(0).max(1).optional(),
16
- green: z.number().min(0).max(1).optional(),
17
- blue: z.number().min(0).max(1).optional(),
18
- alpha: z.number().min(0).max(1).optional(),
19
- })
20
- .optional()
21
- .describe('Fill color (RGBA 0-1)'),
22
- outlineColor: z
23
- .object({
24
- red: z.number().min(0).max(1).optional(),
25
- green: z.number().min(0).max(1).optional(),
26
- blue: z.number().min(0).max(1).optional(),
27
- })
28
- .optional()
29
- .describe('Outline color (RGB 0-1)'),
30
- outlineWeight: z.number().optional().describe('Outline thickness in points'),
31
- outlineDashStyle: z
32
- .enum(['SOLID', 'DOT', 'DASH', 'DASH_DOT', 'LONG_DASH', 'LONG_DASH_DOT'])
33
- .optional()
34
- .describe('Outline dash style'),
35
- }),
36
- execute: async (args, { log }) => {
37
- const slidesApi = await getSlidesClient();
38
- const shapeProperties = {};
39
- const fields = [];
40
-
41
- if (args.backgroundColor) {
42
- shapeProperties.shapeBackgroundFill = {
43
- solidFill: {
44
- color: {
45
- rgbColor: {
46
- red: args.backgroundColor.red || 0,
47
- green: args.backgroundColor.green || 0,
48
- blue: args.backgroundColor.blue || 0,
49
- },
50
- },
51
- alpha: args.backgroundColor.alpha ?? 1,
52
- },
53
- };
54
- fields.push('shapeBackgroundFill');
55
- }
56
-
57
- const outline = {};
58
- let hasOutline = false;
59
-
60
- if (args.outlineColor) {
61
- outline.outlineFill = {
62
- solidFill: {
63
- color: {
64
- rgbColor: {
65
- red: args.outlineColor.red || 0,
66
- green: args.outlineColor.green || 0,
67
- blue: args.outlineColor.blue || 0,
68
- },
69
- },
70
- },
71
- };
72
- hasOutline = true;
73
- }
74
- if (args.outlineWeight !== undefined) {
75
- outline.weight = { magnitude: args.outlineWeight, unit: 'PT' };
76
- hasOutline = true;
77
- }
78
- if (args.outlineDashStyle) {
79
- outline.dashStyle = args.outlineDashStyle;
80
- hasOutline = true;
81
- }
82
- if (hasOutline) {
83
- shapeProperties.outline = outline;
84
- fields.push('outline');
85
- }
86
-
87
- if (fields.length === 0) throw new UserError('No styling options specified');
88
-
89
- try {
90
- await slidesApi.presentations.batchUpdate({
91
- presentationId: args.presentationId,
92
- requestBody: {
93
- requests: [
94
- {
95
- updateShapeProperties: {
96
- objectId: args.objectId,
97
- shapeProperties,
98
- fields: fields.join(','),
99
- },
100
- },
101
- ],
102
- },
103
- });
104
- return JSON.stringify({ success: true, message: `Applied styling to shape ${args.objectId}` });
105
- } catch (error) {
106
- log.error(`Error styling shape: ${error.message || error}`);
107
- throw new UserError(`Failed to style shape: ${error.message || 'Unknown error'}`);
108
- }
109
- },
110
- });
111
- }
1
+ import { UserError } from 'fastmcp';
2
+ import { z } from 'zod';
3
+ import { getSlidesClient } from '../../clients.js';
4
+
5
+ export function register(server) {
6
+ server.addTool({
7
+ name: 'styleSlidesShape',
8
+ description:
9
+ 'Style a shape in Google Slides: set background color, outline color/weight/dash style.',
10
+ parameters: z.object({
11
+ presentationId: z.string().describe('Presentation ID'),
12
+ objectId: z.string().describe('Shape object ID'),
13
+ backgroundColor: z
14
+ .object({
15
+ red: z.number().min(0).max(1).optional(),
16
+ green: z.number().min(0).max(1).optional(),
17
+ blue: z.number().min(0).max(1).optional(),
18
+ alpha: z.number().min(0).max(1).optional(),
19
+ })
20
+ .optional()
21
+ .describe('Fill color (RGBA 0-1)'),
22
+ outlineColor: z
23
+ .object({
24
+ red: z.number().min(0).max(1).optional(),
25
+ green: z.number().min(0).max(1).optional(),
26
+ blue: z.number().min(0).max(1).optional(),
27
+ })
28
+ .optional()
29
+ .describe('Outline color (RGB 0-1)'),
30
+ outlineWeight: z.number().optional().describe('Outline thickness in points'),
31
+ outlineDashStyle: z
32
+ .enum(['SOLID', 'DOT', 'DASH', 'DASH_DOT', 'LONG_DASH', 'LONG_DASH_DOT'])
33
+ .optional()
34
+ .describe('Outline dash style'),
35
+ }),
36
+ execute: async (args, { log }) => {
37
+ const slidesApi = await getSlidesClient();
38
+ const shapeProperties = {};
39
+ const fields = [];
40
+
41
+ if (args.backgroundColor) {
42
+ shapeProperties.shapeBackgroundFill = {
43
+ solidFill: {
44
+ color: {
45
+ rgbColor: {
46
+ red: args.backgroundColor.red || 0,
47
+ green: args.backgroundColor.green || 0,
48
+ blue: args.backgroundColor.blue || 0,
49
+ },
50
+ },
51
+ alpha: args.backgroundColor.alpha ?? 1,
52
+ },
53
+ };
54
+ fields.push('shapeBackgroundFill');
55
+ }
56
+
57
+ const outline = {};
58
+ let hasOutline = false;
59
+
60
+ if (args.outlineColor) {
61
+ outline.outlineFill = {
62
+ solidFill: {
63
+ color: {
64
+ rgbColor: {
65
+ red: args.outlineColor.red || 0,
66
+ green: args.outlineColor.green || 0,
67
+ blue: args.outlineColor.blue || 0,
68
+ },
69
+ },
70
+ },
71
+ };
72
+ hasOutline = true;
73
+ }
74
+ if (args.outlineWeight !== undefined) {
75
+ outline.weight = { magnitude: args.outlineWeight, unit: 'PT' };
76
+ hasOutline = true;
77
+ }
78
+ if (args.outlineDashStyle) {
79
+ outline.dashStyle = args.outlineDashStyle;
80
+ hasOutline = true;
81
+ }
82
+ if (hasOutline) {
83
+ shapeProperties.outline = outline;
84
+ fields.push('outline');
85
+ }
86
+
87
+ if (fields.length === 0) throw new UserError('No styling options specified');
88
+
89
+ try {
90
+ await slidesApi.presentations.batchUpdate({
91
+ presentationId: args.presentationId,
92
+ requestBody: {
93
+ requests: [
94
+ {
95
+ updateShapeProperties: {
96
+ objectId: args.objectId,
97
+ shapeProperties,
98
+ fields: fields.join(','),
99
+ },
100
+ },
101
+ ],
102
+ },
103
+ });
104
+ return JSON.stringify({ success: true, message: `Applied styling to shape ${args.objectId}` });
105
+ } catch (error) {
106
+ log.error(`Error styling shape: ${error.message || error}`);
107
+ throw new UserError(`Failed to style shape: ${error.message || 'Unknown error'}`);
108
+ }
109
+ },
110
+ });
111
+ }
@@ -1,128 +1,128 @@
1
- import { UserError } from 'fastmcp';
2
- import { z } from 'zod';
3
- import { getSlidesClient } from '../../clients.js';
4
-
5
- export function register(server) {
6
- server.addTool({
7
- name: 'updatePresentation',
8
- description:
9
- 'Replace all slides in an existing Google Slides presentation with new content. Deletes existing slides and creates new ones with the provided title/content pairs.',
10
- parameters: z.object({
11
- presentationId: z.string().describe('Presentation ID'),
12
- slides: z
13
- .array(
14
- z.object({
15
- title: z.string().describe('Slide title'),
16
- content: z.string().describe('Slide body content'),
17
- }),
18
- )
19
- .min(1)
20
- .describe('Array of slide objects to replace existing slides'),
21
- }),
22
- execute: async (args, { log }) => {
23
- const slidesApi = await getSlidesClient();
24
- log.info(`Updating presentation: ${args.presentationId}`);
25
-
26
- try {
27
- const currentPresentation = await slidesApi.presentations.get({
28
- presentationId: args.presentationId,
29
- });
30
-
31
- if (!currentPresentation.data.slides) {
32
- throw new UserError('No slides found in presentation');
33
- }
34
-
35
- // Delete all slides except the first, then clear and rewrite the first
36
- const slideIdsToDelete = currentPresentation.data.slides
37
- .slice(1)
38
- .map((s) => s.objectId)
39
- .filter(Boolean);
40
-
41
- const requests = [];
42
-
43
- // Delete extra slides
44
- for (const id of slideIdsToDelete) {
45
- requests.push({ deleteObject: { objectId: id } });
46
- }
47
-
48
- // Clear text from the first slide's text elements
49
- const firstSlide = currentPresentation.data.slides[0];
50
- if (firstSlide?.pageElements) {
51
- for (const el of firstSlide.pageElements) {
52
- if (el.objectId && el.shape?.text) {
53
- requests.push({ deleteText: { objectId: el.objectId, textRange: { type: 'ALL' } } });
54
- }
55
- }
56
- }
57
-
58
- // Insert new content into first slide
59
- const firstContent = args.slides[0];
60
- if (firstSlide?.pageElements) {
61
- let titleId, bodyId;
62
- for (const el of firstSlide.pageElements) {
63
- const pt = el.shape?.placeholder?.type;
64
- if (pt === 'TITLE' || pt === 'CENTERED_TITLE') titleId = el.objectId;
65
- else if (pt === 'BODY' || pt === 'SUBTITLE') bodyId = el.objectId;
66
- }
67
- if (titleId) requests.push({ insertText: { objectId: titleId, text: firstContent.title, insertionIndex: 0 } });
68
- if (bodyId) requests.push({ insertText: { objectId: bodyId, text: firstContent.content, insertionIndex: 0 } });
69
- }
70
-
71
- // Create additional slides
72
- for (let i = 1; i < args.slides.length; i++) {
73
- requests.push({
74
- createSlide: {
75
- objectId: `slide_${Date.now()}_${i}`,
76
- slideLayoutReference: { predefinedLayout: 'TITLE_AND_BODY' },
77
- },
78
- });
79
- }
80
-
81
- await slidesApi.presentations.batchUpdate({
82
- presentationId: args.presentationId,
83
- requestBody: { requests },
84
- });
85
-
86
- // Populate new slides (index 1+)
87
- if (args.slides.length > 1) {
88
- const updated = await slidesApi.presentations.get({ presentationId: args.presentationId });
89
- const contentRequests = [];
90
- for (let i = 1; i < args.slides.length && updated.data.slides; i++) {
91
- const slide = args.slides[i];
92
- const pageSlide = updated.data.slides[i];
93
- if (!pageSlide?.pageElements) continue;
94
- for (const el of pageSlide.pageElements) {
95
- if (!el.objectId) continue;
96
- const pt = el.shape?.placeholder?.type;
97
- if (pt === 'TITLE' || pt === 'CENTERED_TITLE') {
98
- contentRequests.push({ insertText: { objectId: el.objectId, text: slide.title, insertionIndex: 0 } });
99
- } else if (pt === 'BODY' || pt === 'SUBTITLE') {
100
- contentRequests.push({ insertText: { objectId: el.objectId, text: slide.content, insertionIndex: 0 } });
101
- }
102
- }
103
- }
104
- if (contentRequests.length > 0) {
105
- await slidesApi.presentations.batchUpdate({
106
- presentationId: args.presentationId,
107
- requestBody: { requests: contentRequests },
108
- });
109
- }
110
- }
111
-
112
- return JSON.stringify(
113
- {
114
- presentationId: args.presentationId,
115
- slidesUpdated: args.slides.length,
116
- link: `https://docs.google.com/presentation/d/${args.presentationId}`,
117
- },
118
- null,
119
- 2,
120
- );
121
- } catch (error) {
122
- if (error instanceof UserError) throw error;
123
- log.error(`Error updating presentation: ${error.message || error}`);
124
- throw new UserError(`Failed to update presentation: ${error.message || 'Unknown error'}`);
125
- }
126
- },
127
- });
128
- }
1
+ import { UserError } from 'fastmcp';
2
+ import { z } from 'zod';
3
+ import { getSlidesClient } from '../../clients.js';
4
+
5
+ export function register(server) {
6
+ server.addTool({
7
+ name: 'updatePresentation',
8
+ description:
9
+ 'Replace all slides in an existing Google Slides presentation with new content. Deletes existing slides and creates new ones with the provided title/content pairs.',
10
+ parameters: z.object({
11
+ presentationId: z.string().describe('Presentation ID'),
12
+ slides: z
13
+ .array(
14
+ z.object({
15
+ title: z.string().describe('Slide title'),
16
+ content: z.string().describe('Slide body content'),
17
+ }),
18
+ )
19
+ .min(1)
20
+ .describe('Array of slide objects to replace existing slides'),
21
+ }),
22
+ execute: async (args, { log }) => {
23
+ const slidesApi = await getSlidesClient();
24
+ log.info(`Updating presentation: ${args.presentationId}`);
25
+
26
+ try {
27
+ const currentPresentation = await slidesApi.presentations.get({
28
+ presentationId: args.presentationId,
29
+ });
30
+
31
+ if (!currentPresentation.data.slides) {
32
+ throw new UserError('No slides found in presentation');
33
+ }
34
+
35
+ // Delete all slides except the first, then clear and rewrite the first
36
+ const slideIdsToDelete = currentPresentation.data.slides
37
+ .slice(1)
38
+ .map((s) => s.objectId)
39
+ .filter(Boolean);
40
+
41
+ const requests = [];
42
+
43
+ // Delete extra slides
44
+ for (const id of slideIdsToDelete) {
45
+ requests.push({ deleteObject: { objectId: id } });
46
+ }
47
+
48
+ // Clear text from the first slide's text elements
49
+ const firstSlide = currentPresentation.data.slides[0];
50
+ if (firstSlide?.pageElements) {
51
+ for (const el of firstSlide.pageElements) {
52
+ if (el.objectId && el.shape?.text) {
53
+ requests.push({ deleteText: { objectId: el.objectId, textRange: { type: 'ALL' } } });
54
+ }
55
+ }
56
+ }
57
+
58
+ // Insert new content into first slide
59
+ const firstContent = args.slides[0];
60
+ if (firstSlide?.pageElements) {
61
+ let titleId, bodyId;
62
+ for (const el of firstSlide.pageElements) {
63
+ const pt = el.shape?.placeholder?.type;
64
+ if (pt === 'TITLE' || pt === 'CENTERED_TITLE') titleId = el.objectId;
65
+ else if (pt === 'BODY' || pt === 'SUBTITLE') bodyId = el.objectId;
66
+ }
67
+ if (titleId) requests.push({ insertText: { objectId: titleId, text: firstContent.title, insertionIndex: 0 } });
68
+ if (bodyId) requests.push({ insertText: { objectId: bodyId, text: firstContent.content, insertionIndex: 0 } });
69
+ }
70
+
71
+ // Create additional slides
72
+ for (let i = 1; i < args.slides.length; i++) {
73
+ requests.push({
74
+ createSlide: {
75
+ objectId: `slide_${Date.now()}_${i}`,
76
+ slideLayoutReference: { predefinedLayout: 'TITLE_AND_BODY' },
77
+ },
78
+ });
79
+ }
80
+
81
+ await slidesApi.presentations.batchUpdate({
82
+ presentationId: args.presentationId,
83
+ requestBody: { requests },
84
+ });
85
+
86
+ // Populate new slides (index 1+)
87
+ if (args.slides.length > 1) {
88
+ const updated = await slidesApi.presentations.get({ presentationId: args.presentationId });
89
+ const contentRequests = [];
90
+ for (let i = 1; i < args.slides.length && updated.data.slides; i++) {
91
+ const slide = args.slides[i];
92
+ const pageSlide = updated.data.slides[i];
93
+ if (!pageSlide?.pageElements) continue;
94
+ for (const el of pageSlide.pageElements) {
95
+ if (!el.objectId) continue;
96
+ const pt = el.shape?.placeholder?.type;
97
+ if (pt === 'TITLE' || pt === 'CENTERED_TITLE') {
98
+ contentRequests.push({ insertText: { objectId: el.objectId, text: slide.title, insertionIndex: 0 } });
99
+ } else if (pt === 'BODY' || pt === 'SUBTITLE') {
100
+ contentRequests.push({ insertText: { objectId: el.objectId, text: slide.content, insertionIndex: 0 } });
101
+ }
102
+ }
103
+ }
104
+ if (contentRequests.length > 0) {
105
+ await slidesApi.presentations.batchUpdate({
106
+ presentationId: args.presentationId,
107
+ requestBody: { requests: contentRequests },
108
+ });
109
+ }
110
+ }
111
+
112
+ return JSON.stringify(
113
+ {
114
+ presentationId: args.presentationId,
115
+ slidesUpdated: args.slides.length,
116
+ link: `https://docs.google.com/presentation/d/${args.presentationId}`,
117
+ },
118
+ null,
119
+ 2,
120
+ );
121
+ } catch (error) {
122
+ if (error instanceof UserError) throw error;
123
+ log.error(`Error updating presentation: ${error.message || error}`);
124
+ throw new UserError(`Failed to update presentation: ${error.message || 'Unknown error'}`);
125
+ }
126
+ },
127
+ });
128
+ }