gogcli-mcp-slides 4.6.3 → 4.7.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.
@@ -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": "4.6.3"
10
+ "version": "4.7.1"
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": "4.6.3",
18
+ "version": "4.7.1",
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": "4.6.3",
4
+ "version": "4.7.1",
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",
@@ -21,6 +21,6 @@
21
21
  "pdf",
22
22
  "pptx"
23
23
  ],
24
- "skills": "./SKILL.md",
25
- "mcp": "./.mcp.json"
24
+ "skills": ".",
25
+ "mcpServers": "./.mcp.json"
26
26
  }
package/dist/index.js CHANGED
@@ -34479,11 +34479,19 @@ var DEFAULT_MAX_REQUEST_BODY_SIZE = 4 * 1024 * 1024;
34479
34479
  var McpToolError = class extends Error {
34480
34480
  /** Actionable remediation text, when one applies. */
34481
34481
  hint;
34482
+ /** The upstream HTTP status this failure came from, when known. */
34483
+ status;
34484
+ /** What kind of failure this is, when the thrower knows. */
34485
+ kind;
34482
34486
  constructor(message, opts) {
34483
34487
  super(message, opts?.cause !== void 0 ? { cause: opts.cause } : void 0);
34484
34488
  this.name = "McpToolError";
34485
34489
  if (opts?.hint !== void 0)
34486
34490
  this.hint = opts.hint;
34491
+ if (opts?.status !== void 0)
34492
+ this.status = opts.status;
34493
+ if (opts?.kind !== void 0)
34494
+ this.kind = opts.kind;
34487
34495
  Object.setPrototypeOf(this, new.target.prototype);
34488
34496
  }
34489
34497
  };
@@ -34508,7 +34516,7 @@ var API_KEY_RE = new RegExp([
34508
34516
  // webhook signing secret (Stripe-style)
34509
34517
  ].map((p) => `\\b${p}`).join("|"), "g");
34510
34518
  var GOOGLE_OAUTH_TOKEN_RE = /(?<![A-Za-z0-9+/])(?:ya29\.|1\/\/)[A-Za-z0-9._-]{8,}/g;
34511
- var QUERY_SECRET_RE = new RegExp(`([?&](?:(?:access|refresh|id|auth|session|csrf|xsrf)[_-]?token|client[_-]?secret|api[_-]?secret|api[_-]?key|password|passwd|signature|token|key|sig|(?:php|j)?sess(?:ion)?[_-]?id|sid|x[-_]${HEADER_NAME_RUN}?(?:api[-_]?key|token|secret|auth)${HEADER_NAME_RUN})=)[^&#\\s"'<>\`]+`, "gi");
34519
+ var QUERY_SECRET_RE = new RegExp(`([?&](?:(?:access|refresh|id|auth|session|csrf|xsrf)[_-]?token|client[_-]?secret|api[_-]?secret|api[_-]?key|password|passwd|signature|token|key|sig|(?:code[_-]?)?verifier|(?:php|j)?sess(?:ion)?[_-]?id|sid|x[-_]${HEADER_NAME_RUN}?(?:api[-_]?key|token|secret|auth)${HEADER_NAME_RUN})=)[^&#\\s"'<>\`]+`, "gi");
34512
34520
  var OAUTH_CODE_RE = /([?&]code=)(?=[^&#\s"'<>`]{16,})[^&#\s"'<>`]+/gi;
34513
34521
  var FORM_PASSWORD_RE = /((?:^|[\s,;:"'(\[{])(?:password|passwd)=)[^&#\s"'<>`]+/gim;
34514
34522
  var HEADER_SECRET_RE = new RegExp(`(\\b(?:x[-_]${HEADER_NAME_RUN}?(?:api[-_]?key|token|secret|auth)${HEADER_NAME_RUN}|api[-_]?key)\\s*:\\s*)[^\\s,;"'<>\`]+`, "gi");
@@ -34519,6 +34527,8 @@ var JSON_SECRET_KEYS = [
34519
34527
  "api[_-]?secret",
34520
34528
  "(?:x[_-])?api[_-]?key",
34521
34529
  "private[_-]?key",
34530
+ "code[_-]?verifier",
34531
+ // PKCE; a bare `verifier` key is too generic for JSON
34522
34532
  `x[_-]${HEADER_NAME_RUN}?(?:api[_-]?key|token|secret|auth)${HEADER_NAME_RUN}`,
34523
34533
  // bounded like HEADER_SECRET_RE
34524
34534
  "(?:proxy-)?authorization",
@@ -34549,6 +34559,11 @@ function redactSecrets(text) {
34549
34559
  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(GOOGLE_OAUTH_TOKEN_RE, "[REDACTED]").replace(HEADER_SECRET_RE, "$1[REDACTED]").replace(QUERY_SECRET_RE, "$1[REDACTED]").replace(OAUTH_CODE_RE, "$1[REDACTED]").replace(FORM_PASSWORD_RE, "$1[REDACTED]").replace(AWS_SIGV4_RE, "$1[REDACTED]").replace(JSON_COOKIE_DQ_RE, redactJsonCookie('"')).replace(JSON_COOKIE_SQ_RE, redactJsonCookie("'")).replace(JSON_SECRET_DQ_RE, "$1[REDACTED]$2").replace(JSON_SECRET_SQ_RE, "$1[REDACTED]$2").replace(JSON_SECRET_NUM_RE, "$1[REDACTED]").replace(JWT_RE, "[REDACTED]");
34550
34560
  }
34551
34561
  var ERROR_REDACTION_INPUT_MAX = 64 * 1024;
34562
+ function messageOf(err) {
34563
+ if (err instanceof Error)
34564
+ return err.message;
34565
+ return String(err);
34566
+ }
34552
34567
 
34553
34568
  // ../../node_modules/@chrischall/mcp-utils/dist/response/view.js
34554
34569
  function minifiedResult(data) {
@@ -34651,7 +34666,7 @@ function readEnvVar(key, opts = {}) {
34651
34666
  if (typeof raw === "string") {
34652
34667
  const trimmed = raw.trim();
34653
34668
  if (trimmed.length > 0 && trimmed !== "undefined" && trimmed !== "null" && !PLACEHOLDER_RE.test(trimmed)) {
34654
- return trimmed;
34669
+ return opts.trim === false ? raw : trimmed;
34655
34670
  }
34656
34671
  }
34657
34672
  return opts.default;
@@ -34689,12 +34704,14 @@ var SERVER_PROTOCOL_VERSIONS = Object.freeze([
34689
34704
  ...SUPPORTED_PROTOCOL_VERSIONS
34690
34705
  ]);
34691
34706
  function hintResultOrRethrow(err) {
34707
+ if (err instanceof ProtocolError && err.code === ProtocolErrorCode.UrlElicitationRequired)
34708
+ throw err;
34692
34709
  if (err instanceof McpToolError && err.hint) {
34693
34710
  return errorResult(`${err.message}
34694
34711
 
34695
34712
  Hint: ${err.hint}`);
34696
34713
  }
34697
- throw err;
34714
+ return errorResult(messageOf(err));
34698
34715
  }
34699
34716
  function mcpRequestFrom(args) {
34700
34717
  const ctx = args.at(-1);
@@ -34928,7 +34945,7 @@ var PositiveInt = external_exports.number().int().positive();
34928
34945
  var NonNegInt = external_exports.number().int().nonnegative();
34929
34946
  var NonEmptyString = external_exports.string().min(1);
34930
34947
  var IsoDate = external_exports.iso.date();
34931
- var IsoTime = external_exports.string().regex(/^([01]?\d|2[0-3]):[0-5]\d$/, "must be HH:MM (24h), e.g. 19:30");
34948
+ var IsoTime = external_exports.string().regex(/^([01]?\d|2[0-3]):[0-5]\d$/, "must be HH:MM (24h), e.g. 19:30").overwrite((v) => v.padStart(5, "0"));
34932
34949
  var NumericIdString = external_exports.string().regex(/^\d+$/, "must be a numeric id (digits only)").describe("A numeric id string (digits only), safe to interpolate into a URL path.");
34933
34950
  var SafePathSegment = external_exports.string().min(1).regex(/^[^/?#\s]+$/, 'must not contain "/", "?", "#", or whitespace').refine((v) => !v.includes(".."), 'must not contain ".."').describe('A single URL path segment, safe to interpolate: no "/", "..", "?", "#", or whitespace.');
34934
34951
  var schemaOrigin = external_exports.string().optional().describe("Portal origin (e.g. https://<vendor>.example.co) selecting which active session to use. Optional when only one session is active.");
@@ -35619,7 +35636,7 @@ function registerRunTool(server, options) {
35619
35636
  }
35620
35637
  server.registerTool(`gog_${service}_run`, {
35621
35638
  description,
35622
- annotations: { destructiveHint: true },
35639
+ annotations: { destructiveHint: true, openWorldHint: true },
35623
35640
  inputSchema: external_exports.object(inputSchema)
35624
35641
  }, async (rawArgs) => {
35625
35642
  const { subcommand, args, account } = rawArgs;
@@ -35765,13 +35782,13 @@ function formatAuthHealth(raw, now) {
35765
35782
  var spent = createSpentTokenStore();
35766
35783
 
35767
35784
  // ../gogcli-mcp/src/tools/auth.ts
35768
- var AUTH_RUN_SUBCOMMANDS = ["list", "status", "services", "remove", "alias"];
35785
+ var AUTH_RUN_SUBCOMMANDS = ["list", "status", "services", "alias"];
35769
35786
  function registerAuthToolsWith(server, defaultServices) {
35770
35787
  const servicesDescribe = `Services to authorize: "all" or comma-separated list (e.g. "sheets,gmail,calendar"). Default: "${defaultServices}". Prefer the narrowest set you need \u2014 requesting a service whose Google API is not enabled on the OAuth client's project makes Google reject the WHOLE request with invalid_scope.`;
35771
35788
  const extraScopesDescribe = "Additional raw OAuth scope URIs to request, comma-separated, on top of the ones `services` implies. Use for scopes no service covers \u2014 e.g. https://www.googleapis.com/auth/bigquery.readonly, required before gog_sheets_datasource_* can read BigQuery-backed Connected Sheets. Leave unset otherwise: an extra scope whose API is not enabled on the OAuth client project makes Google reject the WHOLE authorization with invalid_scope.";
35772
35789
  server.registerTool("gog_auth_list", {
35773
35790
  description: "List the Google accounts stored in gogcli, with their scopes. This reads local configuration only \u2014 it does not contact Google and does NOT tell you whether an account still works: a signed-out account whose refresh token expired or was revoked is listed here exactly like a healthy one, scopes and all. Use gog_auth_health to check whether an account can actually authenticate.",
35774
- annotations: { readOnlyHint: true },
35791
+ annotations: { readOnlyHint: true, openWorldHint: false },
35775
35792
  inputSchema: external_exports.object({})
35776
35793
  }, async () => {
35777
35794
  try {
@@ -35782,7 +35799,7 @@ function registerAuthToolsWith(server, defaultServices) {
35782
35799
  });
35783
35800
  server.registerTool("gog_auth_status", {
35784
35801
  description: "Show gogcli auth CONFIGURATION: keyring backend, credential files, and auth setup. Despite the name this is not a health check \u2014 it reads local setup and does not contact Google, so it says nothing about whether an account can still authenticate. Use gog_auth_health for that.",
35785
- annotations: { readOnlyHint: true },
35802
+ annotations: { readOnlyHint: true, openWorldHint: false },
35786
35803
  inputSchema: external_exports.object({})
35787
35804
  }, async () => {
35788
35805
  try {
@@ -35793,7 +35810,7 @@ function registerAuthToolsWith(server, defaultServices) {
35793
35810
  });
35794
35811
  server.registerTool("gog_auth_health", {
35795
35812
  description: `Check the LIVE health of each stored Google account. Unlike gog_auth_status (which only reports keyring/config setup), this performs a real token refresh against Google, so it detects expired or revoked (invalid_grant) refresh tokens \u2014 the account-wide sign-out that blocks every service. Reports per account: whether the token is currently valid, the mapped cause when it is not, how long ago it was authorized, and a warning as it approaches the 7-day refresh-token limit that applies to OAuth apps whose consent screen is still in "Testing" mode. Run it proactively to re-authorize on your own schedule instead of mid-task. On a hosted deployment this is the ONLY check that measures Google: a connector showing "connected" or "refreshed" has verified the client's connection to the MCP host, and nothing else \u2014 the Google credential lives in gog's keyring on that host and can be dead while the connection looks perfectly healthy.`,
35796
- annotations: { readOnlyHint: true },
35813
+ annotations: { readOnlyHint: true, openWorldHint: true },
35797
35814
  inputSchema: external_exports.object({})
35798
35815
  }, async () => {
35799
35816
  try {
@@ -35804,7 +35821,7 @@ function registerAuthToolsWith(server, defaultServices) {
35804
35821
  });
35805
35822
  server.registerTool("gog_auth_services", {
35806
35823
  description: "List all Google services supported by gogcli and the OAuth scopes each requires.",
35807
- annotations: { readOnlyHint: true },
35824
+ annotations: { readOnlyHint: true, openWorldHint: false },
35808
35825
  inputSchema: external_exports.object({})
35809
35826
  }, async () => {
35810
35827
  try {
@@ -35815,7 +35832,7 @@ function registerAuthToolsWith(server, defaultServices) {
35815
35832
  });
35816
35833
  server.registerTool("gog_auth_add", {
35817
35834
  description: "Authorize a Google account via browser-based OAuth. Opens a browser window where the user must sign in and grant access. Blocks for up to 5 minutes waiting for the user to complete authorization. If the browser does not open automatically, a fallback URL is included in the response. Use gog_auth_list to check which accounts are already configured.",
35818
- annotations: { destructiveHint: true },
35835
+ annotations: { destructiveHint: true, openWorldHint: true },
35819
35836
  inputSchema: external_exports.object({
35820
35837
  email: external_exports.string().describe("Google account email to authorize"),
35821
35838
  services: external_exports.string().optional().default(defaultServices).describe(servicesDescribe),
@@ -35835,7 +35852,7 @@ function registerAuthToolsWith(server, defaultServices) {
35835
35852
  });
35836
35853
  server.registerTool("gog_auth_add_url", {
35837
35854
  description: "Begin REMOTE/headless Google authorization (step 1 of 2). Returns a sign-in URL to open in any browser \u2014 no local server or terminal on the gogcli host is needed, so this works on a hosted deployment where the interactive gog_auth_add cannot. Hand the URL to the user; after they sign in, the browser is redirected to a localhost URL that fails to load \u2014 that is expected. They copy that full redirected URL (from the address bar) and you pass it to gog_auth_add_complete. The link is valid for 10 minutes. If you pass a custom `services` here, pass the SAME value to gog_auth_add_complete or the second step will not match this one.",
35838
- annotations: { readOnlyHint: true },
35855
+ annotations: { readOnlyHint: true, openWorldHint: false },
35839
35856
  inputSchema: external_exports.object({
35840
35857
  email: external_exports.string().describe("Google account email to authorize"),
35841
35858
  services: external_exports.string().optional().default(defaultServices).describe(servicesDescribe),
@@ -35852,7 +35869,7 @@ function registerAuthToolsWith(server, defaultServices) {
35852
35869
  });
35853
35870
  server.registerTool("gog_auth_add_complete", {
35854
35871
  description: "Complete REMOTE/headless Google authorization (step 2 of 2). Takes the full redirected localhost URL the user copied after finishing gog_auth_add_url, exchanges it for a refresh token, and stores it. Use the SAME `services` value you passed to gog_auth_add_url. Must run within 10 minutes of step 1 and against the same gogcli host.",
35855
- annotations: { destructiveHint: true },
35872
+ annotations: { destructiveHint: true, openWorldHint: true },
35856
35873
  inputSchema: external_exports.object({
35857
35874
  email: external_exports.string().describe("Google account email being authorized (same as step 1)"),
35858
35875
  redirectUrl: external_exports.string().describe(
@@ -35888,7 +35905,7 @@ function registerAuthToolsWith(server, defaultServices) {
35888
35905
  });
35889
35906
  registerRunTool(server, {
35890
35907
  service: "auth",
35891
- examples: '"remove", "alias", "list"',
35908
+ examples: '"alias", "list", "status"',
35892
35909
  omitAccount: true,
35893
35910
  allowedSubcommands: AUTH_RUN_SUBCOMMANDS,
35894
35911
  note: "For browser-based authorization, use gog_auth_add instead."
@@ -35986,7 +36003,7 @@ function registerSlidesTools(server) {
35986
36003
  server.registerTool("gog_slides_export", {
35987
36004
  description: "Export a Google Slides presentation to a local file (pdf or pptx). The out path must be inside the server's GOG_FILE_ROOTS directories.",
35988
36005
  // Writes a file on the gog host and can overwrite one: not read-only.
35989
- annotations: { readOnlyHint: false, destructiveHint: true },
36006
+ annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
35990
36007
  inputSchema: external_exports.object({
35991
36008
  presentationId: external_exports.string().describe("Presentation ID"),
35992
36009
  out: external_exports.string().optional().describe("Output file path"),
@@ -36004,7 +36021,7 @@ function registerSlidesTools(server) {
36004
36021
  });
36005
36022
  server.registerTool("gog_slides_info", {
36006
36023
  description: "Get metadata for a Google Slides presentation (title, ID, slide count, etc.).",
36007
- annotations: { readOnlyHint: true },
36024
+ annotations: { readOnlyHint: true, openWorldHint: true },
36008
36025
  inputSchema: external_exports.object({
36009
36026
  presentationId: external_exports.string().describe("Presentation ID"),
36010
36027
  account: accountParam
@@ -36014,7 +36031,7 @@ function registerSlidesTools(server) {
36014
36031
  });
36015
36032
  server.registerTool("gog_slides_create", {
36016
36033
  description: "Create a new Google Slides presentation, optionally in a folder or copying from a template.",
36017
- annotations: { destructiveHint: true },
36034
+ annotations: { destructiveHint: true, openWorldHint: true },
36018
36035
  inputSchema: external_exports.object({
36019
36036
  title: external_exports.string().describe("Presentation title"),
36020
36037
  parent: external_exports.string().optional().describe("Destination folder ID"),
@@ -36029,7 +36046,7 @@ function registerSlidesTools(server) {
36029
36046
  });
36030
36047
  server.registerTool("gog_slides_copy", {
36031
36048
  description: "Copy a Google Slides presentation to a new presentation with the given title.",
36032
- annotations: { destructiveHint: true },
36049
+ annotations: { destructiveHint: true, openWorldHint: true },
36033
36050
  inputSchema: external_exports.object({
36034
36051
  presentationId: external_exports.string().describe("Presentation ID to copy"),
36035
36052
  title: external_exports.string().describe("Title for the new copy"),
@@ -36043,7 +36060,7 @@ function registerSlidesTools(server) {
36043
36060
  });
36044
36061
  server.registerTool("gog_slides_list_slides", {
36045
36062
  description: "List slides in a Google Slides presentation.",
36046
- annotations: { readOnlyHint: true },
36063
+ annotations: { readOnlyHint: true, openWorldHint: true },
36047
36064
  inputSchema: external_exports.object({
36048
36065
  presentationId: external_exports.string().describe("Presentation ID"),
36049
36066
  account: accountParam
@@ -36053,7 +36070,7 @@ function registerSlidesTools(server) {
36053
36070
  });
36054
36071
  server.registerTool("gog_slides_read_slide", {
36055
36072
  description: "Read the content of a slide (text, shapes, speaker notes). Set detail=true to also include normalized element geometry, styled text runs, paragraphs, table-cell content, and image source URLs.",
36056
- annotations: { readOnlyHint: true },
36073
+ annotations: { readOnlyHint: true, openWorldHint: true },
36057
36074
  inputSchema: external_exports.object({
36058
36075
  presentationId: external_exports.string().describe("Presentation ID"),
36059
36076
  slideId: external_exports.string().describe("Slide ID to read"),
@@ -36069,7 +36086,7 @@ function registerSlidesTools(server) {
36069
36086
  }
36070
36087
 
36071
36088
  // ../gogcli-mcp/src/server.ts
36072
- var VERSION = true ? "4.6.3" : "0.0.0";
36089
+ var VERSION = true ? "4.7.1" : "0.0.0";
36073
36090
 
36074
36091
  // ../gogcli-mcp/src/bootstrap-auth.ts
36075
36092
  import { join as join5 } from "node:path";
@@ -36147,7 +36164,7 @@ var MAX_BLOB_UPLOAD_BYTES = 100 * 1024 * 1024;
36147
36164
  function registerExtraSlidesTools(server) {
36148
36165
  server.registerTool("gog_slides_create_from_markdown", {
36149
36166
  description: "Create a new Google Slides presentation from markdown content (inline or from a file).",
36150
- annotations: { destructiveHint: true },
36167
+ annotations: { destructiveHint: true, openWorldHint: true },
36151
36168
  inputSchema: external_exports.object({
36152
36169
  title: external_exports.string().describe("Presentation title"),
36153
36170
  content: external_exports.string().optional().describe("Inline markdown content"),
@@ -36167,7 +36184,7 @@ function registerExtraSlidesTools(server) {
36167
36184
  });
36168
36185
  server.registerTool("gog_slides_create_from_template", {
36169
36186
  description: "Create a new Google Slides presentation from a template, with optional placeholder replacements.",
36170
- annotations: { destructiveHint: true },
36187
+ annotations: { destructiveHint: true, openWorldHint: true },
36171
36188
  inputSchema: external_exports.object({
36172
36189
  templateId: external_exports.string().describe("Template presentation ID"),
36173
36190
  title: external_exports.string().describe("New presentation title"),
@@ -36192,7 +36209,7 @@ function registerExtraSlidesTools(server) {
36192
36209
  });
36193
36210
  server.registerTool("gog_slides_add_slide", {
36194
36211
  description: "Add a new slide to a presentation from a local image, with optional speaker notes.",
36195
- annotations: { destructiveHint: true },
36212
+ annotations: { destructiveHint: true, openWorldHint: true },
36196
36213
  inputSchema: external_exports.object({
36197
36214
  presentationId: external_exports.string().describe("Presentation ID"),
36198
36215
  image: external_exports.string().describe("Path to the local image file"),
@@ -36212,7 +36229,7 @@ function registerExtraSlidesTools(server) {
36212
36229
  });
36213
36230
  server.registerTool("gog_slides_insert_image", {
36214
36231
  description: "Place an image on an existing slide at a given size and position, from a local file (image) or a public HTTPS URL (url \u2014 no Drive upload or sharing required). Unlike gog_slides_add_slide (which creates a new full-bleed image slide), this inserts onto a slide you already have. width is required; omit height to keep aspect ratio when using a local file (gog requires both width and height when using url).",
36215
- annotations: { destructiveHint: false },
36232
+ annotations: { destructiveHint: false, openWorldHint: true },
36216
36233
  inputSchema: external_exports.object({
36217
36234
  presentationId: external_exports.string().describe("Presentation ID"),
36218
36235
  slideId: external_exports.string().describe("Slide ID (object ID of the target slide)"),
@@ -36239,7 +36256,7 @@ function registerExtraSlidesTools(server) {
36239
36256
  });
36240
36257
  server.registerTool("gog_slides_delete_slide", {
36241
36258
  description: "Delete a slide from a Google Slides presentation.",
36242
- annotations: { destructiveHint: true },
36259
+ annotations: { destructiveHint: true, openWorldHint: true },
36243
36260
  inputSchema: external_exports.object({
36244
36261
  presentationId: external_exports.string().describe("Presentation ID"),
36245
36262
  slideId: external_exports.string().describe("Slide ID to delete"),
@@ -36250,7 +36267,7 @@ function registerExtraSlidesTools(server) {
36250
36267
  });
36251
36268
  server.registerTool("gog_slides_skip_slide", {
36252
36269
  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.",
36253
- annotations: { destructiveHint: false },
36270
+ annotations: { destructiveHint: false, openWorldHint: true },
36254
36271
  inputSchema: external_exports.object({
36255
36272
  presentationId: external_exports.string().describe("Presentation ID"),
36256
36273
  slideId: external_exports.string().describe("Slide ID to skip (from gog_slides_list_slides)"),
@@ -36261,7 +36278,7 @@ function registerExtraSlidesTools(server) {
36261
36278
  });
36262
36279
  server.registerTool("gog_slides_unskip_slide", {
36263
36280
  description: "Include a previously skipped slide again when the deck is presented. Safe to call on a slide that was never skipped.",
36264
- annotations: { destructiveHint: false },
36281
+ annotations: { destructiveHint: false, openWorldHint: true },
36265
36282
  inputSchema: external_exports.object({
36266
36283
  presentationId: external_exports.string().describe("Presentation ID"),
36267
36284
  slideId: external_exports.string().describe("Slide ID to unskip (from gog_slides_list_slides)"),
@@ -36272,7 +36289,7 @@ function registerExtraSlidesTools(server) {
36272
36289
  });
36273
36290
  server.registerTool("gog_slides_update_notes", {
36274
36291
  description: "Update the speaker notes on a slide (inline text or from a file).",
36275
- annotations: { destructiveHint: true },
36292
+ annotations: { destructiveHint: true, openWorldHint: true },
36276
36293
  inputSchema: external_exports.object({
36277
36294
  presentationId: external_exports.string().describe("Presentation ID"),
36278
36295
  slideId: external_exports.string().describe("Slide ID"),
@@ -36289,7 +36306,7 @@ function registerExtraSlidesTools(server) {
36289
36306
  });
36290
36307
  server.registerTool("gog_slides_replace_slide", {
36291
36308
  description: "Replace the image content of an existing slide, from a local file (image) or a public HTTPS URL (url \u2014 no Drive upload or sharing required), with optional speaker notes.",
36292
- annotations: { destructiveHint: true },
36309
+ annotations: { destructiveHint: true, openWorldHint: true },
36293
36310
  inputSchema: external_exports.object({
36294
36311
  presentationId: external_exports.string().describe("Presentation ID"),
36295
36312
  slideId: external_exports.string().describe("Slide ID to replace"),
@@ -36311,7 +36328,7 @@ function registerExtraSlidesTools(server) {
36311
36328
  });
36312
36329
  server.registerTool("gog_slides_raw", {
36313
36330
  description: "Dump the raw Google Slides API response (Presentations.Get) as JSON \u2014 lossless presentation metadata including every page, element, and style. Use gog_slides_read_slide for a friendlier per-slide view.",
36314
- annotations: { readOnlyHint: true },
36331
+ annotations: { readOnlyHint: true, openWorldHint: true },
36315
36332
  inputSchema: external_exports.object({
36316
36333
  presentationId: external_exports.string().describe("Presentation ID"),
36317
36334
  pretty: external_exports.boolean().optional().describe("Pretty-print the JSON (default: compact single line)"),
@@ -36324,7 +36341,7 @@ function registerExtraSlidesTools(server) {
36324
36341
  });
36325
36342
  server.registerTool("gog_slides_locate", {
36326
36343
  description: "Locate literal text in a presentation's shapes and table cells, returning the containing element object IDs and UTF-16 ranges needed for gog_slides_style_text / gog_slides_link / gog_slides_bullets / gog_slides_insert_text. Read-only.",
36327
- annotations: { readOnlyHint: true },
36344
+ annotations: { readOnlyHint: true, openWorldHint: true },
36328
36345
  inputSchema: external_exports.object({
36329
36346
  presentationId: external_exports.string().describe("Presentation ID"),
36330
36347
  text: external_exports.string().describe("Literal text to locate"),
@@ -36347,7 +36364,7 @@ function registerExtraSlidesTools(server) {
36347
36364
  server.registerTool("gog_slides_thumbnail", {
36348
36365
  description: "Get or download a rendered thumbnail image for a single slide.",
36349
36366
  // Writes a file on the gog host and can overwrite one: not read-only (audit SEC-4).
36350
- annotations: { readOnlyHint: false, destructiveHint: true },
36367
+ annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
36351
36368
  inputSchema: external_exports.object({
36352
36369
  presentationId: external_exports.string().describe("Presentation ID"),
36353
36370
  slideId: external_exports.string().describe("Slide object ID"),
@@ -36368,7 +36385,7 @@ function registerExtraSlidesTools(server) {
36368
36385
  });
36369
36386
  server.registerTool("gog_slides_new_slide", {
36370
36387
  description: "Create a new native themed slide with a predefined layout (default BLANK) or an exact presentation layout object ID, at a zero-based insertion index.",
36371
- annotations: { destructiveHint: false },
36388
+ annotations: { destructiveHint: false, openWorldHint: true },
36372
36389
  inputSchema: external_exports.object({
36373
36390
  presentationId: external_exports.string().describe("Presentation ID"),
36374
36391
  layout: external_exports.enum(["BIG_NUMBER", "BLANK", "CAPTION_ONLY", "MAIN_POINT", "ONE_COLUMN_TEXT", "SECTION_HEADER", "SECTION_TITLE_AND_DESCRIPTION", "TITLE", "TITLE_AND_BODY", "TITLE_AND_TWO_COLUMNS", "TITLE_ONLY"]).optional().describe("Predefined slide layout (default: BLANK). Mutually exclusive with layoutId."),
@@ -36385,7 +36402,7 @@ function registerExtraSlidesTools(server) {
36385
36402
  });
36386
36403
  server.registerTool("gog_slides_duplicate_slide", {
36387
36404
  description: "Duplicate a slide by object ID, optionally placing the copy at a zero-based insertion index.",
36388
- annotations: { destructiveHint: false },
36405
+ annotations: { destructiveHint: false, openWorldHint: true },
36389
36406
  inputSchema: external_exports.object({
36390
36407
  presentationId: external_exports.string().describe("Presentation ID"),
36391
36408
  slideId: external_exports.string().describe("Slide object ID to duplicate"),
@@ -36399,7 +36416,7 @@ function registerExtraSlidesTools(server) {
36399
36416
  });
36400
36417
  server.registerTool("gog_slides_move_slide", {
36401
36418
  description: "Move a slide to a zero-based insertion index within the presentation.",
36402
- annotations: { destructiveHint: false },
36419
+ annotations: { destructiveHint: false, openWorldHint: true },
36403
36420
  inputSchema: external_exports.object({
36404
36421
  presentationId: external_exports.string().describe("Presentation ID"),
36405
36422
  slideId: external_exports.string().describe("Slide object ID to move"),
@@ -36411,7 +36428,7 @@ function registerExtraSlidesTools(server) {
36411
36428
  });
36412
36429
  server.registerTool("gog_slides_insert_text", {
36413
36430
  description: "Insert text into an existing page element (shape or table cell) by object ID. Target a table cell with zero-based row + col. Use replace=true to clear the element's existing text first.",
36414
- annotations: { destructiveHint: true },
36431
+ annotations: { destructiveHint: true, openWorldHint: true },
36415
36432
  inputSchema: external_exports.object({
36416
36433
  presentationId: external_exports.string().describe("Presentation ID"),
36417
36434
  objectId: external_exports.string().describe("Object ID of the target shape or table"),
@@ -36432,7 +36449,7 @@ function registerExtraSlidesTools(server) {
36432
36449
  });
36433
36450
  server.registerTool("gog_slides_style_text", {
36434
36451
  description: "Apply range-scoped text styling to one page element. range is a UTF-16 start:end span (use gog_slides_locate to find it). Boolean flags set the attribute; the no* flags clear it.",
36435
- annotations: { destructiveHint: false },
36452
+ annotations: { destructiveHint: false, openWorldHint: true },
36436
36453
  inputSchema: external_exports.object({
36437
36454
  presentationId: external_exports.string().describe("Presentation ID"),
36438
36455
  objectId: external_exports.string().describe("Object ID of the shape or table cell containing the text"),
@@ -36463,7 +36480,7 @@ function registerExtraSlidesTools(server) {
36463
36480
  });
36464
36481
  server.registerTool("gog_slides_link", {
36465
36482
  description: "Apply or clear a hyperlink on a UTF-16 text range in one page element. Provide url to set the link, or clear=true to remove it.",
36466
- annotations: { destructiveHint: false },
36483
+ annotations: { destructiveHint: false, openWorldHint: true },
36467
36484
  inputSchema: external_exports.object({
36468
36485
  presentationId: external_exports.string().describe("Presentation ID"),
36469
36486
  objectId: external_exports.string().describe("Object ID of the shape or table cell containing the text"),
@@ -36480,7 +36497,7 @@ function registerExtraSlidesTools(server) {
36480
36497
  });
36481
36498
  server.registerTool("gog_slides_bullets", {
36482
36499
  description: "Turn paragraph bullets on or off for a UTF-16 paragraph range in one page element. Use on (optionally with a preset glyph) or off.",
36483
- annotations: { destructiveHint: false },
36500
+ annotations: { destructiveHint: false, openWorldHint: true },
36484
36501
  inputSchema: external_exports.object({
36485
36502
  presentationId: external_exports.string().describe("Presentation ID"),
36486
36503
  objectId: external_exports.string().describe("Object ID of the shape or table cell containing the paragraphs"),
@@ -36499,7 +36516,7 @@ function registerExtraSlidesTools(server) {
36499
36516
  });
36500
36517
  server.registerTool("gog_slides_replace_text", {
36501
36518
  description: "Find-and-replace text within an explicit scope. You MUST choose a scope \u2014 restrict to a single shape (object), one or more slides (pages), or the entire presentation (all=true). There is no whole-deck default; gog rejects the call if no scope is given.",
36502
- annotations: { destructiveHint: true },
36519
+ annotations: { destructiveHint: true, openWorldHint: true },
36503
36520
  inputSchema: external_exports.object({
36504
36521
  presentationId: external_exports.string().describe("Presentation ID"),
36505
36522
  find: external_exports.string().describe("Text to find"),
@@ -36520,7 +36537,7 @@ function registerExtraSlidesTools(server) {
36520
36537
  });
36521
36538
  server.registerTool("gog_slides_element_create_shape", {
36522
36539
  description: "Create a native shape on a slide. type is a Slides shape type (e.g. RECTANGLE, TEXT_BOX, ELLIPSE, ROUND_RECTANGLE). Position/size are in unit (default PT).",
36523
- annotations: { destructiveHint: false },
36540
+ annotations: { destructiveHint: false, openWorldHint: true },
36524
36541
  inputSchema: external_exports.object({
36525
36542
  presentationId: external_exports.string().describe("Presentation ID"),
36526
36543
  slideId: external_exports.string().describe("Slide object ID to create the shape on"),
@@ -36546,7 +36563,7 @@ function registerExtraSlidesTools(server) {
36546
36563
  });
36547
36564
  server.registerTool("gog_slides_element_create_line", {
36548
36565
  description: "Create a native line on a slide. category is the connector routing (STRAIGHT, BENT, CURVED). Start position and extent are in unit (default PT).",
36549
- annotations: { destructiveHint: false },
36566
+ annotations: { destructiveHint: false, openWorldHint: true },
36550
36567
  inputSchema: external_exports.object({
36551
36568
  presentationId: external_exports.string().describe("Presentation ID"),
36552
36569
  slideId: external_exports.string().describe("Slide object ID to create the line on"),
@@ -36572,7 +36589,7 @@ function registerExtraSlidesTools(server) {
36572
36589
  });
36573
36590
  server.registerTool("gog_slides_element_style", {
36574
36591
  description: "Style a shape fill/outline or a line. Set kind to shape or line. Colors are #RGB or #RRGGBB.",
36575
- annotations: { destructiveHint: false },
36592
+ annotations: { destructiveHint: false, openWorldHint: true },
36576
36593
  inputSchema: external_exports.object({
36577
36594
  presentationId: external_exports.string().describe("Presentation ID"),
36578
36595
  objectId: external_exports.string().describe("Object ID of the shape or line"),
@@ -36598,7 +36615,7 @@ function registerExtraSlidesTools(server) {
36598
36615
  });
36599
36616
  server.registerTool("gog_slides_element_transform", {
36600
36617
  description: "Move, resize, rotate, or shear a page element. apply-mode RELATIVE (default) composes with the existing transform; ABSOLUTE replaces it. Translation is in unit (default PT).",
36601
- annotations: { destructiveHint: false },
36618
+ annotations: { destructiveHint: false, openWorldHint: true },
36602
36619
  inputSchema: external_exports.object({
36603
36620
  presentationId: external_exports.string().describe("Presentation ID"),
36604
36621
  objectId: external_exports.string().describe("Object ID of the element to transform"),
@@ -36628,7 +36645,7 @@ function registerExtraSlidesTools(server) {
36628
36645
  });
36629
36646
  server.registerTool("gog_slides_element_z_order", {
36630
36647
  description: "Change a page element's stacking order.",
36631
- annotations: { destructiveHint: false },
36648
+ annotations: { destructiveHint: false, openWorldHint: true },
36632
36649
  inputSchema: external_exports.object({
36633
36650
  presentationId: external_exports.string().describe("Presentation ID"),
36634
36651
  objectId: external_exports.string().describe("Object ID of the element to restack"),
@@ -36640,7 +36657,7 @@ function registerExtraSlidesTools(server) {
36640
36657
  });
36641
36658
  server.registerTool("gog_slides_element_group", {
36642
36659
  description: "Group two or more page elements into a single group.",
36643
- annotations: { destructiveHint: false },
36660
+ annotations: { destructiveHint: false, openWorldHint: true },
36644
36661
  inputSchema: external_exports.object({
36645
36662
  presentationId: external_exports.string().describe("Presentation ID"),
36646
36663
  objectIds: external_exports.array(external_exports.string()).min(2).describe("Two or more element object IDs to group"),
@@ -36654,7 +36671,7 @@ function registerExtraSlidesTools(server) {
36654
36671
  });
36655
36672
  server.registerTool("gog_slides_element_ungroup", {
36656
36673
  description: "Ungroup one or more element groups back into their constituent elements.",
36657
- annotations: { destructiveHint: false },
36674
+ annotations: { destructiveHint: false, openWorldHint: true },
36658
36675
  inputSchema: external_exports.object({
36659
36676
  presentationId: external_exports.string().describe("Presentation ID"),
36660
36677
  groupIds: external_exports.array(external_exports.string()).min(1).describe("One or more group object IDs to ungroup"),
@@ -36665,7 +36682,7 @@ function registerExtraSlidesTools(server) {
36665
36682
  });
36666
36683
  server.registerTool("gog_slides_element_alt_text", {
36667
36684
  description: "Set or clear a page element's accessibility title and/or description. Pass an empty string to clear a field.",
36668
- annotations: { destructiveHint: false },
36685
+ annotations: { destructiveHint: false, openWorldHint: true },
36669
36686
  inputSchema: external_exports.object({
36670
36687
  presentationId: external_exports.string().describe("Presentation ID"),
36671
36688
  objectId: external_exports.string().describe("Object ID of the element"),
@@ -36681,7 +36698,7 @@ function registerExtraSlidesTools(server) {
36681
36698
  });
36682
36699
  server.registerTool("gog_slides_element_delete", {
36683
36700
  description: "Delete one page element by object ID.",
36684
- annotations: { destructiveHint: true },
36701
+ annotations: { destructiveHint: true, openWorldHint: true },
36685
36702
  inputSchema: external_exports.object({
36686
36703
  presentationId: external_exports.string().describe("Presentation ID"),
36687
36704
  objectId: external_exports.string().describe("Object ID of the element to delete"),
@@ -36692,7 +36709,7 @@ function registerExtraSlidesTools(server) {
36692
36709
  });
36693
36710
  server.registerTool("gog_slides_table_create", {
36694
36711
  description: "Create an auto-sized native table on a slide with the given row and column counts.",
36695
- annotations: { destructiveHint: false },
36712
+ annotations: { destructiveHint: false, openWorldHint: true },
36696
36713
  inputSchema: external_exports.object({
36697
36714
  presentationId: external_exports.string().describe("Presentation ID"),
36698
36715
  slideId: external_exports.string().describe("Slide object ID to create the table on"),
@@ -36708,7 +36725,7 @@ function registerExtraSlidesTools(server) {
36708
36725
  });
36709
36726
  server.registerTool("gog_slides_table_cell_style", {
36710
36727
  description: "Style one zero-based table cell: background fill, vertical content alignment, and inline text styling (optionally scoped to a UTF-16 range within the cell). Boolean flags set the attribute; the no* flags clear it.",
36711
- annotations: { destructiveHint: false },
36728
+ annotations: { destructiveHint: false, openWorldHint: true },
36712
36729
  inputSchema: external_exports.object({
36713
36730
  presentationId: external_exports.string().describe("Presentation ID"),
36714
36731
  tableObjectId: external_exports.string().describe("Table object ID"),
@@ -36748,7 +36765,7 @@ function registerExtraSlidesTools(server) {
36748
36765
  });
36749
36766
  server.registerTool("gog_slides_table_border_style", {
36750
36767
  description: "Style borders around or within a zero-based table cell range. position selects which borders are affected; dash sets the line style.",
36751
- annotations: { destructiveHint: false },
36768
+ annotations: { destructiveHint: false, openWorldHint: true },
36752
36769
  inputSchema: external_exports.object({
36753
36770
  presentationId: external_exports.string().describe("Presentation ID"),
36754
36771
  tableObjectId: external_exports.string().describe("Table object ID"),
@@ -36776,7 +36793,7 @@ function registerExtraSlidesTools(server) {
36776
36793
  });
36777
36794
  server.registerTool("gog_slides_table_column_insert", {
36778
36795
  description: "Insert one or more columns relative to a zero-based table column. Inserts to the left by default, or to the right with right=true.",
36779
- annotations: { destructiveHint: false },
36796
+ annotations: { destructiveHint: false, openWorldHint: true },
36780
36797
  inputSchema: external_exports.object({
36781
36798
  presentationId: external_exports.string().describe("Presentation ID"),
36782
36799
  tableObjectId: external_exports.string().describe("Table object ID"),
@@ -36793,7 +36810,7 @@ function registerExtraSlidesTools(server) {
36793
36810
  });
36794
36811
  server.registerTool("gog_slides_table_column_delete", {
36795
36812
  description: "Delete the column containing a zero-based table cell.",
36796
- annotations: { destructiveHint: true },
36813
+ annotations: { destructiveHint: true, openWorldHint: true },
36797
36814
  inputSchema: external_exports.object({
36798
36815
  presentationId: external_exports.string().describe("Presentation ID"),
36799
36816
  tableObjectId: external_exports.string().describe("Table object ID"),
@@ -36805,7 +36822,7 @@ function registerExtraSlidesTools(server) {
36805
36822
  });
36806
36823
  server.registerTool("gog_slides_table_column_size", {
36807
36824
  description: "Set the width of a zero-based table column.",
36808
- annotations: { destructiveHint: false },
36825
+ annotations: { destructiveHint: false, openWorldHint: true },
36809
36826
  inputSchema: external_exports.object({
36810
36827
  presentationId: external_exports.string().describe("Presentation ID"),
36811
36828
  tableObjectId: external_exports.string().describe("Table object ID"),
@@ -36818,7 +36835,7 @@ function registerExtraSlidesTools(server) {
36818
36835
  });
36819
36836
  server.registerTool("gog_slides_table_row_insert", {
36820
36837
  description: "Insert one or more rows relative to a zero-based table row. Inserts above by default, or below with below=true.",
36821
- annotations: { destructiveHint: false },
36838
+ annotations: { destructiveHint: false, openWorldHint: true },
36822
36839
  inputSchema: external_exports.object({
36823
36840
  presentationId: external_exports.string().describe("Presentation ID"),
36824
36841
  tableObjectId: external_exports.string().describe("Table object ID"),
@@ -36835,7 +36852,7 @@ function registerExtraSlidesTools(server) {
36835
36852
  });
36836
36853
  server.registerTool("gog_slides_table_row_delete", {
36837
36854
  description: "Delete the row containing a zero-based table cell.",
36838
- annotations: { destructiveHint: true },
36855
+ annotations: { destructiveHint: true, openWorldHint: true },
36839
36856
  inputSchema: external_exports.object({
36840
36857
  presentationId: external_exports.string().describe("Presentation ID"),
36841
36858
  tableObjectId: external_exports.string().describe("Table object ID"),
@@ -36847,7 +36864,7 @@ function registerExtraSlidesTools(server) {
36847
36864
  });
36848
36865
  server.registerTool("gog_slides_table_row_size", {
36849
36866
  description: "Set the minimum height of a zero-based table row.",
36850
- annotations: { destructiveHint: false },
36867
+ annotations: { destructiveHint: false, openWorldHint: true },
36851
36868
  inputSchema: external_exports.object({
36852
36869
  presentationId: external_exports.string().describe("Presentation ID"),
36853
36870
  tableObjectId: external_exports.string().describe("Table object ID"),
@@ -36860,7 +36877,7 @@ function registerExtraSlidesTools(server) {
36860
36877
  });
36861
36878
  server.registerTool("gog_slides_table_merge", {
36862
36879
  description: "Merge a rectangular table cell range starting at a zero-based cell. Content of non-anchor cells is absorbed by the merge; use gog_slides_table_unmerge to split back.",
36863
- annotations: { destructiveHint: true },
36880
+ annotations: { destructiveHint: true, openWorldHint: true },
36864
36881
  inputSchema: external_exports.object({
36865
36882
  presentationId: external_exports.string().describe("Presentation ID"),
36866
36883
  tableObjectId: external_exports.string().describe("Table object ID"),
@@ -36878,7 +36895,7 @@ function registerExtraSlidesTools(server) {
36878
36895
  });
36879
36896
  server.registerTool("gog_slides_table_unmerge", {
36880
36897
  description: "Unmerge (split) a rectangular range of previously merged cells, starting at a zero-based cell.",
36881
- annotations: { destructiveHint: false },
36898
+ annotations: { destructiveHint: false, openWorldHint: true },
36882
36899
  inputSchema: external_exports.object({
36883
36900
  presentationId: external_exports.string().describe("Presentation ID"),
36884
36901
  tableObjectId: external_exports.string().describe("Table object ID"),
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": "4.6.3",
6
+ "version": "4.7.1",
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",
@@ -39,7 +39,10 @@
39
39
  "env": {
40
40
  "GOG_ACCOUNT": "${user_config.gog_account}",
41
41
  "GOG_PATH": "${user_config.gog_path}",
42
- "GOG_FILE_ROOTS": "${user_config.gog_file_roots}"
42
+ "GOG_FILE_ROOTS": "${user_config.gog_file_roots}",
43
+ "DISPLAY_TZ": "${user_config.display_tz}",
44
+ "GOG_READONLY": "${user_config.gog_readonly}",
45
+ "GOG_TIMEZONE": "${user_config.gog_timezone}"
43
46
  }
44
47
  }
45
48
  },
@@ -61,6 +64,24 @@
61
64
  "title": "Allowed file directories",
62
65
  "description": "Directories tools may read files from (attachments, uploads) or write files to (exports, downloads), separated by ':' (';' on Windows). Optional — defaults to ~/gogcli-mcp-files",
63
66
  "required": false
67
+ },
68
+ "display_tz": {
69
+ "type": "string",
70
+ "title": "Display time zone",
71
+ "description": "zone for *Display fields and for interpreting naive gog values; defaults to America/New_York",
72
+ "required": false
73
+ },
74
+ "gog_readonly": {
75
+ "type": "string",
76
+ "title": "Read-only mode",
77
+ "description": "block all mutating gog API requests (injects gog's --readonly); set to 0/false/no/off (or unset) to allow writes",
78
+ "required": false
79
+ },
80
+ "gog_timezone": {
81
+ "type": "string",
82
+ "title": "gog time zone",
83
+ "description": "zone gog formats naive dates in; unset, runner.ts hands gog DISPLAY_TZ so the two cannot diverge",
84
+ "required": false
64
85
  }
65
86
  },
66
87
  "tools": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gogcli-mcp-slides",
3
- "version": "4.6.3",
3
+ "version": "4.7.1",
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": "^2.14.0",
27
+ "@chrischall/mcp-utils": "^3.0.0",
28
28
  "@modelcontextprotocol/server": "^2.3.0",
29
29
  "zod": "^4.6.1"
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": "4.6.3",
10
+ "version": "4.7.1",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "npm",
14
14
  "identifier": "gogcli-mcp-slides",
15
- "version": "4.6.3",
15
+ "version": "4.7.1",
16
16
  "transport": {
17
17
  "type": "stdio"
18
18
  },
@@ -28,6 +28,24 @@
28
28
  "description": "Override path to the gogcli binary (auto-discovered otherwise)",
29
29
  "isRequired": false,
30
30
  "format": "string"
31
+ },
32
+ {
33
+ "name": "DISPLAY_TZ",
34
+ "description": "zone for *Display fields and for interpreting naive gog values; defaults to America/New_York",
35
+ "isRequired": false,
36
+ "format": "string"
37
+ },
38
+ {
39
+ "name": "GOG_READONLY",
40
+ "description": "block all mutating gog API requests (injects gog's --readonly); set to 0/false/no/off (or unset) to allow writes",
41
+ "isRequired": false,
42
+ "format": "string"
43
+ },
44
+ {
45
+ "name": "GOG_TIMEZONE",
46
+ "description": "zone gog formats naive dates in; unset, runner.ts hands gog DISPLAY_TZ so the two cannot diverge",
47
+ "isRequired": false,
48
+ "format": "string"
31
49
  }
32
50
  ]
33
51
  }
@@ -27,7 +27,7 @@ import type { GogArg } from '../../../gogcli-mcp/src/lib.js';
27
27
  export function registerExtraSlidesTools(server: McpServer): void {
28
28
  server.registerTool('gog_slides_create_from_markdown', {
29
29
  description: 'Create a new Google Slides presentation from markdown content (inline or from a file).',
30
- annotations: { destructiveHint: true },
30
+ annotations: { destructiveHint: true, openWorldHint: true },
31
31
  inputSchema: z.object({
32
32
  title: z.string().describe('Presentation title'),
33
33
  content: z.string().optional().describe('Inline markdown content'),
@@ -48,7 +48,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
48
48
 
49
49
  server.registerTool('gog_slides_create_from_template', {
50
50
  description: 'Create a new Google Slides presentation from a template, with optional placeholder replacements.',
51
- annotations: { destructiveHint: true },
51
+ annotations: { destructiveHint: true, openWorldHint: true },
52
52
  inputSchema: z.object({
53
53
  templateId: z.string().describe('Template presentation ID'),
54
54
  title: z.string().describe('New presentation title'),
@@ -74,7 +74,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
74
74
 
75
75
  server.registerTool('gog_slides_add_slide', {
76
76
  description: 'Add a new slide to a presentation from a local image, with optional speaker notes.',
77
- annotations: { destructiveHint: true },
77
+ annotations: { destructiveHint: true, openWorldHint: true },
78
78
  inputSchema: z.object({
79
79
  presentationId: z.string().describe('Presentation ID'),
80
80
  image: z.string().describe('Path to the local image file'),
@@ -95,7 +95,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
95
95
 
96
96
  server.registerTool('gog_slides_insert_image', {
97
97
  description: 'Place an image on an existing slide at a given size and position, from a local file (image) or a public HTTPS URL (url — no Drive upload or sharing required). Unlike gog_slides_add_slide (which creates a new full-bleed image slide), this inserts onto a slide you already have. width is required; omit height to keep aspect ratio when using a local file (gog requires both width and height when using url).',
98
- annotations: { destructiveHint: false },
98
+ annotations: { destructiveHint: false, openWorldHint: true },
99
99
  inputSchema: z.object({
100
100
  presentationId: z.string().describe('Presentation ID'),
101
101
  slideId: z.string().describe('Slide ID (object ID of the target slide)'),
@@ -123,7 +123,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
123
123
 
124
124
  server.registerTool('gog_slides_delete_slide', {
125
125
  description: 'Delete a slide from a Google Slides presentation.',
126
- annotations: { destructiveHint: true },
126
+ annotations: { destructiveHint: true, openWorldHint: true },
127
127
  inputSchema: z.object({
128
128
  presentationId: z.string().describe('Presentation ID'),
129
129
  slideId: z.string().describe('Slide ID to delete'),
@@ -147,7 +147,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
147
147
  'Skip a slide during presentation — it stays in the deck at its current position but is not shown when presenting '
148
148
  + '(and is left out of a PDF export). Use this instead of gog_slides_delete_slide when a slide should be omitted from '
149
149
  + 'a talk without losing it. Reverse with gog_slides_unskip_slide; gog_slides_list_slides reports which slides are skipped.',
150
- annotations: { destructiveHint: false },
150
+ annotations: { destructiveHint: false, openWorldHint: true },
151
151
  inputSchema: z.object({
152
152
  presentationId: z.string().describe('Presentation ID'),
153
153
  slideId: z.string().describe('Slide ID to skip (from gog_slides_list_slides)'),
@@ -160,7 +160,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
160
160
  server.registerTool('gog_slides_unskip_slide', {
161
161
  description:
162
162
  'Include a previously skipped slide again when the deck is presented. Safe to call on a slide that was never skipped.',
163
- annotations: { destructiveHint: false },
163
+ annotations: { destructiveHint: false, openWorldHint: true },
164
164
  inputSchema: z.object({
165
165
  presentationId: z.string().describe('Presentation ID'),
166
166
  slideId: z.string().describe('Slide ID to unskip (from gog_slides_list_slides)'),
@@ -172,7 +172,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
172
172
 
173
173
  server.registerTool('gog_slides_update_notes', {
174
174
  description: 'Update the speaker notes on a slide (inline text or from a file).',
175
- annotations: { destructiveHint: true },
175
+ annotations: { destructiveHint: true, openWorldHint: true },
176
176
  inputSchema: z.object({
177
177
  presentationId: z.string().describe('Presentation ID'),
178
178
  slideId: z.string().describe('Slide ID'),
@@ -190,7 +190,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
190
190
 
191
191
  server.registerTool('gog_slides_replace_slide', {
192
192
  description: 'Replace the image content of an existing slide, from a local file (image) or a public HTTPS URL (url — no Drive upload or sharing required), with optional speaker notes.',
193
- annotations: { destructiveHint: true },
193
+ annotations: { destructiveHint: true, openWorldHint: true },
194
194
  inputSchema: z.object({
195
195
  presentationId: z.string().describe('Presentation ID'),
196
196
  slideId: z.string().describe('Slide ID to replace'),
@@ -215,7 +215,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
215
215
 
216
216
  server.registerTool('gog_slides_raw', {
217
217
  description: 'Dump the raw Google Slides API response (Presentations.Get) as JSON — lossless presentation metadata including every page, element, and style. Use gog_slides_read_slide for a friendlier per-slide view.',
218
- annotations: { readOnlyHint: true },
218
+ annotations: { readOnlyHint: true, openWorldHint: true },
219
219
  inputSchema: z.object({
220
220
  presentationId: z.string().describe('Presentation ID'),
221
221
  pretty: z.boolean().optional().describe('Pretty-print the JSON (default: compact single line)'),
@@ -230,7 +230,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
230
230
 
231
231
  server.registerTool('gog_slides_locate', {
232
232
  description: 'Locate literal text in a presentation\'s shapes and table cells, returning the containing element object IDs and UTF-16 ranges needed for gog_slides_style_text / gog_slides_link / gog_slides_bullets / gog_slides_insert_text. Read-only.',
233
- annotations: { readOnlyHint: true },
233
+ annotations: { readOnlyHint: true, openWorldHint: true },
234
234
  inputSchema: z.object({
235
235
  presentationId: z.string().describe('Presentation ID'),
236
236
  text: z.string().describe('Literal text to locate'),
@@ -254,7 +254,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
254
254
  server.registerTool('gog_slides_thumbnail', {
255
255
  description: 'Get or download a rendered thumbnail image for a single slide.',
256
256
  // Writes a file on the gog host and can overwrite one: not read-only (audit SEC-4).
257
- annotations: { readOnlyHint: false, destructiveHint: true },
257
+ annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
258
258
  inputSchema: z.object({
259
259
  presentationId: z.string().describe('Presentation ID'),
260
260
  slideId: z.string().describe('Slide object ID'),
@@ -278,7 +278,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
278
278
 
279
279
  server.registerTool('gog_slides_new_slide', {
280
280
  description: 'Create a new native themed slide with a predefined layout (default BLANK) or an exact presentation layout object ID, at a zero-based insertion index.',
281
- annotations: { destructiveHint: false },
281
+ annotations: { destructiveHint: false, openWorldHint: true },
282
282
  inputSchema: z.object({
283
283
  presentationId: z.string().describe('Presentation ID'),
284
284
  layout: z.enum(['BIG_NUMBER', 'BLANK', 'CAPTION_ONLY', 'MAIN_POINT', 'ONE_COLUMN_TEXT', 'SECTION_HEADER', 'SECTION_TITLE_AND_DESCRIPTION', 'TITLE', 'TITLE_AND_BODY', 'TITLE_AND_TWO_COLUMNS', 'TITLE_ONLY']).optional().describe('Predefined slide layout (default: BLANK). Mutually exclusive with layoutId.'),
@@ -296,7 +296,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
296
296
 
297
297
  server.registerTool('gog_slides_duplicate_slide', {
298
298
  description: 'Duplicate a slide by object ID, optionally placing the copy at a zero-based insertion index.',
299
- annotations: { destructiveHint: false },
299
+ annotations: { destructiveHint: false, openWorldHint: true },
300
300
  inputSchema: z.object({
301
301
  presentationId: z.string().describe('Presentation ID'),
302
302
  slideId: z.string().describe('Slide object ID to duplicate'),
@@ -311,7 +311,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
311
311
 
312
312
  server.registerTool('gog_slides_move_slide', {
313
313
  description: 'Move a slide to a zero-based insertion index within the presentation.',
314
- annotations: { destructiveHint: false },
314
+ annotations: { destructiveHint: false, openWorldHint: true },
315
315
  inputSchema: z.object({
316
316
  presentationId: z.string().describe('Presentation ID'),
317
317
  slideId: z.string().describe('Slide object ID to move'),
@@ -326,7 +326,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
326
326
 
327
327
  server.registerTool('gog_slides_insert_text', {
328
328
  description: 'Insert text into an existing page element (shape or table cell) by object ID. Target a table cell with zero-based row + col. Use replace=true to clear the element\'s existing text first.',
329
- annotations: { destructiveHint: true },
329
+ annotations: { destructiveHint: true, openWorldHint: true },
330
330
  inputSchema: z.object({
331
331
  presentationId: z.string().describe('Presentation ID'),
332
332
  objectId: z.string().describe('Object ID of the target shape or table'),
@@ -348,7 +348,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
348
348
 
349
349
  server.registerTool('gog_slides_style_text', {
350
350
  description: 'Apply range-scoped text styling to one page element. range is a UTF-16 start:end span (use gog_slides_locate to find it). Boolean flags set the attribute; the no* flags clear it.',
351
- annotations: { destructiveHint: false },
351
+ annotations: { destructiveHint: false, openWorldHint: true },
352
352
  inputSchema: z.object({
353
353
  presentationId: z.string().describe('Presentation ID'),
354
354
  objectId: z.string().describe('Object ID of the shape or table cell containing the text'),
@@ -380,7 +380,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
380
380
 
381
381
  server.registerTool('gog_slides_link', {
382
382
  description: 'Apply or clear a hyperlink on a UTF-16 text range in one page element. Provide url to set the link, or clear=true to remove it.',
383
- annotations: { destructiveHint: false },
383
+ annotations: { destructiveHint: false, openWorldHint: true },
384
384
  inputSchema: z.object({
385
385
  presentationId: z.string().describe('Presentation ID'),
386
386
  objectId: z.string().describe('Object ID of the shape or table cell containing the text'),
@@ -398,7 +398,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
398
398
 
399
399
  server.registerTool('gog_slides_bullets', {
400
400
  description: 'Turn paragraph bullets on or off for a UTF-16 paragraph range in one page element. Use on (optionally with a preset glyph) or off.',
401
- annotations: { destructiveHint: false },
401
+ annotations: { destructiveHint: false, openWorldHint: true },
402
402
  inputSchema: z.object({
403
403
  presentationId: z.string().describe('Presentation ID'),
404
404
  objectId: z.string().describe('Object ID of the shape or table cell containing the paragraphs'),
@@ -418,7 +418,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
418
418
 
419
419
  server.registerTool('gog_slides_replace_text', {
420
420
  description: 'Find-and-replace text within an explicit scope. You MUST choose a scope — restrict to a single shape (object), one or more slides (pages), or the entire presentation (all=true). There is no whole-deck default; gog rejects the call if no scope is given.',
421
- annotations: { destructiveHint: true },
421
+ annotations: { destructiveHint: true, openWorldHint: true },
422
422
  inputSchema: z.object({
423
423
  presentationId: z.string().describe('Presentation ID'),
424
424
  find: z.string().describe('Text to find'),
@@ -442,7 +442,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
442
442
 
443
443
  server.registerTool('gog_slides_element_create_shape', {
444
444
  description: 'Create a native shape on a slide. type is a Slides shape type (e.g. RECTANGLE, TEXT_BOX, ELLIPSE, ROUND_RECTANGLE). Position/size are in unit (default PT).',
445
- annotations: { destructiveHint: false },
445
+ annotations: { destructiveHint: false, openWorldHint: true },
446
446
  inputSchema: z.object({
447
447
  presentationId: z.string().describe('Presentation ID'),
448
448
  slideId: z.string().describe('Slide object ID to create the shape on'),
@@ -469,7 +469,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
469
469
 
470
470
  server.registerTool('gog_slides_element_create_line', {
471
471
  description: 'Create a native line on a slide. category is the connector routing (STRAIGHT, BENT, CURVED). Start position and extent are in unit (default PT).',
472
- annotations: { destructiveHint: false },
472
+ annotations: { destructiveHint: false, openWorldHint: true },
473
473
  inputSchema: z.object({
474
474
  presentationId: z.string().describe('Presentation ID'),
475
475
  slideId: z.string().describe('Slide object ID to create the line on'),
@@ -496,7 +496,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
496
496
 
497
497
  server.registerTool('gog_slides_element_style', {
498
498
  description: 'Style a shape fill/outline or a line. Set kind to shape or line. Colors are #RGB or #RRGGBB.',
499
- annotations: { destructiveHint: false },
499
+ annotations: { destructiveHint: false, openWorldHint: true },
500
500
  inputSchema: z.object({
501
501
  presentationId: z.string().describe('Presentation ID'),
502
502
  objectId: z.string().describe('Object ID of the shape or line'),
@@ -523,7 +523,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
523
523
 
524
524
  server.registerTool('gog_slides_element_transform', {
525
525
  description: 'Move, resize, rotate, or shear a page element. apply-mode RELATIVE (default) composes with the existing transform; ABSOLUTE replaces it. Translation is in unit (default PT).',
526
- annotations: { destructiveHint: false },
526
+ annotations: { destructiveHint: false, openWorldHint: true },
527
527
  inputSchema: z.object({
528
528
  presentationId: z.string().describe('Presentation ID'),
529
529
  objectId: z.string().describe('Object ID of the element to transform'),
@@ -554,7 +554,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
554
554
 
555
555
  server.registerTool('gog_slides_element_z_order', {
556
556
  description: 'Change a page element\'s stacking order.',
557
- annotations: { destructiveHint: false },
557
+ annotations: { destructiveHint: false, openWorldHint: true },
558
558
  inputSchema: z.object({
559
559
  presentationId: z.string().describe('Presentation ID'),
560
560
  objectId: z.string().describe('Object ID of the element to restack'),
@@ -567,7 +567,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
567
567
 
568
568
  server.registerTool('gog_slides_element_group', {
569
569
  description: 'Group two or more page elements into a single group.',
570
- annotations: { destructiveHint: false },
570
+ annotations: { destructiveHint: false, openWorldHint: true },
571
571
  inputSchema: z.object({
572
572
  presentationId: z.string().describe('Presentation ID'),
573
573
  objectIds: z.array(z.string()).min(2).describe('Two or more element object IDs to group'),
@@ -582,7 +582,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
582
582
 
583
583
  server.registerTool('gog_slides_element_ungroup', {
584
584
  description: 'Ungroup one or more element groups back into their constituent elements.',
585
- annotations: { destructiveHint: false },
585
+ annotations: { destructiveHint: false, openWorldHint: true },
586
586
  inputSchema: z.object({
587
587
  presentationId: z.string().describe('Presentation ID'),
588
588
  groupIds: z.array(z.string()).min(1).describe('One or more group object IDs to ungroup'),
@@ -594,7 +594,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
594
594
 
595
595
  server.registerTool('gog_slides_element_alt_text', {
596
596
  description: 'Set or clear a page element\'s accessibility title and/or description. Pass an empty string to clear a field.',
597
- annotations: { destructiveHint: false },
597
+ annotations: { destructiveHint: false, openWorldHint: true },
598
598
  inputSchema: z.object({
599
599
  presentationId: z.string().describe('Presentation ID'),
600
600
  objectId: z.string().describe('Object ID of the element'),
@@ -611,7 +611,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
611
611
 
612
612
  server.registerTool('gog_slides_element_delete', {
613
613
  description: 'Delete one page element by object ID.',
614
- annotations: { destructiveHint: true },
614
+ annotations: { destructiveHint: true, openWorldHint: true },
615
615
  inputSchema: z.object({
616
616
  presentationId: z.string().describe('Presentation ID'),
617
617
  objectId: z.string().describe('Object ID of the element to delete'),
@@ -626,7 +626,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
626
626
 
627
627
  server.registerTool('gog_slides_table_create', {
628
628
  description: 'Create an auto-sized native table on a slide with the given row and column counts.',
629
- annotations: { destructiveHint: false },
629
+ annotations: { destructiveHint: false, openWorldHint: true },
630
630
  inputSchema: z.object({
631
631
  presentationId: z.string().describe('Presentation ID'),
632
632
  slideId: z.string().describe('Slide object ID to create the table on'),
@@ -643,7 +643,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
643
643
 
644
644
  server.registerTool('gog_slides_table_cell_style', {
645
645
  description: 'Style one zero-based table cell: background fill, vertical content alignment, and inline text styling (optionally scoped to a UTF-16 range within the cell). Boolean flags set the attribute; the no* flags clear it.',
646
- annotations: { destructiveHint: false },
646
+ annotations: { destructiveHint: false, openWorldHint: true },
647
647
  inputSchema: z.object({
648
648
  presentationId: z.string().describe('Presentation ID'),
649
649
  tableObjectId: z.string().describe('Table object ID'),
@@ -684,7 +684,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
684
684
 
685
685
  server.registerTool('gog_slides_table_border_style', {
686
686
  description: 'Style borders around or within a zero-based table cell range. position selects which borders are affected; dash sets the line style.',
687
- annotations: { destructiveHint: false },
687
+ annotations: { destructiveHint: false, openWorldHint: true },
688
688
  inputSchema: z.object({
689
689
  presentationId: z.string().describe('Presentation ID'),
690
690
  tableObjectId: z.string().describe('Table object ID'),
@@ -713,7 +713,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
713
713
 
714
714
  server.registerTool('gog_slides_table_column_insert', {
715
715
  description: 'Insert one or more columns relative to a zero-based table column. Inserts to the left by default, or to the right with right=true.',
716
- annotations: { destructiveHint: false },
716
+ annotations: { destructiveHint: false, openWorldHint: true },
717
717
  inputSchema: z.object({
718
718
  presentationId: z.string().describe('Presentation ID'),
719
719
  tableObjectId: z.string().describe('Table object ID'),
@@ -731,7 +731,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
731
731
 
732
732
  server.registerTool('gog_slides_table_column_delete', {
733
733
  description: 'Delete the column containing a zero-based table cell.',
734
- annotations: { destructiveHint: true },
734
+ annotations: { destructiveHint: true, openWorldHint: true },
735
735
  inputSchema: z.object({
736
736
  presentationId: z.string().describe('Presentation ID'),
737
737
  tableObjectId: z.string().describe('Table object ID'),
@@ -744,7 +744,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
744
744
 
745
745
  server.registerTool('gog_slides_table_column_size', {
746
746
  description: 'Set the width of a zero-based table column.',
747
- annotations: { destructiveHint: false },
747
+ annotations: { destructiveHint: false, openWorldHint: true },
748
748
  inputSchema: z.object({
749
749
  presentationId: z.string().describe('Presentation ID'),
750
750
  tableObjectId: z.string().describe('Table object ID'),
@@ -758,7 +758,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
758
758
 
759
759
  server.registerTool('gog_slides_table_row_insert', {
760
760
  description: 'Insert one or more rows relative to a zero-based table row. Inserts above by default, or below with below=true.',
761
- annotations: { destructiveHint: false },
761
+ annotations: { destructiveHint: false, openWorldHint: true },
762
762
  inputSchema: z.object({
763
763
  presentationId: z.string().describe('Presentation ID'),
764
764
  tableObjectId: z.string().describe('Table object ID'),
@@ -776,7 +776,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
776
776
 
777
777
  server.registerTool('gog_slides_table_row_delete', {
778
778
  description: 'Delete the row containing a zero-based table cell.',
779
- annotations: { destructiveHint: true },
779
+ annotations: { destructiveHint: true, openWorldHint: true },
780
780
  inputSchema: z.object({
781
781
  presentationId: z.string().describe('Presentation ID'),
782
782
  tableObjectId: z.string().describe('Table object ID'),
@@ -789,7 +789,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
789
789
 
790
790
  server.registerTool('gog_slides_table_row_size', {
791
791
  description: 'Set the minimum height of a zero-based table row.',
792
- annotations: { destructiveHint: false },
792
+ annotations: { destructiveHint: false, openWorldHint: true },
793
793
  inputSchema: z.object({
794
794
  presentationId: z.string().describe('Presentation ID'),
795
795
  tableObjectId: z.string().describe('Table object ID'),
@@ -803,7 +803,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
803
803
 
804
804
  server.registerTool('gog_slides_table_merge', {
805
805
  description: 'Merge a rectangular table cell range starting at a zero-based cell. Content of non-anchor cells is absorbed by the merge; use gog_slides_table_unmerge to split back.',
806
- annotations: { destructiveHint: true },
806
+ annotations: { destructiveHint: true, openWorldHint: true },
807
807
  inputSchema: z.object({
808
808
  presentationId: z.string().describe('Presentation ID'),
809
809
  tableObjectId: z.string().describe('Table object ID'),
@@ -822,7 +822,7 @@ export function registerExtraSlidesTools(server: McpServer): void {
822
822
 
823
823
  server.registerTool('gog_slides_table_unmerge', {
824
824
  description: 'Unmerge (split) a rectangular range of previously merged cells, starting at a zero-based cell.',
825
- annotations: { destructiveHint: false },
825
+ annotations: { destructiveHint: false, openWorldHint: true },
826
826
  inputSchema: z.object({
827
827
  presentationId: z.string().describe('Presentation ID'),
828
828
  tableObjectId: z.string().describe('Table object ID'),
@@ -0,0 +1,10 @@
1
+ import { authToolsFor, registerSlidesTools } from '../../gogcli-mcp/src/lib.js';
2
+ import { registerExtraSlidesTools } from '../src/tools/slides-extra.js';
3
+ import { describeToolAnnotations, LOCAL_AUTH_TOOLS } from '../../gogcli-mcp/tests/support/tool-annotations.js';
4
+
5
+ // The same registrar list src/index.ts hands to runMcp.
6
+ describeToolAnnotations([authToolsFor('slides'), registerSlidesTools, registerExtraSlidesTools] as never, {
7
+ tools: 55,
8
+ destructive: 20,
9
+ local: [...LOCAL_AUTH_TOOLS],
10
+ });