gogcli-mcp 2.0.7 → 2.0.9

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.0.7"
10
+ "version": "2.0.9"
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.0.7",
18
+ "version": "2.0.9",
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.0.7",
4
+ "version": "2.0.9",
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/dist/index.js CHANGED
@@ -3105,6 +3105,9 @@ var require_utils = __commonJS({
3105
3105
  "use strict";
3106
3106
  var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
3107
3107
  var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
3108
+ var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
3109
+ var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
3110
+ var isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu);
3108
3111
  function stringArrayToHexStripped(input) {
3109
3112
  let acc = "";
3110
3113
  let code = 0;
@@ -3297,27 +3300,77 @@ var require_utils = __commonJS({
3297
3300
  }
3298
3301
  return output.join("");
3299
3302
  }
3300
- function normalizeComponentEncoding(component, esc2) {
3301
- const func = esc2 !== true ? escape : unescape;
3302
- if (component.scheme !== void 0) {
3303
- component.scheme = func(component.scheme);
3304
- }
3305
- if (component.userinfo !== void 0) {
3306
- component.userinfo = func(component.userinfo);
3307
- }
3308
- if (component.host !== void 0) {
3309
- component.host = func(component.host);
3303
+ var HOST_DELIMS = { "@": "%40", "/": "%2F", "?": "%3F", "#": "%23", ":": "%3A" };
3304
+ var HOST_DELIM_RE = /[@/?#:]/g;
3305
+ var HOST_DELIM_NO_COLON_RE = /[@/?#]/g;
3306
+ function reescapeHostDelimiters(host, isIP) {
3307
+ const re = isIP ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_RE;
3308
+ re.lastIndex = 0;
3309
+ return host.replace(re, (ch) => HOST_DELIMS[ch]);
3310
+ }
3311
+ function normalizePercentEncoding(input, decodeUnreserved = false) {
3312
+ if (input.indexOf("%") === -1) {
3313
+ return input;
3310
3314
  }
3311
- if (component.path !== void 0) {
3312
- component.path = func(component.path);
3315
+ let output = "";
3316
+ for (let i = 0; i < input.length; i++) {
3317
+ if (input[i] === "%" && i + 2 < input.length) {
3318
+ const hex3 = input.slice(i + 1, i + 3);
3319
+ if (isHexPair(hex3)) {
3320
+ const normalizedHex = hex3.toUpperCase();
3321
+ const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
3322
+ if (decodeUnreserved && isUnreserved(decoded)) {
3323
+ output += decoded;
3324
+ } else {
3325
+ output += "%" + normalizedHex;
3326
+ }
3327
+ i += 2;
3328
+ continue;
3329
+ }
3330
+ }
3331
+ output += input[i];
3313
3332
  }
3314
- if (component.query !== void 0) {
3315
- component.query = func(component.query);
3333
+ return output;
3334
+ }
3335
+ function normalizePathEncoding(input) {
3336
+ let output = "";
3337
+ for (let i = 0; i < input.length; i++) {
3338
+ if (input[i] === "%" && i + 2 < input.length) {
3339
+ const hex3 = input.slice(i + 1, i + 3);
3340
+ if (isHexPair(hex3)) {
3341
+ const normalizedHex = hex3.toUpperCase();
3342
+ const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
3343
+ if (decoded !== "." && isUnreserved(decoded)) {
3344
+ output += decoded;
3345
+ } else {
3346
+ output += "%" + normalizedHex;
3347
+ }
3348
+ i += 2;
3349
+ continue;
3350
+ }
3351
+ }
3352
+ if (isPathCharacter(input[i])) {
3353
+ output += input[i];
3354
+ } else {
3355
+ output += escape(input[i]);
3356
+ }
3316
3357
  }
3317
- if (component.fragment !== void 0) {
3318
- component.fragment = func(component.fragment);
3358
+ return output;
3359
+ }
3360
+ function escapePreservingEscapes(input) {
3361
+ let output = "";
3362
+ for (let i = 0; i < input.length; i++) {
3363
+ if (input[i] === "%" && i + 2 < input.length) {
3364
+ const hex3 = input.slice(i + 1, i + 3);
3365
+ if (isHexPair(hex3)) {
3366
+ output += "%" + hex3.toUpperCase();
3367
+ i += 2;
3368
+ continue;
3369
+ }
3370
+ }
3371
+ output += escape(input[i]);
3319
3372
  }
3320
- return component;
3373
+ return output;
3321
3374
  }
3322
3375
  function recomposeAuthority(component) {
3323
3376
  const uriTokens = [];
@@ -3332,7 +3385,7 @@ var require_utils = __commonJS({
3332
3385
  if (ipV6res.isIPV6 === true) {
3333
3386
  host = `[${ipV6res.escapedHost}]`;
3334
3387
  } else {
3335
- host = component.host;
3388
+ host = reescapeHostDelimiters(host, false);
3336
3389
  }
3337
3390
  }
3338
3391
  uriTokens.push(host);
@@ -3346,7 +3399,10 @@ var require_utils = __commonJS({
3346
3399
  module.exports = {
3347
3400
  nonSimpleDomain,
3348
3401
  recomposeAuthority,
3349
- normalizeComponentEncoding,
3402
+ reescapeHostDelimiters,
3403
+ normalizePercentEncoding,
3404
+ normalizePathEncoding,
3405
+ escapePreservingEscapes,
3350
3406
  removeDotSegments,
3351
3407
  isIPv4,
3352
3408
  isUUID,
@@ -3570,12 +3626,12 @@ var require_schemes = __commonJS({
3570
3626
  var require_fast_uri = __commonJS({
3571
3627
  "../../node_modules/fast-uri/index.js"(exports, module) {
3572
3628
  "use strict";
3573
- var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils();
3629
+ var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
3574
3630
  var { SCHEMES, getSchemeHandler } = require_schemes();
3575
3631
  function normalize(uri, options) {
3576
3632
  if (typeof uri === "string") {
3577
3633
  uri = /** @type {T} */
3578
- serialize(parse3(uri, options), options);
3634
+ normalizeString(uri, options);
3579
3635
  } else if (typeof uri === "object") {
3580
3636
  uri = /** @type {T} */
3581
3637
  parse3(serialize(uri, options), options);
@@ -3642,19 +3698,9 @@ var require_fast_uri = __commonJS({
3642
3698
  return target;
3643
3699
  }
3644
3700
  function equal(uriA, uriB, options) {
3645
- if (typeof uriA === "string") {
3646
- uriA = unescape(uriA);
3647
- uriA = serialize(normalizeComponentEncoding(parse3(uriA, options), true), { ...options, skipEscape: true });
3648
- } else if (typeof uriA === "object") {
3649
- uriA = serialize(normalizeComponentEncoding(uriA, true), { ...options, skipEscape: true });
3650
- }
3651
- if (typeof uriB === "string") {
3652
- uriB = unescape(uriB);
3653
- uriB = serialize(normalizeComponentEncoding(parse3(uriB, options), true), { ...options, skipEscape: true });
3654
- } else if (typeof uriB === "object") {
3655
- uriB = serialize(normalizeComponentEncoding(uriB, true), { ...options, skipEscape: true });
3656
- }
3657
- return uriA.toLowerCase() === uriB.toLowerCase();
3701
+ const normalizedA = normalizeComparableURI(uriA, options);
3702
+ const normalizedB = normalizeComparableURI(uriB, options);
3703
+ return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA.toLowerCase() === normalizedB.toLowerCase();
3658
3704
  }
3659
3705
  function serialize(cmpts, opts) {
3660
3706
  const component = {
@@ -3679,12 +3725,12 @@ var require_fast_uri = __commonJS({
3679
3725
  if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
3680
3726
  if (component.path !== void 0) {
3681
3727
  if (!options.skipEscape) {
3682
- component.path = escape(component.path);
3728
+ component.path = escapePreservingEscapes(component.path);
3683
3729
  if (component.scheme !== void 0) {
3684
3730
  component.path = component.path.split("%3A").join(":");
3685
3731
  }
3686
3732
  } else {
3687
- component.path = unescape(component.path);
3733
+ component.path = normalizePercentEncoding(component.path);
3688
3734
  }
3689
3735
  }
3690
3736
  if (options.reference !== "suffix" && component.scheme) {
@@ -3719,7 +3765,16 @@ var require_fast_uri = __commonJS({
3719
3765
  return uriTokens.join("");
3720
3766
  }
3721
3767
  var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
3722
- function parse3(uri, opts) {
3768
+ function getParseError(parsed, matches) {
3769
+ if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
3770
+ return 'URI path must start with "/" when authority is present.';
3771
+ }
3772
+ if (typeof parsed.port === "number" && (parsed.port < 0 || parsed.port > 65535)) {
3773
+ return "URI port is malformed.";
3774
+ }
3775
+ return void 0;
3776
+ }
3777
+ function parseWithStatus(uri, opts) {
3723
3778
  const options = Object.assign({}, opts);
3724
3779
  const parsed = {
3725
3780
  scheme: void 0,
@@ -3730,6 +3785,7 @@ var require_fast_uri = __commonJS({
3730
3785
  query: void 0,
3731
3786
  fragment: void 0
3732
3787
  };
3788
+ let malformedAuthorityOrPort = false;
3733
3789
  let isIP = false;
3734
3790
  if (options.reference === "suffix") {
3735
3791
  if (options.scheme) {
@@ -3750,6 +3806,11 @@ var require_fast_uri = __commonJS({
3750
3806
  if (isNaN(parsed.port)) {
3751
3807
  parsed.port = matches[5];
3752
3808
  }
3809
+ const parseError = getParseError(parsed, matches);
3810
+ if (parseError !== void 0) {
3811
+ parsed.error = parsed.error || parseError;
3812
+ malformedAuthorityOrPort = true;
3813
+ }
3753
3814
  if (parsed.host) {
3754
3815
  const ipv4result = isIPv4(parsed.host);
3755
3816
  if (ipv4result === false) {
@@ -3788,14 +3849,18 @@ var require_fast_uri = __commonJS({
3788
3849
  parsed.scheme = unescape(parsed.scheme);
3789
3850
  }
3790
3851
  if (parsed.host !== void 0) {
3791
- parsed.host = unescape(parsed.host);
3852
+ parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
3792
3853
  }
3793
3854
  }
3794
3855
  if (parsed.path) {
3795
- parsed.path = escape(unescape(parsed.path));
3856
+ parsed.path = normalizePathEncoding(parsed.path);
3796
3857
  }
3797
3858
  if (parsed.fragment) {
3798
- parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
3859
+ try {
3860
+ parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
3861
+ } catch {
3862
+ parsed.error = parsed.error || "URI malformed";
3863
+ }
3799
3864
  }
3800
3865
  }
3801
3866
  if (schemeHandler && schemeHandler.parse) {
@@ -3804,7 +3869,29 @@ var require_fast_uri = __commonJS({
3804
3869
  } else {
3805
3870
  parsed.error = parsed.error || "URI can not be parsed.";
3806
3871
  }
3807
- return parsed;
3872
+ return { parsed, malformedAuthorityOrPort };
3873
+ }
3874
+ function parse3(uri, opts) {
3875
+ return parseWithStatus(uri, opts).parsed;
3876
+ }
3877
+ function normalizeString(uri, opts) {
3878
+ return normalizeStringWithStatus(uri, opts).normalized;
3879
+ }
3880
+ function normalizeStringWithStatus(uri, opts) {
3881
+ const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
3882
+ return {
3883
+ normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
3884
+ malformedAuthorityOrPort
3885
+ };
3886
+ }
3887
+ function normalizeComparableURI(uri, opts) {
3888
+ if (typeof uri === "string") {
3889
+ const { normalized, malformedAuthorityOrPort } = normalizeStringWithStatus(uri, opts);
3890
+ return malformedAuthorityOrPort ? void 0 : normalized;
3891
+ }
3892
+ if (typeof uri === "object") {
3893
+ return serialize(uri, opts);
3894
+ }
3808
3895
  }
3809
3896
  var fastUri = {
3810
3897
  SCHEMES,
@@ -8415,8 +8502,8 @@ function emoji() {
8415
8502
  }
8416
8503
  var ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
8417
8504
  var ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
8418
- var mac = (delimiter) => {
8419
- const escapedDelim = escapeRegex(delimiter ?? ":");
8505
+ var mac = (delimiter2) => {
8506
+ const escapedDelim = escapeRegex(delimiter2 ?? ":");
8420
8507
  return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
8421
8508
  };
8422
8509
  var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
@@ -9886,14 +9973,14 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
9886
9973
  return `shape[${k}]._zod.run({ value: input[${k}], issues: [] }, ctx)`;
9887
9974
  };
9888
9975
  doc.write(`const input = payload.value;`);
9889
- const ids = /* @__PURE__ */ Object.create(null);
9976
+ const ids2 = /* @__PURE__ */ Object.create(null);
9890
9977
  let counter = 0;
9891
9978
  for (const key of normalized.keys) {
9892
- ids[key] = `key_${counter++}`;
9979
+ ids2[key] = `key_${counter++}`;
9893
9980
  }
9894
9981
  doc.write(`const newResult = {};`);
9895
9982
  for (const key of normalized.keys) {
9896
- const id = ids[key];
9983
+ const id = ids2[key];
9897
9984
  const k = esc(key);
9898
9985
  const schema = shape[key];
9899
9986
  const isOptionalIn = schema?._zod?.optin === "optional";
@@ -30863,12 +30950,60 @@ var EMPTY_COMPLETION_RESULT = {
30863
30950
 
30864
30951
  // src/runner.ts
30865
30952
  import { spawn } from "node:child_process";
30953
+ import { delimiter } from "node:path";
30866
30954
  var TIMEOUT_MS = 3e4;
30867
30955
  function envOrUndefined(key) {
30868
30956
  const value = process.env[key];
30869
30957
  if (!value || value.startsWith("${")) return void 0;
30870
30958
  return value;
30871
30959
  }
30960
+ function sanitizedEnv() {
30961
+ const result = {};
30962
+ for (const [key, value] of Object.entries(process.env)) {
30963
+ if (key === "GOG_ACCESS_TOKEN") continue;
30964
+ if (key === "GOOGLE_APPLICATION_CREDENTIALS") continue;
30965
+ if (/(_TOKEN|_SECRET|_API_KEY|_PRIVATE_KEY)$/.test(key)) continue;
30966
+ result[key] = value;
30967
+ }
30968
+ return result;
30969
+ }
30970
+ var TOKEN_PATTERNS = [
30971
+ /Bearer\s+[A-Za-z0-9._\-+/=]+/gi,
30972
+ /ya29\.[A-Za-z0-9._\-]+/g,
30973
+ // OAuth2 access tokens
30974
+ /1\/\/[A-Za-z0-9._\-]+/g,
30975
+ // OAuth2 refresh tokens
30976
+ /AIza[A-Za-z0-9_\-]{35}/g
30977
+ // Google API keys
30978
+ ];
30979
+ function redactSecrets(text) {
30980
+ let redacted = text;
30981
+ for (const re of TOKEN_PATTERNS) {
30982
+ redacted = redacted.replace(re, "[REDACTED]");
30983
+ }
30984
+ return redacted;
30985
+ }
30986
+ function augmentedPath() {
30987
+ const home = process.env.HOME;
30988
+ const candidates = [
30989
+ process.env.PATH ?? "",
30990
+ "/opt/homebrew/bin",
30991
+ "/usr/local/bin",
30992
+ home ? `${home}/.local/bin` : "",
30993
+ home ? `${home}/go/bin` : ""
30994
+ ];
30995
+ const seen = /* @__PURE__ */ new Set();
30996
+ const parts = [];
30997
+ for (const c of candidates) {
30998
+ if (!c) continue;
30999
+ for (const dir of c.split(delimiter)) {
31000
+ if (!dir || seen.has(dir)) continue;
31001
+ seen.add(dir);
31002
+ parts.push(dir);
31003
+ }
31004
+ }
31005
+ return parts.join(delimiter);
31006
+ }
30872
31007
  function formatTimeout(ms) {
30873
31008
  const seconds = Math.round(ms / 1e3);
30874
31009
  if (seconds >= 60) {
@@ -30890,8 +31025,8 @@ async function run(args, options = {}) {
30890
31025
  fullArgs.push(...args);
30891
31026
  const effectiveTimeout = timeout ?? TIMEOUT_MS;
30892
31027
  return new Promise((resolve, reject) => {
30893
- const { GOG_ACCESS_TOKEN: _, ...cleanEnv } = process.env;
30894
- const child = spawner(envOrUndefined("GOG_PATH") ?? "gog", fullArgs, { env: cleanEnv });
31028
+ const childEnv = { ...sanitizedEnv(), PATH: augmentedPath() };
31029
+ const child = spawner(envOrUndefined("GOG_PATH") ?? "gog", fullArgs, { env: childEnv });
30895
31030
  const stdoutChunks = [];
30896
31031
  const stderrChunks = [];
30897
31032
  let settled = false;
@@ -30919,13 +31054,19 @@ async function run(args, options = {}) {
30919
31054
  resolve(stdout);
30920
31055
  }
30921
31056
  } else {
30922
- reject(new Error(stderr || `gog exited with code ${code}`));
31057
+ reject(new Error(redactSecrets(stderr || `gog exited with code ${code}`)));
30923
31058
  }
30924
31059
  });
30925
31060
  child.on("error", (err) => {
30926
31061
  clearTimeout(timer);
30927
31062
  if (settled) return;
30928
31063
  settled = true;
31064
+ if (err.code === "ENOENT") {
31065
+ reject(new Error(
31066
+ "gog executable not found. Install gogcli (https://github.com/steipete/gogcli) or set GOG_PATH in your MCP client config to the absolute binary path (run `which gog` in a terminal to find it)."
31067
+ ));
31068
+ return;
31069
+ }
30929
31070
  reject(err);
30930
31071
  });
30931
31072
  });
@@ -30935,6 +31076,55 @@ async function run(args, options = {}) {
30935
31076
  var accountParam = external_exports.string().optional().describe(
30936
31077
  "Google account email to use (overrides GOG_ACCOUNT env var)"
30937
31078
  );
31079
+ var ids = {
31080
+ course: external_exports.string().describe("Course ID"),
31081
+ coursework: external_exports.string().describe("Coursework ID"),
31082
+ submission: external_exports.string().describe("Submission ID"),
31083
+ announcement: external_exports.string().describe("Announcement ID"),
31084
+ topic: external_exports.string().describe("Topic ID"),
31085
+ invitation: external_exports.string().describe("Invitation ID"),
31086
+ spreadsheet: external_exports.string().describe("Spreadsheet ID (from the URL)"),
31087
+ doc: external_exports.string().describe("Doc ID (from the URL)"),
31088
+ presentation: external_exports.string().describe("Presentation ID"),
31089
+ slide: external_exports.string().describe("Slide ID"),
31090
+ file: external_exports.string().describe("File ID"),
31091
+ message: external_exports.string().describe("Message ID"),
31092
+ thread: external_exports.string().describe("Thread ID"),
31093
+ draft: external_exports.string().describe("Draft ID"),
31094
+ label: external_exports.string().describe("Label ID or name"),
31095
+ attachment: external_exports.string().describe("Attachment ID"),
31096
+ comment: external_exports.string().describe("Comment ID"),
31097
+ meetingCode: external_exports.string().describe("Meeting code (e.g. abc-defg-hij)"),
31098
+ permission: external_exports.string().describe("Permission ID"),
31099
+ user: external_exports.string().describe("User ID"),
31100
+ // People API uses fully-qualified resource names ("people/c123") not bare IDs.
31101
+ person: external_exports.string().describe("Person resource name (people/...) or email")
31102
+ };
31103
+ var paginationParams = {
31104
+ max: external_exports.number().int().optional().describe("Max results"),
31105
+ page: external_exports.string().optional().describe("Page token"),
31106
+ all: external_exports.boolean().optional().describe("Fetch all pages")
31107
+ };
31108
+ function registerRunTool(server2, options) {
31109
+ const { service, examples, omitAccount = false, note } = options;
31110
+ const baseDescription = `Run any gog ${service} subcommand not covered by the other tools. Run \`gog ${service} --help\` for the full list of subcommands, or \`gog ${service} <subcommand> --help\` for flags on a specific subcommand.`;
31111
+ const description = note ? `${baseDescription} ${note}` : baseDescription;
31112
+ const inputSchema = {
31113
+ subcommand: external_exports.string().describe(`The gog ${service} subcommand to run, e.g. ${examples}`),
31114
+ args: external_exports.array(external_exports.string()).describe("Additional positional args and flags")
31115
+ };
31116
+ if (!omitAccount) {
31117
+ inputSchema.account = accountParam;
31118
+ }
31119
+ server2.registerTool(`gog_${service}_run`, {
31120
+ description,
31121
+ annotations: { destructiveHint: true },
31122
+ inputSchema
31123
+ }, async (rawArgs) => {
31124
+ const { subcommand, args, account } = rawArgs;
31125
+ return runOrDiagnose([service, subcommand, ...args], { account });
31126
+ });
31127
+ }
30938
31128
  function toText(output) {
30939
31129
  return { content: [{ type: "text", text: output }] };
30940
31130
  }
@@ -31020,15 +31210,11 @@ function registerAuthTools(server2) {
31020
31210
  return toError(err);
31021
31211
  }
31022
31212
  });
31023
- server2.registerTool("gog_auth_run", {
31024
- description: "Run any gog auth subcommand. Run `gog auth --help` to see all available subcommands and flags. Note: for browser-based authorization, use gog_auth_add instead.",
31025
- annotations: { destructiveHint: true },
31026
- inputSchema: {
31027
- subcommand: external_exports.string().describe('The gog auth subcommand, e.g. "remove", "alias", "tokens"'),
31028
- args: external_exports.array(external_exports.string()).describe("Additional positional args and flags")
31029
- }
31030
- }, async ({ subcommand, args }) => {
31031
- return runOrDiagnose(["auth", subcommand, ...args], {});
31213
+ registerRunTool(server2, {
31214
+ service: "auth",
31215
+ examples: '"remove", "alias", "tokens"',
31216
+ omitAccount: true,
31217
+ note: "For browser-based authorization, use gog_auth_add instead."
31032
31218
  });
31033
31219
  }
31034
31220
 
@@ -31139,17 +31325,7 @@ function registerCalendarTools(server2) {
31139
31325
  if (comment) args.push(`--comment=${comment}`);
31140
31326
  return runOrDiagnose(args, { account });
31141
31327
  });
31142
- server2.registerTool("gog_calendar_run", {
31143
- description: "Run any gog calendar subcommand not covered by the other tools. Run `gog calendar --help` for the full list of subcommands, or `gog calendar <subcommand> --help` for flags on a specific subcommand.",
31144
- annotations: { destructiveHint: true },
31145
- inputSchema: {
31146
- subcommand: external_exports.string().describe('The gog calendar subcommand to run, e.g. "calendars", "freebusy"'),
31147
- args: external_exports.array(external_exports.string()).describe("Additional positional args and flags"),
31148
- account: accountParam
31149
- }
31150
- }, async ({ subcommand, args, account }) => {
31151
- return runOrDiagnose(["calendar", subcommand, ...args], { account });
31152
- });
31328
+ registerRunTool(server2, { service: "calendar", examples: '"calendars", "freebusy"' });
31153
31329
  }
31154
31330
 
31155
31331
  // src/tools/classroom.ts
@@ -31514,16 +31690,10 @@ function registerClassroomTools(server2) {
31514
31690
  if (userId) args.push(userId);
31515
31691
  return runOrDiagnose(args, { account });
31516
31692
  });
31517
- server2.registerTool("gog_classroom_run", {
31518
- description: "Run any gog classroom subcommand not covered by the other tools (guardians, guardian-invitations, materials, coursework assignees, announcement assignees, etc.). Run `gog classroom --help` for the full list, or `gog classroom <subcommand> --help` for flags.",
31519
- annotations: { destructiveHint: true },
31520
- inputSchema: {
31521
- subcommand: external_exports.string().describe('The gog classroom subcommand to run, e.g. "guardians", "materials", "guardian-invitations"'),
31522
- args: external_exports.array(external_exports.string()).describe("Additional positional args and flags"),
31523
- account: accountParam
31524
- }
31525
- }, async ({ subcommand, args, account }) => {
31526
- return runOrDiagnose(["classroom", subcommand, ...args], { account });
31693
+ registerRunTool(server2, {
31694
+ service: "classroom",
31695
+ examples: '"guardians", "materials", "guardian-invitations"',
31696
+ note: "Covers anything not wrapped by the dedicated tools (guardians, guardian-invitations, materials, coursework assignees, announcement assignees, etc.)."
31527
31697
  });
31528
31698
  }
31529
31699
 
@@ -31579,17 +31749,7 @@ function registerContactsTools(server2) {
31579
31749
  if (title) args.push(`--title=${title}`);
31580
31750
  return runOrDiagnose(args, { account });
31581
31751
  });
31582
- server2.registerTool("gog_contacts_run", {
31583
- description: "Run any gog contacts subcommand not covered by the other tools. Run `gog contacts --help` for the full list of subcommands, or `gog contacts <subcommand> --help` for flags on a specific subcommand.",
31584
- annotations: { destructiveHint: true },
31585
- inputSchema: {
31586
- subcommand: external_exports.string().describe('The gog contacts subcommand to run, e.g. "update", "delete", "directory"'),
31587
- args: external_exports.array(external_exports.string()).describe("Additional positional args and flags"),
31588
- account: accountParam
31589
- }
31590
- }, async ({ subcommand, args, account }) => {
31591
- return runOrDiagnose(["contacts", subcommand, ...args], { account });
31592
- });
31752
+ registerRunTool(server2, { service: "contacts", examples: '"update", "delete", "directory"' });
31593
31753
  }
31594
31754
 
31595
31755
  // src/tools/docs.ts
@@ -31659,17 +31819,7 @@ function registerDocsTools(server2) {
31659
31819
  }, async ({ docId, account }) => {
31660
31820
  return runOrDiagnose(["docs", "structure", docId], { account });
31661
31821
  });
31662
- server2.registerTool("gog_docs_run", {
31663
- description: "Run any gog docs subcommand not covered by the other tools. Run `gog docs --help` for the full list of subcommands, or `gog docs <subcommand> --help` for flags on a specific subcommand.",
31664
- annotations: { destructiveHint: true },
31665
- inputSchema: {
31666
- subcommand: external_exports.string().describe('The gog docs subcommand to run, e.g. "copy", "clear", "insert", "sed", "export"'),
31667
- args: external_exports.array(external_exports.string()).describe("Additional positional args and flags"),
31668
- account: accountParam
31669
- }
31670
- }, async ({ subcommand, args, account }) => {
31671
- return runOrDiagnose(["docs", subcommand, ...args], { account });
31672
- });
31822
+ registerRunTool(server2, { service: "docs", examples: '"copy", "clear", "insert", "sed", "export"' });
31673
31823
  }
31674
31824
 
31675
31825
  // src/tools/drive.ts
@@ -31777,17 +31927,7 @@ function registerDriveTools(server2) {
31777
31927
  if (role) args.push(`--role=${role}`);
31778
31928
  return runOrDiagnose(args, { account });
31779
31929
  });
31780
- server2.registerTool("gog_drive_run", {
31781
- description: "Run any gog drive subcommand not covered by the other tools. Run `gog drive --help` for the full list of subcommands, or `gog drive <subcommand> --help` for flags on a specific subcommand.",
31782
- annotations: { destructiveHint: true },
31783
- inputSchema: {
31784
- subcommand: external_exports.string().describe('The gog drive subcommand to run, e.g. "copy", "upload", "download", "permissions"'),
31785
- args: external_exports.array(external_exports.string()).describe("Additional positional args and flags"),
31786
- account: accountParam
31787
- }
31788
- }, async ({ subcommand, args, account }) => {
31789
- return runOrDiagnose(["drive", subcommand, ...args], { account });
31790
- });
31930
+ registerRunTool(server2, { service: "drive", examples: '"copy", "upload", "download", "permissions"' });
31791
31931
  }
31792
31932
 
31793
31933
  // src/tools/gmail.ts
@@ -31839,17 +31979,7 @@ function registerGmailTools(server2) {
31839
31979
  if (threadId) args.push(`--thread-id=${threadId}`);
31840
31980
  return runOrDiagnose(args, { account });
31841
31981
  });
31842
- server2.registerTool("gog_gmail_run", {
31843
- description: "Run any gog gmail subcommand not covered by the other tools. Run `gog gmail --help` for the full list of subcommands, or `gog gmail <subcommand> --help` for flags on a specific subcommand.",
31844
- annotations: { destructiveHint: true },
31845
- inputSchema: {
31846
- subcommand: external_exports.string().describe('The gog gmail subcommand to run, e.g. "archive", "mark-read", "labels"'),
31847
- args: external_exports.array(external_exports.string()).describe("Additional positional args and flags"),
31848
- account: accountParam
31849
- }
31850
- }, async ({ subcommand, args, account }) => {
31851
- return runOrDiagnose(["gmail", subcommand, ...args], { account });
31852
- });
31982
+ registerRunTool(server2, { service: "gmail", examples: '"archive", "mark-read", "labels"' });
31853
31983
  }
31854
31984
 
31855
31985
  // src/tools/sheets.ts
@@ -31938,17 +32068,7 @@ function registerSheetsTools(server2) {
31938
32068
  }, async ({ spreadsheetId, find, replace, account }) => {
31939
32069
  return runOrDiagnose(["sheets", "find-replace", spreadsheetId, find, replace], { account });
31940
32070
  });
31941
- server2.registerTool("gog_sheets_run", {
31942
- description: "Run any gog sheets subcommand not covered by the other tools. Run `gog sheets --help` for the full list of subcommands, or `gog sheets <subcommand> --help` for flags on a specific subcommand.",
31943
- annotations: { destructiveHint: true },
31944
- inputSchema: {
31945
- subcommand: external_exports.string().describe('The gog sheets subcommand to run, e.g. "freeze", "add-tab", "rename-tab"'),
31946
- args: external_exports.array(external_exports.string()).describe('Additional positional args and flags, e.g. ["<spreadsheetId>", "--rows=1"]'),
31947
- account: accountParam
31948
- }
31949
- }, async ({ subcommand, args, account }) => {
31950
- return runOrDiagnose(["sheets", subcommand, ...args], { account });
31951
- });
32071
+ registerRunTool(server2, { service: "sheets", examples: '"freeze", "add-tab", "rename-tab"' });
31952
32072
  }
31953
32073
 
31954
32074
  // src/tools/slides.ts
@@ -32026,17 +32146,7 @@ function registerSlidesTools(server2) {
32026
32146
  }, async ({ presentationId, slideId, account }) => {
32027
32147
  return runOrDiagnose(["slides", "read-slide", presentationId, slideId], { account });
32028
32148
  });
32029
- server2.registerTool("gog_slides_run", {
32030
- description: "Run any gog slides subcommand not covered by the other tools. Run `gog slides --help` for the full list of subcommands, or `gog slides <subcommand> --help` for flags on a specific subcommand.",
32031
- annotations: { destructiveHint: true },
32032
- inputSchema: {
32033
- subcommand: external_exports.string().describe("The gog slides subcommand to run"),
32034
- args: external_exports.array(external_exports.string()).describe("Additional positional args and flags"),
32035
- account: accountParam
32036
- }
32037
- }, async ({ subcommand, args, account }) => {
32038
- return runOrDiagnose(["slides", subcommand, ...args], { account });
32039
- });
32149
+ registerRunTool(server2, { service: "slides", examples: '"add-slide", "delete-slide", "update-notes"' });
32040
32150
  }
32041
32151
 
32042
32152
  // src/tools/tasks.ts
@@ -32109,21 +32219,11 @@ function registerTasksTools(server2) {
32109
32219
  }, async ({ tasklistId, taskId, account }) => {
32110
32220
  return runOrDiagnose(["tasks", "delete", tasklistId, taskId], { account });
32111
32221
  });
32112
- server2.registerTool("gog_tasks_run", {
32113
- description: "Run any gog tasks subcommand not covered by the other tools. Run `gog tasks --help` for the full list of subcommands, or `gog tasks <subcommand> --help` for flags on a specific subcommand.",
32114
- annotations: { destructiveHint: true },
32115
- inputSchema: {
32116
- subcommand: external_exports.string().describe('The gog tasks subcommand to run, e.g. "update", "undo", "clear"'),
32117
- args: external_exports.array(external_exports.string()).describe("Additional positional args and flags"),
32118
- account: accountParam
32119
- }
32120
- }, async ({ subcommand, args, account }) => {
32121
- return runOrDiagnose(["tasks", subcommand, ...args], { account });
32122
- });
32222
+ registerRunTool(server2, { service: "tasks", examples: '"update", "undo", "clear"' });
32123
32223
  }
32124
32224
 
32125
32225
  // src/server.ts
32126
- var VERSION = true ? "2.0.7" : "0.0.0";
32226
+ var VERSION = true ? "2.0.9" : "0.0.0";
32127
32227
  function createServer(options) {
32128
32228
  return new McpServer({
32129
32229
  name: options?.name ?? "gogcli",