gogcli-mcp-sheets 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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/dist/index.js +15659 -18919
- package/manifest.json +1 -1
- package/mint.yaml +37 -33
- package/package.json +3 -3
- package/server.json +2 -2
- package/src/index.ts +3 -4
- package/src/tools/sheets-extra.ts +120 -120
- package/tests/tools/sheets-extra.test.ts +5 -10
- package/tsconfig.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/server';
|
|
2
|
+
import type { CallToolResult } from '@modelcontextprotocol/server';
|
|
2
3
|
import { z } from 'zod';
|
|
3
|
-
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
4
4
|
import { rawTextResult } from '@chrischall/mcp-utils';
|
|
5
5
|
import { accountParam, runOrDiagnose, run, diagnose, errorText, payloadArg } from '../../../gogcli-mcp/src/lib.js';
|
|
6
6
|
|
|
@@ -81,10 +81,10 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
81
81
|
server.registerTool('gog_sheets_list_tabs', {
|
|
82
82
|
description: 'List tabs (sheets) in a spreadsheet with their titles, sheetIds, and indices. A friendlier view than gog_sheets_metadata when you only need the tab list — useful for restructuring a workbook over a long agent session without losing track of names.',
|
|
83
83
|
annotations: { readOnlyHint: true },
|
|
84
|
-
inputSchema: {
|
|
84
|
+
inputSchema: z.object({
|
|
85
85
|
spreadsheetId: z.string().describe('Spreadsheet ID (from the URL)'),
|
|
86
86
|
account: accountParam,
|
|
87
|
-
},
|
|
87
|
+
}),
|
|
88
88
|
}, async ({ spreadsheetId, account }) => {
|
|
89
89
|
// jq projection keeps the response compact: sheetId, title, index, gridProperties only.
|
|
90
90
|
return runOrDiagnose(
|
|
@@ -95,11 +95,11 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
95
95
|
|
|
96
96
|
server.registerTool('gog_sheets_add_tab', {
|
|
97
97
|
description: 'Add a new sheet tab to a spreadsheet.',
|
|
98
|
-
inputSchema: {
|
|
98
|
+
inputSchema: z.object({
|
|
99
99
|
spreadsheetId: z.string().describe('Spreadsheet ID (from the URL)'),
|
|
100
100
|
tabName: z.string().describe('Name for the new tab'),
|
|
101
101
|
account: accountParam,
|
|
102
|
-
},
|
|
102
|
+
}),
|
|
103
103
|
}, async ({ spreadsheetId, tabName, account }) => {
|
|
104
104
|
return runOrDiagnose(['sheets', 'add-tab', spreadsheetId, tabName], { account });
|
|
105
105
|
});
|
|
@@ -107,11 +107,11 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
107
107
|
server.registerTool('gog_sheets_delete_tab', {
|
|
108
108
|
description: 'Delete a sheet tab from a spreadsheet.',
|
|
109
109
|
annotations: { destructiveHint: true },
|
|
110
|
-
inputSchema: {
|
|
110
|
+
inputSchema: z.object({
|
|
111
111
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
112
112
|
tabName: z.string().describe('Name of the tab to delete'),
|
|
113
113
|
account: accountParam,
|
|
114
|
-
},
|
|
114
|
+
}),
|
|
115
115
|
}, async ({ spreadsheetId, tabName, account }) => {
|
|
116
116
|
return runOrDiagnose(['sheets', 'delete-tab', spreadsheetId, tabName, '--force'], { account }); // gog gates this op; without --force the runner's --no-input makes it refuse
|
|
117
117
|
});
|
|
@@ -119,24 +119,24 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
119
119
|
server.registerTool('gog_sheets_rename_tab', {
|
|
120
120
|
description: 'Rename a sheet tab.',
|
|
121
121
|
annotations: { destructiveHint: true },
|
|
122
|
-
inputSchema: {
|
|
122
|
+
inputSchema: z.object({
|
|
123
123
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
124
124
|
oldName: z.string().describe('Current tab name'),
|
|
125
125
|
newName: z.string().describe('New tab name'),
|
|
126
126
|
account: accountParam,
|
|
127
|
-
},
|
|
127
|
+
}),
|
|
128
128
|
}, async ({ spreadsheetId, oldName, newName, account }) => {
|
|
129
129
|
return runOrDiagnose(['sheets', 'rename-tab', spreadsheetId, oldName, newName], { account });
|
|
130
130
|
});
|
|
131
131
|
|
|
132
132
|
server.registerTool('gog_sheets_copy', {
|
|
133
133
|
description: 'Copy a spreadsheet to a new spreadsheet with the given title.',
|
|
134
|
-
inputSchema: {
|
|
134
|
+
inputSchema: z.object({
|
|
135
135
|
spreadsheetId: z.string().describe('Spreadsheet ID to copy'),
|
|
136
136
|
title: z.string().describe('Title for the new copy'),
|
|
137
137
|
parent: z.string().optional().describe('Parent folder ID to place the copy in'),
|
|
138
138
|
account: accountParam,
|
|
139
|
-
},
|
|
139
|
+
}),
|
|
140
140
|
}, async ({ spreadsheetId, title, parent, account }) => {
|
|
141
141
|
const args = ['sheets', 'copy', spreadsheetId, title];
|
|
142
142
|
if (parent) args.push(`--parent=${parent}`);
|
|
@@ -146,13 +146,13 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
146
146
|
server.registerTool('gog_sheets_export', {
|
|
147
147
|
description: 'Export a spreadsheet as CSV, TSV, or PDF.',
|
|
148
148
|
annotations: { readOnlyHint: true },
|
|
149
|
-
inputSchema: {
|
|
149
|
+
inputSchema: z.object({
|
|
150
150
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
151
151
|
format: z.string().optional().describe('Export format: csv, tsv, pdf (default: csv)'),
|
|
152
152
|
out: z.string().optional().describe('Output file path'),
|
|
153
153
|
overwrite: z.boolean().optional().describe('Overwrite the output file if it already exists (gog refuses otherwise)'),
|
|
154
154
|
account: accountParam,
|
|
155
|
-
},
|
|
155
|
+
}),
|
|
156
156
|
}, async ({ spreadsheetId, format, out, overwrite, account }) => {
|
|
157
157
|
const args = ['sheets', 'export', spreadsheetId];
|
|
158
158
|
if (format) args.push(`--format=${format}`);
|
|
@@ -164,13 +164,13 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
164
164
|
server.registerTool('gog_sheets_freeze', {
|
|
165
165
|
description: 'Freeze rows and/or columns in a sheet.',
|
|
166
166
|
annotations: { destructiveHint: true },
|
|
167
|
-
inputSchema: {
|
|
167
|
+
inputSchema: z.object({
|
|
168
168
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
169
169
|
rows: z.number().optional().describe('Number of rows to freeze'),
|
|
170
170
|
cols: z.number().optional().describe('Number of columns to freeze'),
|
|
171
171
|
sheet: z.string().optional().describe('Sheet tab name (default: first sheet)'),
|
|
172
172
|
account: accountParam,
|
|
173
|
-
},
|
|
173
|
+
}),
|
|
174
174
|
}, async ({ spreadsheetId, rows, cols, sheet, account }) => {
|
|
175
175
|
const args = ['sheets', 'freeze', spreadsheetId];
|
|
176
176
|
if (rows !== undefined) args.push(`--rows=${rows}`);
|
|
@@ -182,7 +182,7 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
182
182
|
server.registerTool('gog_sheets_insert', {
|
|
183
183
|
description: 'Insert rows or columns into a sheet. With after:false (default), the new dimension lands at start. With after:true, the new dimension lands at start+1 (the existing dimension at start is preserved).',
|
|
184
184
|
annotations: { destructiveHint: true },
|
|
185
|
-
inputSchema: {
|
|
185
|
+
inputSchema: z.object({
|
|
186
186
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
187
187
|
sheet: z.string().describe('Sheet tab name'),
|
|
188
188
|
dimension: z.string().describe('Dimension to insert: ROWS or COLUMNS'),
|
|
@@ -191,7 +191,7 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
191
191
|
after: z.boolean().optional().describe('Insert after the start index instead of before. With after:true the new dimension lands at start+1, leaving the existing dimension at start untouched.'),
|
|
192
192
|
inheritFromBefore: z.boolean().optional().describe('Inherit number format / styling from the row/column before the insertion. Defaults to true with after:true, false otherwise; pass false to inherit from the row/column after the insertion instead. Cannot inherit from before when inserting at the first row/column.'),
|
|
193
193
|
account: accountParam,
|
|
194
|
-
},
|
|
194
|
+
}),
|
|
195
195
|
}, async ({ spreadsheetId, sheet, dimension, start, count, after, inheritFromBefore, account }) => {
|
|
196
196
|
// gog's positional `<start>` is 1-based, and it rejects 0 ("start must be >= 1").
|
|
197
197
|
// Without --after it inserts *before* the position, so API start_index = positional - 1;
|
|
@@ -209,14 +209,14 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
209
209
|
server.registerTool('gog_sheets_copy_paste', {
|
|
210
210
|
description: 'Copy a source range\'s values/formulas/format to a destination range via the Sheets CopyPasteRequest. A destination larger than the source tiles the source to fill it — the canonical way to fill formulas down or across with relative references adjusted (aliases: fill, copy-range). Use type to control what is pasted (NORMAL pastes everything; FORMULA fills formulas with adjusted references; VALUES/FORMAT/etc. paste only that aspect).',
|
|
211
211
|
annotations: { destructiveHint: true },
|
|
212
|
-
inputSchema: {
|
|
212
|
+
inputSchema: z.object({
|
|
213
213
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
214
214
|
source: z.string().describe('Source range (e.g. Sheet1!A2:H71)'),
|
|
215
215
|
dest: z.string().describe('Destination range (e.g. Sheet1!A2:H120). Larger than the source tiles/fills it.'),
|
|
216
216
|
type: z.enum(['NORMAL', 'VALUES', 'FORMAT', 'FORMULA', 'NO_BORDERS', 'DATA_VALIDATION', 'CONDITIONAL_FORMATTING']).optional().describe('Paste type (default: NORMAL pastes everything)'),
|
|
217
217
|
transpose: z.boolean().optional().describe('Paste transposed (swap rows and columns)'),
|
|
218
218
|
account: accountParam,
|
|
219
|
-
},
|
|
219
|
+
}),
|
|
220
220
|
}, async ({ spreadsheetId, source, dest, type, transpose, account }) => {
|
|
221
221
|
const args = ['sheets', 'copy-paste', spreadsheetId, source, dest];
|
|
222
222
|
if (type) args.push(`--type=${type}`);
|
|
@@ -227,12 +227,12 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
227
227
|
server.registerTool('gog_sheets_merge', {
|
|
228
228
|
description: 'Merge cells in a range.',
|
|
229
229
|
annotations: { destructiveHint: true },
|
|
230
|
-
inputSchema: {
|
|
230
|
+
inputSchema: z.object({
|
|
231
231
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
232
232
|
range: z.string().describe('Range to merge (e.g. Sheet1!A1:C3)'),
|
|
233
233
|
type: z.string().optional().describe('Merge type: MERGE_ALL, MERGE_COLUMNS, MERGE_ROWS'),
|
|
234
234
|
account: accountParam,
|
|
235
|
-
},
|
|
235
|
+
}),
|
|
236
236
|
}, async ({ spreadsheetId, range, type, account }) => {
|
|
237
237
|
const args = ['sheets', 'merge', spreadsheetId, range];
|
|
238
238
|
if (type) args.push(`--type=${type}`);
|
|
@@ -242,11 +242,11 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
242
242
|
server.registerTool('gog_sheets_unmerge', {
|
|
243
243
|
description: 'Unmerge previously merged cells in a range.',
|
|
244
244
|
annotations: { destructiveHint: true },
|
|
245
|
-
inputSchema: {
|
|
245
|
+
inputSchema: z.object({
|
|
246
246
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
247
247
|
range: z.string().describe('Range to unmerge (e.g. Sheet1!A1:C3)'),
|
|
248
248
|
account: accountParam,
|
|
249
|
-
},
|
|
249
|
+
}),
|
|
250
250
|
}, async ({ spreadsheetId, range, account }) => {
|
|
251
251
|
return runOrDiagnose(['sheets', 'unmerge', spreadsheetId, range], { account });
|
|
252
252
|
});
|
|
@@ -254,7 +254,7 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
254
254
|
server.registerTool('gog_sheets_format', {
|
|
255
255
|
description: 'Apply cell formatting to a range. The named flags (bold, italic, backgroundColor, etc.) compose into a Sheets API CellFormat — use them for the 90% case. For full API control, pass formatJson + formatFields (Sheets CellFormat + field mask) directly.',
|
|
256
256
|
annotations: { destructiveHint: true },
|
|
257
|
-
inputSchema: {
|
|
257
|
+
inputSchema: z.object({
|
|
258
258
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
259
259
|
range: z.string().describe('Range to format (e.g. Sheet1!A1:C3)'),
|
|
260
260
|
bold: z.boolean().optional().describe('Set bold'),
|
|
@@ -271,7 +271,7 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
271
271
|
formatJson: z.string().optional().describe('Escape hatch: raw CellFormat JSON. When provided, named flags above are ignored and formatJson is sent as-is.'),
|
|
272
272
|
formatFields: z.string().optional().describe('Comma-separated field mask (e.g. textFormat.bold,backgroundColor). Required when using formatJson; auto-computed when using named flags.'),
|
|
273
273
|
account: accountParam,
|
|
274
|
-
},
|
|
274
|
+
}),
|
|
275
275
|
}, async (rawArgs) => {
|
|
276
276
|
const a = rawArgs as {
|
|
277
277
|
spreadsheetId: string;
|
|
@@ -343,14 +343,14 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
343
343
|
server.registerTool('gog_sheets_number_format', {
|
|
344
344
|
description: 'Set number format on a range (currency, percentage, date, etc.). When type is DATE or DATE_TIME, the target range is peeked first; if every numeric cell is a small integer (< 10000), a warning is prepended to the response because Sheets will render those as 1899/1900 day-serials. Pass force:true to skip the check.',
|
|
345
345
|
annotations: { destructiveHint: true },
|
|
346
|
-
inputSchema: {
|
|
346
|
+
inputSchema: z.object({
|
|
347
347
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
348
348
|
range: z.string().describe('Range to format (e.g. Sheet1!A1:A10)'),
|
|
349
349
|
type: z.string().optional().describe('Format type: NUMBER, CURRENCY, PERCENT, DATE, DATE_TIME, TIME, SCIENTIFIC, etc.'),
|
|
350
350
|
pattern: z.string().optional().describe('Custom format pattern (e.g. "#,##0.00", "yyyy-mm-dd")'),
|
|
351
351
|
force: z.boolean().optional().describe('Skip the DATE/DATE_TIME small-integer warning check'),
|
|
352
352
|
account: accountParam,
|
|
353
|
-
},
|
|
353
|
+
}),
|
|
354
354
|
}, async ({ spreadsheetId, range, type, pattern, force, account }) => {
|
|
355
355
|
const isDateType = type === 'DATE' || type === 'DATE_TIME';
|
|
356
356
|
const warning = isDateType && !force
|
|
@@ -369,12 +369,12 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
369
369
|
server.registerTool('gog_sheets_read_format', {
|
|
370
370
|
description: 'Read cell formatting for a range.',
|
|
371
371
|
annotations: { readOnlyHint: true },
|
|
372
|
-
inputSchema: {
|
|
372
|
+
inputSchema: z.object({
|
|
373
373
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
374
374
|
range: z.string().describe('Range to read formatting from'),
|
|
375
375
|
effective: z.boolean().optional().describe('Return effective (computed) format including inherited styles'),
|
|
376
376
|
account: accountParam,
|
|
377
|
-
},
|
|
377
|
+
}),
|
|
378
378
|
}, async ({ spreadsheetId, range, effective, account }) => {
|
|
379
379
|
const args = ['sheets', 'read-format', spreadsheetId, range];
|
|
380
380
|
if (effective) args.push('--effective');
|
|
@@ -384,13 +384,13 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
384
384
|
server.registerTool('gog_sheets_resize_columns', {
|
|
385
385
|
description: 'Resize column widths. Use --auto for auto-fit or --width for a specific pixel width.',
|
|
386
386
|
annotations: { destructiveHint: true },
|
|
387
|
-
inputSchema: {
|
|
387
|
+
inputSchema: z.object({
|
|
388
388
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
389
389
|
columns: z.string().describe('Column range (e.g. A:C, or Sheet1!A:C)'),
|
|
390
390
|
width: z.number().optional().describe('Width in pixels'),
|
|
391
391
|
auto: z.boolean().optional().describe('Auto-fit column width to content'),
|
|
392
392
|
account: accountParam,
|
|
393
|
-
},
|
|
393
|
+
}),
|
|
394
394
|
}, async ({ spreadsheetId, columns, width, auto, account }) => {
|
|
395
395
|
const args = ['sheets', 'resize-columns', spreadsheetId, columns];
|
|
396
396
|
if (width !== undefined) args.push(`--width=${width}`);
|
|
@@ -401,13 +401,13 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
401
401
|
server.registerTool('gog_sheets_resize_rows', {
|
|
402
402
|
description: 'Resize row heights. Use --auto for auto-fit or --height for a specific pixel height.',
|
|
403
403
|
annotations: { destructiveHint: true },
|
|
404
|
-
inputSchema: {
|
|
404
|
+
inputSchema: z.object({
|
|
405
405
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
406
406
|
rows: z.string().describe('Row range (e.g. 1:10, or Sheet1!1:10)'),
|
|
407
407
|
height: z.number().optional().describe('Height in pixels'),
|
|
408
408
|
auto: z.boolean().optional().describe('Auto-fit row height to content'),
|
|
409
409
|
account: accountParam,
|
|
410
|
-
},
|
|
410
|
+
}),
|
|
411
411
|
}, async ({ spreadsheetId, rows, height, auto, account }) => {
|
|
412
412
|
const args = ['sheets', 'resize-rows', spreadsheetId, rows];
|
|
413
413
|
if (height !== undefined) args.push(`--height=${height}`);
|
|
@@ -418,11 +418,11 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
418
418
|
server.registerTool('gog_sheets_notes', {
|
|
419
419
|
description: 'Read cell notes in a range.',
|
|
420
420
|
annotations: { readOnlyHint: true },
|
|
421
|
-
inputSchema: {
|
|
421
|
+
inputSchema: z.object({
|
|
422
422
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
423
423
|
range: z.string().describe('Range to read notes from (e.g. Sheet1!A1:B5)'),
|
|
424
424
|
account: accountParam,
|
|
425
|
-
},
|
|
425
|
+
}),
|
|
426
426
|
}, async ({ spreadsheetId, range, account }) => {
|
|
427
427
|
return runOrDiagnose(['sheets', 'notes', spreadsheetId, range], { account });
|
|
428
428
|
});
|
|
@@ -430,12 +430,12 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
430
430
|
server.registerTool('gog_sheets_update_note', {
|
|
431
431
|
description: 'Add, update, or clear a cell note. Pass an empty string to clear the note.',
|
|
432
432
|
annotations: { destructiveHint: true },
|
|
433
|
-
inputSchema: {
|
|
433
|
+
inputSchema: z.object({
|
|
434
434
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
435
435
|
range: z.string().describe('Cell or range to set the note on (e.g. Sheet1!A1)'),
|
|
436
436
|
note: z.string().describe('Note text (empty string clears the note). Large notes are written to a temp file and passed to gog as --note-file automatically.'),
|
|
437
437
|
account: accountParam,
|
|
438
|
-
},
|
|
438
|
+
}),
|
|
439
439
|
}, async ({ spreadsheetId, range, note, account }) => {
|
|
440
440
|
// payloadArg keeps normal notes on `--note=` and spills a large one to a
|
|
441
441
|
// temp file passed as `--note-file`, so it can't blow the argv size cap.
|
|
@@ -450,11 +450,11 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
450
450
|
server.registerTool('gog_sheets_links', {
|
|
451
451
|
description: 'List hyperlinks in a range.',
|
|
452
452
|
annotations: { readOnlyHint: true },
|
|
453
|
-
inputSchema: {
|
|
453
|
+
inputSchema: z.object({
|
|
454
454
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
455
455
|
range: z.string().describe('Range to scan for hyperlinks (e.g. Sheet1!A1:Z100)'),
|
|
456
456
|
account: accountParam,
|
|
457
|
-
},
|
|
457
|
+
}),
|
|
458
458
|
}, async ({ spreadsheetId, range, account }) => {
|
|
459
459
|
return runOrDiagnose(['sheets', 'links', spreadsheetId, range], { account });
|
|
460
460
|
});
|
|
@@ -465,7 +465,7 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
465
465
|
'(2) multi-link cell — pass cell + runsJson, a JSON array of rich-text runs (a run with an empty uri is plain text); ' +
|
|
466
466
|
'(3) batch — pass cellsJson, a JSON array of {cell,url,text} or {cell,runs:[...]} objects written in one request.',
|
|
467
467
|
annotations: { destructiveHint: true },
|
|
468
|
-
inputSchema: {
|
|
468
|
+
inputSchema: z.object({
|
|
469
469
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
470
470
|
cell: z.string().optional().describe('Target cell in A1 notation (e.g. Sheet1!B2). Used by single-link and runsJson modes; omit for batch (cellsJson).'),
|
|
471
471
|
url: z.string().optional().describe('Hyperlink URL for single-link mode'),
|
|
@@ -473,7 +473,7 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
473
473
|
runsJson: z.string().optional().describe('Multi-link cell: JSON array of runs, e.g. [{"text":"Act A","uri":"https://a"},{"text":" / "},{"text":"Act B","uri":"https://b"}]. A run with an empty uri is plain text.'),
|
|
474
474
|
cellsJson: z.string().optional().describe('Batch: JSON array of {cell,url,text} or {cell,runs:[{text,uri}]} objects, written in one request. Inline JSON or @file (a path gog reads itself — cheaper than inlining a large batch). gog also accepts @- for stdin, but this server never writes to gog\'s stdin, so @- would hang until the call times out.'),
|
|
475
475
|
account: accountParam,
|
|
476
|
-
},
|
|
476
|
+
}),
|
|
477
477
|
}, async ({ spreadsheetId, cell, url, text, runsJson, cellsJson, account }) => {
|
|
478
478
|
const args = ['sheets', 'links', 'set', spreadsheetId];
|
|
479
479
|
if (cell) args.push(cell);
|
|
@@ -487,11 +487,11 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
487
487
|
server.registerTool('gog_sheets_validation_get', {
|
|
488
488
|
description: 'Read the data-validation rules (dropdowns, checkboxes, number/date conditions, custom formulas) applied to a range.',
|
|
489
489
|
annotations: { readOnlyHint: true },
|
|
490
|
-
inputSchema: {
|
|
490
|
+
inputSchema: z.object({
|
|
491
491
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
492
492
|
range: z.string().describe('Range to inspect (e.g. Sheet1!A1:A10)'),
|
|
493
493
|
account: accountParam,
|
|
494
|
-
},
|
|
494
|
+
}),
|
|
495
495
|
}, async ({ spreadsheetId, range, account }) => {
|
|
496
496
|
return runOrDiagnose(['sheets', 'validation', 'get', spreadsheetId, range], { account });
|
|
497
497
|
});
|
|
@@ -499,7 +499,7 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
499
499
|
server.registerTool('gog_sheets_validation_set', {
|
|
500
500
|
description: 'Set a data-validation rule on a range — dropdowns (ONE_OF_LIST / ONE_OF_RANGE), checkboxes (BOOLEAN), number/date conditions, or custom formulas. Overwrites any existing rule on the range. Repeat values for list entries or between-bounds.',
|
|
501
501
|
annotations: { destructiveHint: true },
|
|
502
|
-
inputSchema: {
|
|
502
|
+
inputSchema: z.object({
|
|
503
503
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
504
504
|
range: z.string().describe('Range to apply the rule to (e.g. Sheet1!A1:A10)'),
|
|
505
505
|
type: z.string().describe('Condition type, e.g. ONE_OF_LIST, ONE_OF_RANGE, NUMBER_BETWEEN, NUMBER_GREATER, DATE_AFTER, BOOLEAN, CUSTOM_FORMULA'),
|
|
@@ -509,7 +509,7 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
509
509
|
showCustomUi: z.boolean().optional().describe('Show dropdown or checkbox UI where supported'),
|
|
510
510
|
filteredRowsIncluded: z.boolean().optional().describe('Apply the rule to filtered rows too; required for table-managed dropdown columns'),
|
|
511
511
|
account: accountParam,
|
|
512
|
-
},
|
|
512
|
+
}),
|
|
513
513
|
}, async ({ spreadsheetId, range, type, values, strict, inputMessage, showCustomUi, filteredRowsIncluded, account }) => {
|
|
514
514
|
const args = ['sheets', 'validation', 'set', spreadsheetId, range, `--type=${type}`];
|
|
515
515
|
if (values) for (const v of values) args.push(`--value=${v}`);
|
|
@@ -523,12 +523,12 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
523
523
|
server.registerTool('gog_sheets_validation_clear', {
|
|
524
524
|
description: 'Remove all data-validation rules from a range.',
|
|
525
525
|
annotations: { destructiveHint: true },
|
|
526
|
-
inputSchema: {
|
|
526
|
+
inputSchema: z.object({
|
|
527
527
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
528
528
|
range: z.string().describe('Range to clear (e.g. Sheet1!A1:A10)'),
|
|
529
529
|
filteredRowsIncluded: z.boolean().optional().describe('Clear rules from filtered rows too; required for table-managed dropdown columns'),
|
|
530
530
|
account: accountParam,
|
|
531
|
-
},
|
|
531
|
+
}),
|
|
532
532
|
}, async ({ spreadsheetId, range, filteredRowsIncluded, account }) => {
|
|
533
533
|
const args = ['sheets', 'validation', 'clear', spreadsheetId, range];
|
|
534
534
|
if (filteredRowsIncluded) args.push('--filtered-rows-included');
|
|
@@ -538,14 +538,14 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
538
538
|
server.registerTool('gog_sheets_delete_dimension', {
|
|
539
539
|
description: 'Delete a span of rows or columns, table-aware: intersecting table objects are preserved (shrunk) along with their remaining data, instead of being corrupted as with a raw DeleteDimension batch update. Target by A1 range (e.g. Sheet1!5:7 or Sheet1!C:D) or by sheet name plus start/end.',
|
|
540
540
|
annotations: { destructiveHint: true },
|
|
541
|
-
inputSchema: {
|
|
541
|
+
inputSchema: z.object({
|
|
542
542
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
543
543
|
rangeOrSheet: z.string().describe('A1 range covering the rows/columns to delete, or a sheet name (then start/end are required)'),
|
|
544
544
|
dimension: z.enum(['ROWS', 'COLUMNS']).describe('Dimension to delete'),
|
|
545
545
|
start: z.number().int().optional().describe('First row/column to delete (1-based, inclusive; required with a sheet-name target)'),
|
|
546
546
|
end: z.number().int().optional().describe('Last row/column to delete (1-based, inclusive; required with a sheet-name target)'),
|
|
547
547
|
account: accountParam,
|
|
548
|
-
},
|
|
548
|
+
}),
|
|
549
549
|
}, async ({ spreadsheetId, rangeOrSheet, dimension, start, end, account }) => {
|
|
550
550
|
const args = ['sheets', 'delete-dimension', spreadsheetId, rangeOrSheet, `--dimension=${dimension}`];
|
|
551
551
|
if (start !== undefined) args.push(`--start=${start}`);
|
|
@@ -557,10 +557,10 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
557
557
|
server.registerTool('gog_sheets_named_ranges_list', {
|
|
558
558
|
description: 'List all named ranges in a spreadsheet.',
|
|
559
559
|
annotations: { readOnlyHint: true },
|
|
560
|
-
inputSchema: {
|
|
560
|
+
inputSchema: z.object({
|
|
561
561
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
562
562
|
account: accountParam,
|
|
563
|
-
},
|
|
563
|
+
}),
|
|
564
564
|
}, async ({ spreadsheetId, account }) => {
|
|
565
565
|
return runOrDiagnose(['sheets', 'named-ranges', 'list', spreadsheetId], { account });
|
|
566
566
|
});
|
|
@@ -568,23 +568,23 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
568
568
|
server.registerTool('gog_sheets_named_ranges_get', {
|
|
569
569
|
description: 'Get a named range by name or ID.',
|
|
570
570
|
annotations: { readOnlyHint: true },
|
|
571
|
-
inputSchema: {
|
|
571
|
+
inputSchema: z.object({
|
|
572
572
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
573
573
|
nameOrId: z.string().describe('Named range name or ID'),
|
|
574
574
|
account: accountParam,
|
|
575
|
-
},
|
|
575
|
+
}),
|
|
576
576
|
}, async ({ spreadsheetId, nameOrId, account }) => {
|
|
577
577
|
return runOrDiagnose(['sheets', 'named-ranges', 'get', spreadsheetId, nameOrId], { account });
|
|
578
578
|
});
|
|
579
579
|
|
|
580
580
|
server.registerTool('gog_sheets_named_ranges_add', {
|
|
581
581
|
description: 'Create a new named range.',
|
|
582
|
-
inputSchema: {
|
|
582
|
+
inputSchema: z.object({
|
|
583
583
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
584
584
|
name: z.string().describe('Name for the range'),
|
|
585
585
|
range: z.string().describe('Cell range (e.g. Sheet1!A1:B10)'),
|
|
586
586
|
account: accountParam,
|
|
587
|
-
},
|
|
587
|
+
}),
|
|
588
588
|
}, async ({ spreadsheetId, name, range, account }) => {
|
|
589
589
|
return runOrDiagnose(['sheets', 'named-ranges', 'add', spreadsheetId, name, range], { account });
|
|
590
590
|
});
|
|
@@ -592,13 +592,13 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
592
592
|
server.registerTool('gog_sheets_named_ranges_update', {
|
|
593
593
|
description: 'Update a named range (change its name, range, or both).',
|
|
594
594
|
annotations: { destructiveHint: true },
|
|
595
|
-
inputSchema: {
|
|
595
|
+
inputSchema: z.object({
|
|
596
596
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
597
597
|
nameOrId: z.string().describe('Current named range name or ID'),
|
|
598
598
|
name: z.string().optional().describe('New name'),
|
|
599
599
|
range: z.string().optional().describe('New cell range'),
|
|
600
600
|
account: accountParam,
|
|
601
|
-
},
|
|
601
|
+
}),
|
|
602
602
|
}, async ({ spreadsheetId, nameOrId, name, range, account }) => {
|
|
603
603
|
const args = ['sheets', 'named-ranges', 'update', spreadsheetId, nameOrId];
|
|
604
604
|
if (name) args.push(`--name=${name}`);
|
|
@@ -609,11 +609,11 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
609
609
|
server.registerTool('gog_sheets_named_ranges_delete', {
|
|
610
610
|
description: 'Delete a named range.',
|
|
611
611
|
annotations: { destructiveHint: true },
|
|
612
|
-
inputSchema: {
|
|
612
|
+
inputSchema: z.object({
|
|
613
613
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
614
614
|
nameOrId: z.string().describe('Named range name or ID to delete'),
|
|
615
615
|
account: accountParam,
|
|
616
|
-
},
|
|
616
|
+
}),
|
|
617
617
|
}, async ({ spreadsheetId, nameOrId, account }) => {
|
|
618
618
|
return runOrDiagnose(['sheets', 'named-ranges', 'delete', spreadsheetId, nameOrId], { account });
|
|
619
619
|
});
|
|
@@ -621,7 +621,7 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
621
621
|
server.registerTool('gog_sheets_batch_update', {
|
|
622
622
|
description: 'Update values in multiple ranges with one Sheets API request. dataJson is a JSON array of {range, values} objects — pass it inline as a literal JSON string. Atomic — either all ranges update or none do. (The CLI also accepts "@/path/to/file.json", but that file is read on the gog server\'s filesystem, not the caller\'s, so inline JSON is the right form for remote MCP callers.)',
|
|
623
623
|
annotations: { destructiveHint: true },
|
|
624
|
-
inputSchema: {
|
|
624
|
+
inputSchema: z.object({
|
|
625
625
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
626
626
|
dataJson: z.string().describe('Value ranges as an inline JSON array, e.g. [{"range":"Sheet1!A1:B2","values":[["a","b"]]}]. (An "@/path" form is read on the gog server filesystem, not yours — inline the JSON instead.)'),
|
|
627
627
|
input: z.enum(['RAW', 'USER_ENTERED']).optional().describe('Value input option (default: USER_ENTERED)'),
|
|
@@ -629,7 +629,7 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
629
629
|
responseRender: z.enum(['FORMATTED_VALUE', 'UNFORMATTED_VALUE', 'FORMULA']).optional().describe('Response value render option'),
|
|
630
630
|
responseDateTimeRender: z.enum(['SERIAL_NUMBER', 'FORMATTED_STRING']).optional().describe('Response date/time render option'),
|
|
631
631
|
account: accountParam,
|
|
632
|
-
},
|
|
632
|
+
}),
|
|
633
633
|
}, async ({ spreadsheetId, dataJson, input, includeValuesInResponse, responseRender, responseDateTimeRender, account }) => {
|
|
634
634
|
const args = ['sheets', 'batch-update', spreadsheetId, `--data-json=${dataJson}`];
|
|
635
635
|
if (input) args.push(`--input=${input}`);
|
|
@@ -642,12 +642,12 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
642
642
|
server.registerTool('gog_sheets_reorder_tab', {
|
|
643
643
|
description: 'Move a tab to a specific 0-based position. `tab` is the tab name or numeric sheetId; `to=0` is the leftmost slot.',
|
|
644
644
|
annotations: { destructiveHint: true },
|
|
645
|
-
inputSchema: {
|
|
645
|
+
inputSchema: z.object({
|
|
646
646
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
647
647
|
tab: z.string().describe('Target tab by name or numeric sheet ID'),
|
|
648
648
|
to: z.number().int().min(0).describe('Destination final 0-based tab index'),
|
|
649
649
|
account: accountParam,
|
|
650
|
-
},
|
|
650
|
+
}),
|
|
651
651
|
}, async ({ spreadsheetId, tab, to, account }) => {
|
|
652
652
|
return runOrDiagnose(
|
|
653
653
|
['sheets', 'reorder-tab', spreadsheetId, `--tab=${tab}`, `--to=${to}`],
|
|
@@ -660,10 +660,10 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
660
660
|
server.registerTool('gog_sheets_chart_list', {
|
|
661
661
|
description: 'List embedded charts in a spreadsheet (chartId, type, position).',
|
|
662
662
|
annotations: { readOnlyHint: true },
|
|
663
|
-
inputSchema: {
|
|
663
|
+
inputSchema: z.object({
|
|
664
664
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
665
665
|
account: accountParam,
|
|
666
|
-
},
|
|
666
|
+
}),
|
|
667
667
|
}, async ({ spreadsheetId, account }) => {
|
|
668
668
|
return runOrDiagnose(['sheets', 'chart', 'list', spreadsheetId], { account });
|
|
669
669
|
});
|
|
@@ -671,18 +671,18 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
671
671
|
server.registerTool('gog_sheets_chart_get', {
|
|
672
672
|
description: 'Get the full definition (spec + position) of a single chart by its numeric chart ID.',
|
|
673
673
|
annotations: { readOnlyHint: true },
|
|
674
|
-
inputSchema: {
|
|
674
|
+
inputSchema: z.object({
|
|
675
675
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
676
676
|
chartId: z.string().describe('Numeric chart ID (from gog_sheets_chart_list)'),
|
|
677
677
|
account: accountParam,
|
|
678
|
-
},
|
|
678
|
+
}),
|
|
679
679
|
}, async ({ spreadsheetId, chartId, account }) => {
|
|
680
680
|
return runOrDiagnose(['sheets', 'chart', 'get', spreadsheetId, chartId], { account });
|
|
681
681
|
});
|
|
682
682
|
|
|
683
683
|
server.registerTool('gog_sheets_chart_create', {
|
|
684
684
|
description: 'Create an embedded chart from a JSON spec. specJson is a Sheets API ChartSpec (or full EmbeddedChart) — inline or @/path/to/file.json. Anchor the chart with sheet + anchor (A1 cell), and optionally size it with width/height pixels.',
|
|
685
|
-
inputSchema: {
|
|
685
|
+
inputSchema: z.object({
|
|
686
686
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
687
687
|
specJson: z.string().describe('ChartSpec or EmbeddedChart JSON (inline or @file)'),
|
|
688
688
|
sheet: z.string().optional().describe('Sheet name for the anchor (resolved to sheetId)'),
|
|
@@ -690,7 +690,7 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
690
690
|
width: z.number().optional().describe('Chart width in pixels (default: 600)'),
|
|
691
691
|
height: z.number().optional().describe('Chart height in pixels (default: 371)'),
|
|
692
692
|
account: accountParam,
|
|
693
|
-
},
|
|
693
|
+
}),
|
|
694
694
|
}, async ({ spreadsheetId, specJson, sheet, anchor, width, height, account }) => {
|
|
695
695
|
const args = ['sheets', 'chart', 'create', spreadsheetId, `--spec-json=${specJson}`];
|
|
696
696
|
if (sheet) args.push(`--sheet=${sheet}`);
|
|
@@ -703,12 +703,12 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
703
703
|
server.registerTool('gog_sheets_chart_update', {
|
|
704
704
|
description: 'Replace a chart spec by chart ID. specJson is a Sheets API ChartSpec (or full EmbeddedChart) — inline or @/path/to/file.json.',
|
|
705
705
|
annotations: { destructiveHint: true },
|
|
706
|
-
inputSchema: {
|
|
706
|
+
inputSchema: z.object({
|
|
707
707
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
708
708
|
chartId: z.string().describe('Numeric chart ID to update'),
|
|
709
709
|
specJson: z.string().describe('ChartSpec or EmbeddedChart JSON (inline or @file)'),
|
|
710
710
|
account: accountParam,
|
|
711
|
-
},
|
|
711
|
+
}),
|
|
712
712
|
}, async ({ spreadsheetId, chartId, specJson, account }) => {
|
|
713
713
|
return runOrDiagnose(
|
|
714
714
|
['sheets', 'chart', 'update', spreadsheetId, chartId, `--spec-json=${specJson}`],
|
|
@@ -719,11 +719,11 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
719
719
|
server.registerTool('gog_sheets_chart_delete', {
|
|
720
720
|
description: 'Delete a chart by its numeric chart ID.',
|
|
721
721
|
annotations: { destructiveHint: true },
|
|
722
|
-
inputSchema: {
|
|
722
|
+
inputSchema: z.object({
|
|
723
723
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
724
724
|
chartId: z.string().describe('Numeric chart ID to delete'),
|
|
725
725
|
account: accountParam,
|
|
726
|
-
},
|
|
726
|
+
}),
|
|
727
727
|
}, async ({ spreadsheetId, chartId, account }) => {
|
|
728
728
|
return runOrDiagnose(['sheets', 'chart', 'delete', spreadsheetId, chartId, '--force'], { account }); // gog gates this op; without --force the runner's --no-input makes it refuse
|
|
729
729
|
});
|
|
@@ -733,10 +733,10 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
733
733
|
server.registerTool('gog_sheets_table_list', {
|
|
734
734
|
description: 'List Google Sheets tables in a spreadsheet (tableId, name, range).',
|
|
735
735
|
annotations: { readOnlyHint: true },
|
|
736
|
-
inputSchema: {
|
|
736
|
+
inputSchema: z.object({
|
|
737
737
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
738
738
|
account: accountParam,
|
|
739
|
-
},
|
|
739
|
+
}),
|
|
740
740
|
}, async ({ spreadsheetId, account }) => {
|
|
741
741
|
return runOrDiagnose(['sheets', 'table', 'list', spreadsheetId], { account });
|
|
742
742
|
});
|
|
@@ -744,24 +744,24 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
744
744
|
server.registerTool('gog_sheets_table_get', {
|
|
745
745
|
description: 'Get a single Google Sheets table (definition + columns) by its table ID.',
|
|
746
746
|
annotations: { readOnlyHint: true },
|
|
747
|
-
inputSchema: {
|
|
747
|
+
inputSchema: z.object({
|
|
748
748
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
749
749
|
tableId: z.string().describe('Table ID (from gog_sheets_table_list)'),
|
|
750
750
|
account: accountParam,
|
|
751
|
-
},
|
|
751
|
+
}),
|
|
752
752
|
}, async ({ spreadsheetId, tableId, account }) => {
|
|
753
753
|
return runOrDiagnose(['sheets', 'table', 'get', spreadsheetId, tableId], { account });
|
|
754
754
|
});
|
|
755
755
|
|
|
756
756
|
server.registerTool('gog_sheets_table_create', {
|
|
757
757
|
description: 'Create a Google Sheets table over a range. columnsJson is a JSON array of column definitions (each {columnName, columnType?}); valid columnType values: TEXT, DOUBLE, BOOLEAN, DATE, DROPDOWN. Inline JSON or @/path/to/file.json.',
|
|
758
|
-
inputSchema: {
|
|
758
|
+
inputSchema: z.object({
|
|
759
759
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
760
760
|
range: z.string().describe('Range the table covers (e.g. Sheet1!A1:D20)'),
|
|
761
761
|
name: z.string().describe('Table name'),
|
|
762
762
|
columnsJson: z.string().describe('Column definitions as JSON array or @file (columnName + optional columnType)'),
|
|
763
763
|
account: accountParam,
|
|
764
|
-
},
|
|
764
|
+
}),
|
|
765
765
|
}, async ({ spreadsheetId, range, name, columnsJson, account }) => {
|
|
766
766
|
return runOrDiagnose(
|
|
767
767
|
['sheets', 'table', 'create', spreadsheetId, range, `--name=${name}`, `--columns-json=${columnsJson}`],
|
|
@@ -771,13 +771,13 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
771
771
|
|
|
772
772
|
server.registerTool('gog_sheets_table_append', {
|
|
773
773
|
description: 'Append data rows to a table. valuesJson is a JSON 2D array of row values.',
|
|
774
|
-
inputSchema: {
|
|
774
|
+
inputSchema: z.object({
|
|
775
775
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
776
776
|
tableId: z.string().describe('Table ID to append to'),
|
|
777
777
|
valuesJson: z.string().describe('Values as JSON 2D array (e.g. [["a",1],["b",2]])'),
|
|
778
778
|
input: z.enum(['RAW', 'USER_ENTERED']).optional().describe('Value input option (default: USER_ENTERED)'),
|
|
779
779
|
account: accountParam,
|
|
780
|
-
},
|
|
780
|
+
}),
|
|
781
781
|
}, async ({ spreadsheetId, tableId, valuesJson, input, account }) => {
|
|
782
782
|
const args = ['sheets', 'table', 'append', spreadsheetId, tableId, `--values-json=${valuesJson}`];
|
|
783
783
|
if (input) args.push(`--input=${input}`);
|
|
@@ -787,11 +787,11 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
787
787
|
server.registerTool('gog_sheets_table_clear', {
|
|
788
788
|
description: 'Clear all data rows from a table (keeps the table and its columns).',
|
|
789
789
|
annotations: { destructiveHint: true },
|
|
790
|
-
inputSchema: {
|
|
790
|
+
inputSchema: z.object({
|
|
791
791
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
792
792
|
tableId: z.string().describe('Table ID to clear'),
|
|
793
793
|
account: accountParam,
|
|
794
|
-
},
|
|
794
|
+
}),
|
|
795
795
|
}, async ({ spreadsheetId, tableId, account }) => {
|
|
796
796
|
return runOrDiagnose(['sheets', 'table', 'clear', spreadsheetId, tableId, '--force'], { account }); // gog gates this op; without --force the runner's --no-input makes it refuse
|
|
797
797
|
});
|
|
@@ -803,14 +803,14 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
803
803
|
'Formatting and banding are still lost; data-validation dropdowns are also not restored automatically, but you can snapshot them first with gog_sheets_validation_get and re-apply with gog_sheets_validation_set. ' +
|
|
804
804
|
'Set keep_data=false to delete the table AND wipe its cell data (the raw destructive behaviour). To preserve everything, snapshot the whole spreadsheet first with gog_sheets_snapshot.',
|
|
805
805
|
annotations: { destructiveHint: true },
|
|
806
|
-
inputSchema: {
|
|
806
|
+
inputSchema: z.object({
|
|
807
807
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
808
808
|
tableId: z.string().describe('Table ID to delete'),
|
|
809
809
|
keep_data: z.boolean().optional().describe(
|
|
810
810
|
'Default true: preserve the table\'s cell values and formulas (read → delete → restore), emulating "Convert to range". Set false to delete the table AND its data.',
|
|
811
811
|
),
|
|
812
812
|
account: accountParam,
|
|
813
|
-
},
|
|
813
|
+
}),
|
|
814
814
|
}, async ({ spreadsheetId, tableId, keep_data = true, account }) => {
|
|
815
815
|
if (!keep_data) {
|
|
816
816
|
// Raw destructive delete: removes the table and its cell data. gog ≥ 0.23
|
|
@@ -868,11 +868,11 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
868
868
|
server.registerTool('gog_sheets_banding_list', {
|
|
869
869
|
description: 'List alternating-color banded ranges. Optionally scope to a single sheet.',
|
|
870
870
|
annotations: { readOnlyHint: true },
|
|
871
|
-
inputSchema: {
|
|
871
|
+
inputSchema: z.object({
|
|
872
872
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
873
873
|
sheet: z.string().optional().describe('Only list banding from this sheet'),
|
|
874
874
|
account: accountParam,
|
|
875
|
-
},
|
|
875
|
+
}),
|
|
876
876
|
}, async ({ spreadsheetId, sheet, account }) => {
|
|
877
877
|
const args = ['sheets', 'banding', 'list', spreadsheetId];
|
|
878
878
|
if (sheet) args.push(`--sheet=${sheet}`);
|
|
@@ -881,13 +881,13 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
881
881
|
|
|
882
882
|
server.registerTool('gog_sheets_banding_set', {
|
|
883
883
|
description: 'Apply alternating colors to a range. Provide rowPropertiesJson and/or columnPropertiesJson — each a Sheets API BandingProperties JSON object ({headerColor, firstBandColor, secondBandColor, footerColor}). At least one is required.',
|
|
884
|
-
inputSchema: {
|
|
884
|
+
inputSchema: z.object({
|
|
885
885
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
886
886
|
range: z.string().describe('Range to band (e.g. Sheet1!A1:D20)'),
|
|
887
887
|
rowPropertiesJson: z.string().optional().describe('BandingProperties JSON for row colors'),
|
|
888
888
|
columnPropertiesJson: z.string().optional().describe('BandingProperties JSON for column colors'),
|
|
889
889
|
account: accountParam,
|
|
890
|
-
},
|
|
890
|
+
}),
|
|
891
891
|
}, async ({ spreadsheetId, range, rowPropertiesJson, columnPropertiesJson, account }) => {
|
|
892
892
|
const args = ['sheets', 'banding', 'set', spreadsheetId, range];
|
|
893
893
|
if (rowPropertiesJson) args.push(`--row-properties-json=${rowPropertiesJson}`);
|
|
@@ -898,13 +898,13 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
898
898
|
server.registerTool('gog_sheets_banding_clear', {
|
|
899
899
|
description: 'Remove alternating-color banding. Pass id to remove a single banded range, or all:true with sheet to remove every banding on that sheet.',
|
|
900
900
|
annotations: { destructiveHint: true },
|
|
901
|
-
inputSchema: {
|
|
901
|
+
inputSchema: z.object({
|
|
902
902
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
903
903
|
id: z.number().optional().describe('Banded range ID to remove'),
|
|
904
904
|
all: z.boolean().optional().describe('Remove all banding from the sheet (requires sheet)'),
|
|
905
905
|
sheet: z.string().optional().describe('Sheet name (used with all:true)'),
|
|
906
906
|
account: accountParam,
|
|
907
|
-
},
|
|
907
|
+
}),
|
|
908
908
|
}, async ({ spreadsheetId, id, all, sheet, account }) => {
|
|
909
909
|
const args = ['sheets', 'banding', 'clear', spreadsheetId];
|
|
910
910
|
if (id !== undefined) args.push(`--id=${id}`);
|
|
@@ -918,12 +918,12 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
918
918
|
|
|
919
919
|
server.registerTool('gog_sheets_filter_set', {
|
|
920
920
|
description: 'Set a basic filter on a range (the filter/sort header Sheets shows on a data range). A sheet can hold one basic filter; replacing an existing one requires replace=true — without it, gog refuses rather than silently overwriting.',
|
|
921
|
-
inputSchema: {
|
|
921
|
+
inputSchema: z.object({
|
|
922
922
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
923
923
|
range: z.string().describe('Range to filter (A1 notation with sheet name, e.g. Sheet1!A1:C100, or a named range name)'),
|
|
924
924
|
replace: z.boolean().optional().describe('Replace the sheet\'s existing basic filter if one is set (appends --force)'),
|
|
925
925
|
account: accountParam,
|
|
926
|
-
},
|
|
926
|
+
}),
|
|
927
927
|
}, async ({ spreadsheetId, range, replace, account }) => {
|
|
928
928
|
const args = ['sheets', 'filter', 'set', spreadsheetId, range];
|
|
929
929
|
if (replace) args.push('--force');
|
|
@@ -935,11 +935,11 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
935
935
|
server.registerTool('gog_sheets_conditional_format_list', {
|
|
936
936
|
description: 'List conditional formatting rules. Optionally scope to a single sheet.',
|
|
937
937
|
annotations: { readOnlyHint: true },
|
|
938
|
-
inputSchema: {
|
|
938
|
+
inputSchema: z.object({
|
|
939
939
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
940
940
|
sheet: z.string().optional().describe('Only list rules from this sheet'),
|
|
941
941
|
account: accountParam,
|
|
942
|
-
},
|
|
942
|
+
}),
|
|
943
943
|
}, async ({ spreadsheetId, sheet, account }) => {
|
|
944
944
|
const args = ['sheets', 'conditional-format', 'list', spreadsheetId];
|
|
945
945
|
if (sheet) args.push(`--sheet=${sheet}`);
|
|
@@ -948,7 +948,7 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
948
948
|
|
|
949
949
|
server.registerTool('gog_sheets_conditional_format_add', {
|
|
950
950
|
description: 'Add a conditional formatting rule to a range. Boolean rules: type picks the condition, expr is its value/formula (omit for blank/not-blank), formatJson is the CellFormat to apply when the condition matches (inline or @file); use formatFields to force-send zero/false fields (e.g. backgroundColor,textFormat.bold). Gradient rules (color scales): pass gradientRuleJson instead — a GradientRule JSON with minpoint/maxpoint (and optional midpoint), each {"color":{...},"type":"MIN|MAX|NUMBER|PERCENT|PERCENTILE","value":"..."}. The two modes are mutually exclusive.',
|
|
951
|
-
inputSchema: {
|
|
951
|
+
inputSchema: z.object({
|
|
952
952
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
953
953
|
range: z.string().describe('Range the rule applies to (e.g. Sheet1!A1:A100)'),
|
|
954
954
|
type: z.enum([
|
|
@@ -961,7 +961,7 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
961
961
|
formatFields: z.string().optional().describe('Format field mask for force-sending zero/false fields (e.g. backgroundColor,textFormat.bold)'),
|
|
962
962
|
gradientRuleJson: z.string().optional().describe('GradientRule JSON for gradient conditional formats (inline or @file; must include minpoint and maxpoint)'),
|
|
963
963
|
account: accountParam,
|
|
964
|
-
},
|
|
964
|
+
}),
|
|
965
965
|
}, async ({ spreadsheetId, range, type, formatJson, expr, formatFields, gradientRuleJson, account }) => {
|
|
966
966
|
const args = ['sheets', 'conditional-format', 'add', spreadsheetId, range];
|
|
967
967
|
if (type) args.push(`--type=${type}`);
|
|
@@ -975,13 +975,13 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
975
975
|
server.registerTool('gog_sheets_conditional_format_clear', {
|
|
976
976
|
description: 'Remove conditional formatting rules from a sheet. Pass index to remove a single rule by its 0-based index, or all:true to remove every rule on the sheet.',
|
|
977
977
|
annotations: { destructiveHint: true },
|
|
978
|
-
inputSchema: {
|
|
978
|
+
inputSchema: z.object({
|
|
979
979
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
980
980
|
sheet: z.string().describe('Sheet name to clear rules from'),
|
|
981
981
|
index: z.number().optional().describe('0-based rule index to remove'),
|
|
982
982
|
all: z.boolean().optional().describe('Remove all conditional formatting rules from the sheet'),
|
|
983
983
|
account: accountParam,
|
|
984
|
-
},
|
|
984
|
+
}),
|
|
985
985
|
}, async ({ spreadsheetId, sheet, index, all, account }) => {
|
|
986
986
|
const args = ['sheets', 'conditional-format', 'clear', spreadsheetId, `--sheet=${sheet}`];
|
|
987
987
|
if (index !== undefined) args.push(`--index=${index}`);
|
|
@@ -994,12 +994,12 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
994
994
|
description:
|
|
995
995
|
'Make a backup copy of an entire spreadsheet — a one-call safety snapshot to take BEFORE a risky or destructive edit (table delete, bulk clear, large rewrite). ' +
|
|
996
996
|
'Returns the new copy\'s file ID and URL; if the edit goes wrong, restore by copying the backup back or sharing it. The copy is independent — later edits to the original do not affect it.',
|
|
997
|
-
inputSchema: {
|
|
997
|
+
inputSchema: z.object({
|
|
998
998
|
spreadsheetId: z.string().describe('Spreadsheet ID to back up'),
|
|
999
999
|
name: z.string().describe('Name for the backup copy, e.g. "Budget — backup before table delete"'),
|
|
1000
1000
|
parent: z.string().optional().describe('Destination folder ID for the copy (default: same location as the original)'),
|
|
1001
1001
|
account: accountParam,
|
|
1002
|
-
},
|
|
1002
|
+
}),
|
|
1003
1003
|
}, async ({ spreadsheetId, name, parent, account }) => {
|
|
1004
1004
|
const args = ['drive', 'copy', spreadsheetId, name];
|
|
1005
1005
|
if (parent) args.push(`--parent=${parent}`);
|
|
@@ -1032,10 +1032,10 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
1032
1032
|
'and current execution status. This is the discovery call — start here to get the dataSourceId the describe tool wants. ' +
|
|
1033
1033
|
'Deliberately does not print custom SQL; use gog_sheets_datasource_describe for that.' + bigQueryScopeNote,
|
|
1034
1034
|
annotations: { readOnlyHint: true },
|
|
1035
|
-
inputSchema: {
|
|
1035
|
+
inputSchema: z.object({
|
|
1036
1036
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
1037
1037
|
account: accountParam,
|
|
1038
|
-
},
|
|
1038
|
+
}),
|
|
1039
1039
|
}, async ({ spreadsheetId, account }) => {
|
|
1040
1040
|
return runOrDiagnose(['sheets', 'datasource', 'list', spreadsheetId], { account });
|
|
1041
1041
|
});
|
|
@@ -1047,11 +1047,11 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
1047
1047
|
'Refreshes are asynchronous and this tool cannot start one — poll it until state is SUCCEEDED or FAILED, and read the ' +
|
|
1048
1048
|
'status error text when it is FAILED.' + bigQueryScopeNote,
|
|
1049
1049
|
annotations: { readOnlyHint: true },
|
|
1050
|
-
inputSchema: {
|
|
1050
|
+
inputSchema: z.object({
|
|
1051
1051
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
1052
1052
|
dataSourceId: z.string().describe('Data source ID, as reported by gog_sheets_datasource_list'),
|
|
1053
1053
|
account: accountParam,
|
|
1054
|
-
},
|
|
1054
|
+
}),
|
|
1055
1055
|
}, async ({ spreadsheetId, dataSourceId, account }) => {
|
|
1056
1056
|
return runOrDiagnose(['sheets', 'datasource', 'describe', spreadsheetId, dataSourceId], { account });
|
|
1057
1057
|
});
|
|
@@ -1063,11 +1063,11 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
1063
1063
|
'sheet-qualified A1 anchor (e.g. "Extracts!B3"). That anchor is what the describe and read tools take. Filter with ' +
|
|
1064
1064
|
'dataSourceId to see only one source\'s extracts.' + bigQueryScopeNote,
|
|
1065
1065
|
annotations: { readOnlyHint: true },
|
|
1066
|
-
inputSchema: {
|
|
1066
|
+
inputSchema: z.object({
|
|
1067
1067
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
1068
1068
|
dataSourceId: z.string().optional().describe('Only list tables belonging to this data source ID'),
|
|
1069
1069
|
account: accountParam,
|
|
1070
|
-
},
|
|
1070
|
+
}),
|
|
1071
1071
|
}, async ({ spreadsheetId, dataSourceId, account }) => {
|
|
1072
1072
|
const args = ['sheets', 'datasource', 'table', 'list', spreadsheetId];
|
|
1073
1073
|
if (dataSourceId) args.push(`--data-source-id=${dataSourceId}`);
|
|
@@ -1080,11 +1080,11 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
1080
1080
|
'row limit. Read this before gog_sheets_datasource_table_read when you need to know what the columns MEAN — the read ' +
|
|
1081
1081
|
'returns values, not the extract\'s definition.' + bigQueryScopeNote,
|
|
1082
1082
|
annotations: { readOnlyHint: true },
|
|
1083
|
-
inputSchema: {
|
|
1083
|
+
inputSchema: z.object({
|
|
1084
1084
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
1085
1085
|
anchor: z.string().describe('Sheet-qualified A1 anchor of the extract\'s top-left cell, e.g. "Extracts!B3". Get it from gog_sheets_datasource_table_list — an extract has no other identifier.'),
|
|
1086
1086
|
account: accountParam,
|
|
1087
|
-
},
|
|
1087
|
+
}),
|
|
1088
1088
|
}, async ({ spreadsheetId, anchor, account }) => {
|
|
1089
1089
|
return runOrDiagnose(['sheets', 'datasource', 'table', 'describe', spreadsheetId, anchor], { account });
|
|
1090
1090
|
});
|
|
@@ -1097,13 +1097,13 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
1097
1097
|
'conclude a value is absent from it; raise maxRows or narrow the extract instead. Use render=UNFORMATTED_VALUE for ' +
|
|
1098
1098
|
'arithmetic (FORMATTED_VALUE returns display strings) or render=FORMULA to see the cell formulas.' + bigQueryScopeNote,
|
|
1099
1099
|
annotations: { readOnlyHint: true },
|
|
1100
|
-
inputSchema: {
|
|
1100
|
+
inputSchema: z.object({
|
|
1101
1101
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
1102
1102
|
anchor: z.string().describe('Sheet-qualified A1 anchor of the extract\'s top-left cell, e.g. "Extracts!B3" (from gog_sheets_datasource_table_list)'),
|
|
1103
1103
|
maxRows: z.number().int().positive().optional().describe('Maximum data rows to read (gog default: 1000). The header row is returned separately and does not count against this.'),
|
|
1104
1104
|
render: z.enum(['FORMATTED_VALUE', 'UNFORMATTED_VALUE', 'FORMULA']).optional().describe('How cell values are rendered (gog default: FORMATTED_VALUE)'),
|
|
1105
1105
|
account: accountParam,
|
|
1106
|
-
},
|
|
1106
|
+
}),
|
|
1107
1107
|
}, async ({ spreadsheetId, anchor, maxRows, render, account }) => {
|
|
1108
1108
|
const args = ['sheets', 'datasource', 'table', 'read', spreadsheetId, anchor];
|
|
1109
1109
|
if (maxRows !== undefined) args.push(`--max-rows=${maxRows}`);
|
|
@@ -1138,7 +1138,7 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
1138
1138
|
'BigQuery project charged for the query; tableProject only names which project OWNS the table, and defaults to the ' +
|
|
1139
1139
|
'billing project. Returns the new dataSourceId, which every other datasource tool takes.' +
|
|
1140
1140
|
bigQueryChargeNote + bigQueryScopeNote,
|
|
1141
|
-
inputSchema: {
|
|
1141
|
+
inputSchema: z.object({
|
|
1142
1142
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
1143
1143
|
billingProject: z.string().describe('Billing-enabled BigQuery project charged for this source\'s queries'),
|
|
1144
1144
|
query: z.string().optional().describe('BigQuery SQL to run. Mutually exclusive with dataset/table/tableProject.'),
|
|
@@ -1146,7 +1146,7 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
1146
1146
|
table: z.string().optional().describe('BigQuery table ID. Requires dataset; mutually exclusive with query.'),
|
|
1147
1147
|
tableProject: z.string().optional().describe('BigQuery project that owns the table (default: the billing project). Only valid with dataset/table.'),
|
|
1148
1148
|
account: accountParam,
|
|
1149
|
-
},
|
|
1149
|
+
}),
|
|
1150
1150
|
}, async ({ spreadsheetId, billingProject, query, dataset, table, tableProject, account }) => {
|
|
1151
1151
|
const tableFlags = tableProject !== undefined || dataset !== undefined || table !== undefined;
|
|
1152
1152
|
if (query !== undefined && tableFlags) {
|
|
@@ -1171,7 +1171,7 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
1171
1171
|
'gog_sheets_datasource_describe first if you are unsure which kind it is. Replacing the SQL DISCARDS the source\'s ' +
|
|
1172
1172
|
'current results.' + bigQueryChargeNote + bigQueryScopeNote,
|
|
1173
1173
|
annotations: { destructiveHint: true },
|
|
1174
|
-
inputSchema: {
|
|
1174
|
+
inputSchema: z.object({
|
|
1175
1175
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
1176
1176
|
dataSourceId: z.string().describe('Data source ID, as reported by gog_sheets_datasource_list'),
|
|
1177
1177
|
billingProject: z.string().optional().describe('New billing-enabled BigQuery project to charge executions to'),
|
|
@@ -1180,7 +1180,7 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
1180
1180
|
table: z.string().optional().describe('Replacement table ID. Only valid on a table-backed source.'),
|
|
1181
1181
|
tableProject: z.string().optional().describe('Replacement project owning the table. Only valid on a table-backed source.'),
|
|
1182
1182
|
account: accountParam,
|
|
1183
|
-
},
|
|
1183
|
+
}),
|
|
1184
1184
|
}, async ({ spreadsheetId, dataSourceId, billingProject, query, dataset, table, tableProject, account }) => {
|
|
1185
1185
|
const tableFlags = tableProject !== undefined || dataset !== undefined || table !== undefined;
|
|
1186
1186
|
if (query !== undefined && tableFlags) {
|
|
@@ -1218,12 +1218,12 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
1218
1218
|
'Re-run a Connected Sheets data source so its sheet and extracts pick up current BigQuery data. Google refuses to ' +
|
|
1219
1219
|
'refresh a source whose previous execution FAILED; forceRefresh overrides that, which is what you want after fixing ' +
|
|
1220
1220
|
'the underlying query or permissions.' + bigQueryChargeNote + bigQueryScopeNote,
|
|
1221
|
-
inputSchema: {
|
|
1221
|
+
inputSchema: z.object({
|
|
1222
1222
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
1223
1223
|
dataSourceId: z.string().describe('Data source ID, as reported by gog_sheets_datasource_list'),
|
|
1224
1224
|
forceRefresh: z.boolean().optional().describe('Refresh even when the previous execution failed'),
|
|
1225
1225
|
account: accountParam,
|
|
1226
|
-
},
|
|
1226
|
+
}),
|
|
1227
1227
|
}, async ({ spreadsheetId, dataSourceId, forceRefresh, account }) => {
|
|
1228
1228
|
const args = ['sheets', 'datasource', 'refresh', spreadsheetId, dataSourceId];
|
|
1229
1229
|
if (forceRefresh) args.push('--force-refresh');
|
|
@@ -1237,11 +1237,11 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
1237
1237
|
'objects on other tabs that the caller never named. Take gog_sheets_snapshot first if any of that matters. The ' +
|
|
1238
1238
|
'BigQuery data itself is untouched; only the spreadsheet\'s connection to it goes away.' + bigQueryScopeNote,
|
|
1239
1239
|
annotations: { destructiveHint: true },
|
|
1240
|
-
inputSchema: {
|
|
1240
|
+
inputSchema: z.object({
|
|
1241
1241
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
1242
1242
|
dataSourceId: z.string().describe('Data source ID, as reported by gog_sheets_datasource_list'),
|
|
1243
1243
|
account: accountParam,
|
|
1244
|
-
},
|
|
1244
|
+
}),
|
|
1245
1245
|
}, async ({ spreadsheetId, dataSourceId, account }) => {
|
|
1246
1246
|
// gog gates this delete behind a confirmation; the runner injects
|
|
1247
1247
|
// --no-input, so without --force it refuses at runtime. Verified live
|