gogcli-mcp-drive 2.23.1 → 2.24.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": "Extended Google Drive for Claude via gogcli — auth + full Drive support (upload, download, permissions, comments, shared drives)",
10
- "version": "2.23.1"
10
+ "version": "2.24.0"
11
11
  },
12
12
  "plugins": [
13
13
  {
@@ -15,7 +15,7 @@
15
15
  "displayName": "gogcli (Drive)",
16
16
  "source": "./",
17
17
  "description": "Extended Google Drive for Claude via gogcli — auth + full Drive support (upload, download, permissions, comments, shared drives)",
18
- "version": "2.23.1",
18
+ "version": "2.24.0",
19
19
  "author": {
20
20
  "name": "Chris Hall"
21
21
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gogcli-mcp-drive",
3
3
  "displayName": "gogcli (Drive)",
4
- "version": "2.23.1",
4
+ "version": "2.24.0",
5
5
  "description": "Extended Google Drive for Claude via gogcli — auth + full Drive support (upload, download, permissions, comments, shared drives)",
6
6
  "author": {
7
7
  "name": "Chris Hall",
package/dist/index.js CHANGED
@@ -31552,6 +31552,26 @@ function normalizeTimestamps(text, tz = displayTimeZone(), naiveTz = naiveSource
31552
31552
  return JSON.stringify(parsed, null, detectIndent(text));
31553
31553
  }
31554
31554
 
31555
+ // ../gogcli-mcp/src/pagination.ts
31556
+ function detectIndent2(text) {
31557
+ const match = /\n(\s+)\S/.exec(text);
31558
+ return match ? match[1].replace(/\t/g, " ").length : 0;
31559
+ }
31560
+ function stripConsumedPageToken(text) {
31561
+ const trimmed = text.trim();
31562
+ if (trimmed === "" || !trimmed.startsWith("{")) return text;
31563
+ let parsed;
31564
+ try {
31565
+ parsed = JSON.parse(trimmed);
31566
+ } catch {
31567
+ return text;
31568
+ }
31569
+ const obj = parsed;
31570
+ if (obj.nextPageToken !== "") return text;
31571
+ delete obj.nextPageToken;
31572
+ return JSON.stringify(obj, null, detectIndent2(text));
31573
+ }
31574
+
31555
31575
  // ../gogcli-mcp/src/tools/utils.ts
31556
31576
  var accountParam = external_exports.string().optional().describe(
31557
31577
  "Google account email to use, e.g. you@gmail.com \u2014 must be the full address, not a bare username. Overrides the GOG_ACCOUNT env var. Omit to use the single configured account."
@@ -31580,14 +31600,25 @@ var ids = {
31580
31600
  // People API uses fully-qualified resource names ("people/c123") not bare IDs.
31581
31601
  person: external_exports.string().describe("Person resource name (people/...) or email")
31582
31602
  };
31603
+ var pageTokenParam = external_exports.string().optional().describe(
31604
+ "Cursor for the NEXT page. Pass back the nextPageToken from a previous response verbatim, keeping the query and max identical: call once, then call again with pageToken=<that value>. A response with NO nextPageToken is the last page."
31605
+ );
31606
+ var pageAliasParam = external_exports.string().optional().describe(
31607
+ "Deprecated alias for pageToken, accepted so existing callers keep working. Use pageToken \u2014 it matches the nextPageToken field in the response."
31608
+ );
31609
+ function resolvePageToken(p) {
31610
+ return p.pageToken ?? p.page;
31611
+ }
31583
31612
  var paginationParams = {
31584
31613
  max: external_exports.number().int().optional().describe("Max results"),
31585
- page: external_exports.string().optional().describe("Page token"),
31614
+ pageToken: pageTokenParam,
31615
+ page: pageAliasParam,
31586
31616
  all: external_exports.boolean().optional().describe("Fetch all pages")
31587
31617
  };
31588
31618
  function pushPaginationFlags(args, p) {
31589
31619
  if (p.max !== void 0) args.push(`--max=${p.max}`);
31590
- if (p.page) args.push(`--page=${p.page}`);
31620
+ const token = resolvePageToken(p);
31621
+ if (token) args.push(`--page=${token}`);
31591
31622
  if (p.all) args.push("--all");
31592
31623
  }
31593
31624
  function registerRunTool(server, options) {
@@ -31662,7 +31693,7 @@ ${accounts || "(none)"}${hint}`);
31662
31693
  async function runOrDiagnose(args, options) {
31663
31694
  try {
31664
31695
  const raw = await run(args, options);
31665
- return rawTextResult(options.lossless ? raw : normalizeTimestamps(raw));
31696
+ return rawTextResult(options.lossless ? raw : stripConsumedPageToken(normalizeTimestamps(raw)));
31666
31697
  } catch (err) {
31667
31698
  return diagnose(err);
31668
31699
  }
@@ -31712,6 +31743,7 @@ function formatAuthHealth(raw, now) {
31712
31743
  // ../gogcli-mcp/src/tools/auth.ts
31713
31744
  function registerAuthToolsWith(server, defaultServices) {
31714
31745
  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.`;
31746
+ 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.";
31715
31747
  server.registerTool("gog_auth_list", {
31716
31748
  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.",
31717
31749
  annotations: { readOnlyHint: true },
@@ -31761,11 +31793,14 @@ function registerAuthToolsWith(server, defaultServices) {
31761
31793
  annotations: { destructiveHint: true },
31762
31794
  inputSchema: {
31763
31795
  email: external_exports.string().describe("Google account email to authorize"),
31764
- services: external_exports.string().optional().default(defaultServices).describe(servicesDescribe)
31796
+ services: external_exports.string().optional().default(defaultServices).describe(servicesDescribe),
31797
+ extraScopes: external_exports.string().optional().describe(extraScopesDescribe)
31765
31798
  }
31766
- }, async ({ email: email3, services = defaultServices }) => {
31799
+ }, async ({ email: email3, services = defaultServices, extraScopes }) => {
31767
31800
  try {
31768
- return rawTextResult(await run(["auth", "add", email3, "--services", services], {
31801
+ const args = ["auth", "add", email3, "--services", services];
31802
+ if (extraScopes) args.push(`--extra-scopes=${extraScopes}`, "--force-consent");
31803
+ return rawTextResult(await run(args, {
31769
31804
  interactive: true,
31770
31805
  timeout: 3e5
31771
31806
  }));
@@ -31777,14 +31812,14 @@ function registerAuthToolsWith(server, defaultServices) {
31777
31812
  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 over the hosted connector 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.",
31778
31813
  inputSchema: {
31779
31814
  email: external_exports.string().describe("Google account email to authorize"),
31780
- services: external_exports.string().optional().default(defaultServices).describe(servicesDescribe)
31815
+ services: external_exports.string().optional().default(defaultServices).describe(servicesDescribe),
31816
+ extraScopes: external_exports.string().optional().describe(`${extraScopesDescribe} Pass the SAME value to gog_auth_add_complete.`)
31781
31817
  }
31782
- }, async ({ email: email3, services = defaultServices }) => {
31818
+ }, async ({ email: email3, services = defaultServices, extraScopes }) => {
31783
31819
  try {
31784
- return rawTextResult(await run(
31785
- ["auth", "add", email3, "--remote", "--step", "1", "--services", services, "--force-consent"],
31786
- { redactMode: "tokens" }
31787
- ));
31820
+ const args = ["auth", "add", email3, "--remote", "--step", "1", "--services", services, "--force-consent"];
31821
+ if (extraScopes) args.push(`--extra-scopes=${extraScopes}`);
31822
+ return rawTextResult(await run(args, { redactMode: "tokens" }));
31788
31823
  } catch (err) {
31789
31824
  return errorResult(errorText(err));
31790
31825
  }
@@ -31799,25 +31834,28 @@ function registerAuthToolsWith(server, defaultServices) {
31799
31834
  ),
31800
31835
  services: external_exports.string().optional().default(defaultServices).describe(
31801
31836
  `Services authorized \u2014 MUST match the value passed to gog_auth_add_url. Default: "${defaultServices}".`
31837
+ ),
31838
+ extraScopes: external_exports.string().optional().describe(
31839
+ "Extra OAuth scope URIs \u2014 MUST match the value passed to gog_auth_add_url, for the same reason `services` must: the two steps have to describe the same grant."
31802
31840
  )
31803
31841
  }
31804
- }, async ({ email: email3, redirectUrl, services = defaultServices }) => {
31842
+ }, async ({ email: email3, redirectUrl, services = defaultServices, extraScopes }) => {
31805
31843
  try {
31806
- return rawTextResult(await run(
31807
- [
31808
- "auth",
31809
- "add",
31810
- email3,
31811
- "--remote",
31812
- "--step",
31813
- "2",
31814
- "--auth-url",
31815
- redirectUrl,
31816
- "--services",
31817
- services,
31818
- "--force-consent"
31819
- ]
31820
- ));
31844
+ const args = [
31845
+ "auth",
31846
+ "add",
31847
+ email3,
31848
+ "--remote",
31849
+ "--step",
31850
+ "2",
31851
+ "--auth-url",
31852
+ redirectUrl,
31853
+ "--services",
31854
+ services,
31855
+ "--force-consent"
31856
+ ];
31857
+ if (extraScopes) args.push(`--extra-scopes=${extraScopes}`);
31858
+ return rawTextResult(await run(args));
31821
31859
  } catch (err) {
31822
31860
  return errorResult(errorText(err));
31823
31861
  }
@@ -31847,16 +31885,18 @@ function registerDriveTools(server) {
31847
31885
  inputSchema: {
31848
31886
  folderId: external_exports.string().optional().describe("Folder ID to list (default: root)"),
31849
31887
  max: external_exports.number().optional().describe("Max results (default: 20)"),
31850
- page: external_exports.string().optional().describe("Page token for pagination"),
31888
+ pageToken: pageTokenParam,
31889
+ page: pageAliasParam,
31851
31890
  query: external_exports.string().optional().describe(`Drive query filter (e.g. "name contains 'budget'")`),
31852
31891
  allDrives: external_exports.boolean().optional().describe("Include shared drives (default: true). Set false for My Drive only."),
31853
31892
  account: accountParam
31854
31893
  }
31855
- }, async ({ folderId, max, page, query, allDrives, account }) => {
31894
+ }, async ({ folderId, max, pageToken, page, query, allDrives, account }) => {
31856
31895
  const args = ["drive", "ls"];
31857
31896
  if (folderId) args.push(`--parent=${folderId}`);
31858
31897
  if (max !== void 0) args.push(`--max=${max}`);
31859
- if (page) args.push(`--page=${page}`);
31898
+ const token = resolvePageToken({ pageToken, page });
31899
+ if (token) args.push(`--page=${token}`);
31860
31900
  if (query) args.push(`--query=${query}`);
31861
31901
  if (allDrives === false) args.push("--no-all-drives");
31862
31902
  return runOrDiagnose(args, { account });
@@ -32056,7 +32096,7 @@ var failIfNotEmptyParam = external_exports.boolean().optional().describe(
32056
32096
  );
32057
32097
 
32058
32098
  // ../gogcli-mcp/src/server.ts
32059
- var VERSION = true ? "2.23.1" : "0.0.0";
32099
+ var VERSION = true ? "2.24.0" : "0.0.0";
32060
32100
 
32061
32101
  // ../gogcli-mcp/src/auth-log.ts
32062
32102
  var FAILURES = /* @__PURE__ */ new Set([
@@ -32638,13 +32678,15 @@ function registerExtraDriveTools(server) {
32638
32678
  inputSchema: {
32639
32679
  fileId: external_exports.string().describe("File ID"),
32640
32680
  max: external_exports.number().optional().describe("Max results (default: 100)"),
32641
- page: external_exports.string().optional().describe("Page token"),
32681
+ pageToken: pageTokenParam,
32682
+ page: pageAliasParam,
32642
32683
  account: accountParam
32643
32684
  }
32644
- }, async ({ fileId, max, page, account }) => {
32685
+ }, async ({ fileId, max, pageToken, page, account }) => {
32645
32686
  const args = ["drive", "permissions", fileId];
32646
32687
  if (max !== void 0) args.push(`--max=${max}`);
32647
- if (page) args.push(`--page=${page}`);
32688
+ const token = resolvePageToken({ pageToken, page });
32689
+ if (token) args.push(`--page=${token}`);
32648
32690
  return runOrDiagnose(args, { account });
32649
32691
  });
32650
32692
  server.registerTool("gog_drive_unshare", {
@@ -32663,15 +32705,17 @@ function registerExtraDriveTools(server) {
32663
32705
  annotations: { readOnlyHint: true },
32664
32706
  inputSchema: {
32665
32707
  max: external_exports.number().optional().describe("Max results (default: 100, max allowed: 100)"),
32666
- page: external_exports.string().optional().describe("Page token"),
32708
+ pageToken: pageTokenParam,
32709
+ page: pageAliasParam,
32667
32710
  all: external_exports.boolean().optional().describe("Fetch all pages"),
32668
32711
  query: external_exports.string().optional().describe("Search query for filtering shared drives"),
32669
32712
  account: accountParam
32670
32713
  }
32671
- }, async ({ max, page, all, query, account }) => {
32714
+ }, async ({ max, pageToken, page, all, query, account }) => {
32672
32715
  const args = ["drive", "drives"];
32673
32716
  if (max !== void 0) args.push(`--max=${max}`);
32674
- if (page) args.push(`--page=${page}`);
32717
+ const token = resolvePageToken({ pageToken, page });
32718
+ if (token) args.push(`--page=${token}`);
32675
32719
  if (all) args.push("--all");
32676
32720
  if (query) args.push(`--query=${query}`);
32677
32721
  return runOrDiagnose(args, { account });
@@ -32831,16 +32875,18 @@ function registerExtraDriveTools(server) {
32831
32875
  inputSchema: {
32832
32876
  token: external_exports.string().describe("Start page token or next page token"),
32833
32877
  max: external_exports.number().optional().describe("Max results (default: 100)"),
32834
- page: external_exports.string().optional().describe("Alias for token when continuing a page"),
32878
+ pageToken: pageTokenParam,
32879
+ page: pageAliasParam,
32835
32880
  all: external_exports.boolean().optional().describe("Fetch all pages"),
32836
32881
  includeRemoved: external_exports.boolean().optional().describe("Include removed changes"),
32837
32882
  drive: external_exports.string().optional().describe("Shared drive ID for a shared-drive change log"),
32838
32883
  account: accountParam
32839
32884
  }
32840
- }, async ({ token, max, page, all, includeRemoved, drive, account }) => {
32885
+ }, async ({ token, max, pageToken, page, all, includeRemoved, drive, account }) => {
32841
32886
  const args = ["drive", "changes", "list", `--token=${token}`];
32842
32887
  if (max !== void 0) args.push(`--max=${max}`);
32843
- if (page) args.push(`--page=${page}`);
32888
+ const cursor = resolvePageToken({ pageToken, page });
32889
+ if (cursor) args.push(`--page=${cursor}`);
32844
32890
  if (all) args.push("--all");
32845
32891
  if (includeRemoved) args.push("--include-removed");
32846
32892
  if (drive) args.push(`--drive=${drive}`);
@@ -32892,10 +32938,16 @@ function registerExtraDriveTools(server) {
32892
32938
  minimumRole: external_exports.string().optional().describe("Minimum role filter (e.g. READER, APPLIER, ORGANIZER)"),
32893
32939
  publishedOnly: external_exports.boolean().optional().describe("Only list published labels"),
32894
32940
  adminAccess: external_exports.boolean().optional().describe("Use admin access for Workspace admin accounts"),
32941
+ max: external_exports.number().int().optional().describe("Max results"),
32942
+ pageToken: pageTokenParam,
32943
+ page: pageAliasParam,
32895
32944
  account: accountParam
32896
32945
  }
32897
- }, async ({ language, view, minimumRole, publishedOnly, adminAccess, account }) => {
32946
+ }, async ({ language, view, minimumRole, publishedOnly, adminAccess, max, pageToken, page, account }) => {
32898
32947
  const args = ["drive", "labels", "list"];
32948
+ if (max !== void 0) args.push(`--max=${max}`);
32949
+ const token = resolvePageToken({ pageToken, page });
32950
+ if (token) args.push(`--page=${token}`);
32899
32951
  if (language) args.push(`--language=${language}`);
32900
32952
  if (view) args.push(`--view=${view}`);
32901
32953
  if (minimumRole) args.push(`--minimum-role=${minimumRole}`);
@@ -32926,13 +32978,15 @@ function registerExtraDriveTools(server) {
32926
32978
  inputSchema: {
32927
32979
  fileId: external_exports.string().describe("File ID"),
32928
32980
  max: external_exports.number().optional().describe("Max results (default: 100)"),
32929
- page: external_exports.string().optional().describe("Page token"),
32981
+ pageToken: pageTokenParam,
32982
+ page: pageAliasParam,
32930
32983
  account: accountParam
32931
32984
  }
32932
- }, async ({ fileId, max, page, account }) => {
32985
+ }, async ({ fileId, max, pageToken, page, account }) => {
32933
32986
  const args = ["drive", "labels", "file", "list", fileId];
32934
32987
  if (max !== void 0) args.push(`--max=${max}`);
32935
- if (page) args.push(`--page=${page}`);
32988
+ const token = resolvePageToken({ pageToken, page });
32989
+ if (token) args.push(`--page=${token}`);
32936
32990
  return runOrDiagnose(args, { account });
32937
32991
  });
32938
32992
  server.registerTool("gog_drive_labels_file_apply", {
@@ -32982,12 +33036,13 @@ function registerExtraDriveTools(server) {
32982
33036
  to: external_exports.string().optional().describe("Upper activity time bound (RFC3339)"),
32983
33037
  filter: external_exports.string().optional().describe("Raw Drive Activity filter expression appended with AND"),
32984
33038
  max: external_exports.number().optional().describe("Page size (default: 10)"),
32985
- page: external_exports.string().optional().describe("Page token"),
33039
+ pageToken: pageTokenParam,
33040
+ page: pageAliasParam,
32986
33041
  all: external_exports.boolean().optional().describe("Fetch all pages"),
32987
33042
  consolidate: external_exports.boolean().optional().describe("Use Drive Activity legacy consolidation strategy"),
32988
33043
  account: accountParam
32989
33044
  }
32990
- }, async ({ file: file2, folder, actions, from, to, filter, max, page, all, consolidate, account }) => {
33045
+ }, async ({ file: file2, folder, actions, from, to, filter, max, pageToken, page, all, consolidate, account }) => {
32991
33046
  const args = ["drive", "activity", "query"];
32992
33047
  if (file2) args.push(`--file=${file2}`);
32993
33048
  if (folder) args.push(`--folder=${folder}`);
@@ -32996,7 +33051,8 @@ function registerExtraDriveTools(server) {
32996
33051
  if (to) args.push(`--to=${to}`);
32997
33052
  if (filter) args.push(`--filter=${filter}`);
32998
33053
  if (max !== void 0) args.push(`--max=${max}`);
32999
- if (page) args.push(`--page=${page}`);
33054
+ const token = resolvePageToken({ pageToken, page });
33055
+ if (token) args.push(`--page=${token}`);
33000
33056
  if (all) args.push("--all");
33001
33057
  if (consolidate) args.push("--consolidate");
33002
33058
  return runOrDiagnose(args, { account });
package/manifest.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "manifest_version": "0.3",
4
4
  "name": "gogcli-mcp-drive",
5
5
  "display_name": "gogcli (Drive)",
6
- "version": "2.23.1",
6
+ "version": "2.24.0",
7
7
  "description": "Extended Google Drive for Claude via gogcli — auth + full Drive support (upload, download, permissions, comments, shared drives)",
8
8
  "author": {
9
9
  "name": "Chris Hall",
@@ -227,7 +227,7 @@
227
227
  },
228
228
  {
229
229
  "name": "gog_drive_labels_list",
230
- "description": "List Drive label schemas"
230
+ "description": "List Drive label schemas available to the account; paginated"
231
231
  },
232
232
  {
233
233
  "name": "gog_drive_labels_get",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gogcli-mcp-drive",
3
- "version": "2.23.1",
3
+ "version": "2.24.0",
4
4
  "mcpName": "io.github.chrischall/gogcli-mcp-drive",
5
5
  "description": "Extended Google Drive MCP server via gogcli — auth + full Drive support (upload/download/permissions/comments/shared drives)",
6
6
  "author": "Claude Code (AI) <https://www.anthropic.com/claude>",
package/server.json CHANGED
@@ -7,12 +7,12 @@
7
7
  "source": "github",
8
8
  "subfolder": "packages/gogcli-mcp-drive"
9
9
  },
10
- "version": "2.23.1",
10
+ "version": "2.24.0",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "npm",
14
14
  "identifier": "gogcli-mcp-drive",
15
- "version": "2.23.1",
15
+ "version": "2.24.0",
16
16
  "transport": {
17
17
  "type": "stdio"
18
18
  },
@@ -1,6 +1,6 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { z } from 'zod';
3
- import { accountParam, runOrDiagnose, paginationParams, pushPaginationFlags } from '../../../gogcli-mcp/src/lib.js';
3
+ import { accountParam, runOrDiagnose, paginationParams, pushPaginationFlags, pageTokenParam, pageAliasParam, resolvePageToken} from '../../../gogcli-mcp/src/lib.js';
4
4
 
5
5
  export function registerExtraDriveTools(server: McpServer): void {
6
6
  server.registerTool('gog_drive_download', {
@@ -111,13 +111,15 @@ export function registerExtraDriveTools(server: McpServer): void {
111
111
  inputSchema: {
112
112
  fileId: z.string().describe('File ID'),
113
113
  max: z.number().optional().describe('Max results (default: 100)'),
114
- page: z.string().optional().describe('Page token'),
114
+ pageToken: pageTokenParam,
115
+ page: pageAliasParam,
115
116
  account: accountParam,
116
117
  },
117
- }, async ({ fileId, max, page, account }) => {
118
+ }, async ({ fileId, max, pageToken, page, account }) => {
118
119
  const args = ['drive', 'permissions', fileId];
119
120
  if (max !== undefined) args.push(`--max=${max}`);
120
- if (page) args.push(`--page=${page}`);
121
+ const token = resolvePageToken({ pageToken, page });
122
+ if (token) args.push(`--page=${token}`);
121
123
  return runOrDiagnose(args, { account });
122
124
  });
123
125
 
@@ -138,15 +140,17 @@ export function registerExtraDriveTools(server: McpServer): void {
138
140
  annotations: { readOnlyHint: true },
139
141
  inputSchema: {
140
142
  max: z.number().optional().describe('Max results (default: 100, max allowed: 100)'),
141
- page: z.string().optional().describe('Page token'),
143
+ pageToken: pageTokenParam,
144
+ page: pageAliasParam,
142
145
  all: z.boolean().optional().describe('Fetch all pages'),
143
146
  query: z.string().optional().describe('Search query for filtering shared drives'),
144
147
  account: accountParam,
145
148
  },
146
- }, async ({ max, page, all, query, account }) => {
149
+ }, async ({ max, pageToken, page, all, query, account }) => {
147
150
  const args = ['drive', 'drives'];
148
151
  if (max !== undefined) args.push(`--max=${max}`);
149
- if (page) args.push(`--page=${page}`);
152
+ const token = resolvePageToken({ pageToken, page });
153
+ if (token) args.push(`--page=${token}`);
150
154
  if (all) args.push('--all');
151
155
  if (query) args.push(`--query=${query}`);
152
156
  return runOrDiagnose(args, { account });
@@ -320,16 +324,20 @@ export function registerExtraDriveTools(server: McpServer): void {
320
324
  inputSchema: {
321
325
  token: z.string().describe('Start page token or next page token'),
322
326
  max: z.number().optional().describe('Max results (default: 100)'),
323
- page: z.string().optional().describe('Alias for token when continuing a page'),
327
+ pageToken: pageTokenParam,
328
+ page: pageAliasParam,
324
329
  all: z.boolean().optional().describe('Fetch all pages'),
325
330
  includeRemoved: z.boolean().optional().describe('Include removed changes'),
326
331
  drive: z.string().optional().describe('Shared drive ID for a shared-drive change log'),
327
332
  account: accountParam,
328
333
  },
329
- }, async ({ token, max, page, all, includeRemoved, drive, account }) => {
334
+ }, async ({ token, max, pageToken, page, all, includeRemoved, drive, account }) => {
330
335
  const args = ['drive', 'changes', 'list', `--token=${token}`];
331
336
  if (max !== undefined) args.push(`--max=${max}`);
332
- if (page) args.push(`--page=${page}`);
337
+ // NOT `token` — this tool already binds that name to the start-page token
338
+ // it takes as a required arg, which is a different value entirely.
339
+ const cursor = resolvePageToken({ pageToken, page });
340
+ if (cursor) args.push(`--page=${cursor}`);
333
341
  if (all) args.push('--all');
334
342
  if (includeRemoved) args.push('--include-removed');
335
343
  if (drive) args.push(`--drive=${drive}`);
@@ -385,10 +393,16 @@ export function registerExtraDriveTools(server: McpServer): void {
385
393
  minimumRole: z.string().optional().describe('Minimum role filter (e.g. READER, APPLIER, ORGANIZER)'),
386
394
  publishedOnly: z.boolean().optional().describe('Only list published labels'),
387
395
  adminAccess: z.boolean().optional().describe('Use admin access for Workspace admin accounts'),
396
+ max: z.number().int().optional().describe('Max results'),
397
+ pageToken: pageTokenParam,
398
+ page: pageAliasParam,
388
399
  account: accountParam,
389
400
  },
390
- }, async ({ language, view, minimumRole, publishedOnly, adminAccess, account }) => {
401
+ }, async ({ language, view, minimumRole, publishedOnly, adminAccess, max, pageToken, page, account }) => {
391
402
  const args = ['drive', 'labels', 'list'];
403
+ if (max !== undefined) args.push(`--max=${max}`);
404
+ const token = resolvePageToken({ pageToken, page });
405
+ if (token) args.push(`--page=${token}`);
392
406
  if (language) args.push(`--language=${language}`);
393
407
  if (view) args.push(`--view=${view}`);
394
408
  if (minimumRole) args.push(`--minimum-role=${minimumRole}`);
@@ -421,13 +435,15 @@ export function registerExtraDriveTools(server: McpServer): void {
421
435
  inputSchema: {
422
436
  fileId: z.string().describe('File ID'),
423
437
  max: z.number().optional().describe('Max results (default: 100)'),
424
- page: z.string().optional().describe('Page token'),
438
+ pageToken: pageTokenParam,
439
+ page: pageAliasParam,
425
440
  account: accountParam,
426
441
  },
427
- }, async ({ fileId, max, page, account }) => {
442
+ }, async ({ fileId, max, pageToken, page, account }) => {
428
443
  const args = ['drive', 'labels', 'file', 'list', fileId];
429
444
  if (max !== undefined) args.push(`--max=${max}`);
430
- if (page) args.push(`--page=${page}`);
445
+ const token = resolvePageToken({ pageToken, page });
446
+ if (token) args.push(`--page=${token}`);
431
447
  return runOrDiagnose(args, { account });
432
448
  });
433
449
 
@@ -480,12 +496,13 @@ export function registerExtraDriveTools(server: McpServer): void {
480
496
  to: z.string().optional().describe('Upper activity time bound (RFC3339)'),
481
497
  filter: z.string().optional().describe('Raw Drive Activity filter expression appended with AND'),
482
498
  max: z.number().optional().describe('Page size (default: 10)'),
483
- page: z.string().optional().describe('Page token'),
499
+ pageToken: pageTokenParam,
500
+ page: pageAliasParam,
484
501
  all: z.boolean().optional().describe('Fetch all pages'),
485
502
  consolidate: z.boolean().optional().describe('Use Drive Activity legacy consolidation strategy'),
486
503
  account: accountParam,
487
504
  },
488
- }, async ({ file, folder, actions, from, to, filter, max, page, all, consolidate, account }) => {
505
+ }, async ({ file, folder, actions, from, to, filter, max, pageToken, page, all, consolidate, account }) => {
489
506
  const args = ['drive', 'activity', 'query'];
490
507
  if (file) args.push(`--file=${file}`);
491
508
  if (folder) args.push(`--folder=${folder}`);
@@ -494,7 +511,8 @@ export function registerExtraDriveTools(server: McpServer): void {
494
511
  if (to) args.push(`--to=${to}`);
495
512
  if (filter) args.push(`--filter=${filter}`);
496
513
  if (max !== undefined) args.push(`--max=${max}`);
497
- if (page) args.push(`--page=${page}`);
514
+ const token = resolvePageToken({ pageToken, page });
515
+ if (token) args.push(`--page=${token}`);
498
516
  if (all) args.push('--all');
499
517
  if (consolidate) args.push('--consolidate');
500
518
  return runOrDiagnose(args, { account });
@@ -459,6 +459,22 @@ describe('gog_drive_labels_list', () => {
459
459
  await harness.callTool('gog_drive_labels_list', { publishedOnly: false, adminAccess: false });
460
460
  expect(lib.runOrDiagnose).toHaveBeenCalledWith(['drive', 'labels', 'list'], { account: undefined });
461
461
  });
462
+
463
+ // gog drive labels list is paginated upstream; the tool exposed neither max
464
+ // nor a cursor, so later pages were unreachable.
465
+ it('passes --max and --page through', async () => {
466
+ await harness.callTool('gog_drive_labels_list', { max: 50, pageToken: 'CURSOR' });
467
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
468
+ ['drive', 'labels', 'list', '--max=50', '--page=CURSOR'], { account: undefined },
469
+ );
470
+ });
471
+
472
+ it('accepts the deprecated page alias', async () => {
473
+ await harness.callTool('gog_drive_labels_list', { page: 'CURSOR' });
474
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
475
+ ['drive', 'labels', 'list', '--page=CURSOR'], { account: undefined },
476
+ );
477
+ });
462
478
  });
463
479
 
464
480
  describe('gog_drive_labels_get', () => {