gogcli-mcp-slides 2.30.0 → 4.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.
@@ -1,4 +1,4 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
1
+ import { McpServer } from '@modelcontextprotocol/server';
2
2
  import { z } from 'zod';
3
3
  import { accountParam, runOrDiagnose, payloadArg } from '../../../gogcli-mcp/src/lib.js';
4
4
  import type { GogArg } from '../../../gogcli-mcp/src/lib.js';
@@ -27,14 +27,14 @@ import type { GogArg } from '../../../gogcli-mcp/src/lib.js';
27
27
  export function registerExtraSlidesTools(server: McpServer): void {
28
28
  server.registerTool('gog_slides_create_from_markdown', {
29
29
  description: 'Create a new Google Slides presentation from markdown content (inline or from a file).',
30
- inputSchema: {
30
+ inputSchema: z.object({
31
31
  title: z.string().describe('Presentation title'),
32
32
  content: z.string().optional().describe('Inline markdown content'),
33
33
  contentFile: z.string().optional().describe('Path to a markdown file'),
34
34
  parent: z.string().optional().describe('Destination folder ID'),
35
35
  debug: z.boolean().optional().describe('Enable debug output'),
36
36
  account: accountParam,
37
- },
37
+ }),
38
38
  }, async ({ title, content, contentFile, parent, debug, account }) => {
39
39
  const args: GogArg[] = ['slides', 'create-from-markdown', title];
40
40
  if (content) args.push(payloadArg('content', 'content-file', content, 'md'));
@@ -46,7 +46,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
46
46
 
47
47
  server.registerTool('gog_slides_create_from_template', {
48
48
  description: 'Create a new Google Slides presentation from a template, with optional placeholder replacements.',
49
- inputSchema: {
49
+ inputSchema: z.object({
50
50
  templateId: z.string().describe('Template presentation ID'),
51
51
  title: z.string().describe('New presentation title'),
52
52
  replacements: z.record(z.string(), z.string()).optional().describe('Placeholder replacements as a key/value object (emitted as --replace=k=v for each entry)'),
@@ -54,7 +54,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
54
54
  parent: z.string().optional().describe('Destination folder ID'),
55
55
  exact: z.boolean().optional().describe('Require exact placeholder matches'),
56
56
  account: accountParam,
57
- },
57
+ }),
58
58
  }, async ({ templateId, title, replacements, replacementsFile, parent, exact, account }) => {
59
59
  const args = ['slides', 'create-from-template', templateId, title];
60
60
  if (replacements) {
@@ -70,14 +70,14 @@ export function registerExtraSlidesTools(server: McpServer): void {
70
70
 
71
71
  server.registerTool('gog_slides_add_slide', {
72
72
  description: 'Add a new slide to a presentation from a local image, with optional speaker notes.',
73
- inputSchema: {
73
+ inputSchema: z.object({
74
74
  presentationId: z.string().describe('Presentation ID'),
75
75
  image: z.string().describe('Path to the local image file'),
76
76
  notes: z.string().optional().describe('Speaker notes text'),
77
77
  notesFile: z.string().optional().describe('Path to a file containing speaker notes'),
78
78
  before: z.string().optional().describe('Insert before this slide ID (default: append at end)'),
79
79
  account: accountParam,
80
- },
80
+ }),
81
81
  }, async ({ presentationId, image, notes, notesFile, before, account }) => {
82
82
  const args: GogArg[] = ['slides', 'add-slide', presentationId, image];
83
83
  if (notes) args.push(payloadArg('notes', 'notes-file', notes));
@@ -88,7 +88,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
88
88
 
89
89
  server.registerTool('gog_slides_insert_image', {
90
90
  description: 'Place an image on an existing slide at a given size and position, from a local file (image) or a public HTTPS URL (url — no Drive upload or sharing required). Unlike gog_slides_add_slide (which creates a new full-bleed image slide), this inserts onto a slide you already have. width is required; omit height to keep aspect ratio when using a local file (gog requires both width and height when using url).',
91
- inputSchema: {
91
+ inputSchema: z.object({
92
92
  presentationId: z.string().describe('Presentation ID'),
93
93
  slideId: z.string().describe('Slide ID (object ID of the target slide)'),
94
94
  image: z.string().optional().describe('Path to the local image file (exactly one of image or url)'),
@@ -99,7 +99,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
99
99
  y: z.number().optional().describe('Top position of the image, in unit'),
100
100
  unit: z.enum(['PT', 'EMU']).optional().describe('Measurement unit for x/y/width/height (default: PT)'),
101
101
  account: accountParam,
102
- },
102
+ }),
103
103
  }, async ({ presentationId, slideId, image, url, width, height, x, y, unit, account }) => {
104
104
  const args = ['slides', 'insert-image', presentationId, slideId];
105
105
  if (image) args.push(image);
@@ -115,11 +115,11 @@ export function registerExtraSlidesTools(server: McpServer): void {
115
115
  server.registerTool('gog_slides_delete_slide', {
116
116
  description: 'Delete a slide from a Google Slides presentation.',
117
117
  annotations: { destructiveHint: true },
118
- inputSchema: {
118
+ inputSchema: z.object({
119
119
  presentationId: z.string().describe('Presentation ID'),
120
120
  slideId: z.string().describe('Slide ID to delete'),
121
121
  account: accountParam,
122
- },
122
+ }),
123
123
  }, async ({ presentationId, slideId, account }) => {
124
124
  // --force: gog refuses this delete under the runner's --no-input without it.
125
125
  return runOrDiagnose(['slides', 'delete-slide', presentationId, slideId, '--force'], { account });
@@ -138,11 +138,11 @@ export function registerExtraSlidesTools(server: McpServer): void {
138
138
  'Skip a slide during presentation — it stays in the deck at its current position but is not shown when presenting '
139
139
  + '(and is left out of a PDF export). Use this instead of gog_slides_delete_slide when a slide should be omitted from '
140
140
  + 'a talk without losing it. Reverse with gog_slides_unskip_slide; gog_slides_list_slides reports which slides are skipped.',
141
- inputSchema: {
141
+ inputSchema: z.object({
142
142
  presentationId: z.string().describe('Presentation ID'),
143
143
  slideId: z.string().describe('Slide ID to skip (from gog_slides_list_slides)'),
144
144
  account: accountParam,
145
- },
145
+ }),
146
146
  }, async ({ presentationId, slideId, account }) => {
147
147
  return runOrDiagnose(['slides', 'skip-slide', presentationId, slideId], { account });
148
148
  });
@@ -150,11 +150,11 @@ export function registerExtraSlidesTools(server: McpServer): void {
150
150
  server.registerTool('gog_slides_unskip_slide', {
151
151
  description:
152
152
  'Include a previously skipped slide again when the deck is presented. Safe to call on a slide that was never skipped.',
153
- inputSchema: {
153
+ inputSchema: z.object({
154
154
  presentationId: z.string().describe('Presentation ID'),
155
155
  slideId: z.string().describe('Slide ID to unskip (from gog_slides_list_slides)'),
156
156
  account: accountParam,
157
- },
157
+ }),
158
158
  }, async ({ presentationId, slideId, account }) => {
159
159
  return runOrDiagnose(['slides', 'unskip-slide', presentationId, slideId], { account });
160
160
  });
@@ -162,13 +162,13 @@ export function registerExtraSlidesTools(server: McpServer): void {
162
162
  server.registerTool('gog_slides_update_notes', {
163
163
  description: 'Update the speaker notes on a slide (inline text or from a file).',
164
164
  annotations: { destructiveHint: true },
165
- inputSchema: {
165
+ inputSchema: z.object({
166
166
  presentationId: z.string().describe('Presentation ID'),
167
167
  slideId: z.string().describe('Slide ID'),
168
168
  notes: z.string().optional().describe('New speaker notes text'),
169
169
  notesFile: z.string().optional().describe('Path to a file containing new speaker notes'),
170
170
  account: accountParam,
171
- },
171
+ }),
172
172
  }, async ({ presentationId, slideId, notes, notesFile, account }) => {
173
173
  const args: GogArg[] = ['slides', 'update-notes', presentationId, slideId];
174
174
  if (notes) args.push(payloadArg('notes', 'notes-file', notes));
@@ -179,7 +179,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
179
179
  server.registerTool('gog_slides_replace_slide', {
180
180
  description: 'Replace the image content of an existing slide, from a local file (image) or a public HTTPS URL (url — no Drive upload or sharing required), with optional speaker notes.',
181
181
  annotations: { destructiveHint: true },
182
- inputSchema: {
182
+ inputSchema: z.object({
183
183
  presentationId: z.string().describe('Presentation ID'),
184
184
  slideId: z.string().describe('Slide ID to replace'),
185
185
  image: z.string().optional().describe('Path to the new local image file (exactly one of image or url)'),
@@ -187,7 +187,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
187
187
  notes: z.string().optional().describe('Speaker notes text'),
188
188
  notesFile: z.string().optional().describe('Path to a file containing speaker notes'),
189
189
  account: accountParam,
190
- },
190
+ }),
191
191
  }, async ({ presentationId, slideId, image, url, notes, notesFile, account }) => {
192
192
  const args: GogArg[] = ['slides', 'replace-slide', presentationId, slideId];
193
193
  if (image) args.push(image);
@@ -202,11 +202,11 @@ export function registerExtraSlidesTools(server: McpServer): void {
202
202
  server.registerTool('gog_slides_raw', {
203
203
  description: 'Dump the raw Google Slides API response (Presentations.Get) as JSON — lossless presentation metadata including every page, element, and style. Use gog_slides_read_slide for a friendlier per-slide view.',
204
204
  annotations: { readOnlyHint: true },
205
- inputSchema: {
205
+ inputSchema: z.object({
206
206
  presentationId: z.string().describe('Presentation ID'),
207
207
  pretty: z.boolean().optional().describe('Pretty-print the JSON (default: compact single line)'),
208
208
  account: accountParam,
209
- },
209
+ }),
210
210
  }, async ({ presentationId, pretty, account }) => {
211
211
  const args = ['slides', 'raw', presentationId];
212
212
  if (pretty) args.push('--pretty');
@@ -217,7 +217,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
217
217
  server.registerTool('gog_slides_locate', {
218
218
  description: 'Locate literal text in a presentation\'s shapes and table cells, returning the containing element object IDs and UTF-16 ranges needed for gog_slides_style_text / gog_slides_link / gog_slides_bullets / gog_slides_insert_text. Read-only.',
219
219
  annotations: { readOnlyHint: true },
220
- inputSchema: {
220
+ inputSchema: z.object({
221
221
  presentationId: z.string().describe('Presentation ID'),
222
222
  text: z.string().describe('Literal text to locate'),
223
223
  page: z.string().optional().describe('Limit matches to one slide object ID'),
@@ -226,7 +226,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
226
226
  matchCase: z.boolean().optional().describe('Case-sensitive matching'),
227
227
  failEmpty: z.boolean().optional().describe('Treat no matches as an error instead of returning an empty result'),
228
228
  account: accountParam,
229
- },
229
+ }),
230
230
  }, async ({ presentationId, text, page, occurrence, all, matchCase, failEmpty, account }) => {
231
231
  const args = ['slides', 'locate', presentationId, text];
232
232
  if (page) args.push(`--page=${page}`);
@@ -240,7 +240,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
240
240
  server.registerTool('gog_slides_thumbnail', {
241
241
  description: 'Get or download a rendered thumbnail image for a single slide.',
242
242
  annotations: { readOnlyHint: true },
243
- inputSchema: {
243
+ inputSchema: z.object({
244
244
  presentationId: z.string().describe('Presentation ID'),
245
245
  slideId: z.string().describe('Slide object ID'),
246
246
  format: z.enum(['png', 'jpeg']).optional().describe('Thumbnail image format'),
@@ -248,7 +248,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
248
248
  out: z.string().optional().describe('Write the thumbnail image to a local file'),
249
249
  overwrite: z.boolean().optional().describe('Overwrite the output file if it already exists'),
250
250
  account: accountParam,
251
- },
251
+ }),
252
252
  }, async ({ presentationId, slideId, format, size, out, overwrite, account }) => {
253
253
  const args = ['slides', 'thumbnail', presentationId, slideId];
254
254
  if (format) args.push(`--format=${format}`);
@@ -262,13 +262,13 @@ export function registerExtraSlidesTools(server: McpServer): void {
262
262
 
263
263
  server.registerTool('gog_slides_new_slide', {
264
264
  description: 'Create a new native themed slide with a predefined layout (default BLANK) or an exact presentation layout object ID, at a zero-based insertion index.',
265
- inputSchema: {
265
+ inputSchema: z.object({
266
266
  presentationId: z.string().describe('Presentation ID'),
267
267
  layout: z.enum(['BIG_NUMBER', 'BLANK', 'CAPTION_ONLY', 'MAIN_POINT', 'ONE_COLUMN_TEXT', 'SECTION_HEADER', 'SECTION_TITLE_AND_DESCRIPTION', 'TITLE', 'TITLE_AND_BODY', 'TITLE_AND_TWO_COLUMNS', 'TITLE_ONLY']).optional().describe('Predefined slide layout (default: BLANK). Mutually exclusive with layoutId.'),
268
268
  layoutId: z.string().optional().describe('Exact presentation layout object ID (from gog_slides_info --json). Mutually exclusive with layout.'),
269
269
  index: z.number().int().optional().describe('Zero-based insertion index for the new slide'),
270
270
  account: accountParam,
271
- },
271
+ }),
272
272
  }, async ({ presentationId, layout, layoutId, index, account }) => {
273
273
  const args = ['slides', 'new-slide', presentationId];
274
274
  if (layout) args.push(`--layout=${layout}`);
@@ -279,12 +279,12 @@ export function registerExtraSlidesTools(server: McpServer): void {
279
279
 
280
280
  server.registerTool('gog_slides_duplicate_slide', {
281
281
  description: 'Duplicate a slide by object ID, optionally placing the copy at a zero-based insertion index.',
282
- inputSchema: {
282
+ inputSchema: z.object({
283
283
  presentationId: z.string().describe('Presentation ID'),
284
284
  slideId: z.string().describe('Slide object ID to duplicate'),
285
285
  toIndex: z.number().int().optional().describe('Zero-based insertion index for the duplicated slide'),
286
286
  account: accountParam,
287
- },
287
+ }),
288
288
  }, async ({ presentationId, slideId, toIndex, account }) => {
289
289
  const args = ['slides', 'duplicate-slide', presentationId, slideId];
290
290
  if (toIndex !== undefined) args.push(`--to-index=${toIndex}`);
@@ -293,12 +293,12 @@ export function registerExtraSlidesTools(server: McpServer): void {
293
293
 
294
294
  server.registerTool('gog_slides_move_slide', {
295
295
  description: 'Move a slide to a zero-based insertion index within the presentation.',
296
- inputSchema: {
296
+ inputSchema: z.object({
297
297
  presentationId: z.string().describe('Presentation ID'),
298
298
  slideId: z.string().describe('Slide object ID to move'),
299
299
  toIndex: z.number().int().describe('Zero-based insertion index where the slide should be moved'),
300
300
  account: accountParam,
301
- },
301
+ }),
302
302
  }, async ({ presentationId, slideId, toIndex, account }) => {
303
303
  return runOrDiagnose(['slides', 'move-slide', presentationId, slideId, `--to-index=${toIndex}`], { account });
304
304
  });
@@ -308,7 +308,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
308
308
  server.registerTool('gog_slides_insert_text', {
309
309
  description: 'Insert text into an existing page element (shape or table cell) by object ID. Target a table cell with zero-based row + col. Use replace=true to clear the element\'s existing text first.',
310
310
  annotations: { destructiveHint: true },
311
- inputSchema: {
311
+ inputSchema: z.object({
312
312
  presentationId: z.string().describe('Presentation ID'),
313
313
  objectId: z.string().describe('Object ID of the target shape or table'),
314
314
  text: z.string().describe('Text to insert'),
@@ -317,7 +317,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
317
317
  insertionIndex: z.number().int().optional().describe('Zero-based index where text is inserted within the element\'s existing text'),
318
318
  replace: z.boolean().optional().describe('Clear the element\'s existing text before inserting'),
319
319
  account: accountParam,
320
- },
320
+ }),
321
321
  }, async ({ presentationId, objectId, text, row, col, insertionIndex, replace, account }) => {
322
322
  const args = ['slides', 'insert-text', presentationId, objectId, text];
323
323
  if (row !== undefined) args.push(`--row=${row}`);
@@ -329,7 +329,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
329
329
 
330
330
  server.registerTool('gog_slides_style_text', {
331
331
  description: 'Apply range-scoped text styling to one page element. range is a UTF-16 start:end span (use gog_slides_locate to find it). Boolean flags set the attribute; the no* flags clear it.',
332
- inputSchema: {
332
+ inputSchema: z.object({
333
333
  presentationId: z.string().describe('Presentation ID'),
334
334
  objectId: z.string().describe('Object ID of the shape or table cell containing the text'),
335
335
  range: z.string().describe('UTF-16 text range as start:end'),
@@ -343,7 +343,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
343
343
  underline: z.boolean().optional().describe('Set underline'),
344
344
  noUnderline: z.boolean().optional().describe('Clear underline'),
345
345
  account: accountParam,
346
- },
346
+ }),
347
347
  }, async ({ presentationId, objectId, range, font, size, textColor, bold, noBold, italic, noItalic, underline, noUnderline, account }) => {
348
348
  const args = ['slides', 'style-text', presentationId, objectId, `--range=${range}`];
349
349
  if (font) args.push(`--font=${font}`);
@@ -360,14 +360,14 @@ export function registerExtraSlidesTools(server: McpServer): void {
360
360
 
361
361
  server.registerTool('gog_slides_link', {
362
362
  description: 'Apply or clear a hyperlink on a UTF-16 text range in one page element. Provide url to set the link, or clear=true to remove it.',
363
- inputSchema: {
363
+ inputSchema: z.object({
364
364
  presentationId: z.string().describe('Presentation ID'),
365
365
  objectId: z.string().describe('Object ID of the shape or table cell containing the text'),
366
366
  range: z.string().describe('UTF-16 text range as start:end'),
367
367
  url: z.string().optional().describe('External URL to apply as the hyperlink'),
368
368
  clear: z.boolean().optional().describe('Remove the hyperlink from the selected range'),
369
369
  account: accountParam,
370
- },
370
+ }),
371
371
  }, async ({ presentationId, objectId, range, url, clear, account }) => {
372
372
  const args = ['slides', 'link', presentationId, objectId, `--range=${range}`];
373
373
  if (url) args.push(`--url=${url}`);
@@ -377,7 +377,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
377
377
 
378
378
  server.registerTool('gog_slides_bullets', {
379
379
  description: 'Turn paragraph bullets on or off for a UTF-16 paragraph range in one page element. Use on (optionally with a preset glyph) or off.',
380
- inputSchema: {
380
+ inputSchema: z.object({
381
381
  presentationId: z.string().describe('Presentation ID'),
382
382
  objectId: z.string().describe('Object ID of the shape or table cell containing the paragraphs'),
383
383
  range: z.string().describe('UTF-16 paragraph range as start:end'),
@@ -385,7 +385,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
385
385
  off: z.boolean().optional().describe('Turn bullets off for the selected paragraphs'),
386
386
  preset: z.string().optional().describe('Slides bullet glyph preset to use with on (e.g. BULLET_DISC_CIRCLE_SQUARE)'),
387
387
  account: accountParam,
388
- },
388
+ }),
389
389
  }, async ({ presentationId, objectId, range, on, off, preset, account }) => {
390
390
  const args = ['slides', 'bullets', presentationId, objectId, `--range=${range}`];
391
391
  if (on) args.push('--on');
@@ -397,7 +397,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
397
397
  server.registerTool('gog_slides_replace_text', {
398
398
  description: 'Find-and-replace text within an explicit scope. You MUST choose a scope — restrict to a single shape (object), one or more slides (pages), or the entire presentation (all=true). There is no whole-deck default; gog rejects the call if no scope is given.',
399
399
  annotations: { destructiveHint: true },
400
- inputSchema: {
400
+ inputSchema: z.object({
401
401
  presentationId: z.string().describe('Presentation ID'),
402
402
  find: z.string().describe('Text to find'),
403
403
  replacement: z.string().describe('Replacement text'),
@@ -406,7 +406,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
406
406
  all: z.boolean().optional().describe('Scope: replace matching text across the entire presentation'),
407
407
  matchCase: z.boolean().optional().describe('Case-sensitive match (default: false)'),
408
408
  account: accountParam,
409
- },
409
+ }),
410
410
  }, async ({ presentationId, find, replacement, object, pages, all, matchCase, account }) => {
411
411
  const args = ['slides', 'replace-text', presentationId, find, replacement];
412
412
  if (object) args.push(`--object=${object}`);
@@ -420,7 +420,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
420
420
 
421
421
  server.registerTool('gog_slides_element_create_shape', {
422
422
  description: 'Create a native shape on a slide. type is a Slides shape type (e.g. RECTANGLE, TEXT_BOX, ELLIPSE, ROUND_RECTANGLE). Position/size are in unit (default PT).',
423
- inputSchema: {
423
+ inputSchema: z.object({
424
424
  presentationId: z.string().describe('Presentation ID'),
425
425
  slideId: z.string().describe('Slide object ID to create the shape on'),
426
426
  type: z.string().optional().describe('Slides shape type (e.g. RECTANGLE, TEXT_BOX, ELLIPSE)'),
@@ -431,7 +431,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
431
431
  unit: z.enum(['PT', 'EMU']).optional().describe('Geometry unit (default: PT)'),
432
432
  objectId: z.string().optional().describe('Optional stable object ID (5-50 chars: letters, digits, _, -, :)'),
433
433
  account: accountParam,
434
- },
434
+ }),
435
435
  }, async ({ presentationId, slideId, type, x, y, width, height, unit, objectId, account }) => {
436
436
  const args = ['slides', 'element', 'create-shape', presentationId, slideId];
437
437
  if (type) args.push(`--type=${type}`);
@@ -446,7 +446,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
446
446
 
447
447
  server.registerTool('gog_slides_element_create_line', {
448
448
  description: 'Create a native line on a slide. category is the connector routing (STRAIGHT, BENT, CURVED). Start position and extent are in unit (default PT).',
449
- inputSchema: {
449
+ inputSchema: z.object({
450
450
  presentationId: z.string().describe('Presentation ID'),
451
451
  slideId: z.string().describe('Slide object ID to create the line on'),
452
452
  category: z.enum(['STRAIGHT', 'BENT', 'CURVED']).optional().describe('Line category / routing (default: STRAIGHT)'),
@@ -457,7 +457,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
457
457
  unit: z.enum(['PT', 'EMU']).optional().describe('Geometry unit (default: PT)'),
458
458
  objectId: z.string().optional().describe('Optional stable object ID (5-50 chars: letters, digits, _, -, :)'),
459
459
  account: accountParam,
460
- },
460
+ }),
461
461
  }, async ({ presentationId, slideId, category, x, y, width, height, unit, objectId, account }) => {
462
462
  const args = ['slides', 'element', 'create-line', presentationId, slideId];
463
463
  if (category) args.push(`--category=${category}`);
@@ -472,7 +472,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
472
472
 
473
473
  server.registerTool('gog_slides_element_style', {
474
474
  description: 'Style a shape fill/outline or a line. Set kind to shape or line. Colors are #RGB or #RRGGBB.',
475
- inputSchema: {
475
+ inputSchema: z.object({
476
476
  presentationId: z.string().describe('Presentation ID'),
477
477
  objectId: z.string().describe('Object ID of the shape or line'),
478
478
  kind: z.enum(['shape', 'line']).optional().describe('Element kind (default: shape)'),
@@ -483,7 +483,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
483
483
  outlineDash: z.enum(['SOLID', 'DOT', 'DASH', 'DASH_DOT', 'LONG_DASH', 'LONG_DASH_DOT']).optional().describe('Shape outline or line dash style'),
484
484
  outlineTransparent: z.boolean().optional().describe('Remove the shape outline or make the line transparent'),
485
485
  account: accountParam,
486
- },
486
+ }),
487
487
  }, async ({ presentationId, objectId, kind, fillColor, fillTransparent, outlineColor, outlineWeight, outlineDash, outlineTransparent, account }) => {
488
488
  const args = ['slides', 'element', 'style', presentationId, objectId];
489
489
  if (kind) args.push(`--kind=${kind}`);
@@ -498,7 +498,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
498
498
 
499
499
  server.registerTool('gog_slides_element_transform', {
500
500
  description: 'Move, resize, rotate, or shear a page element. apply-mode RELATIVE (default) composes with the existing transform; ABSOLUTE replaces it. Translation is in unit (default PT).',
501
- inputSchema: {
501
+ inputSchema: z.object({
502
502
  presentationId: z.string().describe('Presentation ID'),
503
503
  objectId: z.string().describe('Object ID of the element to transform'),
504
504
  translateX: z.number().optional().describe('X translation'),
@@ -511,7 +511,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
511
511
  applyMode: z.enum(['RELATIVE', 'ABSOLUTE']).optional().describe('Compose with (RELATIVE, default) or replace (ABSOLUTE) the existing transform'),
512
512
  unit: z.enum(['PT', 'EMU']).optional().describe('Translation unit (default: PT)'),
513
513
  account: accountParam,
514
- },
514
+ }),
515
515
  }, async ({ presentationId, objectId, translateX, translateY, scaleX, scaleY, shearX, shearY, rotate, applyMode, unit, account }) => {
516
516
  const args = ['slides', 'element', 'transform', presentationId, objectId];
517
517
  if (translateX !== undefined) args.push(`--translate-x=${translateX}`);
@@ -528,24 +528,24 @@ export function registerExtraSlidesTools(server: McpServer): void {
528
528
 
529
529
  server.registerTool('gog_slides_element_z_order', {
530
530
  description: 'Change a page element\'s stacking order.',
531
- inputSchema: {
531
+ inputSchema: z.object({
532
532
  presentationId: z.string().describe('Presentation ID'),
533
533
  objectId: z.string().describe('Object ID of the element to restack'),
534
534
  operation: z.enum(['BRING_FORWARD', 'BRING_TO_FRONT', 'SEND_BACKWARD', 'SEND_TO_BACK']).describe('Stacking operation'),
535
535
  account: accountParam,
536
- },
536
+ }),
537
537
  }, async ({ presentationId, objectId, operation, account }) => {
538
538
  return runOrDiagnose(['slides', 'element', 'z-order', presentationId, objectId, `--operation=${operation}`], { account });
539
539
  });
540
540
 
541
541
  server.registerTool('gog_slides_element_group', {
542
542
  description: 'Group two or more page elements into a single group.',
543
- inputSchema: {
543
+ inputSchema: z.object({
544
544
  presentationId: z.string().describe('Presentation ID'),
545
545
  objectIds: z.array(z.string()).min(2).describe('Two or more element object IDs to group'),
546
546
  groupId: z.string().optional().describe('Optional stable group object ID'),
547
547
  account: accountParam,
548
- },
548
+ }),
549
549
  }, async ({ presentationId, objectIds, groupId, account }) => {
550
550
  const args = ['slides', 'element', 'group', presentationId, ...objectIds];
551
551
  if (groupId) args.push(`--group-id=${groupId}`);
@@ -554,24 +554,24 @@ export function registerExtraSlidesTools(server: McpServer): void {
554
554
 
555
555
  server.registerTool('gog_slides_element_ungroup', {
556
556
  description: 'Ungroup one or more element groups back into their constituent elements.',
557
- inputSchema: {
557
+ inputSchema: z.object({
558
558
  presentationId: z.string().describe('Presentation ID'),
559
559
  groupIds: z.array(z.string()).min(1).describe('One or more group object IDs to ungroup'),
560
560
  account: accountParam,
561
- },
561
+ }),
562
562
  }, async ({ presentationId, groupIds, account }) => {
563
563
  return runOrDiagnose(['slides', 'element', 'ungroup', presentationId, ...groupIds], { account });
564
564
  });
565
565
 
566
566
  server.registerTool('gog_slides_element_alt_text', {
567
567
  description: 'Set or clear a page element\'s accessibility title and/or description. Pass an empty string to clear a field.',
568
- inputSchema: {
568
+ inputSchema: z.object({
569
569
  presentationId: z.string().describe('Presentation ID'),
570
570
  objectId: z.string().describe('Object ID of the element'),
571
571
  title: z.string().optional().describe('Accessibility title (empty string clears it)'),
572
572
  description: z.string().optional().describe('Accessibility description (empty string clears it)'),
573
573
  account: accountParam,
574
- },
574
+ }),
575
575
  }, async ({ presentationId, objectId, title, description, account }) => {
576
576
  const args = ['slides', 'element', 'alt-text', presentationId, objectId];
577
577
  if (title !== undefined) args.push(`--title=${title}`);
@@ -582,11 +582,11 @@ export function registerExtraSlidesTools(server: McpServer): void {
582
582
  server.registerTool('gog_slides_element_delete', {
583
583
  description: 'Delete one page element by object ID.',
584
584
  annotations: { destructiveHint: true },
585
- inputSchema: {
585
+ inputSchema: z.object({
586
586
  presentationId: z.string().describe('Presentation ID'),
587
587
  objectId: z.string().describe('Object ID of the element to delete'),
588
588
  account: accountParam,
589
- },
589
+ }),
590
590
  }, async ({ presentationId, objectId, account }) => {
591
591
  // --force: gog refuses this delete under the runner's --no-input without it.
592
592
  return runOrDiagnose(['slides', 'element', 'delete', presentationId, objectId, '--force'], { account });
@@ -596,14 +596,14 @@ export function registerExtraSlidesTools(server: McpServer): void {
596
596
 
597
597
  server.registerTool('gog_slides_table_create', {
598
598
  description: 'Create an auto-sized native table on a slide with the given row and column counts.',
599
- inputSchema: {
599
+ inputSchema: z.object({
600
600
  presentationId: z.string().describe('Presentation ID'),
601
601
  slideId: z.string().describe('Slide object ID to create the table on'),
602
602
  rows: z.number().int().min(1).describe('Number of rows (>=1)'),
603
603
  cols: z.number().int().min(1).describe('Number of columns (>=1)'),
604
604
  objectId: z.string().optional().describe('Optional stable table object ID (5-50 chars: letters, digits, _, -, :)'),
605
605
  account: accountParam,
606
- },
606
+ }),
607
607
  }, async ({ presentationId, slideId, rows, cols, objectId, account }) => {
608
608
  const args = ['slides', 'table', 'create', presentationId, slideId, `--rows=${rows}`, `--cols=${cols}`];
609
609
  if (objectId) args.push(`--object-id=${objectId}`);
@@ -612,7 +612,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
612
612
 
613
613
  server.registerTool('gog_slides_table_cell_style', {
614
614
  description: 'Style one zero-based table cell: background fill, vertical content alignment, and inline text styling (optionally scoped to a UTF-16 range within the cell). Boolean flags set the attribute; the no* flags clear it.',
615
- inputSchema: {
615
+ inputSchema: z.object({
616
616
  presentationId: z.string().describe('Presentation ID'),
617
617
  tableObjectId: z.string().describe('Table object ID'),
618
618
  row: z.number().int().describe('0-based table row index'),
@@ -631,7 +631,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
631
631
  underline: z.boolean().optional().describe('Set underline'),
632
632
  noUnderline: z.boolean().optional().describe('Clear underline'),
633
633
  account: accountParam,
634
- },
634
+ }),
635
635
  }, async ({ presentationId, tableObjectId, row, col, range, fillColor, fillTransparent, contentAlign, font, size, textColor, bold, noBold, italic, noItalic, underline, noUnderline, account }) => {
636
636
  const args = ['slides', 'table', 'cell', 'style', presentationId, tableObjectId, `--row=${row}`, `--col=${col}`];
637
637
  if (range) args.push(`--range=${range}`);
@@ -652,7 +652,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
652
652
 
653
653
  server.registerTool('gog_slides_table_border_style', {
654
654
  description: 'Style borders around or within a zero-based table cell range. position selects which borders are affected; dash sets the line style.',
655
- inputSchema: {
655
+ inputSchema: z.object({
656
656
  presentationId: z.string().describe('Presentation ID'),
657
657
  tableObjectId: z.string().describe('Table object ID'),
658
658
  row: z.number().int().describe('0-based starting row index'),
@@ -665,7 +665,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
665
665
  dash: z.enum(['SOLID', 'DOT', 'DASH', 'DASH_DOT', 'LONG_DASH', 'LONG_DASH_DOT']).optional().describe('Border dash style'),
666
666
  transparent: z.boolean().optional().describe('Make the selected borders transparent'),
667
667
  account: accountParam,
668
- },
668
+ }),
669
669
  }, async ({ presentationId, tableObjectId, row, col, rowSpan, colSpan, position, borderColor, weight, dash, transparent, account }) => {
670
670
  const args = ['slides', 'table', 'border', 'style', presentationId, tableObjectId, `--row=${row}`, `--col=${col}`];
671
671
  if (rowSpan !== undefined) args.push(`--row-span=${rowSpan}`);
@@ -680,14 +680,14 @@ export function registerExtraSlidesTools(server: McpServer): void {
680
680
 
681
681
  server.registerTool('gog_slides_table_column_insert', {
682
682
  description: 'Insert one or more columns relative to a zero-based table column. Inserts to the left by default, or to the right with right=true.',
683
- inputSchema: {
683
+ inputSchema: z.object({
684
684
  presentationId: z.string().describe('Presentation ID'),
685
685
  tableObjectId: z.string().describe('Table object ID'),
686
686
  col: z.number().int().describe('0-based reference column index'),
687
687
  count: z.number().int().optional().describe('Number of columns to insert (default: 1)'),
688
688
  right: z.boolean().optional().describe('Insert to the right of the reference column instead of the left'),
689
689
  account: accountParam,
690
- },
690
+ }),
691
691
  }, async ({ presentationId, tableObjectId, col, count, right, account }) => {
692
692
  const args = ['slides', 'table', 'column', 'insert', presentationId, tableObjectId, `--col=${col}`];
693
693
  if (count !== undefined) args.push(`--count=${count}`);
@@ -698,39 +698,39 @@ export function registerExtraSlidesTools(server: McpServer): void {
698
698
  server.registerTool('gog_slides_table_column_delete', {
699
699
  description: 'Delete the column containing a zero-based table cell.',
700
700
  annotations: { destructiveHint: true },
701
- inputSchema: {
701
+ inputSchema: z.object({
702
702
  presentationId: z.string().describe('Presentation ID'),
703
703
  tableObjectId: z.string().describe('Table object ID'),
704
704
  col: z.number().int().describe('0-based column index to delete'),
705
705
  account: accountParam,
706
- },
706
+ }),
707
707
  }, async ({ presentationId, tableObjectId, col, account }) => {
708
708
  return runOrDiagnose(['slides', 'table', 'column', 'delete', presentationId, tableObjectId, `--col=${col}`, '--force'], { account });
709
709
  });
710
710
 
711
711
  server.registerTool('gog_slides_table_column_size', {
712
712
  description: 'Set the width of a zero-based table column.',
713
- inputSchema: {
713
+ inputSchema: z.object({
714
714
  presentationId: z.string().describe('Presentation ID'),
715
715
  tableObjectId: z.string().describe('Table object ID'),
716
716
  col: z.number().int().describe('0-based column index'),
717
717
  width: z.number().describe('Column width in points'),
718
718
  account: accountParam,
719
- },
719
+ }),
720
720
  }, async ({ presentationId, tableObjectId, col, width, account }) => {
721
721
  return runOrDiagnose(['slides', 'table', 'column', 'size', presentationId, tableObjectId, `--col=${col}`, `--width=${width}`], { account });
722
722
  });
723
723
 
724
724
  server.registerTool('gog_slides_table_row_insert', {
725
725
  description: 'Insert one or more rows relative to a zero-based table row. Inserts above by default, or below with below=true.',
726
- inputSchema: {
726
+ inputSchema: z.object({
727
727
  presentationId: z.string().describe('Presentation ID'),
728
728
  tableObjectId: z.string().describe('Table object ID'),
729
729
  row: z.number().int().describe('0-based reference row index'),
730
730
  count: z.number().int().optional().describe('Number of rows to insert (default: 1)'),
731
731
  below: z.boolean().optional().describe('Insert below the reference row instead of above'),
732
732
  account: accountParam,
733
- },
733
+ }),
734
734
  }, async ({ presentationId, tableObjectId, row, count, below, account }) => {
735
735
  const args = ['slides', 'table', 'row', 'insert', presentationId, tableObjectId, `--row=${row}`];
736
736
  if (count !== undefined) args.push(`--count=${count}`);
@@ -741,25 +741,25 @@ export function registerExtraSlidesTools(server: McpServer): void {
741
741
  server.registerTool('gog_slides_table_row_delete', {
742
742
  description: 'Delete the row containing a zero-based table cell.',
743
743
  annotations: { destructiveHint: true },
744
- inputSchema: {
744
+ inputSchema: z.object({
745
745
  presentationId: z.string().describe('Presentation ID'),
746
746
  tableObjectId: z.string().describe('Table object ID'),
747
747
  row: z.number().int().describe('0-based row index to delete'),
748
748
  account: accountParam,
749
- },
749
+ }),
750
750
  }, async ({ presentationId, tableObjectId, row, account }) => {
751
751
  return runOrDiagnose(['slides', 'table', 'row', 'delete', presentationId, tableObjectId, `--row=${row}`, '--force'], { account });
752
752
  });
753
753
 
754
754
  server.registerTool('gog_slides_table_row_size', {
755
755
  description: 'Set the minimum height of a zero-based table row.',
756
- inputSchema: {
756
+ inputSchema: z.object({
757
757
  presentationId: z.string().describe('Presentation ID'),
758
758
  tableObjectId: z.string().describe('Table object ID'),
759
759
  row: z.number().int().describe('0-based row index'),
760
760
  height: z.number().describe('Minimum row height in points'),
761
761
  account: accountParam,
762
- },
762
+ }),
763
763
  }, async ({ presentationId, tableObjectId, row, height, account }) => {
764
764
  return runOrDiagnose(['slides', 'table', 'row', 'size', presentationId, tableObjectId, `--row=${row}`, `--height=${height}`], { account });
765
765
  });
@@ -767,7 +767,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
767
767
  server.registerTool('gog_slides_table_merge', {
768
768
  description: 'Merge a rectangular table cell range starting at a zero-based cell. Content of non-anchor cells is absorbed by the merge; use gog_slides_table_unmerge to split back.',
769
769
  annotations: { destructiveHint: true },
770
- inputSchema: {
770
+ inputSchema: z.object({
771
771
  presentationId: z.string().describe('Presentation ID'),
772
772
  tableObjectId: z.string().describe('Table object ID'),
773
773
  row: z.number().int().describe('0-based anchor row index'),
@@ -775,7 +775,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
775
775
  rowSpan: z.number().int().optional().describe('Number of rows to merge'),
776
776
  colSpan: z.number().int().optional().describe('Number of columns to merge'),
777
777
  account: accountParam,
778
- },
778
+ }),
779
779
  }, async ({ presentationId, tableObjectId, row, col, rowSpan, colSpan, account }) => {
780
780
  const args = ['slides', 'table', 'merge', presentationId, tableObjectId, `--row=${row}`, `--col=${col}`];
781
781
  if (rowSpan !== undefined) args.push(`--row-span=${rowSpan}`);
@@ -785,7 +785,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
785
785
 
786
786
  server.registerTool('gog_slides_table_unmerge', {
787
787
  description: 'Unmerge (split) a rectangular range of previously merged cells, starting at a zero-based cell.',
788
- inputSchema: {
788
+ inputSchema: z.object({
789
789
  presentationId: z.string().describe('Presentation ID'),
790
790
  tableObjectId: z.string().describe('Table object ID'),
791
791
  row: z.number().int().describe('0-based anchor row index'),
@@ -793,7 +793,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
793
793
  rowSpan: z.number().int().optional().describe('Number of rows in the range'),
794
794
  colSpan: z.number().int().optional().describe('Number of columns in the range'),
795
795
  account: accountParam,
796
- },
796
+ }),
797
797
  }, async ({ presentationId, tableObjectId, row, col, rowSpan, colSpan, account }) => {
798
798
  const args = ['slides', 'table', 'unmerge', presentationId, tableObjectId, `--row=${row}`, `--col=${col}`];
799
799
  if (rowSpan !== undefined) args.push(`--row-span=${rowSpan}`);