gogcli-mcp 2.27.1 → 2.29.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.
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "metadata": {
9
9
  "description": "Google Sheets (and more) for Claude via gogcli — read, write, and manage spreadsheets",
10
- "version": "2.27.1"
10
+ "version": "2.29.0"
11
11
  },
12
12
  "plugins": [
13
13
  {
@@ -15,7 +15,7 @@
15
15
  "displayName": "gogcli",
16
16
  "source": "./",
17
17
  "description": "Google Sheets (and more) for Claude via gogcli — read, write, and manage spreadsheets",
18
- "version": "2.27.1",
18
+ "version": "2.29.0",
19
19
  "author": {
20
20
  "name": "Chris Hall"
21
21
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gogcli-mcp",
3
3
  "displayName": "gogcli",
4
- "version": "2.27.1",
4
+ "version": "2.29.0",
5
5
  "description": "Google Sheets (and more) for Claude via gogcli — read, write, and manage spreadsheets",
6
6
  "author": {
7
7
  "name": "Chris Hall",
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  > [!WARNING]
4
4
  > **AI-developed project.** This codebase was built and is actively maintained by [Claude Code](https://www.anthropic.com/claude). Review all code and tool permissions before use.
5
5
 
6
- Base [Model Context Protocol](https://modelcontextprotocol.io) server that gives Claude access to Google Workspace via [gogcli](https://github.com/openclaw/gogcli). Includes 114 tools across 13 services: Sheets, Docs, Gmail, Calendar, Drive, Slides, Classroom, Chat, Apps Script, Tasks, Contacts, the generic Discovery API escape hatch, and Auth.
6
+ Base [Model Context Protocol](https://modelcontextprotocol.io) server that gives Claude access to Google Workspace via [gogcli](https://github.com/openclaw/gogcli). Includes 115 tools across 13 services: Sheets, Docs, Gmail, Calendar, Drive, Slides, Classroom, Chat, Apps Script, Tasks, Contacts, the generic Discovery API escape hatch, and Auth.
7
7
 
8
8
  For extended Sheets or Docs support, see [gogcli-mcp-sheets](https://www.npmjs.com/package/gogcli-mcp-sheets) and [gogcli-mcp-docs](https://www.npmjs.com/package/gogcli-mcp-docs).
9
9
 
@@ -46,7 +46,7 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
46
46
  claude mcp add gogcli-mcp -- gogcli-mcp
47
47
  ```
48
48
 
49
- ## Tools (114)
49
+ ## Tools (115)
50
50
 
51
51
  | Service | Tools | Includes |
52
52
  |---------|-------|----------|
@@ -57,7 +57,7 @@ claude mcp add gogcli-mcp -- gogcli-mcp
57
57
  | **Drive** | 11 | ls, search, get, mkdir, rename, move, delete, share, extract-text, read-bytes, run |
58
58
  | **Slides** | 7 | export, info, create, copy, list-slides, read-slide, run |
59
59
  | **Classroom** | 25 | courses, students, teachers, roster, coursework, submissions (grade/return/turn-in/reclaim), announcements, topics, invitations, profile, run |
60
- | **Chat** | 12 | spaces list/find/create, threads list, messages list/send, dm send/space, reactions list/create/delete, run |
60
+ | **Chat** | 13 | spaces list/find/create, threads list, messages list/search/send, dm send/space, reactions list/create/delete, run |
61
61
  | **Apps Script** | 8 | get, content, pull, create, deployments, versions, run-function, run |
62
62
  | **Tasks** | 7 | lists, list, get, add, done, delete, run |
63
63
  | **Contacts** | 5 | search, list, get, create, run |
package/SKILL.md CHANGED
@@ -32,7 +32,7 @@ MCP server wrapping [gogcli](https://github.com/openclaw/gogcli) — provides Cl
32
32
 
33
33
  `GOG_ACCOUNT` is optional — omit it to use gogcli's configured default account.
34
34
 
35
- ## Tools (114)
35
+ ## Tools (115)
36
36
 
37
37
  | Service | Tools |
38
38
  |---------|-------|
@@ -43,7 +43,7 @@ MCP server wrapping [gogcli](https://github.com/openclaw/gogcli) — provides Cl
43
43
  | **Drive** (11) | ls, search, get, mkdir, rename, move, delete, share, extract-text, read-bytes, run |
44
44
  | **Slides** (7) | export, info, create, copy, list-slides, read-slide, run |
45
45
  | **Classroom** (25) | courses, students, teachers, roster, coursework, submissions (grade/return/turn-in/reclaim), announcements, topics, invitations, profile, run |
46
- | **Chat** (12) | spaces list/find/create, threads list, messages list/send, dm send/space, reactions list/create/delete, run |
46
+ | **Chat** (13) | spaces list/find/create, threads list, messages list/search/send, dm send/space, reactions list/create/delete, run |
47
47
  | **Apps Script** (8) | get, content, pull, create, deployments, versions, run-function, run |
48
48
  | **Tasks** (7) | lists, list, get, add, done, delete, run |
49
49
  | **Contacts** (5) | search, list, get, create, run |
package/dist/index.js CHANGED
@@ -31323,6 +31323,77 @@ function redactSecrets(text) {
31323
31323
  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]");
31324
31324
  }
31325
31325
 
31326
+ // ../../node_modules/@chrischall/mcp-utils/dist/response/view.js
31327
+ var VIEWS = ["compact", "full", "raw"];
31328
+ var DEFAULT_VIEW = "compact";
31329
+ var BLURB = {
31330
+ compact: '"compact" (default) drops fields the response already carries elsewhere',
31331
+ full: '"full" returns every field this server understands',
31332
+ raw: '"raw" returns the upstream payload unprojected'
31333
+ };
31334
+ function viewParam(honoured, opts = {}) {
31335
+ if (honoured.length < 2) {
31336
+ throw new Error("viewParam needs at least two rungs: a parameter offering one value decides nothing");
31337
+ }
31338
+ if (!honoured.includes("compact")) {
31339
+ throw new Error('viewParam must offer "compact": a tool with no cheap rung has nothing to default to');
31340
+ }
31341
+ const ordered = VIEWS.filter((v) => honoured.includes(v));
31342
+ const sentence = `Response shape: ${ordered.map((v) => BLURB[v]).join("; ")}.`;
31343
+ return external_exports.enum(Object.fromEntries(ordered.map((v) => [v, v]))).optional().describe(opts.note ? `${sentence} ${opts.note}` : sentence);
31344
+ }
31345
+ function resolveView(value, honoured) {
31346
+ return value !== void 0 && honoured.includes(value) ? value : DEFAULT_VIEW;
31347
+ }
31348
+ function minifiedResult(data) {
31349
+ return { content: [{ type: "text", text: JSON.stringify(data) }] };
31350
+ }
31351
+
31352
+ // ../../node_modules/@chrischall/mcp-utils/dist/response/media.js
31353
+ var MEDIA_NOUN = "(?:avatar|tall_avatar|cover_photo|cover_image|picture|photo|thumbnail|thumb|image|icon|banner|profile_pic(?:ture)?|logo)";
31354
+ var MEDIA_KEY = new RegExp(`^${MEDIA_NOUN}s?(?:(?:link|uri|url)s?)?$`, "i");
31355
+ var MEDIA_URL = /^https?:\/\/[^\s]+?\.(png|jpe?g|gif|webp|svg|avif|bmp|ico)([?#]|$)/i;
31356
+ function stripMediaUrls(value, opts = {}) {
31357
+ const keep = new Set((opts.keep ?? []).map((k) => k.toLowerCase()));
31358
+ const drop = (opts.drop ?? []).map((rule) => typeof rule === "string" ? rule.toLowerCase() : new RegExp(rule.source, rule.flags));
31359
+ return walk(value, keep, drop);
31360
+ }
31361
+ function alsoDrop(key, drop) {
31362
+ const lower = key.toLowerCase();
31363
+ for (const rule of drop) {
31364
+ if (typeof rule === "string") {
31365
+ if (rule === lower)
31366
+ return true;
31367
+ continue;
31368
+ }
31369
+ rule.lastIndex = 0;
31370
+ if (rule.test(key))
31371
+ return true;
31372
+ }
31373
+ return false;
31374
+ }
31375
+ function walk(value, keep, drop) {
31376
+ if (Array.isArray(value))
31377
+ return value.map((v) => walk(v, keep, drop));
31378
+ if (value === null || typeof value !== "object")
31379
+ return value;
31380
+ if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
31381
+ return value;
31382
+ const out = {};
31383
+ for (const [key, v] of Object.entries(value)) {
31384
+ if (keep.has(key.toLowerCase())) {
31385
+ out[key] = v;
31386
+ continue;
31387
+ }
31388
+ if (MEDIA_KEY.test(key) || alsoDrop(key, drop))
31389
+ continue;
31390
+ if (typeof v === "string" && MEDIA_URL.test(v))
31391
+ continue;
31392
+ out[key] = walk(v, keep, drop);
31393
+ }
31394
+ return out;
31395
+ }
31396
+
31326
31397
  // ../../node_modules/@chrischall/mcp-utils/dist/response/index.js
31327
31398
  function rawTextResult(text) {
31328
31399
  return { content: [{ type: "text", text }] };
@@ -31852,11 +31923,11 @@ function parseTimestampValue(key, value, assumeNaiveIn) {
31852
31923
  }
31853
31924
  return null;
31854
31925
  }
31855
- function walk(node, tz, naiveTz) {
31926
+ function walk2(node, tz, naiveTz) {
31856
31927
  let changed = false;
31857
31928
  if (Array.isArray(node)) {
31858
31929
  for (const item of node) {
31859
- if (walk(item, tz, naiveTz)) changed = true;
31930
+ if (walk2(item, tz, naiveTz)) changed = true;
31860
31931
  }
31861
31932
  return changed;
31862
31933
  }
@@ -31865,7 +31936,7 @@ function walk(node, tz, naiveTz) {
31865
31936
  for (const key of Object.keys(obj)) {
31866
31937
  const value = obj[key];
31867
31938
  if (value !== null && typeof value === "object") {
31868
- if (walk(value, tz, naiveTz)) changed = true;
31939
+ if (walk2(value, tz, naiveTz)) changed = true;
31869
31940
  continue;
31870
31941
  }
31871
31942
  if (ZONE_NAME_KEYS.has(key) || !TIMESTAMP_KEYS.has(key)) continue;
@@ -31891,7 +31962,7 @@ function normalizeTimestamps(text, tz = displayTimeZone(), naiveTz = naiveSource
31891
31962
  } catch {
31892
31963
  return text;
31893
31964
  }
31894
- if (!walk(parsed, tz, naiveTz)) return text;
31965
+ if (!walk2(parsed, tz, naiveTz)) return text;
31895
31966
  return JSON.stringify(parsed, null, detectIndent(text));
31896
31967
  }
31897
31968
 
@@ -32069,10 +32140,38 @@ ${accounts || "(none)"}${hint}`);
32069
32140
  return errorResult(`${errText}${hint}`);
32070
32141
  }
32071
32142
  }
32143
+ function minifiedOrRawText(text, stripMedia = false) {
32144
+ const trimmed = text.trim();
32145
+ if (trimmed === "" || !/^[[{]/.test(trimmed)) return rawTextResult(text);
32146
+ try {
32147
+ const parsed = JSON.parse(trimmed);
32148
+ return minifiedResult(stripMedia ? stripMediaUrls(parsed) : parsed);
32149
+ } catch {
32150
+ return rawTextResult(text);
32151
+ }
32152
+ }
32153
+ function isRejectedFieldMask(err) {
32154
+ return /invalidParameter|invalid field selection/i.test(String(err));
32155
+ }
32156
+ async function runProjected(args, options) {
32157
+ const { fieldsMask } = options;
32158
+ if (!fieldsMask) return run(args, options);
32159
+ try {
32160
+ return await run([...args, `--fields=${fieldsMask}`], options);
32161
+ } catch (err) {
32162
+ if (!isRejectedFieldMask(err)) throw err;
32163
+ process.stderr.write(
32164
+ `gogcli-mcp: Google rejected the compact field mask (${fieldsMask}); retrying unprojected
32165
+ `
32166
+ );
32167
+ return run(args, options);
32168
+ }
32169
+ }
32072
32170
  async function runOrDiagnose(args, options) {
32073
32171
  try {
32074
- const raw = await run(args, options);
32075
- return rawTextResult(options.lossless ? raw : stripConsumedPageToken(normalizeTimestamps(raw)));
32172
+ const raw = await runProjected(args, options);
32173
+ if (options.lossless) return rawTextResult(raw);
32174
+ return minifiedOrRawText(stripConsumedPageToken(normalizeTimestamps(raw)), options.stripMedia);
32076
32175
  } catch (err) {
32077
32176
  return diagnose(err);
32078
32177
  }
@@ -32446,6 +32545,7 @@ function pushReminderFlags(args, p) {
32446
32545
  }
32447
32546
  for (const reminder of p.reminders) args.push(`--reminder=${reminder}`);
32448
32547
  }
32548
+ var CALENDAR_EVENTS_COMPACT_FIELDS = "nextPageToken,items(id,summary,start,end,location,status,htmlLink)";
32449
32549
  function registerCalendarTools(server) {
32450
32550
  server.registerTool("gog_calendar_events", {
32451
32551
  description: 'List calendar events. Describe the window ONE way and one way only (gog >= 0.36.0 rejects the rest as ambiguous rather than silently discarding a flag): today on its own; or from + to; or from + days; or days on its own (a window of that many days starting today). today cannot be combined with from, to or days, and days cannot be combined with to. gog returns only 10 events by default, so a wide date range is USUALLY INCOMPLETE: raise max, or page with pageToken until the response carries no nextPageToken. A response carrying "truncated": true is an incomplete view \u2014 never conclude an event does not exist from one.',
@@ -32468,9 +32568,12 @@ function registerCalendarTools(server) {
32468
32568
  all: external_exports.boolean().optional().describe('Fetch events from ALL CALENDARS. NOTE: unlike the gmail search tools, this does NOT mean "all pages" \u2014 it widens the calendar set, not the page window. Use pageToken to reach later pages.'),
32469
32569
  eventTypes: external_exports.array(external_exports.enum(["default", "birthday", "focus-time", "from-gmail", "out-of-office", "working-location"])).optional().describe("Filter to specific event types (repeatable)"),
32470
32570
  timezone: external_exports.string().optional().describe(`Display timezone for event times (IANA name, e.g. America/New_York, or "local" for the system timezone). Default: each event's timezone, then its calendar's timezone.`),
32571
+ view: viewParam(["compact", "full"], {
32572
+ note: "compact (the default) drops description and attendees \u2014 together two thirds of a listing's bytes \u2014 plus etag/iCalUID/kind. Ask for full when you need a body or a guest list."
32573
+ }),
32471
32574
  account: accountParam
32472
32575
  }
32473
- }, async ({ calendarId, from, to, days, today, query, max, pageToken, page, all, eventTypes, timezone, account }) => {
32576
+ }, async ({ calendarId, from, to, days, today, query, max, pageToken, page, all, eventTypes, timezone, view, account }) => {
32474
32577
  const args = ["calendar", "events"];
32475
32578
  if (calendarId) args.push(calendarId);
32476
32579
  if (from) args.push(`--from=${from}`);
@@ -32484,7 +32587,11 @@ function registerCalendarTools(server) {
32484
32587
  if (all) args.push("--all");
32485
32588
  if (eventTypes) for (const t of eventTypes) args.push(`--event-types=${t}`);
32486
32589
  if (timezone) args.push(`--timezone=${timezone}`);
32487
- const result = await runOrDiagnose(args, { account });
32590
+ const rung = resolveView(view, ["compact", "full"]);
32591
+ const result = await runOrDiagnose(args, {
32592
+ account,
32593
+ fieldsMask: rung === "compact" ? CALENDAR_EVENTS_COMPACT_FIELDS : void 0
32594
+ });
32488
32595
  return annotateTruncatedList(result, "events");
32489
32596
  });
32490
32597
  server.registerTool("gog_calendar_get", {
@@ -32755,6 +32862,30 @@ function registerChatTools(server) {
32755
32862
  pushPaginationFlags(args, { max, pageToken, page, all });
32756
32863
  return runOrDiagnose(args, { account });
32757
32864
  });
32865
+ server.registerTool("gog_chat_messages_search", {
32866
+ description: 'Search Chat messages ACROSS every space and DM the account can see (gog >= 0.39.0) \u2014 the tool to reach for when the user asks "where did we discuss X" without naming a room, since gog_chat_messages_list needs a space up front. The query is Google Chat filter syntax, so it takes plain keywords or filters like sender, space, date, mention, unread, link and attachment. It is a search, NOT an export: Chat excludes some conversations (muted spaces among them), so an empty result does not prove a message never existed. view="full" adds each hit\'s read state and space mute setting; read state works on an ordinary chat grant, but the mute setting needs chat.users.spacesettings, which gog\'s chat scope set does NOT request (re-auth with extraScopes to get it). Missing metadata is OMITTED rather than defaulted, so an absent `read` means unknown while an explicit false means unread.' + workspaceOnlyNote,
32867
+ annotations: { readOnlyHint: true },
32868
+ inputSchema: {
32869
+ query: external_exports.string().describe('Google Chat filter-syntax query \u2014 keywords, or filters such as "from:alice@example.com budget"'),
32870
+ order: external_exports.enum(["create_time desc", "relevance desc"]).optional().describe(
32871
+ `Sort order. NOTE the snake_case, which differs from gog_chat_messages_list's camelCase. "relevance desc" needs Google Developer Preview access and errors without it`
32872
+ ),
32873
+ view: external_exports.enum(["basic", "full"]).optional().describe(
32874
+ 'Result view (default "basic"). "full" also requests read state (covered by an ordinary chat grant) and space mute setting (needs chat.users.spacesettings, which that grant does not include)'
32875
+ ),
32876
+ markup: external_exports.enum(["chat", "markdown"]).optional().describe("Syntax to render each hit's formatted text in"),
32877
+ ...paginationParams,
32878
+ max: external_exports.number().int().min(1).max(100).optional().describe("Max results per page (1-100; Chat search caps a page at 100)"),
32879
+ account: accountParam
32880
+ }
32881
+ }, async ({ query, order, view, markup, max, pageToken, page, all, account }) => {
32882
+ const args = ["chat", "messages", "search", query];
32883
+ if (order) args.push(`--order=${order}`);
32884
+ if (view) args.push(`--view=${view}`);
32885
+ if (markup) args.push(`--markup=${markup}`);
32886
+ pushPaginationFlags(args, { max, pageToken, page, all });
32887
+ return runOrDiagnose(args, { account });
32888
+ });
32758
32889
  server.registerTool("gog_chat_messages_send", {
32759
32890
  description: "Post a message to a Chat space. THIS IS IMMEDIATELY VISIBLE TO EVERYONE IN THE SPACE and cannot be unsent through this tool, so treat it like sending mail, not like saving a draft. Pass `thread` to reply inside an existing conversation (from gog_chat_threads_list or a message's thread field); omit it to start a new one. Text supports Chat's markdown-ish formatting (*bold*, _italic_, `code`)." + workspaceOnlyNote,
32760
32891
  inputSchema: {
@@ -33393,6 +33524,7 @@ function fileMeta(raw) {
33393
33524
  const f = parsed.file ?? parsed;
33394
33525
  return { name: f.name, mimeType: f.mimeType };
33395
33526
  }
33527
+ var DRIVE_LS_COMPACT_FIELDS = "nextPageToken,files(id,name,mimeType,modifiedTime,size,webViewLink)";
33396
33528
  function registerDriveTools(server) {
33397
33529
  server.registerTool("gog_drive_ls", {
33398
33530
  description: "List files in a Google Drive folder (default: root).",
@@ -33404,9 +33536,12 @@ function registerDriveTools(server) {
33404
33536
  page: pageAliasParam,
33405
33537
  query: external_exports.string().optional().describe(`Drive query filter (e.g. "name contains 'budget'")`),
33406
33538
  allDrives: external_exports.boolean().optional().describe("Include shared drives (default: true). Set false for My Drive only."),
33539
+ view: viewParam(["compact", "full"], {
33540
+ note: "compact (the default) drops owners, parents, thumbnailLink and hasThumbnail \u2014 near-constant across a listing and 48% of its bytes. Ask for full to get them."
33541
+ }),
33407
33542
  account: accountParam
33408
33543
  }
33409
- }, async ({ folderId, max, pageToken, page, query, allDrives, account }) => {
33544
+ }, async ({ folderId, max, pageToken, page, query, allDrives, view, account }) => {
33410
33545
  const args = ["drive", "ls"];
33411
33546
  if (folderId) args.push(`--parent=${folderId}`);
33412
33547
  if (max !== void 0) args.push(`--max=${max}`);
@@ -33414,27 +33549,48 @@ function registerDriveTools(server) {
33414
33549
  if (token) args.push(`--page=${token}`);
33415
33550
  if (query) args.push(`--query=${query}`);
33416
33551
  if (allDrives === false) args.push("--no-all-drives");
33417
- return runOrDiagnose(args, { account });
33552
+ const rung = resolveView(view, ["compact", "full"]);
33553
+ return runOrDiagnose(args, {
33554
+ account,
33555
+ fieldsMask: rung === "compact" ? DRIVE_LS_COMPACT_FIELDS : void 0
33556
+ });
33418
33557
  });
33419
33558
  server.registerTool("gog_drive_search", {
33420
33559
  description: "Search Google Drive files by full-text query.",
33421
33560
  annotations: { readOnlyHint: true },
33422
33561
  inputSchema: {
33423
33562
  query: external_exports.string().describe("Search query"),
33563
+ // gog's `drive search` accepts no --fields mask, so unlike gog_drive_ls
33564
+ // this tool's compact rung is a LOCAL projection. Same vocabulary either
33565
+ // way: a caller does not need to know which lever is being pulled.
33566
+ view: viewParam(["compact", "full"], { note: "compact (the default) drops thumbnailLink \u2014 a URL a model cannot see, and 30%+ of a Drive file record. Ask for full to get it back." }),
33424
33567
  account: accountParam
33425
33568
  }
33426
- }, async ({ query, account }) => {
33427
- return runOrDiagnose(["drive", "search", query], { account });
33569
+ }, async ({ query, view, account }) => {
33570
+ return runOrDiagnose(["drive", "search", query], {
33571
+ account,
33572
+ stripMedia: resolveView(view, ["compact", "full"]) === "compact"
33573
+ });
33428
33574
  });
33429
33575
  server.registerTool("gog_drive_get", {
33430
33576
  description: "Get metadata for a Google Drive file.",
33431
33577
  annotations: { readOnlyHint: true },
33432
33578
  inputSchema: {
33433
33579
  fileId: external_exports.string().describe("File ID"),
33580
+ // A --fields mask saves only 7% here: the default set is already narrow,
33581
+ // which is why this tool takes no mask. The media strip saves 27.5% of
33582
+ // the tool's actual output, measured end to end over stdio, which is why
33583
+ // it takes a view after all. (An earlier note said 32.9%; that was a
33584
+ // minified-vs-stripped comparison of the raw gog payload rather than of
33585
+ // what the tool returns. The end-to-end figure is the one a caller sees.)
33586
+ view: viewParam(["compact", "full"], { note: "compact (the default) drops thumbnailLink \u2014 a URL a model cannot see, and 30%+ of a Drive file record. Ask for full to get it back." }),
33434
33587
  account: accountParam
33435
33588
  }
33436
- }, async ({ fileId, account }) => {
33437
- return runOrDiagnose(["drive", "get", fileId], { account });
33589
+ }, async ({ fileId, view, account }) => {
33590
+ return runOrDiagnose(["drive", "get", fileId], {
33591
+ account,
33592
+ stripMedia: resolveView(view, ["compact", "full"]) === "compact"
33593
+ });
33438
33594
  });
33439
33595
  server.registerTool("gog_drive_mkdir", {
33440
33596
  description: "Create a new folder in Google Drive.",
@@ -34167,7 +34323,7 @@ function registerTasksTools(server) {
34167
34323
  }
34168
34324
 
34169
34325
  // src/server.ts
34170
- var VERSION = true ? "2.27.1" : "0.0.0";
34326
+ var VERSION = true ? "2.29.0" : "0.0.0";
34171
34327
  var BASE_TOOL_REGISTRARS = [
34172
34328
  registerApiTools,
34173
34329
  registerAppScriptTools,