gogcli-mcp 2.0.4 → 2.0.7
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 +12 -531
- package/dist/lib.js +12 -531
- package/manifest.json +1 -145
- package/package.json +1 -1
- package/server.json +2 -2
- package/src/runner.ts +12 -2
- package/src/tools/calendar.ts +0 -92
- package/src/tools/classroom.ts +2 -297
- package/src/tools/contacts.ts +1 -75
- package/src/tools/slides.ts +1 -108
- package/tests/helpers/extras-harness.ts +31 -0
- package/tests/runner.test.ts +63 -0
- package/tests/tools/calendar.test.ts +0 -137
- package/tests/tools/classroom.test.ts +0 -352
- package/tests/tools/contacts.test.ts +0 -100
- package/tests/tools/slides.test.ts +6 -278
package/manifest.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"manifest_version": "0.3",
|
|
4
4
|
"name": "gogcli-mcp",
|
|
5
5
|
"display_name": "gogcli",
|
|
6
|
-
"version": "2.0.
|
|
6
|
+
"version": "2.0.7",
|
|
7
7
|
"description": "Google Sheets (and more) for Claude via gogcli — read, write, and manage spreadsheets",
|
|
8
8
|
"author": {
|
|
9
9
|
"name": "Chris Hall",
|
|
@@ -120,30 +120,6 @@
|
|
|
120
120
|
"name": "gog_calendar_run",
|
|
121
121
|
"description": "Run any gog calendar subcommand (escape hatch)"
|
|
122
122
|
},
|
|
123
|
-
{
|
|
124
|
-
"name": "gog_meet_create",
|
|
125
|
-
"description": "Create a Google Meet space"
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
"name": "gog_meet_get",
|
|
129
|
-
"description": "Get a Google Meet space by meeting code"
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
"name": "gog_meet_update",
|
|
133
|
-
"description": "Update a Google Meet space configuration"
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
"name": "gog_meet_end",
|
|
137
|
-
"description": "End the active conference in a Meet space"
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
"name": "gog_meet_history",
|
|
141
|
-
"description": "List past calls in a Meet space"
|
|
142
|
-
},
|
|
143
|
-
{
|
|
144
|
-
"name": "gog_meet_participants",
|
|
145
|
-
"description": "List participants from a Meet call"
|
|
146
|
-
},
|
|
147
123
|
{
|
|
148
124
|
"name": "gog_classroom_courses_list",
|
|
149
125
|
"description": "List Google Classroom courses"
|
|
@@ -152,26 +128,6 @@
|
|
|
152
128
|
"name": "gog_classroom_courses_get",
|
|
153
129
|
"description": "Get a single course by ID"
|
|
154
130
|
},
|
|
155
|
-
{
|
|
156
|
-
"name": "gog_classroom_courses_create",
|
|
157
|
-
"description": "Create a new course"
|
|
158
|
-
},
|
|
159
|
-
{
|
|
160
|
-
"name": "gog_classroom_courses_update",
|
|
161
|
-
"description": "Update an existing course"
|
|
162
|
-
},
|
|
163
|
-
{
|
|
164
|
-
"name": "gog_classroom_courses_delete",
|
|
165
|
-
"description": "Delete a course"
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
"name": "gog_classroom_courses_archive",
|
|
169
|
-
"description": "Archive a course"
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
"name": "gog_classroom_courses_unarchive",
|
|
173
|
-
"description": "Unarchive a course"
|
|
174
|
-
},
|
|
175
131
|
{
|
|
176
132
|
"name": "gog_classroom_students_list",
|
|
177
133
|
"description": "List students in a course"
|
|
@@ -180,14 +136,6 @@
|
|
|
180
136
|
"name": "gog_classroom_students_get",
|
|
181
137
|
"description": "Get a specific student"
|
|
182
138
|
},
|
|
183
|
-
{
|
|
184
|
-
"name": "gog_classroom_students_add",
|
|
185
|
-
"description": "Add a student to a course"
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
"name": "gog_classroom_students_remove",
|
|
189
|
-
"description": "Remove a student from a course"
|
|
190
|
-
},
|
|
191
139
|
{
|
|
192
140
|
"name": "gog_classroom_teachers_list",
|
|
193
141
|
"description": "List teachers in a course"
|
|
@@ -196,14 +144,6 @@
|
|
|
196
144
|
"name": "gog_classroom_teachers_get",
|
|
197
145
|
"description": "Get a specific teacher"
|
|
198
146
|
},
|
|
199
|
-
{
|
|
200
|
-
"name": "gog_classroom_teachers_add",
|
|
201
|
-
"description": "Add a teacher to a course"
|
|
202
|
-
},
|
|
203
|
-
{
|
|
204
|
-
"name": "gog_classroom_teachers_remove",
|
|
205
|
-
"description": "Remove a teacher from a course"
|
|
206
|
-
},
|
|
207
147
|
{
|
|
208
148
|
"name": "gog_classroom_roster",
|
|
209
149
|
"description": "List the full course roster (students and/or teachers)"
|
|
@@ -216,18 +156,6 @@
|
|
|
216
156
|
"name": "gog_classroom_coursework_get",
|
|
217
157
|
"description": "Get a single coursework item"
|
|
218
158
|
},
|
|
219
|
-
{
|
|
220
|
-
"name": "gog_classroom_coursework_create",
|
|
221
|
-
"description": "Create coursework (assignment/question)"
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
"name": "gog_classroom_coursework_update",
|
|
225
|
-
"description": "Update existing coursework"
|
|
226
|
-
},
|
|
227
|
-
{
|
|
228
|
-
"name": "gog_classroom_coursework_delete",
|
|
229
|
-
"description": "Delete coursework"
|
|
230
|
-
},
|
|
231
159
|
{
|
|
232
160
|
"name": "gog_classroom_submissions_list",
|
|
233
161
|
"description": "List student submissions for coursework"
|
|
@@ -264,14 +192,6 @@
|
|
|
264
192
|
"name": "gog_classroom_announcements_create",
|
|
265
193
|
"description": "Create an announcement"
|
|
266
194
|
},
|
|
267
|
-
{
|
|
268
|
-
"name": "gog_classroom_announcements_update",
|
|
269
|
-
"description": "Update an announcement"
|
|
270
|
-
},
|
|
271
|
-
{
|
|
272
|
-
"name": "gog_classroom_announcements_delete",
|
|
273
|
-
"description": "Delete an announcement"
|
|
274
|
-
},
|
|
275
195
|
{
|
|
276
196
|
"name": "gog_classroom_topics_list",
|
|
277
197
|
"description": "List topics in a course"
|
|
@@ -280,18 +200,6 @@
|
|
|
280
200
|
"name": "gog_classroom_topics_get",
|
|
281
201
|
"description": "Get a topic"
|
|
282
202
|
},
|
|
283
|
-
{
|
|
284
|
-
"name": "gog_classroom_topics_create",
|
|
285
|
-
"description": "Create a topic"
|
|
286
|
-
},
|
|
287
|
-
{
|
|
288
|
-
"name": "gog_classroom_topics_update",
|
|
289
|
-
"description": "Rename a topic"
|
|
290
|
-
},
|
|
291
|
-
{
|
|
292
|
-
"name": "gog_classroom_topics_delete",
|
|
293
|
-
"description": "Delete a topic"
|
|
294
|
-
},
|
|
295
203
|
{
|
|
296
204
|
"name": "gog_classroom_invitations_list",
|
|
297
205
|
"description": "List classroom invitations"
|
|
@@ -300,18 +208,10 @@
|
|
|
300
208
|
"name": "gog_classroom_invitations_get",
|
|
301
209
|
"description": "Get an invitation"
|
|
302
210
|
},
|
|
303
|
-
{
|
|
304
|
-
"name": "gog_classroom_invitations_create",
|
|
305
|
-
"description": "Create an invitation"
|
|
306
|
-
},
|
|
307
211
|
{
|
|
308
212
|
"name": "gog_classroom_invitations_accept",
|
|
309
213
|
"description": "Accept an invitation"
|
|
310
214
|
},
|
|
311
|
-
{
|
|
312
|
-
"name": "gog_classroom_invitations_delete",
|
|
313
|
-
"description": "Delete (revoke) an invitation"
|
|
314
|
-
},
|
|
315
215
|
{
|
|
316
216
|
"name": "gog_classroom_profile_get",
|
|
317
217
|
"description": "Get a classroom user profile (omit userId for self)"
|
|
@@ -404,26 +304,6 @@
|
|
|
404
304
|
"name": "gog_contacts_run",
|
|
405
305
|
"description": "Run any gog contacts subcommand (escape hatch)"
|
|
406
306
|
},
|
|
407
|
-
{
|
|
408
|
-
"name": "gog_people_me",
|
|
409
|
-
"description": "Show your own Google People profile"
|
|
410
|
-
},
|
|
411
|
-
{
|
|
412
|
-
"name": "gog_people_get",
|
|
413
|
-
"description": "Get a People profile by resource name"
|
|
414
|
-
},
|
|
415
|
-
{
|
|
416
|
-
"name": "gog_people_search",
|
|
417
|
-
"description": "Search the Google Workspace directory"
|
|
418
|
-
},
|
|
419
|
-
{
|
|
420
|
-
"name": "gog_people_relations",
|
|
421
|
-
"description": "Get relations (manager, reports) for a user"
|
|
422
|
-
},
|
|
423
|
-
{
|
|
424
|
-
"name": "gog_people_raw",
|
|
425
|
-
"description": "Dump raw Google People API JSON for a person"
|
|
426
|
-
},
|
|
427
307
|
{
|
|
428
308
|
"name": "gog_docs_info",
|
|
429
309
|
"description": "Get Google Doc metadata (title, ID, properties)"
|
|
@@ -496,42 +376,18 @@
|
|
|
496
376
|
"name": "gog_slides_create",
|
|
497
377
|
"description": "Create a new Google Slides presentation"
|
|
498
378
|
},
|
|
499
|
-
{
|
|
500
|
-
"name": "gog_slides_create_from_markdown",
|
|
501
|
-
"description": "Create a new Google Slides presentation from markdown content"
|
|
502
|
-
},
|
|
503
|
-
{
|
|
504
|
-
"name": "gog_slides_create_from_template",
|
|
505
|
-
"description": "Create a new Google Slides presentation from a template with placeholder replacements"
|
|
506
|
-
},
|
|
507
379
|
{
|
|
508
380
|
"name": "gog_slides_copy",
|
|
509
381
|
"description": "Copy a Google Slides presentation"
|
|
510
382
|
},
|
|
511
|
-
{
|
|
512
|
-
"name": "gog_slides_add_slide",
|
|
513
|
-
"description": "Add a slide to a presentation from a local image"
|
|
514
|
-
},
|
|
515
383
|
{
|
|
516
384
|
"name": "gog_slides_list_slides",
|
|
517
385
|
"description": "List slides in a presentation"
|
|
518
386
|
},
|
|
519
|
-
{
|
|
520
|
-
"name": "gog_slides_delete_slide",
|
|
521
|
-
"description": "Delete a slide from a presentation"
|
|
522
|
-
},
|
|
523
387
|
{
|
|
524
388
|
"name": "gog_slides_read_slide",
|
|
525
389
|
"description": "Read the content of a slide"
|
|
526
390
|
},
|
|
527
|
-
{
|
|
528
|
-
"name": "gog_slides_update_notes",
|
|
529
|
-
"description": "Update speaker notes on a slide"
|
|
530
|
-
},
|
|
531
|
-
{
|
|
532
|
-
"name": "gog_slides_replace_slide",
|
|
533
|
-
"description": "Replace the image content of an existing slide"
|
|
534
|
-
},
|
|
535
391
|
{
|
|
536
392
|
"name": "gog_slides_run",
|
|
537
393
|
"description": "Run any gog slides subcommand (escape hatch)"
|
package/package.json
CHANGED
package/server.json
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
"source": "github",
|
|
8
8
|
"subfolder": "packages/gogcli-mcp"
|
|
9
9
|
},
|
|
10
|
-
"version": "2.0.
|
|
10
|
+
"version": "2.0.7",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"identifier": "gogcli-mcp",
|
|
15
|
-
"version": "2.0.
|
|
15
|
+
"version": "2.0.7",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
18
18
|
},
|
package/src/runner.ts
CHANGED
|
@@ -16,6 +16,16 @@ export interface RunOptions {
|
|
|
16
16
|
|
|
17
17
|
const TIMEOUT_MS = 30_000;
|
|
18
18
|
|
|
19
|
+
// Treat unresolved .mcpb placeholders ("${user_config.gog_path}") and empty
|
|
20
|
+
// strings the same as an unset env var. When an optional .mcpb user_config
|
|
21
|
+
// field is left blank, some clients pass the literal placeholder text through
|
|
22
|
+
// to the spawned server instead of substituting "" or omitting the key.
|
|
23
|
+
function envOrUndefined(key: string): string | undefined {
|
|
24
|
+
const value = process.env[key];
|
|
25
|
+
if (!value || value.startsWith('${')) return undefined;
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
|
|
19
29
|
function formatTimeout(ms: number): string {
|
|
20
30
|
const seconds = Math.round(ms / 1000);
|
|
21
31
|
if (seconds >= 60) {
|
|
@@ -28,7 +38,7 @@ function formatTimeout(ms: number): string {
|
|
|
28
38
|
export async function run(args: string[], options: RunOptions = {}): Promise<string> {
|
|
29
39
|
const { account, spawner = spawn as unknown as Spawner, interactive = false, timeout } = options;
|
|
30
40
|
|
|
31
|
-
const effectiveAccount = account ??
|
|
41
|
+
const effectiveAccount = account ?? envOrUndefined('GOG_ACCOUNT');
|
|
32
42
|
|
|
33
43
|
const fullArgs = ['--json', '--color=never'];
|
|
34
44
|
if (!interactive) {
|
|
@@ -45,7 +55,7 @@ export async function run(args: string[], options: RunOptions = {}): Promise<str
|
|
|
45
55
|
// Strip GOG_ACCESS_TOKEN so gogcli uses stored refresh tokens instead of
|
|
46
56
|
// a potentially stale direct access token passed through MCP env config.
|
|
47
57
|
const { GOG_ACCESS_TOKEN: _, ...cleanEnv } = process.env;
|
|
48
|
-
const child = spawner(
|
|
58
|
+
const child = spawner(envOrUndefined('GOG_PATH') ?? 'gog', fullArgs, { env: cleanEnv });
|
|
49
59
|
const stdoutChunks: Buffer[] = [];
|
|
50
60
|
const stderrChunks: Buffer[] = [];
|
|
51
61
|
let settled = false;
|
package/src/tools/calendar.ts
CHANGED
|
@@ -125,96 +125,4 @@ export function registerCalendarTools(server: McpServer): void {
|
|
|
125
125
|
}, async ({ subcommand, args, account }) => {
|
|
126
126
|
return runOrDiagnose(['calendar', subcommand, ...args], { account });
|
|
127
127
|
});
|
|
128
|
-
|
|
129
|
-
// ─── Meet API tools ────────────────────────────────────────────
|
|
130
|
-
// Folded into the calendar wrapper because Meet spaces are the
|
|
131
|
-
// conferencing surface attached to calendar events.
|
|
132
|
-
|
|
133
|
-
server.registerTool('gog_meet_create', {
|
|
134
|
-
description: 'Create a Google Meet space and return its meeting code.',
|
|
135
|
-
inputSchema: {
|
|
136
|
-
access: z.enum(['open', 'trusted', 'restricted']).optional().describe('Access type (default: trusted)'),
|
|
137
|
-
open: z.boolean().optional().describe('Open the meeting in a browser after creation'),
|
|
138
|
-
account: accountParam,
|
|
139
|
-
},
|
|
140
|
-
}, async ({ access, open, account }) => {
|
|
141
|
-
const args = ['meet', 'create'];
|
|
142
|
-
if (access) args.push(`--access=${access}`);
|
|
143
|
-
if (open) args.push('--open');
|
|
144
|
-
return runOrDiagnose(args, { account });
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
server.registerTool('gog_meet_get', {
|
|
148
|
-
description: 'Get a Google Meet space by its meeting code.',
|
|
149
|
-
annotations: { readOnlyHint: true },
|
|
150
|
-
inputSchema: {
|
|
151
|
-
meetingCode: z.string().describe('Meeting code (e.g. abc-defg-hij)'),
|
|
152
|
-
account: accountParam,
|
|
153
|
-
},
|
|
154
|
-
}, async ({ meetingCode, account }) => {
|
|
155
|
-
return runOrDiagnose(['meet', 'get', meetingCode], { account });
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
server.registerTool('gog_meet_update', {
|
|
159
|
-
description: 'Update a Google Meet space configuration.',
|
|
160
|
-
annotations: { destructiveHint: true },
|
|
161
|
-
inputSchema: {
|
|
162
|
-
meetingCode: z.string().describe('Meeting code'),
|
|
163
|
-
access: z.enum(['open', 'trusted', 'restricted']).optional().describe('Access type'),
|
|
164
|
-
account: accountParam,
|
|
165
|
-
},
|
|
166
|
-
}, async ({ meetingCode, access, account }) => {
|
|
167
|
-
const args = ['meet', 'update', meetingCode];
|
|
168
|
-
if (access) args.push(`--access=${access}`);
|
|
169
|
-
return runOrDiagnose(args, { account });
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
server.registerTool('gog_meet_end', {
|
|
173
|
-
description: 'End the active conference in a Google Meet space.',
|
|
174
|
-
annotations: { destructiveHint: true },
|
|
175
|
-
inputSchema: {
|
|
176
|
-
meetingCode: z.string().describe('Meeting code'),
|
|
177
|
-
account: accountParam,
|
|
178
|
-
},
|
|
179
|
-
}, async ({ meetingCode, account }) => {
|
|
180
|
-
return runOrDiagnose(['meet', 'end', meetingCode], { account });
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
server.registerTool('gog_meet_history', {
|
|
184
|
-
description: 'List past calls (conferences) in a Google Meet space.',
|
|
185
|
-
annotations: { readOnlyHint: true },
|
|
186
|
-
inputSchema: {
|
|
187
|
-
meetingCode: z.string().describe('Meeting code'),
|
|
188
|
-
max: z.number().optional().describe('Max results (default: 20)'),
|
|
189
|
-
page: z.string().optional().describe('Page token'),
|
|
190
|
-
all: z.boolean().optional().describe('Fetch all pages'),
|
|
191
|
-
account: accountParam,
|
|
192
|
-
},
|
|
193
|
-
}, async ({ meetingCode, max, page, all, account }) => {
|
|
194
|
-
const args = ['meet', 'history', meetingCode];
|
|
195
|
-
if (max !== undefined) args.push(`--max=${max}`);
|
|
196
|
-
if (page) args.push(`--page=${page}`);
|
|
197
|
-
if (all) args.push('--all');
|
|
198
|
-
return runOrDiagnose(args, { account });
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
server.registerTool('gog_meet_participants', {
|
|
202
|
-
description: 'List participants from the latest (or a specific) Meet call.',
|
|
203
|
-
annotations: { readOnlyHint: true },
|
|
204
|
-
inputSchema: {
|
|
205
|
-
meetingCode: z.string().describe('Meeting code'),
|
|
206
|
-
conference: z.string().optional().describe('Specific conference ID (default: most recent)'),
|
|
207
|
-
max: z.number().optional().describe('Max results (default: 50)'),
|
|
208
|
-
page: z.string().optional().describe('Page token'),
|
|
209
|
-
all: z.boolean().optional().describe('Fetch all pages'),
|
|
210
|
-
account: accountParam,
|
|
211
|
-
},
|
|
212
|
-
}, async ({ meetingCode, conference, max, page, all, account }) => {
|
|
213
|
-
const args = ['meet', 'participants', meetingCode];
|
|
214
|
-
if (conference) args.push(`--conference=${conference}`);
|
|
215
|
-
if (max !== undefined) args.push(`--max=${max}`);
|
|
216
|
-
if (page) args.push(`--page=${page}`);
|
|
217
|
-
if (all) args.push('--all');
|
|
218
|
-
return runOrDiagnose(args, { account });
|
|
219
|
-
});
|
|
220
128
|
}
|