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,104 +1,104 @@
1
- import { UserError } from 'fastmcp';
2
- import { z } from 'zod';
3
- import { getSlidesClient, getDriveClient } from '../../clients.js';
4
-
5
- export function register(server) {
6
- server.addTool({
7
- name: 'createPresentation',
8
- description:
9
- 'Create a new Google Slides presentation with initial slides. Each slide has a title and content body using the TITLE_AND_BODY layout.',
10
- parameters: z.object({
11
- name: z.string().describe('Presentation name'),
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 with title and content'),
21
- parentFolderId: z.string().optional().describe('Parent Drive folder ID (defaults to root)'),
22
- }),
23
- execute: async (args, { log }) => {
24
- const slides = await getSlidesClient();
25
- const drive = await getDriveClient();
26
- log.info(`Creating presentation: ${args.name}`);
27
-
28
- try {
29
- // Create the presentation
30
- const presentation = await slides.presentations.create({
31
- requestBody: { title: args.name },
32
- });
33
- const presentationId = presentation.data.presentationId;
34
-
35
- // Move to folder if specified
36
- if (args.parentFolderId) {
37
- await drive.files.update({
38
- fileId: presentationId,
39
- addParents: args.parentFolderId,
40
- removeParents: 'root',
41
- supportsAllDrives: true,
42
- });
43
- }
44
-
45
- // Create each slide and populate content
46
- for (const slide of args.slides) {
47
- const slideObjectId = `slide_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
48
- await slides.presentations.batchUpdate({
49
- presentationId,
50
- requestBody: {
51
- requests: [
52
- {
53
- createSlide: {
54
- objectId: slideObjectId,
55
- slideLayoutReference: { predefinedLayout: 'TITLE_AND_BODY' },
56
- },
57
- },
58
- ],
59
- },
60
- });
61
-
62
- // Get the slide to find placeholder IDs
63
- const slidePage = await slides.presentations.pages.get({
64
- presentationId,
65
- pageObjectId: slideObjectId,
66
- });
67
-
68
- let titleId = '';
69
- let bodyId = '';
70
- for (const el of slidePage.data.pageElements || []) {
71
- if (el.shape?.placeholder?.type === 'TITLE') titleId = el.objectId;
72
- else if (el.shape?.placeholder?.type === 'BODY') bodyId = el.objectId;
73
- }
74
-
75
- const insertRequests = [];
76
- if (titleId) insertRequests.push({ insertText: { objectId: titleId, text: slide.title, insertionIndex: 0 } });
77
- if (bodyId) insertRequests.push({ insertText: { objectId: bodyId, text: slide.content, insertionIndex: 0 } });
78
-
79
- if (insertRequests.length > 0) {
80
- await slides.presentations.batchUpdate({
81
- presentationId,
82
- requestBody: { requests: insertRequests },
83
- });
84
- }
85
- }
86
-
87
- return JSON.stringify(
88
- {
89
- presentationId,
90
- title: args.name,
91
- link: `https://docs.google.com/presentation/d/${presentationId}`,
92
- slidesCreated: args.slides.length,
93
- },
94
- null,
95
- 2,
96
- );
97
- } catch (error) {
98
- log.error(`Error creating presentation: ${error.message || error}`);
99
- if (error.code === 401) throw new UserError('Authentication failed. Try logging out and re-authenticating.');
100
- throw new UserError(`Failed to create presentation: ${error.message || 'Unknown error'}`);
101
- }
102
- },
103
- });
104
- }
1
+ import { UserError } from 'fastmcp';
2
+ import { z } from 'zod';
3
+ import { getSlidesClient, getDriveClient } from '../../clients.js';
4
+
5
+ export function register(server) {
6
+ server.addTool({
7
+ name: 'createPresentation',
8
+ description:
9
+ 'Create a new Google Slides presentation with initial slides. Each slide has a title and content body using the TITLE_AND_BODY layout.',
10
+ parameters: z.object({
11
+ name: z.string().describe('Presentation name'),
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 with title and content'),
21
+ parentFolderId: z.string().optional().describe('Parent Drive folder ID (defaults to root)'),
22
+ }),
23
+ execute: async (args, { log }) => {
24
+ const slides = await getSlidesClient();
25
+ const drive = await getDriveClient();
26
+ log.info(`Creating presentation: ${args.name}`);
27
+
28
+ try {
29
+ // Create the presentation
30
+ const presentation = await slides.presentations.create({
31
+ requestBody: { title: args.name },
32
+ });
33
+ const presentationId = presentation.data.presentationId;
34
+
35
+ // Move to folder if specified
36
+ if (args.parentFolderId) {
37
+ await drive.files.update({
38
+ fileId: presentationId,
39
+ addParents: args.parentFolderId,
40
+ removeParents: 'root',
41
+ supportsAllDrives: true,
42
+ });
43
+ }
44
+
45
+ // Create each slide and populate content
46
+ for (const slide of args.slides) {
47
+ const slideObjectId = `slide_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
48
+ await slides.presentations.batchUpdate({
49
+ presentationId,
50
+ requestBody: {
51
+ requests: [
52
+ {
53
+ createSlide: {
54
+ objectId: slideObjectId,
55
+ slideLayoutReference: { predefinedLayout: 'TITLE_AND_BODY' },
56
+ },
57
+ },
58
+ ],
59
+ },
60
+ });
61
+
62
+ // Get the slide to find placeholder IDs
63
+ const slidePage = await slides.presentations.pages.get({
64
+ presentationId,
65
+ pageObjectId: slideObjectId,
66
+ });
67
+
68
+ let titleId = '';
69
+ let bodyId = '';
70
+ for (const el of slidePage.data.pageElements || []) {
71
+ if (el.shape?.placeholder?.type === 'TITLE') titleId = el.objectId;
72
+ else if (el.shape?.placeholder?.type === 'BODY') bodyId = el.objectId;
73
+ }
74
+
75
+ const insertRequests = [];
76
+ if (titleId) insertRequests.push({ insertText: { objectId: titleId, text: slide.title, insertionIndex: 0 } });
77
+ if (bodyId) insertRequests.push({ insertText: { objectId: bodyId, text: slide.content, insertionIndex: 0 } });
78
+
79
+ if (insertRequests.length > 0) {
80
+ await slides.presentations.batchUpdate({
81
+ presentationId,
82
+ requestBody: { requests: insertRequests },
83
+ });
84
+ }
85
+ }
86
+
87
+ return JSON.stringify(
88
+ {
89
+ presentationId,
90
+ title: args.name,
91
+ link: `https://docs.google.com/presentation/d/${presentationId}`,
92
+ slidesCreated: args.slides.length,
93
+ },
94
+ null,
95
+ 2,
96
+ );
97
+ } catch (error) {
98
+ log.error(`Error creating presentation: ${error.message || error}`);
99
+ if (error.code === 401) throw new UserError('Authentication failed. Try logging out and re-authenticating.');
100
+ throw new UserError(`Failed to create presentation: ${error.message || 'Unknown error'}`);
101
+ }
102
+ },
103
+ });
104
+ }
@@ -1,92 +1,92 @@
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: 'createSlidesShape',
8
- description:
9
- 'Create a shape on a slide in Google Slides. Position and size are in EMU (914400 EMU = 1 inch).',
10
- parameters: z.object({
11
- presentationId: z.string().describe('Presentation ID'),
12
- pageObjectId: z.string().describe('Slide page object ID'),
13
- shapeType: z
14
- .enum(['RECTANGLE', 'ELLIPSE', 'DIAMOND', 'TRIANGLE', 'STAR', 'ROUND_RECTANGLE', 'ARROW'])
15
- .describe('Shape type'),
16
- x: z.number().describe('X position in EMU'),
17
- y: z.number().describe('Y position in EMU'),
18
- width: z.number().describe('Width in EMU'),
19
- height: z.number().describe('Height in EMU'),
20
- backgroundColor: z
21
- .object({
22
- red: z.number().min(0).max(1).optional(),
23
- green: z.number().min(0).max(1).optional(),
24
- blue: z.number().min(0).max(1).optional(),
25
- alpha: z.number().min(0).max(1).optional(),
26
- })
27
- .optional()
28
- .describe('Fill color (RGBA 0-1)'),
29
- }),
30
- execute: async (args, { log }) => {
31
- const slidesApi = await getSlidesClient();
32
- const elementId = `shape_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
33
-
34
- const requests = [
35
- {
36
- createShape: {
37
- objectId: elementId,
38
- shapeType: args.shapeType,
39
- elementProperties: {
40
- pageObjectId: args.pageObjectId,
41
- size: {
42
- width: { magnitude: args.width, unit: 'EMU' },
43
- height: { magnitude: args.height, unit: 'EMU' },
44
- },
45
- transform: {
46
- scaleX: 1,
47
- scaleY: 1,
48
- translateX: args.x,
49
- translateY: args.y,
50
- unit: 'EMU',
51
- },
52
- },
53
- },
54
- },
55
- ];
56
-
57
- if (args.backgroundColor) {
58
- requests.push({
59
- updateShapeProperties: {
60
- objectId: elementId,
61
- shapeProperties: {
62
- shapeBackgroundFill: {
63
- solidFill: {
64
- color: {
65
- rgbColor: {
66
- red: args.backgroundColor.red || 0,
67
- green: args.backgroundColor.green || 0,
68
- blue: args.backgroundColor.blue || 0,
69
- },
70
- },
71
- alpha: args.backgroundColor.alpha ?? 1,
72
- },
73
- },
74
- },
75
- fields: 'shapeBackgroundFill',
76
- },
77
- });
78
- }
79
-
80
- try {
81
- await slidesApi.presentations.batchUpdate({
82
- presentationId: args.presentationId,
83
- requestBody: { requests },
84
- });
85
- return JSON.stringify({ success: true, objectId: elementId, message: `Created ${args.shapeType} shape: ${elementId}` });
86
- } catch (error) {
87
- log.error(`Error creating shape: ${error.message || error}`);
88
- throw new UserError(`Failed to create shape: ${error.message || 'Unknown error'}`);
89
- }
90
- },
91
- });
92
- }
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: 'createSlidesShape',
8
+ description:
9
+ 'Create a shape on a slide in Google Slides. Position and size are in EMU (914400 EMU = 1 inch).',
10
+ parameters: z.object({
11
+ presentationId: z.string().describe('Presentation ID'),
12
+ pageObjectId: z.string().describe('Slide page object ID'),
13
+ shapeType: z
14
+ .enum(['RECTANGLE', 'ELLIPSE', 'DIAMOND', 'TRIANGLE', 'STAR', 'ROUND_RECTANGLE', 'ARROW'])
15
+ .describe('Shape type'),
16
+ x: z.number().describe('X position in EMU'),
17
+ y: z.number().describe('Y position in EMU'),
18
+ width: z.number().describe('Width in EMU'),
19
+ height: z.number().describe('Height in EMU'),
20
+ backgroundColor: z
21
+ .object({
22
+ red: z.number().min(0).max(1).optional(),
23
+ green: z.number().min(0).max(1).optional(),
24
+ blue: z.number().min(0).max(1).optional(),
25
+ alpha: z.number().min(0).max(1).optional(),
26
+ })
27
+ .optional()
28
+ .describe('Fill color (RGBA 0-1)'),
29
+ }),
30
+ execute: async (args, { log }) => {
31
+ const slidesApi = await getSlidesClient();
32
+ const elementId = `shape_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
33
+
34
+ const requests = [
35
+ {
36
+ createShape: {
37
+ objectId: elementId,
38
+ shapeType: args.shapeType,
39
+ elementProperties: {
40
+ pageObjectId: args.pageObjectId,
41
+ size: {
42
+ width: { magnitude: args.width, unit: 'EMU' },
43
+ height: { magnitude: args.height, unit: 'EMU' },
44
+ },
45
+ transform: {
46
+ scaleX: 1,
47
+ scaleY: 1,
48
+ translateX: args.x,
49
+ translateY: args.y,
50
+ unit: 'EMU',
51
+ },
52
+ },
53
+ },
54
+ },
55
+ ];
56
+
57
+ if (args.backgroundColor) {
58
+ requests.push({
59
+ updateShapeProperties: {
60
+ objectId: elementId,
61
+ shapeProperties: {
62
+ shapeBackgroundFill: {
63
+ solidFill: {
64
+ color: {
65
+ rgbColor: {
66
+ red: args.backgroundColor.red || 0,
67
+ green: args.backgroundColor.green || 0,
68
+ blue: args.backgroundColor.blue || 0,
69
+ },
70
+ },
71
+ alpha: args.backgroundColor.alpha ?? 1,
72
+ },
73
+ },
74
+ },
75
+ fields: 'shapeBackgroundFill',
76
+ },
77
+ });
78
+ }
79
+
80
+ try {
81
+ await slidesApi.presentations.batchUpdate({
82
+ presentationId: args.presentationId,
83
+ requestBody: { requests },
84
+ });
85
+ return JSON.stringify({ success: true, objectId: elementId, message: `Created ${args.shapeType} shape: ${elementId}` });
86
+ } catch (error) {
87
+ log.error(`Error creating shape: ${error.message || error}`);
88
+ throw new UserError(`Failed to create shape: ${error.message || 'Unknown error'}`);
89
+ }
90
+ },
91
+ });
92
+ }
@@ -1,82 +1,82 @@
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: 'createSlidesTextBox',
8
- description:
9
- 'Create a text box on a slide in Google Slides. Position and size are in EMU (English Metric Units: 914400 EMU = 1 inch).',
10
- parameters: z.object({
11
- presentationId: z.string().describe('Presentation ID'),
12
- pageObjectId: z.string().describe('Slide page object ID'),
13
- text: z.string().describe('Text content'),
14
- x: z.number().describe('X position in EMU'),
15
- y: z.number().describe('Y position in EMU'),
16
- width: z.number().describe('Width in EMU'),
17
- height: z.number().describe('Height in EMU'),
18
- fontSize: z.number().optional().describe('Font size in points'),
19
- bold: z.boolean().optional().describe('Make text bold'),
20
- italic: z.boolean().optional().describe('Make text italic'),
21
- }),
22
- execute: async (args, { log }) => {
23
- const slidesApi = await getSlidesClient();
24
- const elementId = `textBox_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
25
-
26
- const requests = [
27
- {
28
- createShape: {
29
- objectId: elementId,
30
- shapeType: 'TEXT_BOX',
31
- elementProperties: {
32
- pageObjectId: args.pageObjectId,
33
- size: {
34
- width: { magnitude: args.width, unit: 'EMU' },
35
- height: { magnitude: args.height, unit: 'EMU' },
36
- },
37
- transform: {
38
- scaleX: 1,
39
- scaleY: 1,
40
- translateX: args.x,
41
- translateY: args.y,
42
- unit: 'EMU',
43
- },
44
- },
45
- },
46
- },
47
- {
48
- insertText: { objectId: elementId, text: args.text, insertionIndex: 0 },
49
- },
50
- ];
51
-
52
- // Optional formatting
53
- const textStyle = {};
54
- const fields = [];
55
- if (args.fontSize) { textStyle.fontSize = { magnitude: args.fontSize, unit: 'PT' }; fields.push('fontSize'); }
56
- if (args.bold !== undefined) { textStyle.bold = args.bold; fields.push('bold'); }
57
- if (args.italic !== undefined) { textStyle.italic = args.italic; fields.push('italic'); }
58
-
59
- if (fields.length > 0) {
60
- requests.push({
61
- updateTextStyle: {
62
- objectId: elementId,
63
- style: textStyle,
64
- fields: fields.join(','),
65
- textRange: { type: 'ALL' },
66
- },
67
- });
68
- }
69
-
70
- try {
71
- await slidesApi.presentations.batchUpdate({
72
- presentationId: args.presentationId,
73
- requestBody: { requests },
74
- });
75
- return JSON.stringify({ success: true, objectId: elementId, message: `Created text box: ${elementId}` });
76
- } catch (error) {
77
- log.error(`Error creating text box: ${error.message || error}`);
78
- throw new UserError(`Failed to create text box: ${error.message || 'Unknown error'}`);
79
- }
80
- },
81
- });
82
- }
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: 'createSlidesTextBox',
8
+ description:
9
+ 'Create a text box on a slide in Google Slides. Position and size are in EMU (English Metric Units: 914400 EMU = 1 inch).',
10
+ parameters: z.object({
11
+ presentationId: z.string().describe('Presentation ID'),
12
+ pageObjectId: z.string().describe('Slide page object ID'),
13
+ text: z.string().describe('Text content'),
14
+ x: z.number().describe('X position in EMU'),
15
+ y: z.number().describe('Y position in EMU'),
16
+ width: z.number().describe('Width in EMU'),
17
+ height: z.number().describe('Height in EMU'),
18
+ fontSize: z.number().optional().describe('Font size in points'),
19
+ bold: z.boolean().optional().describe('Make text bold'),
20
+ italic: z.boolean().optional().describe('Make text italic'),
21
+ }),
22
+ execute: async (args, { log }) => {
23
+ const slidesApi = await getSlidesClient();
24
+ const elementId = `textBox_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
25
+
26
+ const requests = [
27
+ {
28
+ createShape: {
29
+ objectId: elementId,
30
+ shapeType: 'TEXT_BOX',
31
+ elementProperties: {
32
+ pageObjectId: args.pageObjectId,
33
+ size: {
34
+ width: { magnitude: args.width, unit: 'EMU' },
35
+ height: { magnitude: args.height, unit: 'EMU' },
36
+ },
37
+ transform: {
38
+ scaleX: 1,
39
+ scaleY: 1,
40
+ translateX: args.x,
41
+ translateY: args.y,
42
+ unit: 'EMU',
43
+ },
44
+ },
45
+ },
46
+ },
47
+ {
48
+ insertText: { objectId: elementId, text: args.text, insertionIndex: 0 },
49
+ },
50
+ ];
51
+
52
+ // Optional formatting
53
+ const textStyle = {};
54
+ const fields = [];
55
+ if (args.fontSize) { textStyle.fontSize = { magnitude: args.fontSize, unit: 'PT' }; fields.push('fontSize'); }
56
+ if (args.bold !== undefined) { textStyle.bold = args.bold; fields.push('bold'); }
57
+ if (args.italic !== undefined) { textStyle.italic = args.italic; fields.push('italic'); }
58
+
59
+ if (fields.length > 0) {
60
+ requests.push({
61
+ updateTextStyle: {
62
+ objectId: elementId,
63
+ style: textStyle,
64
+ fields: fields.join(','),
65
+ textRange: { type: 'ALL' },
66
+ },
67
+ });
68
+ }
69
+
70
+ try {
71
+ await slidesApi.presentations.batchUpdate({
72
+ presentationId: args.presentationId,
73
+ requestBody: { requests },
74
+ });
75
+ return JSON.stringify({ success: true, objectId: elementId, message: `Created text box: ${elementId}` });
76
+ } catch (error) {
77
+ log.error(`Error creating text box: ${error.message || error}`);
78
+ throw new UserError(`Failed to create text box: ${error.message || 'Unknown error'}`);
79
+ }
80
+ },
81
+ });
82
+ }
@@ -1,30 +1,30 @@
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: 'deleteSlide',
8
- description: 'Delete a slide from a Google Slides presentation.',
9
- parameters: z.object({
10
- presentationId: z.string().describe('Presentation ID'),
11
- slideObjectId: z.string().describe('Object ID of the slide to delete'),
12
- }),
13
- execute: async (args, { log }) => {
14
- const slidesApi = await getSlidesClient();
15
-
16
- try {
17
- await slidesApi.presentations.batchUpdate({
18
- presentationId: args.presentationId,
19
- requestBody: {
20
- requests: [{ deleteObject: { objectId: args.slideObjectId } }],
21
- },
22
- });
23
- return JSON.stringify({ success: true, message: `Deleted slide ${args.slideObjectId}` });
24
- } catch (error) {
25
- log.error(`Error deleting slide: ${error.message || error}`);
26
- throw new UserError(`Failed to delete slide: ${error.message || 'Unknown error'}`);
27
- }
28
- },
29
- });
30
- }
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: 'deleteSlide',
8
+ description: 'Delete a slide from a Google Slides presentation.',
9
+ parameters: z.object({
10
+ presentationId: z.string().describe('Presentation ID'),
11
+ slideObjectId: z.string().describe('Object ID of the slide to delete'),
12
+ }),
13
+ execute: async (args, { log }) => {
14
+ const slidesApi = await getSlidesClient();
15
+
16
+ try {
17
+ await slidesApi.presentations.batchUpdate({
18
+ presentationId: args.presentationId,
19
+ requestBody: {
20
+ requests: [{ deleteObject: { objectId: args.slideObjectId } }],
21
+ },
22
+ });
23
+ return JSON.stringify({ success: true, message: `Deleted slide ${args.slideObjectId}` });
24
+ } catch (error) {
25
+ log.error(`Error deleting slide: ${error.message || error}`);
26
+ throw new UserError(`Failed to delete slide: ${error.message || 'Unknown error'}`);
27
+ }
28
+ },
29
+ });
30
+ }