gogcli-mcp-contacts 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.
package/dist/index.js CHANGED
@@ -31542,6 +31542,26 @@ function normalizeTimestamps(text, tz = displayTimeZone(), naiveTz = naiveSource
31542
31542
  return JSON.stringify(parsed, null, detectIndent(text));
31543
31543
  }
31544
31544
 
31545
+ // ../gogcli-mcp/src/pagination.ts
31546
+ function detectIndent2(text) {
31547
+ const match = /\n(\s+)\S/.exec(text);
31548
+ return match ? match[1].replace(/\t/g, " ").length : 0;
31549
+ }
31550
+ function stripConsumedPageToken(text) {
31551
+ const trimmed = text.trim();
31552
+ if (trimmed === "" || !trimmed.startsWith("{")) return text;
31553
+ let parsed;
31554
+ try {
31555
+ parsed = JSON.parse(trimmed);
31556
+ } catch {
31557
+ return text;
31558
+ }
31559
+ const obj = parsed;
31560
+ if (obj.nextPageToken !== "") return text;
31561
+ delete obj.nextPageToken;
31562
+ return JSON.stringify(obj, null, detectIndent2(text));
31563
+ }
31564
+
31545
31565
  // ../gogcli-mcp/src/tools/utils.ts
31546
31566
  var accountParam = external_exports.string().optional().describe(
31547
31567
  "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."
@@ -31570,9 +31590,19 @@ var ids = {
31570
31590
  // People API uses fully-qualified resource names ("people/c123") not bare IDs.
31571
31591
  person: external_exports.string().describe("Person resource name (people/...) or email")
31572
31592
  };
31593
+ var pageTokenParam = external_exports.string().optional().describe(
31594
+ "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."
31595
+ );
31596
+ var pageAliasParam = external_exports.string().optional().describe(
31597
+ "Deprecated alias for pageToken, accepted so existing callers keep working. Use pageToken \u2014 it matches the nextPageToken field in the response."
31598
+ );
31599
+ function resolvePageToken(p) {
31600
+ return p.pageToken ?? p.page;
31601
+ }
31573
31602
  var paginationParams = {
31574
31603
  max: external_exports.number().int().optional().describe("Max results"),
31575
- page: external_exports.string().optional().describe("Page token"),
31604
+ pageToken: pageTokenParam,
31605
+ page: pageAliasParam,
31576
31606
  all: external_exports.boolean().optional().describe("Fetch all pages")
31577
31607
  };
31578
31608
  function registerRunTool(server, options) {
@@ -31647,7 +31677,7 @@ ${accounts || "(none)"}${hint}`);
31647
31677
  async function runOrDiagnose(args, options) {
31648
31678
  try {
31649
31679
  const raw = await run(args, options);
31650
- return rawTextResult(options.lossless ? raw : normalizeTimestamps(raw));
31680
+ return rawTextResult(options.lossless ? raw : stripConsumedPageToken(normalizeTimestamps(raw)));
31651
31681
  } catch (err) {
31652
31682
  return diagnose(err);
31653
31683
  }
@@ -31697,6 +31727,7 @@ function formatAuthHealth(raw, now) {
31697
31727
  // ../gogcli-mcp/src/tools/auth.ts
31698
31728
  function registerAuthToolsWith(server, defaultServices) {
31699
31729
  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.`;
31730
+ 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.";
31700
31731
  server.registerTool("gog_auth_list", {
31701
31732
  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.",
31702
31733
  annotations: { readOnlyHint: true },
@@ -31746,11 +31777,14 @@ function registerAuthToolsWith(server, defaultServices) {
31746
31777
  annotations: { destructiveHint: true },
31747
31778
  inputSchema: {
31748
31779
  email: external_exports.string().describe("Google account email to authorize"),
31749
- services: external_exports.string().optional().default(defaultServices).describe(servicesDescribe)
31780
+ services: external_exports.string().optional().default(defaultServices).describe(servicesDescribe),
31781
+ extraScopes: external_exports.string().optional().describe(extraScopesDescribe)
31750
31782
  }
31751
- }, async ({ email: email3, services = defaultServices }) => {
31783
+ }, async ({ email: email3, services = defaultServices, extraScopes }) => {
31752
31784
  try {
31753
- return rawTextResult(await run(["auth", "add", email3, "--services", services], {
31785
+ const args = ["auth", "add", email3, "--services", services];
31786
+ if (extraScopes) args.push(`--extra-scopes=${extraScopes}`, "--force-consent");
31787
+ return rawTextResult(await run(args, {
31754
31788
  interactive: true,
31755
31789
  timeout: 3e5
31756
31790
  }));
@@ -31762,14 +31796,14 @@ function registerAuthToolsWith(server, defaultServices) {
31762
31796
  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.",
31763
31797
  inputSchema: {
31764
31798
  email: external_exports.string().describe("Google account email to authorize"),
31765
- services: external_exports.string().optional().default(defaultServices).describe(servicesDescribe)
31799
+ services: external_exports.string().optional().default(defaultServices).describe(servicesDescribe),
31800
+ extraScopes: external_exports.string().optional().describe(`${extraScopesDescribe} Pass the SAME value to gog_auth_add_complete.`)
31766
31801
  }
31767
- }, async ({ email: email3, services = defaultServices }) => {
31802
+ }, async ({ email: email3, services = defaultServices, extraScopes }) => {
31768
31803
  try {
31769
- return rawTextResult(await run(
31770
- ["auth", "add", email3, "--remote", "--step", "1", "--services", services, "--force-consent"],
31771
- { redactMode: "tokens" }
31772
- ));
31804
+ const args = ["auth", "add", email3, "--remote", "--step", "1", "--services", services, "--force-consent"];
31805
+ if (extraScopes) args.push(`--extra-scopes=${extraScopes}`);
31806
+ return rawTextResult(await run(args, { redactMode: "tokens" }));
31773
31807
  } catch (err) {
31774
31808
  return errorResult(errorText(err));
31775
31809
  }
@@ -31784,25 +31818,28 @@ function registerAuthToolsWith(server, defaultServices) {
31784
31818
  ),
31785
31819
  services: external_exports.string().optional().default(defaultServices).describe(
31786
31820
  `Services authorized \u2014 MUST match the value passed to gog_auth_add_url. Default: "${defaultServices}".`
31821
+ ),
31822
+ extraScopes: external_exports.string().optional().describe(
31823
+ "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."
31787
31824
  )
31788
31825
  }
31789
- }, async ({ email: email3, redirectUrl, services = defaultServices }) => {
31826
+ }, async ({ email: email3, redirectUrl, services = defaultServices, extraScopes }) => {
31790
31827
  try {
31791
- return rawTextResult(await run(
31792
- [
31793
- "auth",
31794
- "add",
31795
- email3,
31796
- "--remote",
31797
- "--step",
31798
- "2",
31799
- "--auth-url",
31800
- redirectUrl,
31801
- "--services",
31802
- services,
31803
- "--force-consent"
31804
- ]
31805
- ));
31828
+ const args = [
31829
+ "auth",
31830
+ "add",
31831
+ email3,
31832
+ "--remote",
31833
+ "--step",
31834
+ "2",
31835
+ "--auth-url",
31836
+ redirectUrl,
31837
+ "--services",
31838
+ services,
31839
+ "--force-consent"
31840
+ ];
31841
+ if (extraScopes) args.push(`--extra-scopes=${extraScopes}`);
31842
+ return rawTextResult(await run(args));
31806
31843
  } catch (err) {
31807
31844
  return errorResult(errorText(err));
31808
31845
  }
@@ -31883,7 +31920,7 @@ var failIfNotEmptyParam = external_exports.boolean().optional().describe(
31883
31920
  );
31884
31921
 
31885
31922
  // ../gogcli-mcp/src/server.ts
31886
- var VERSION = true ? "2.23.1" : "0.0.0";
31923
+ var VERSION = true ? "2.24.0" : "0.0.0";
31887
31924
 
31888
31925
  // ../gogcli-mcp/src/auth-log.ts
31889
31926
  var FAILURES = /* @__PURE__ */ new Set([
@@ -32396,14 +32433,16 @@ function registerExtraContactsTools(server) {
32396
32433
  inputSchema: {
32397
32434
  query: external_exports.string().describe("Search query (name, email, etc.)"),
32398
32435
  max: external_exports.number().optional().describe("Max results (default: 50)"),
32399
- page: external_exports.string().optional().describe("Page token"),
32436
+ pageToken: pageTokenParam,
32437
+ page: pageAliasParam,
32400
32438
  all: external_exports.boolean().optional().describe("Fetch all pages"),
32401
32439
  account: accountParam
32402
32440
  }
32403
- }, async ({ query, max, page, all, account }) => {
32441
+ }, async ({ query, max, pageToken, page, all, account }) => {
32404
32442
  const args = ["people", "search", query];
32405
32443
  if (max !== void 0) args.push(`--max=${max}`);
32406
- if (page) args.push(`--page=${page}`);
32444
+ const token = resolvePageToken({ pageToken, page });
32445
+ if (token) args.push(`--page=${token}`);
32407
32446
  if (all) args.push("--all");
32408
32447
  return runOrDiagnose(args, { account });
32409
32448
  });
@@ -32472,17 +32511,19 @@ function registerExtraContactsTools(server) {
32472
32511
  all: external_exports.boolean().optional().describe("Export all personal contacts"),
32473
32512
  out: external_exports.string().optional().describe("Output path (.vcf), or - for stdout (default: stdout)"),
32474
32513
  max: external_exports.number().optional().describe("Max results for query (1-30)"),
32475
- page: external_exports.string().optional().describe("Start page token for all"),
32514
+ pageToken: pageTokenParam,
32515
+ page: pageAliasParam,
32476
32516
  account: accountParam
32477
32517
  }
32478
- }, async ({ selector, query, all, out, max, page, account }) => {
32518
+ }, async ({ selector, query, all, out, max, pageToken, page, account }) => {
32479
32519
  const args = ["contacts", "export"];
32480
32520
  if (selector) args.push(selector);
32481
32521
  if (query) args.push(`--query=${query}`);
32482
32522
  if (all) args.push("--all");
32483
32523
  if (out) args.push(`--out=${out}`);
32484
32524
  if (max !== void 0) args.push(`--max=${max}`);
32485
- if (page) args.push(`--page=${page}`);
32525
+ const token = resolvePageToken({ pageToken, page });
32526
+ if (token) args.push(`--page=${token}`);
32486
32527
  return runOrDiagnose(args, { account });
32487
32528
  });
32488
32529
  server.registerTool("gog_contacts_dedupe", {
@@ -32511,14 +32552,16 @@ function registerExtraContactsTools(server) {
32511
32552
  annotations: { readOnlyHint: true },
32512
32553
  inputSchema: {
32513
32554
  max: external_exports.number().optional().describe("Max results (default: 50)"),
32514
- page: external_exports.string().optional().describe("Page token"),
32555
+ pageToken: pageTokenParam,
32556
+ page: pageAliasParam,
32515
32557
  all: external_exports.boolean().optional().describe("Fetch all pages"),
32516
32558
  account: accountParam
32517
32559
  }
32518
- }, async ({ max, page, all, account }) => {
32560
+ }, async ({ max, pageToken, page, all, account }) => {
32519
32561
  const args = ["contacts", "directory", "list"];
32520
32562
  if (max !== void 0) args.push(`--max=${max}`);
32521
- if (page) args.push(`--page=${page}`);
32563
+ const token = resolvePageToken({ pageToken, page });
32564
+ if (token) args.push(`--page=${token}`);
32522
32565
  if (all) args.push("--all");
32523
32566
  return runOrDiagnose(args, { account });
32524
32567
  });
@@ -32527,14 +32570,16 @@ function registerExtraContactsTools(server) {
32527
32570
  annotations: { readOnlyHint: true },
32528
32571
  inputSchema: {
32529
32572
  max: external_exports.number().optional().describe("Max results (default: 100)"),
32530
- page: external_exports.string().optional().describe("Page token"),
32573
+ pageToken: pageTokenParam,
32574
+ page: pageAliasParam,
32531
32575
  all: external_exports.boolean().optional().describe("Fetch all pages"),
32532
32576
  account: accountParam
32533
32577
  }
32534
- }, async ({ max, page, all, account }) => {
32578
+ }, async ({ max, pageToken, page, all, account }) => {
32535
32579
  const args = ["contacts", "other", "list"];
32536
32580
  if (max !== void 0) args.push(`--max=${max}`);
32537
- if (page) args.push(`--page=${page}`);
32581
+ const token = resolvePageToken({ pageToken, page });
32582
+ if (token) args.push(`--page=${token}`);
32538
32583
  if (all) args.push("--all");
32539
32584
  return runOrDiagnose(args, { account });
32540
32585
  });
package/manifest.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "manifest_version": "0.3",
4
4
  "name": "gogcli-mcp-contacts",
5
5
  "display_name": "gogcli (Contacts)",
6
- "version": "2.23.1",
6
+ "version": "2.24.0",
7
7
  "description": "Extended Google Contacts for Claude via gogcli — auth + Contacts + Workspace directory (People API)",
8
8
  "author": {
9
9
  "name": "Chris Hall",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gogcli-mcp-contacts",
3
- "version": "2.23.1",
3
+ "version": "2.24.0",
4
4
  "mcpName": "io.github.chrischall/gogcli-mcp-contacts",
5
5
  "description": "Extended Google Contacts + People MCP server via gogcli — auth + Contacts + Workspace directory (People API)",
6
6
  "author": "Claude Code (AI) <https://www.anthropic.com/claude>",
@@ -1,6 +1,6 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { z } from 'zod';
3
- import { accountParam, runOrDiagnose } from '../../../gogcli-mcp/src/lib.js';
3
+ import { accountParam, runOrDiagnose, pageTokenParam, pageAliasParam, resolvePageToken} from '../../../gogcli-mcp/src/lib.js';
4
4
 
5
5
  // People is the richer API behind Google Contacts: Workspace directory
6
6
  // search, profile fields, and relations.
@@ -32,14 +32,16 @@ export function registerExtraContactsTools(server: McpServer): void {
32
32
  inputSchema: {
33
33
  query: z.string().describe('Search query (name, email, etc.)'),
34
34
  max: z.number().optional().describe('Max results (default: 50)'),
35
- page: z.string().optional().describe('Page token'),
35
+ pageToken: pageTokenParam,
36
+ page: pageAliasParam,
36
37
  all: z.boolean().optional().describe('Fetch all pages'),
37
38
  account: accountParam,
38
39
  },
39
- }, async ({ query, max, page, all, account }) => {
40
+ }, async ({ query, max, pageToken, page, all, account }) => {
40
41
  const args = ['people', 'search', query];
41
42
  if (max !== undefined) args.push(`--max=${max}`);
42
- if (page) args.push(`--page=${page}`);
43
+ const token = resolvePageToken({ pageToken, page });
44
+ if (token) args.push(`--page=${token}`);
43
45
  if (all) args.push('--all');
44
46
  return runOrDiagnose(args, { account });
45
47
  });
@@ -112,17 +114,19 @@ export function registerExtraContactsTools(server: McpServer): void {
112
114
  all: z.boolean().optional().describe('Export all personal contacts'),
113
115
  out: z.string().optional().describe('Output path (.vcf), or - for stdout (default: stdout)'),
114
116
  max: z.number().optional().describe('Max results for query (1-30)'),
115
- page: z.string().optional().describe('Start page token for all'),
117
+ pageToken: pageTokenParam,
118
+ page: pageAliasParam,
116
119
  account: accountParam,
117
120
  },
118
- }, async ({ selector, query, all, out, max, page, account }) => {
121
+ }, async ({ selector, query, all, out, max, pageToken, page, account }) => {
119
122
  const args = ['contacts', 'export'];
120
123
  if (selector) args.push(selector);
121
124
  if (query) args.push(`--query=${query}`);
122
125
  if (all) args.push('--all');
123
126
  if (out) args.push(`--out=${out}`);
124
127
  if (max !== undefined) args.push(`--max=${max}`);
125
- if (page) args.push(`--page=${page}`);
128
+ const token = resolvePageToken({ pageToken, page });
129
+ if (token) args.push(`--page=${token}`);
126
130
  return runOrDiagnose(args, { account });
127
131
  });
128
132
 
@@ -153,14 +157,16 @@ export function registerExtraContactsTools(server: McpServer): void {
153
157
  annotations: { readOnlyHint: true },
154
158
  inputSchema: {
155
159
  max: z.number().optional().describe('Max results (default: 50)'),
156
- page: z.string().optional().describe('Page token'),
160
+ pageToken: pageTokenParam,
161
+ page: pageAliasParam,
157
162
  all: z.boolean().optional().describe('Fetch all pages'),
158
163
  account: accountParam,
159
164
  },
160
- }, async ({ max, page, all, account }) => {
165
+ }, async ({ max, pageToken, page, all, account }) => {
161
166
  const args = ['contacts', 'directory', 'list'];
162
167
  if (max !== undefined) args.push(`--max=${max}`);
163
- if (page) args.push(`--page=${page}`);
168
+ const token = resolvePageToken({ pageToken, page });
169
+ if (token) args.push(`--page=${token}`);
164
170
  if (all) args.push('--all');
165
171
  return runOrDiagnose(args, { account });
166
172
  });
@@ -170,14 +176,16 @@ export function registerExtraContactsTools(server: McpServer): void {
170
176
  annotations: { readOnlyHint: true },
171
177
  inputSchema: {
172
178
  max: z.number().optional().describe('Max results (default: 100)'),
173
- page: z.string().optional().describe('Page token'),
179
+ pageToken: pageTokenParam,
180
+ page: pageAliasParam,
174
181
  all: z.boolean().optional().describe('Fetch all pages'),
175
182
  account: accountParam,
176
183
  },
177
- }, async ({ max, page, all, account }) => {
184
+ }, async ({ max, pageToken, page, all, account }) => {
178
185
  const args = ['contacts', 'other', 'list'];
179
186
  if (max !== undefined) args.push(`--max=${max}`);
180
- if (page) args.push(`--page=${page}`);
187
+ const token = resolvePageToken({ pageToken, page });
188
+ if (token) args.push(`--page=${token}`);
181
189
  if (all) args.push('--all');
182
190
  return runOrDiagnose(args, { account });
183
191
  });