gogcli-mcp-sheets 2.3.0 → 2.4.1
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 +23 -4
- package/manifest.json +5 -1
- package/package.json +1 -1
- package/server.json +2 -2
- package/src/tools/sheets-extra.ts +23 -3
- package/tests/tools/sheets-extra.test.ts +37 -0
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"metadata": {
|
|
9
9
|
"description": "Extended Google Sheets for Claude via gogcli — auth + full Sheets support",
|
|
10
|
-
"version": "2.
|
|
10
|
+
"version": "2.4.1"
|
|
11
11
|
},
|
|
12
12
|
"plugins": [
|
|
13
13
|
{
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"displayName": "gogcli (Sheets)",
|
|
16
16
|
"source": "./",
|
|
17
17
|
"description": "Extended Google Sheets for Claude via gogcli — auth + full Sheets support",
|
|
18
|
-
"version": "2.
|
|
18
|
+
"version": "2.4.1",
|
|
19
19
|
"author": {
|
|
20
20
|
"name": "Chris Hall"
|
|
21
21
|
},
|
package/dist/index.js
CHANGED
|
@@ -31399,7 +31399,7 @@ function registerSheetsTools(server2) {
|
|
|
31399
31399
|
}
|
|
31400
31400
|
|
|
31401
31401
|
// ../gogcli-mcp/src/server.ts
|
|
31402
|
-
var VERSION = true ? "2.
|
|
31402
|
+
var VERSION = true ? "2.4.1" : "0.0.0";
|
|
31403
31403
|
function createServer(options) {
|
|
31404
31404
|
return new McpServer({
|
|
31405
31405
|
name: options?.name ?? "gogcli",
|
|
@@ -31548,13 +31548,32 @@ function registerExtraSheetsTools(server2) {
|
|
|
31548
31548
|
start: external_exports.number().describe("Start index (0-based)"),
|
|
31549
31549
|
count: external_exports.number().optional().describe("Number of rows/columns to insert (default: 1)"),
|
|
31550
31550
|
after: external_exports.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."),
|
|
31551
|
+
inheritFromBefore: external_exports.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."),
|
|
31551
31552
|
account: accountParam
|
|
31552
31553
|
}
|
|
31553
|
-
}, async ({ spreadsheetId, sheet, dimension, start, count, after, account }) => {
|
|
31554
|
+
}, async ({ spreadsheetId, sheet, dimension, start, count, after, inheritFromBefore, account }) => {
|
|
31554
31555
|
const effectiveStart = after ? start + 1 : start;
|
|
31555
31556
|
const args = ["sheets", "insert", spreadsheetId, sheet, dimension, String(effectiveStart)];
|
|
31556
31557
|
if (count !== void 0) args.push(`--count=${count}`);
|
|
31557
31558
|
if (after) args.push("--after");
|
|
31559
|
+
if (inheritFromBefore !== void 0) args.push(`--inherit-from-before=${inheritFromBefore}`);
|
|
31560
|
+
return runOrDiagnose(args, { account });
|
|
31561
|
+
});
|
|
31562
|
+
server2.registerTool("gog_sheets_copy_paste", {
|
|
31563
|
+
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 \u2014 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).",
|
|
31564
|
+
annotations: { destructiveHint: true },
|
|
31565
|
+
inputSchema: {
|
|
31566
|
+
spreadsheetId: external_exports.string().describe("Spreadsheet ID"),
|
|
31567
|
+
source: external_exports.string().describe("Source range (e.g. Sheet1!A2:H71)"),
|
|
31568
|
+
dest: external_exports.string().describe("Destination range (e.g. Sheet1!A2:H120). Larger than the source tiles/fills it."),
|
|
31569
|
+
type: external_exports.enum(["NORMAL", "VALUES", "FORMAT", "FORMULA", "NO_BORDERS", "DATA_VALIDATION", "CONDITIONAL_FORMATTING"]).optional().describe("Paste type (default: NORMAL pastes everything)"),
|
|
31570
|
+
transpose: external_exports.boolean().optional().describe("Paste transposed (swap rows and columns)"),
|
|
31571
|
+
account: accountParam
|
|
31572
|
+
}
|
|
31573
|
+
}, async ({ spreadsheetId, source, dest, type, transpose, account }) => {
|
|
31574
|
+
const args = ["sheets", "copy-paste", spreadsheetId, source, dest];
|
|
31575
|
+
if (type) args.push(`--type=${type}`);
|
|
31576
|
+
if (transpose) args.push("--transpose");
|
|
31558
31577
|
return runOrDiagnose(args, { account });
|
|
31559
31578
|
});
|
|
31560
31579
|
server2.registerTool("gog_sheets_merge", {
|
|
@@ -31835,11 +31854,11 @@ ${result.content[0].text}` }] };
|
|
|
31835
31854
|
return runOrDiagnose(["sheets", "named-ranges", "delete", spreadsheetId, nameOrId], { account });
|
|
31836
31855
|
});
|
|
31837
31856
|
server2.registerTool("gog_sheets_batch_update", {
|
|
31838
|
-
description:
|
|
31857
|
+
description: `Update values in multiple ranges with one Sheets API request. dataJson is a JSON array of {range, values} objects \u2014 pass it inline as a literal JSON string. Atomic \u2014 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.)`,
|
|
31839
31858
|
annotations: { destructiveHint: true },
|
|
31840
31859
|
inputSchema: {
|
|
31841
31860
|
spreadsheetId: external_exports.string().describe("Spreadsheet ID"),
|
|
31842
|
-
dataJson: external_exports.string().describe('Value ranges as JSON array,
|
|
31861
|
+
dataJson: external_exports.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 \u2014 inline the JSON instead.)'),
|
|
31843
31862
|
input: external_exports.enum(["RAW", "USER_ENTERED"]).optional().describe("Value input option (default: USER_ENTERED)"),
|
|
31844
31863
|
includeValuesInResponse: external_exports.boolean().optional().describe("Include updated values in the response"),
|
|
31845
31864
|
responseRender: external_exports.enum(["FORMATTED_VALUE", "UNFORMATTED_VALUE", "FORMULA"]).optional().describe("Response value render option"),
|
package/manifest.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"manifest_version": "0.3",
|
|
4
4
|
"name": "gogcli-mcp-sheets",
|
|
5
5
|
"display_name": "gogcli (Sheets)",
|
|
6
|
-
"version": "2.
|
|
6
|
+
"version": "2.4.1",
|
|
7
7
|
"description": "Extended Google Sheets for Claude via gogcli — auth + full Sheets support",
|
|
8
8
|
"author": {
|
|
9
9
|
"name": "Chris Hall",
|
|
@@ -136,6 +136,10 @@
|
|
|
136
136
|
"name": "gog_sheets_insert",
|
|
137
137
|
"description": "Insert rows or columns into a sheet."
|
|
138
138
|
},
|
|
139
|
+
{
|
|
140
|
+
"name": "gog_sheets_copy_paste",
|
|
141
|
+
"description": "Copy a range's values/formulas/format to another range (tiles to fill down/across)."
|
|
142
|
+
},
|
|
139
143
|
{
|
|
140
144
|
"name": "gog_sheets_merge",
|
|
141
145
|
"description": "Merge cells in a range."
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gogcli-mcp-sheets",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"mcpName": "io.github.chrischall/gogcli-mcp-sheets",
|
|
5
5
|
"description": "Extended Google Sheets MCP server via gogcli — all base tools plus full Sheets support",
|
|
6
6
|
"author": "Claude Code (AI) <https://www.anthropic.com/claude>",
|
package/server.json
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
"source": "github",
|
|
8
8
|
"subfolder": "packages/gogcli-mcp-sheets"
|
|
9
9
|
},
|
|
10
|
-
"version": "2.
|
|
10
|
+
"version": "2.4.1",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"identifier": "gogcli-mcp-sheets",
|
|
15
|
-
"version": "2.
|
|
15
|
+
"version": "2.4.1",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
18
18
|
},
|
|
@@ -178,9 +178,10 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
178
178
|
start: z.number().describe('Start index (0-based)'),
|
|
179
179
|
count: z.number().optional().describe('Number of rows/columns to insert (default: 1)'),
|
|
180
180
|
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.'),
|
|
181
|
+
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.'),
|
|
181
182
|
account: accountParam,
|
|
182
183
|
},
|
|
183
|
-
}, async ({ spreadsheetId, sheet, dimension, start, count, after, account }) => {
|
|
184
|
+
}, async ({ spreadsheetId, sheet, dimension, start, count, after, inheritFromBefore, account }) => {
|
|
184
185
|
// The underlying `gog sheets insert` treats `start` as 1-based with `--after` shifting +1.
|
|
185
186
|
// To honor our 0-based `start` and make `after:true` actually shift the insertion to start+1
|
|
186
187
|
// (issue #42), we send `start+1` when `after:true`. With after:false the CLI's `start-1`
|
|
@@ -189,6 +190,25 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
189
190
|
const args = ['sheets', 'insert', spreadsheetId, sheet, dimension, String(effectiveStart)];
|
|
190
191
|
if (count !== undefined) args.push(`--count=${count}`);
|
|
191
192
|
if (after) args.push('--after');
|
|
193
|
+
if (inheritFromBefore !== undefined) args.push(`--inherit-from-before=${inheritFromBefore}`);
|
|
194
|
+
return runOrDiagnose(args, { account });
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
server.registerTool('gog_sheets_copy_paste', {
|
|
198
|
+
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).',
|
|
199
|
+
annotations: { destructiveHint: true },
|
|
200
|
+
inputSchema: {
|
|
201
|
+
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
202
|
+
source: z.string().describe('Source range (e.g. Sheet1!A2:H71)'),
|
|
203
|
+
dest: z.string().describe('Destination range (e.g. Sheet1!A2:H120). Larger than the source tiles/fills it.'),
|
|
204
|
+
type: z.enum(['NORMAL', 'VALUES', 'FORMAT', 'FORMULA', 'NO_BORDERS', 'DATA_VALIDATION', 'CONDITIONAL_FORMATTING']).optional().describe('Paste type (default: NORMAL pastes everything)'),
|
|
205
|
+
transpose: z.boolean().optional().describe('Paste transposed (swap rows and columns)'),
|
|
206
|
+
account: accountParam,
|
|
207
|
+
},
|
|
208
|
+
}, async ({ spreadsheetId, source, dest, type, transpose, account }) => {
|
|
209
|
+
const args = ['sheets', 'copy-paste', spreadsheetId, source, dest];
|
|
210
|
+
if (type) args.push(`--type=${type}`);
|
|
211
|
+
if (transpose) args.push('--transpose');
|
|
192
212
|
return runOrDiagnose(args, { account });
|
|
193
213
|
});
|
|
194
214
|
|
|
@@ -485,11 +505,11 @@ export function registerExtraSheetsTools(server: McpServer): void {
|
|
|
485
505
|
});
|
|
486
506
|
|
|
487
507
|
server.registerTool('gog_sheets_batch_update', {
|
|
488
|
-
description: 'Update values in multiple ranges with one Sheets API request. dataJson is a JSON array of {range, values} objects
|
|
508
|
+
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.)',
|
|
489
509
|
annotations: { destructiveHint: true },
|
|
490
510
|
inputSchema: {
|
|
491
511
|
spreadsheetId: z.string().describe('Spreadsheet ID'),
|
|
492
|
-
dataJson: z.string().describe('Value ranges as JSON array,
|
|
512
|
+
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.)'),
|
|
493
513
|
input: z.enum(['RAW', 'USER_ENTERED']).optional().describe('Value input option (default: USER_ENTERED)'),
|
|
494
514
|
includeValuesInResponse: z.boolean().optional().describe('Include updated values in the response'),
|
|
495
515
|
responseRender: z.enum(['FORMATTED_VALUE', 'UNFORMATTED_VALUE', 'FORMULA']).optional().describe('Response value render option'),
|
|
@@ -149,6 +149,43 @@ describe('gog_sheets_insert', () => {
|
|
|
149
149
|
await handlers.get('gog_sheets_insert')!({ spreadsheetId: 'sid', sheet: 'S1', dimension: 'ROWS', start: 0, after: false });
|
|
150
150
|
expect(lib.runOrDiagnose).toHaveBeenCalledWith(['sheets', 'insert', 'sid', 'S1', 'ROWS', '0'], { account: undefined });
|
|
151
151
|
});
|
|
152
|
+
|
|
153
|
+
it('passes --inherit-from-before=true when set', async () => {
|
|
154
|
+
vi.mocked(lib.runOrDiagnose).mockResolvedValue(toText('{}'));
|
|
155
|
+
const handlers = setupHandlers();
|
|
156
|
+
await handlers.get('gog_sheets_insert')!({ spreadsheetId: 'sid', sheet: 'S1', dimension: 'ROWS', start: 5, after: true, inheritFromBefore: true });
|
|
157
|
+
expect(lib.runOrDiagnose).toHaveBeenCalledWith(['sheets', 'insert', 'sid', 'S1', 'ROWS', '6', '--after', '--inherit-from-before=true'], { account: undefined });
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('passes --inherit-from-before=false to inherit from the following neighbor', async () => {
|
|
161
|
+
vi.mocked(lib.runOrDiagnose).mockResolvedValue(toText('{}'));
|
|
162
|
+
const handlers = setupHandlers();
|
|
163
|
+
await handlers.get('gog_sheets_insert')!({ spreadsheetId: 'sid', sheet: 'S1', dimension: 'ROWS', start: 5, after: true, inheritFromBefore: false });
|
|
164
|
+
expect(lib.runOrDiagnose).toHaveBeenCalledWith(['sheets', 'insert', 'sid', 'S1', 'ROWS', '6', '--after', '--inherit-from-before=false'], { account: undefined });
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe('gog_sheets_copy_paste', () => {
|
|
169
|
+
it('calls runOrDiagnose with required source/dest', async () => {
|
|
170
|
+
vi.mocked(lib.runOrDiagnose).mockResolvedValue(toText('{}'));
|
|
171
|
+
const handlers = setupHandlers();
|
|
172
|
+
await handlers.get('gog_sheets_copy_paste')!({ spreadsheetId: 'sid', source: 'Sheet1!A2:H71', dest: 'Sheet1!A2:H120' });
|
|
173
|
+
expect(lib.runOrDiagnose).toHaveBeenCalledWith(['sheets', 'copy-paste', 'sid', 'Sheet1!A2:H71', 'Sheet1!A2:H120'], { account: undefined });
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('appends --type and --transpose when provided', async () => {
|
|
177
|
+
vi.mocked(lib.runOrDiagnose).mockResolvedValue(toText('{}'));
|
|
178
|
+
const handlers = setupHandlers();
|
|
179
|
+
await handlers.get('gog_sheets_copy_paste')!({ spreadsheetId: 'sid', source: 'A1:B2', dest: 'D1:E2', type: 'FORMULA', transpose: true });
|
|
180
|
+
expect(lib.runOrDiagnose).toHaveBeenCalledWith(['sheets', 'copy-paste', 'sid', 'A1:B2', 'D1:E2', '--type=FORMULA', '--transpose'], { account: undefined });
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('forwards account', async () => {
|
|
184
|
+
vi.mocked(lib.runOrDiagnose).mockResolvedValue(toText('{}'));
|
|
185
|
+
const handlers = setupHandlers();
|
|
186
|
+
await handlers.get('gog_sheets_copy_paste')!({ spreadsheetId: 'sid', source: 'A1', dest: 'B1', account: 'a@b.com' });
|
|
187
|
+
expect(lib.runOrDiagnose).toHaveBeenCalledWith(['sheets', 'copy-paste', 'sid', 'A1', 'B1'], { account: 'a@b.com' });
|
|
188
|
+
});
|
|
152
189
|
});
|
|
153
190
|
|
|
154
191
|
// 8. merge
|