gogcli-mcp-slides 2.25.0 → 2.26.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/README.md +4 -2
- package/SKILL.md +2 -0
- package/dist/index.js +104 -41
- package/manifest.json +9 -1
- package/mint.yaml +106 -0
- package/package.json +2 -2
- package/server.json +2 -2
- package/src/tools/slides-extra.ts +34 -0
- package/tests/tools/slides-extra.test.ts +28 -0
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"metadata": {
|
|
9
9
|
"description": "Extended Google Slides for Claude via gogcli — auth + full Slides support (create, edit, export, templates, markdown)",
|
|
10
|
-
"version": "2.
|
|
10
|
+
"version": "2.26.0"
|
|
11
11
|
},
|
|
12
12
|
"plugins": [
|
|
13
13
|
{
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"displayName": "gogcli (Slides)",
|
|
16
16
|
"source": "./",
|
|
17
17
|
"description": "Extended Google Slides for Claude via gogcli — auth + full Slides support (create, edit, export, templates, markdown)",
|
|
18
|
-
"version": "2.
|
|
18
|
+
"version": "2.26.0",
|
|
19
19
|
"author": {
|
|
20
20
|
"name": "Chris Hall"
|
|
21
21
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gogcli-mcp-slides",
|
|
3
3
|
"displayName": "gogcli (Slides)",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.26.0",
|
|
5
5
|
"description": "Extended Google Slides for Claude via gogcli — auth + full Slides support (create, edit, export, templates, markdown)",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Chris Hall",
|
package/README.md
CHANGED
|
@@ -44,9 +44,9 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
|
44
44
|
claude mcp add gogcli-slides -- gogcli-mcp-slides
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
## Slides Tools
|
|
47
|
+
## Slides Tools
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
The package registers **55** tools: 40 Slides authoring tools, 7 base Slides tools, and 8 auth tools. The table below covers the most-used; `manifest.json` lists every one.
|
|
50
50
|
|
|
51
51
|
| Tool | Description |
|
|
52
52
|
|------|-------------|
|
|
@@ -59,6 +59,8 @@ Plus 5 auth tools and 1 `gog_slides_run` escape hatch for a total of 18 tools.
|
|
|
59
59
|
| `gog_slides_add_slide` | Add a new slide from a local image |
|
|
60
60
|
| `gog_slides_list_slides` | List slides in a presentation |
|
|
61
61
|
| `gog_slides_delete_slide` | Delete a slide |
|
|
62
|
+
| `gog_slides_skip_slide` | Skip a slide when presenting (keeps it in the deck) |
|
|
63
|
+
| `gog_slides_unskip_slide` | Include a previously skipped slide again |
|
|
62
64
|
| `gog_slides_read_slide` | Read the content of a slide |
|
|
63
65
|
| `gog_slides_update_notes` | Update speaker notes on a slide |
|
|
64
66
|
| `gog_slides_replace_slide` | Replace the image content of an existing slide |
|
package/SKILL.md
CHANGED
|
@@ -43,6 +43,8 @@ Extended Google Slides MCP server via [gogcli](https://github.com/openclaw/gogcl
|
|
|
43
43
|
| `gog_slides_add_slide` | Add a slide from a local image |
|
|
44
44
|
| `gog_slides_list_slides` | List slides in a presentation |
|
|
45
45
|
| `gog_slides_delete_slide` | Delete a slide |
|
|
46
|
+
| `gog_slides_skip_slide` | Skip a slide when presenting (keeps it in the deck) |
|
|
47
|
+
| `gog_slides_unskip_slide` | Include a previously skipped slide again |
|
|
46
48
|
| `gog_slides_read_slide` | Read the content of a slide |
|
|
47
49
|
| `gog_slides_update_notes` | Update speaker notes |
|
|
48
50
|
| `gog_slides_replace_slide` | Replace the image on an existing slide |
|
package/dist/index.js
CHANGED
|
@@ -31000,9 +31000,82 @@ var StdioServerTransport = class {
|
|
|
31000
31000
|
}
|
|
31001
31001
|
};
|
|
31002
31002
|
|
|
31003
|
+
// ../../node_modules/@chrischall/mcp-utils/dist/errors/index.js
|
|
31004
|
+
var McpToolError = class extends Error {
|
|
31005
|
+
/** Actionable remediation text, when one applies. */
|
|
31006
|
+
hint;
|
|
31007
|
+
constructor(message, opts) {
|
|
31008
|
+
super(message, opts?.cause !== void 0 ? { cause: opts.cause } : void 0);
|
|
31009
|
+
this.name = "McpToolError";
|
|
31010
|
+
if (opts?.hint !== void 0)
|
|
31011
|
+
this.hint = opts.hint;
|
|
31012
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
31013
|
+
}
|
|
31014
|
+
};
|
|
31015
|
+
var BEARER_RE = /(bearer\s+)[A-Za-z0-9._~+/=-]{8,}/gi;
|
|
31016
|
+
var JWT_RE = /\b[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{8,}\b/g;
|
|
31017
|
+
var BASIC_AUTH_RE = /(authorization\s*:\s*basic\s+)[A-Za-z0-9+/=_-]{6,}/gi;
|
|
31018
|
+
var SET_COOKIE_RE = /(\bset-cookie\s*:\s*)([^=;,\s]+)=[^;,\s]*/gi;
|
|
31019
|
+
var COOKIE_HEADER_RE = /((?<!set-)\bcookie\s*:\s*)((?:[^=;,\s]+=[^;,\s]*)(?:;\s*[^=;,\s]+=[^;,\s]*)*)/gi;
|
|
31020
|
+
var API_KEY_RE = new RegExp([
|
|
31021
|
+
"sk-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])",
|
|
31022
|
+
// OpenAI / Anthropic (incl. sk-ant-…)
|
|
31023
|
+
"gh[pousr]_[A-Za-z0-9]{36,}\\b",
|
|
31024
|
+
// GitHub ghp_/gho_/ghu_/ghs_/ghr_
|
|
31025
|
+
"xox[baprs]-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])",
|
|
31026
|
+
// Slack
|
|
31027
|
+
"AIza[0-9A-Za-z_-]{35}(?![0-9A-Za-z_-])",
|
|
31028
|
+
// Google API key (39 chars total)
|
|
31029
|
+
"AKIA[0-9A-Z]{16}\\b",
|
|
31030
|
+
// AWS access key id (20 chars total)
|
|
31031
|
+
"whsec_[A-Za-z0-9]{16,}\\b"
|
|
31032
|
+
// webhook signing secret (Stripe-style)
|
|
31033
|
+
].map((p) => `\\b${p}`).join("|"), "g");
|
|
31034
|
+
var QUERY_SECRET_RE = /([?&](?:access_token|refresh_token|client_secret|api_?key|signature|token|key|sig)=)[^&#\s"'<>`]+/gi;
|
|
31035
|
+
var AWS_SIGV4_RE = /([?&]X-Amz-(?:Signature|Security-Token|Credential)=)[^&#\s"'<>`]+/gi;
|
|
31036
|
+
var JSON_SECRET_KEYS = "access_token|refresh_token|client_secret|api_?key|password|passwd|secret|token";
|
|
31037
|
+
var JSON_SECRET_DQ_RE = new RegExp(`("(?:${JSON_SECRET_KEYS})"\\s*:\\s*")[^"]*(")`, "gi");
|
|
31038
|
+
var JSON_SECRET_SQ_RE = new RegExp(`('(?:${JSON_SECRET_KEYS})'\\s*:\\s*')[^']*(')`, "gi");
|
|
31039
|
+
function redactSecrets(text) {
|
|
31040
|
+
return text.replace(BEARER_RE, "$1[REDACTED]").replace(BASIC_AUTH_RE, "$1[REDACTED]").replace(SET_COOKIE_RE, "$1$2=[REDACTED]").replace(COOKIE_HEADER_RE, (_m, prefix, pairs) => `${prefix}${pairs.replace(/=[^;,\s]*/g, "=[REDACTED]")}`).replace(API_KEY_RE, "[REDACTED]").replace(QUERY_SECRET_RE, "$1[REDACTED]").replace(AWS_SIGV4_RE, "$1[REDACTED]").replace(JSON_SECRET_DQ_RE, "$1[REDACTED]$2").replace(JSON_SECRET_SQ_RE, "$1[REDACTED]$2").replace(JWT_RE, "[REDACTED]");
|
|
31041
|
+
}
|
|
31042
|
+
|
|
31043
|
+
// ../../node_modules/@chrischall/mcp-utils/dist/response/index.js
|
|
31044
|
+
function rawTextResult(text) {
|
|
31045
|
+
return { content: [{ type: "text", text }] };
|
|
31046
|
+
}
|
|
31047
|
+
function errorResult(message) {
|
|
31048
|
+
return {
|
|
31049
|
+
content: [{ type: "text", text: redactSecrets(message) }],
|
|
31050
|
+
isError: true
|
|
31051
|
+
};
|
|
31052
|
+
}
|
|
31053
|
+
|
|
31003
31054
|
// ../../node_modules/@chrischall/mcp-utils/dist/server/index.js
|
|
31055
|
+
function hintResultOrRethrow(err) {
|
|
31056
|
+
if (err instanceof McpToolError && err.hint) {
|
|
31057
|
+
return errorResult(`${err.message}
|
|
31058
|
+
|
|
31059
|
+
Hint: ${err.hint}`);
|
|
31060
|
+
}
|
|
31061
|
+
throw err;
|
|
31062
|
+
}
|
|
31063
|
+
function surfaceToolHints(server) {
|
|
31064
|
+
const register = server.registerTool.bind(server);
|
|
31065
|
+
server.registerTool = (name, config2, cb) => register(name, config2, (...args) => {
|
|
31066
|
+
let result;
|
|
31067
|
+
try {
|
|
31068
|
+
result = cb(...args);
|
|
31069
|
+
} catch (err) {
|
|
31070
|
+
return hintResultOrRethrow(err);
|
|
31071
|
+
}
|
|
31072
|
+
return result instanceof Promise ? result.catch(hintResultOrRethrow) : result;
|
|
31073
|
+
});
|
|
31074
|
+
}
|
|
31004
31075
|
async function createMcpServer(opts) {
|
|
31005
31076
|
const server = new McpServer({ name: opts.name, version: opts.version });
|
|
31077
|
+
if (opts.surfaceHints !== false)
|
|
31078
|
+
surfaceToolHints(server);
|
|
31006
31079
|
if (opts.banner !== void 0) {
|
|
31007
31080
|
console.error(opts.banner);
|
|
31008
31081
|
}
|
|
@@ -31047,46 +31120,6 @@ async function runMcp(opts) {
|
|
|
31047
31120
|
return server;
|
|
31048
31121
|
}
|
|
31049
31122
|
|
|
31050
|
-
// ../../node_modules/@chrischall/mcp-utils/dist/errors/index.js
|
|
31051
|
-
var BEARER_RE = /(bearer\s+)[A-Za-z0-9._~+/=-]{8,}/gi;
|
|
31052
|
-
var JWT_RE = /\b[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{8,}\b/g;
|
|
31053
|
-
var BASIC_AUTH_RE = /(authorization\s*:\s*basic\s+)[A-Za-z0-9+/=_-]{6,}/gi;
|
|
31054
|
-
var SET_COOKIE_RE = /(\bset-cookie\s*:\s*)([^=;,\s]+)=[^;,\s]*/gi;
|
|
31055
|
-
var COOKIE_HEADER_RE = /((?<!set-)\bcookie\s*:\s*)((?:[^=;,\s]+=[^;,\s]*)(?:;\s*[^=;,\s]+=[^;,\s]*)*)/gi;
|
|
31056
|
-
var API_KEY_RE = new RegExp([
|
|
31057
|
-
"sk-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])",
|
|
31058
|
-
// OpenAI / Anthropic (incl. sk-ant-…)
|
|
31059
|
-
"gh[pousr]_[A-Za-z0-9]{36,}\\b",
|
|
31060
|
-
// GitHub ghp_/gho_/ghu_/ghs_/ghr_
|
|
31061
|
-
"xox[baprs]-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])",
|
|
31062
|
-
// Slack
|
|
31063
|
-
"AIza[0-9A-Za-z_-]{35}(?![0-9A-Za-z_-])",
|
|
31064
|
-
// Google API key (39 chars total)
|
|
31065
|
-
"AKIA[0-9A-Z]{16}\\b",
|
|
31066
|
-
// AWS access key id (20 chars total)
|
|
31067
|
-
"whsec_[A-Za-z0-9]{16,}\\b"
|
|
31068
|
-
// webhook signing secret (Stripe-style)
|
|
31069
|
-
].map((p) => `\\b${p}`).join("|"), "g");
|
|
31070
|
-
var QUERY_SECRET_RE = /([?&](?:access_token|refresh_token|client_secret|api_?key|signature|token|key|sig)=)[^&#\s"'<>`]+/gi;
|
|
31071
|
-
var AWS_SIGV4_RE = /([?&]X-Amz-(?:Signature|Security-Token|Credential)=)[^&#\s"'<>`]+/gi;
|
|
31072
|
-
var JSON_SECRET_KEYS = "access_token|refresh_token|client_secret|api_?key|password|passwd|secret|token";
|
|
31073
|
-
var JSON_SECRET_DQ_RE = new RegExp(`("(?:${JSON_SECRET_KEYS})"\\s*:\\s*")[^"]*(")`, "gi");
|
|
31074
|
-
var JSON_SECRET_SQ_RE = new RegExp(`('(?:${JSON_SECRET_KEYS})'\\s*:\\s*')[^']*(')`, "gi");
|
|
31075
|
-
function redactSecrets(text) {
|
|
31076
|
-
return text.replace(BEARER_RE, "$1[REDACTED]").replace(BASIC_AUTH_RE, "$1[REDACTED]").replace(SET_COOKIE_RE, "$1$2=[REDACTED]").replace(COOKIE_HEADER_RE, (_m, prefix, pairs) => `${prefix}${pairs.replace(/=[^;,\s]*/g, "=[REDACTED]")}`).replace(API_KEY_RE, "[REDACTED]").replace(QUERY_SECRET_RE, "$1[REDACTED]").replace(AWS_SIGV4_RE, "$1[REDACTED]").replace(JSON_SECRET_DQ_RE, "$1[REDACTED]$2").replace(JSON_SECRET_SQ_RE, "$1[REDACTED]$2").replace(JWT_RE, "[REDACTED]");
|
|
31077
|
-
}
|
|
31078
|
-
|
|
31079
|
-
// ../../node_modules/@chrischall/mcp-utils/dist/response/index.js
|
|
31080
|
-
function rawTextResult(text) {
|
|
31081
|
-
return { content: [{ type: "text", text }] };
|
|
31082
|
-
}
|
|
31083
|
-
function errorResult(message) {
|
|
31084
|
-
return {
|
|
31085
|
-
content: [{ type: "text", text: redactSecrets(message) }],
|
|
31086
|
-
isError: true
|
|
31087
|
-
};
|
|
31088
|
-
}
|
|
31089
|
-
|
|
31090
31123
|
// ../../node_modules/@chrischall/mcp-utils/dist/config/index.js
|
|
31091
31124
|
var PLACEHOLDER_RE = /^\$\{[^}]*\}$/;
|
|
31092
31125
|
function readEnvVar(key, opts = {}) {
|
|
@@ -31886,6 +31919,16 @@ function authToolsFor(defaultServices) {
|
|
|
31886
31919
|
return (server) => registerAuthToolsWith(server, defaultServices);
|
|
31887
31920
|
}
|
|
31888
31921
|
|
|
31922
|
+
// ../gogcli-mcp/src/tools/calendar.ts
|
|
31923
|
+
var reminderParams = {
|
|
31924
|
+
reminders: external_exports.array(external_exports.string()).max(5).optional().describe(
|
|
31925
|
+
`Reminders as method:duration, e.g. ["popup:30m", "email:1d"]. Method is popup or email; duration accepts m/h/d (max 40320 minutes = 4 weeks). Google allows at most 5. These REPLACE the event's reminders \u2014 on update, pass an EMPTY array to drop custom reminders and go back to the calendar's defaults. Cannot be combined with noReminders.`
|
|
31926
|
+
),
|
|
31927
|
+
noReminders: external_exports.boolean().optional().describe(
|
|
31928
|
+
"Give the event no reminders at all, overriding the calendar's defaults. Different from an empty reminders array, which RESTORES those defaults. Cannot be combined with reminders."
|
|
31929
|
+
)
|
|
31930
|
+
};
|
|
31931
|
+
|
|
31889
31932
|
// ../gogcli-mcp/src/attachments.ts
|
|
31890
31933
|
var MAX_INLINE_ATTACHMENT_BYTES = 8 * 1024 * 1024;
|
|
31891
31934
|
var RUNNER_MAX_BODY_BYTES = 32 * 1024 * 1024;
|
|
@@ -31999,7 +32042,7 @@ function registerSlidesTools(server) {
|
|
|
31999
32042
|
}
|
|
32000
32043
|
|
|
32001
32044
|
// ../gogcli-mcp/src/server.ts
|
|
32002
|
-
var VERSION = true ? "2.
|
|
32045
|
+
var VERSION = true ? "2.26.0" : "0.0.0";
|
|
32003
32046
|
|
|
32004
32047
|
// ../gogcli-mcp/src/auth-log.ts
|
|
32005
32048
|
var FAILURES = /* @__PURE__ */ new Set([
|
|
@@ -32581,6 +32624,26 @@ function registerExtraSlidesTools(server) {
|
|
|
32581
32624
|
}, async ({ presentationId, slideId, account }) => {
|
|
32582
32625
|
return runOrDiagnose(["slides", "delete-slide", presentationId, slideId, "--force"], { account });
|
|
32583
32626
|
});
|
|
32627
|
+
server.registerTool("gog_slides_skip_slide", {
|
|
32628
|
+
description: "Skip a slide during presentation \u2014 it stays in the deck at its current position but is not shown when presenting (and is left out of a PDF export). Use this instead of gog_slides_delete_slide when a slide should be omitted from a talk without losing it. Reverse with gog_slides_unskip_slide; gog_slides_list_slides reports which slides are skipped.",
|
|
32629
|
+
inputSchema: {
|
|
32630
|
+
presentationId: external_exports.string().describe("Presentation ID"),
|
|
32631
|
+
slideId: external_exports.string().describe("Slide ID to skip (from gog_slides_list_slides)"),
|
|
32632
|
+
account: accountParam
|
|
32633
|
+
}
|
|
32634
|
+
}, async ({ presentationId, slideId, account }) => {
|
|
32635
|
+
return runOrDiagnose(["slides", "skip-slide", presentationId, slideId], { account });
|
|
32636
|
+
});
|
|
32637
|
+
server.registerTool("gog_slides_unskip_slide", {
|
|
32638
|
+
description: "Include a previously skipped slide again when the deck is presented. Safe to call on a slide that was never skipped.",
|
|
32639
|
+
inputSchema: {
|
|
32640
|
+
presentationId: external_exports.string().describe("Presentation ID"),
|
|
32641
|
+
slideId: external_exports.string().describe("Slide ID to unskip (from gog_slides_list_slides)"),
|
|
32642
|
+
account: accountParam
|
|
32643
|
+
}
|
|
32644
|
+
}, async ({ presentationId, slideId, account }) => {
|
|
32645
|
+
return runOrDiagnose(["slides", "unskip-slide", presentationId, slideId], { account });
|
|
32646
|
+
});
|
|
32584
32647
|
server.registerTool("gog_slides_update_notes", {
|
|
32585
32648
|
description: "Update the speaker notes on a slide (inline text or from a file).",
|
|
32586
32649
|
annotations: { destructiveHint: true },
|
package/manifest.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"manifest_version": "0.3",
|
|
4
4
|
"name": "gogcli-mcp-slides",
|
|
5
5
|
"display_name": "gogcli (Slides)",
|
|
6
|
-
"version": "2.
|
|
6
|
+
"version": "2.26.0",
|
|
7
7
|
"description": "Extended Google Slides for Claude via gogcli — auth + full Slides support (create, edit, export, templates, markdown)",
|
|
8
8
|
"author": {
|
|
9
9
|
"name": "Chris Hall",
|
|
@@ -129,6 +129,14 @@
|
|
|
129
129
|
"name": "gog_slides_delete_slide",
|
|
130
130
|
"description": "Delete a slide"
|
|
131
131
|
},
|
|
132
|
+
{
|
|
133
|
+
"name": "gog_slides_skip_slide",
|
|
134
|
+
"description": "Skip a slide during presentation without removing it from the deck"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"name": "gog_slides_unskip_slide",
|
|
138
|
+
"description": "Include a previously skipped slide again when presenting"
|
|
139
|
+
},
|
|
132
140
|
{
|
|
133
141
|
"name": "gog_slides_read_slide",
|
|
134
142
|
"description": "Read the content of a slide"
|
package/mint.yaml
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
name: Google Slides (gogcli)
|
|
3
|
+
slug: gogcli-mcp-slides
|
|
4
|
+
summary: >-
|
|
5
|
+
Extended Google Slides MCP server via gogcli — auth + full Slides support
|
|
6
|
+
command:
|
|
7
|
+
# This package publishes a single bin; naming it keeps the install
|
|
8
|
+
# unambiguous alongside its eight sibling packages.
|
|
9
|
+
bin: gogcli-mcp-slides
|
|
10
|
+
env:
|
|
11
|
+
- name: GOG_CLIENT_ID
|
|
12
|
+
required: false
|
|
13
|
+
help: >-
|
|
14
|
+
Google OAuth client id. NOTE: on the local-spawn path the child `gog`
|
|
15
|
+
receives a sanitized env — runner.ts drops GOG_ACCESS_TOKEN and every
|
|
16
|
+
*_TOKEN / *_SECRET / *_API_KEY / *_PRIVATE_KEY variable — so the CLI
|
|
17
|
+
authenticates from its own stored credentials under $HOME (see
|
|
18
|
+
state.dataDir), not from these variables being passed through.
|
|
19
|
+
- name: GOG_CLIENT_SECRET
|
|
20
|
+
secret: true
|
|
21
|
+
required: false
|
|
22
|
+
help: >-
|
|
23
|
+
Google OAuth client secret. Stripped from the spawned CLI's environment
|
|
24
|
+
by runner.ts's *_SECRET rule — see GOG_CLIENT_ID.
|
|
25
|
+
- name: GOG_REFRESH_TOKEN
|
|
26
|
+
secret: true
|
|
27
|
+
required: false
|
|
28
|
+
help: >-
|
|
29
|
+
Google OAuth refresh token. Stripped from the spawned CLI's environment
|
|
30
|
+
by runner.ts's *_TOKEN rule — see GOG_CLIENT_ID. A hosted deployment must
|
|
31
|
+
therefore carry gog's authorised-account state in its persisted data dir,
|
|
32
|
+
or drive a remote runner via GOG_RUNNER_URL.
|
|
33
|
+
- name: GOG_ACCESS_TOKEN
|
|
34
|
+
secret: true
|
|
35
|
+
required: false
|
|
36
|
+
help: >-
|
|
37
|
+
Deliberately removed from the spawned CLI's environment by runner.ts, so
|
|
38
|
+
that a stale directly-passed token cannot shadow gog's stored refresh
|
|
39
|
+
credential. Leave unset.
|
|
40
|
+
- name: GOG_ACCOUNT
|
|
41
|
+
required: false
|
|
42
|
+
help: >-
|
|
43
|
+
Which configured Google account to act as, when more than one is
|
|
44
|
+
authorised. Defaults to the single/most recent account.
|
|
45
|
+
- name: GOG_READONLY
|
|
46
|
+
required: false
|
|
47
|
+
help: >-
|
|
48
|
+
Set to 1 to refuse every mutating operation. Recommended when the
|
|
49
|
+
connector is shared or you only need reads.
|
|
50
|
+
- name: GOG_PATH
|
|
51
|
+
required: false
|
|
52
|
+
help: >-
|
|
53
|
+
Path to the `gog` binary. Leave unset when the dependency below supplies
|
|
54
|
+
it; set it only to point at a binary you manage yourself.
|
|
55
|
+
- name: GOG_RUNNER_URL
|
|
56
|
+
required: false
|
|
57
|
+
help: >-
|
|
58
|
+
URL of a remote gog runner to execute against instead of spawning the
|
|
59
|
+
local binary. If you set this, add its host to egress.allow.
|
|
60
|
+
- name: GOG_RUNNER_KEY
|
|
61
|
+
secret: true
|
|
62
|
+
required: false
|
|
63
|
+
help: >-
|
|
64
|
+
Shared key authenticating calls to GOG_RUNNER_URL. Required whenever that
|
|
65
|
+
is set.
|
|
66
|
+
- name: GOG_TIMEZONE
|
|
67
|
+
required: false
|
|
68
|
+
help: >-
|
|
69
|
+
The IANA zone gog itself formats its naive timestamps in. The wrapper
|
|
70
|
+
reads it (naiveSourceTimeZone) to re-attach the correct offset, so it
|
|
71
|
+
should match gog's own configuration. Falls back to DISPLAY_TZ, then to
|
|
72
|
+
America/New_York.
|
|
73
|
+
- name: DISPLAY_TZ
|
|
74
|
+
required: false
|
|
75
|
+
help: >-
|
|
76
|
+
The IANA zone every rendered *Display field uses (displayTimeZone,
|
|
77
|
+
default America/New_York). It does not read GOG_TIMEZONE — the fallback
|
|
78
|
+
runs the other way, so this is also what GOG_TIMEZONE falls back to. An
|
|
79
|
+
invalid value degrades to the default rather than throwing.
|
|
80
|
+
dependencies:
|
|
81
|
+
# Every tool shells out to the `gog` CLI; without it the server starts and
|
|
82
|
+
# then fails on the first call. This tag must track
|
|
83
|
+
# packages/gogcli-mcp/src/runner.ts's MIN_GOG_VERSION (the floor the tools
|
|
84
|
+
# assume) and the fly-gog-runner/Dockerfile GOG_VERSION build arg. See
|
|
85
|
+
# CLAUDE.md "Required gog version" — bumping the floor means bumping these
|
|
86
|
+
# nine pins too.
|
|
87
|
+
- kind: github-release
|
|
88
|
+
repo: openclaw/gogcli
|
|
89
|
+
tag: v0.38.1
|
|
90
|
+
asset: "gogcli_*_linux_amd64.tar.gz"
|
|
91
|
+
bin: [gog]
|
|
92
|
+
state:
|
|
93
|
+
dataDir: true
|
|
94
|
+
reason: >-
|
|
95
|
+
`gog` keeps its authorised-account state and token cache under $HOME.
|
|
96
|
+
Without a persistent data dir every cold start has no account configured and
|
|
97
|
+
every tool call fails until the credentials are re-supplied.
|
|
98
|
+
egress:
|
|
99
|
+
allow:
|
|
100
|
+
# Google OAuth token exchange and the Google REST APIs the CLI calls.
|
|
101
|
+
- oauth2.googleapis.com
|
|
102
|
+
- www.googleapis.com
|
|
103
|
+
- googleapis.com
|
|
104
|
+
#
|
|
105
|
+
# NOTE: if you set GOG_RUNNER_URL to run against a remote gog runner, add
|
|
106
|
+
# that host here too — it is supplied at runtime and cannot be declared.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gogcli-mcp-slides",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.26.0",
|
|
4
4
|
"mcpName": "io.github.chrischall/gogcli-mcp-slides",
|
|
5
5
|
"description": "Extended Google Slides MCP server via gogcli — auth + full Slides support",
|
|
6
6
|
"author": "Claude Code (AI) <https://www.anthropic.com/claude>",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"test:coverage": "vitest run --coverage"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@chrischall/mcp-utils": "^0.
|
|
27
|
+
"@chrischall/mcp-utils": "^0.15.0",
|
|
28
28
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
29
29
|
"zod": "^4.4.3"
|
|
30
30
|
},
|
package/server.json
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
"source": "github",
|
|
8
8
|
"subfolder": "packages/gogcli-mcp-slides"
|
|
9
9
|
},
|
|
10
|
-
"version": "2.
|
|
10
|
+
"version": "2.26.0",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"identifier": "gogcli-mcp-slides",
|
|
15
|
-
"version": "2.
|
|
15
|
+
"version": "2.26.0",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
18
18
|
},
|
|
@@ -125,6 +125,40 @@ export function registerExtraSlidesTools(server: McpServer): void {
|
|
|
125
125
|
return runOrDiagnose(['slides', 'delete-slide', presentationId, slideId, '--force'], { account });
|
|
126
126
|
});
|
|
127
127
|
|
|
128
|
+
// Slide visibility (gog >= 0.38.0, openclaw/gogcli#1009). Skipping is NOT
|
|
129
|
+
// deleting and not hiding: the slide keeps its position, content and ID, and
|
|
130
|
+
// still appears in the editor and in gog_slides_list_slides (which reports
|
|
131
|
+
// isSkipped in JSON) — it is only left out when the deck is presented or
|
|
132
|
+
// exported to PDF. Fully reversible, so neither tool is annotated
|
|
133
|
+
// destructive: skip is the safe alternative to gog_slides_delete_slide when
|
|
134
|
+
// the ask is "leave this out of the talk". Neither is confirmation-gated in
|
|
135
|
+
// gog, so neither takes --force (verified live against gog 0.38.0).
|
|
136
|
+
server.registerTool('gog_slides_skip_slide', {
|
|
137
|
+
description:
|
|
138
|
+
'Skip a slide during presentation — it stays in the deck at its current position but is not shown when presenting '
|
|
139
|
+
+ '(and is left out of a PDF export). Use this instead of gog_slides_delete_slide when a slide should be omitted from '
|
|
140
|
+
+ 'a talk without losing it. Reverse with gog_slides_unskip_slide; gog_slides_list_slides reports which slides are skipped.',
|
|
141
|
+
inputSchema: {
|
|
142
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
143
|
+
slideId: z.string().describe('Slide ID to skip (from gog_slides_list_slides)'),
|
|
144
|
+
account: accountParam,
|
|
145
|
+
},
|
|
146
|
+
}, async ({ presentationId, slideId, account }) => {
|
|
147
|
+
return runOrDiagnose(['slides', 'skip-slide', presentationId, slideId], { account });
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
server.registerTool('gog_slides_unskip_slide', {
|
|
151
|
+
description:
|
|
152
|
+
'Include a previously skipped slide again when the deck is presented. Safe to call on a slide that was never skipped.',
|
|
153
|
+
inputSchema: {
|
|
154
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
155
|
+
slideId: z.string().describe('Slide ID to unskip (from gog_slides_list_slides)'),
|
|
156
|
+
account: accountParam,
|
|
157
|
+
},
|
|
158
|
+
}, async ({ presentationId, slideId, account }) => {
|
|
159
|
+
return runOrDiagnose(['slides', 'unskip-slide', presentationId, slideId], { account });
|
|
160
|
+
});
|
|
161
|
+
|
|
128
162
|
server.registerTool('gog_slides_update_notes', {
|
|
129
163
|
description: 'Update the speaker notes on a slide (inline text or from a file).',
|
|
130
164
|
annotations: { destructiveHint: true },
|
|
@@ -759,3 +759,31 @@ describe('gog_slides_table_unmerge', () => {
|
|
|
759
759
|
['slides', 'table', 'unmerge', 'p1', 't1', '--row=1', '--col=1'], { account: undefined });
|
|
760
760
|
});
|
|
761
761
|
});
|
|
762
|
+
|
|
763
|
+
describe('gog_slides_skip_slide', () => {
|
|
764
|
+
it('calls runOrDiagnose with presentationId and slideId', async () => {
|
|
765
|
+
await harness.callTool('gog_slides_skip_slide', { presentationId: 'p1', slideId: 's1' });
|
|
766
|
+
expect(lib.runOrDiagnose).toHaveBeenCalledWith(
|
|
767
|
+
['slides', 'skip-slide', 'p1', 's1'],
|
|
768
|
+
{ account: undefined },
|
|
769
|
+
);
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
it('passes the account through', async () => {
|
|
773
|
+
await harness.callTool('gog_slides_skip_slide', { presentationId: 'p1', slideId: 's1', account: 'me@x.com' });
|
|
774
|
+
expect(lib.runOrDiagnose).toHaveBeenCalledWith(
|
|
775
|
+
['slides', 'skip-slide', 'p1', 's1'],
|
|
776
|
+
{ account: 'me@x.com' },
|
|
777
|
+
);
|
|
778
|
+
});
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
describe('gog_slides_unskip_slide', () => {
|
|
782
|
+
it('calls runOrDiagnose with presentationId and slideId', async () => {
|
|
783
|
+
await harness.callTool('gog_slides_unskip_slide', { presentationId: 'p1', slideId: 's1' });
|
|
784
|
+
expect(lib.runOrDiagnose).toHaveBeenCalledWith(
|
|
785
|
+
['slides', 'unskip-slide', 'p1', 's1'],
|
|
786
|
+
{ account: undefined },
|
|
787
|
+
);
|
|
788
|
+
});
|
|
789
|
+
});
|