gogcli-mcp 4.5.0 → 4.5.2

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
@@ -956,14 +956,14 @@ function promiseAllObject(promisesObj) {
956
956
  }
957
957
  function randomString(length = 10) {
958
958
  const chars = "abcdefghijklmnopqrstuvwxyz";
959
- let str = "";
959
+ let str2 = "";
960
960
  for (let i = 0; i < length; i++) {
961
- str += chars[Math.floor(Math.random() * chars.length)];
961
+ str2 += chars[Math.floor(Math.random() * chars.length)];
962
962
  }
963
- return str;
963
+ return str2;
964
964
  }
965
- function esc(str) {
966
- return JSON.stringify(str);
965
+ function esc(str2) {
966
+ return JSON.stringify(str2);
967
967
  }
968
968
  function slugify(input2) {
969
969
  return input2.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
@@ -1077,8 +1077,8 @@ var primitiveTypes = /* @__PURE__ */ new Set([
1077
1077
  "symbol",
1078
1078
  "undefined"
1079
1079
  ]);
1080
- function escapeRegex(str) {
1081
- return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1080
+ function escapeRegex(str2) {
1081
+ return str2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1082
1082
  }
1083
1083
  function clone(inst, def, params) {
1084
1084
  const cl = new inst._zod.constr(def ?? inst._zod.def);
@@ -1332,13 +1332,13 @@ function getSizableOrigin(input2) {
1332
1332
  return "unknown";
1333
1333
  }
1334
1334
  var highSurrogate = /[\uD800-\uDBFF]/;
1335
- function codePointLength(str) {
1336
- const units = str.length;
1337
- if (!highSurrogate.test(str))
1335
+ function codePointLength(str2) {
1336
+ const units = str2.length;
1337
+ if (!highSurrogate.test(str2))
1338
1338
  return units;
1339
1339
  let count = units;
1340
1340
  for (let i = 0; i < units - 1; i++) {
1341
- if ((str.charCodeAt(i) & 64512) === 55296 && (str.charCodeAt(i + 1) & 64512) === 56320) {
1341
+ if ((str2.charCodeAt(i) & 64512) === 55296 && (str2.charCodeAt(i + 1) & 64512) === 56320) {
1342
1342
  count--;
1343
1343
  i++;
1344
1344
  }
@@ -19790,7 +19790,7 @@ function date4(params) {
19790
19790
  return _coercedDate(ZodDate, params);
19791
19791
  }
19792
19792
 
19793
- // ../../node_modules/@modelcontextprotocol/core/dist/auth-CUe6YdwF.mjs
19793
+ // ../../node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core/dist/auth-CGP0BDVq.mjs
19794
19794
  var LATEST_PROTOCOL_VERSION = "2025-11-25";
19795
19795
  var SUPPORTED_PROTOCOL_VERSIONS = [
19796
19796
  LATEST_PROTOCOL_VERSION,
@@ -20627,7 +20627,8 @@ var OAuthMetadataSchema = looseObject({
20627
20627
  introspection_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
20628
20628
  code_challenge_methods_supported: array(string2()).optional(),
20629
20629
  client_id_metadata_document_supported: boolean2().optional(),
20630
- authorization_response_iss_parameter_supported: boolean2().optional().catch(void 0)
20630
+ authorization_response_iss_parameter_supported: boolean2().optional().catch(void 0),
20631
+ dpop_signing_alg_values_supported: array(string2()).optional()
20631
20632
  });
20632
20633
  var OpenIdProviderMetadataSchema = looseObject({
20633
20634
  issuer: string2(),
@@ -20728,7 +20729,7 @@ var OAuthTokenRevocationRequestSchema = object({
20728
20729
  token_type_hint: string2().optional()
20729
20730
  }).strip();
20730
20731
 
20731
- // ../../node_modules/@modelcontextprotocol/server/dist/src-CX2iR2pK.mjs
20732
+ // ../../node_modules/@modelcontextprotocol/server/dist/src-D-y6h4N7.mjs
20732
20733
  var BRANDS = /* @__PURE__ */ Symbol.for("mcp.sdk.errorBrands");
20733
20734
  function stampErrorBrands(instance, ctor) {
20734
20735
  const brands = /* @__PURE__ */ new Set();
@@ -20842,8 +20843,18 @@ var SdkError = class extends Error {
20842
20843
  if (typeof this !== "function") throw new TypeError("isInstance must be called on the class (e.g. `SdkError.isInstance(value)`); for callbacks use `v => SdkError.isInstance(v)`");
20843
20844
  return brandedHasInstance(this, value);
20844
20845
  }
20845
- constructor(code, message, data) {
20846
- super(message);
20846
+ /**
20847
+ * @param code - Stable string code identifying the failure ({@linkcode SdkErrorCode}).
20848
+ * @param message - Human-readable description.
20849
+ * @param data - Optional structured payload (for example the HTTP status carried by
20850
+ * {@linkcode SdkHttpError}). Opaque to the SDK: a `cause` key inside `data` is not
20851
+ * promoted to `Error.cause`.
20852
+ * @param options - Standard `ErrorOptions`, forwarded to `Error`. Pass the underlying
20853
+ * failure as `{ cause }` so it is reachable through the `Error.cause` chain that
20854
+ * loggers and error trackers walk.
20855
+ */
20856
+ constructor(code, message, data, options) {
20857
+ super(message, options);
20847
20858
  this.code = code;
20848
20859
  this.data = data;
20849
20860
  this.name = "SdkError";
@@ -20854,8 +20865,11 @@ var SdkHttpError = class extends SdkError {
20854
20865
  static {
20855
20866
  Object.defineProperty(this, "mcpBrand", { value: "mcp.SdkHttpError" });
20856
20867
  }
20857
- constructor(code, message, data) {
20858
- super(code, message, data);
20868
+ /**
20869
+ * @param options - Standard `ErrorOptions`, forwarded to `Error` (see {@linkcode SdkError}).
20870
+ */
20871
+ constructor(code, message, data, options) {
20872
+ super(code, message, data, options);
20859
20873
  this.name = "SdkHttpError";
20860
20874
  }
20861
20875
  get status() {
@@ -23806,7 +23820,7 @@ var INBOUND_VALIDATION_LADDER = [
23806
23820
  evaluatedAt: "pre-dispatch",
23807
23821
  codes: [HEADER_MISMATCH_ERROR_CODE],
23808
23822
  conformance: ["http-header-validation"],
23809
- rationale: "SEP-2243 standard `Mcp-Method` / `Mcp-Name` headers \u2014 presence, sentinel decoding, and `Mcp-Name` \u2194 body cross-check \u2014 are validated by the HTTP entry on a modern-classified request after the supported-revision gate and before dispatch. The classifier\u2019s own header-mismatch cells (protocol-version, `Mcp-Method` mismatch) stay on the edge `era-classification` rung; this rung carries the entry-layer presence/`Mcp-Name` half. Evaluated before the capability gate, the factory call, and the `Mcp-Param-*` rung so a request that fails several rungs is answered by the standard-header rung first. The documented order (after method-registry 5 and request-params 6) is NOT the observed precedence: serveModern evaluates this rung immediately after the supported-revision gate, so a request that also fails a dispatch rung is answered here before the dispatch rungs (5\u20136) are consulted."
23823
+ rationale: "SEP-2243 standard `MCP-Protocol-Version` / `Mcp-Method` / `Mcp-Name` headers \u2014 presence, sentinel decoding, and `Mcp-Name` \u2194 body cross-check \u2014 are validated by the HTTP entry on a modern-classified request after the supported-revision gate and before dispatch. The spec requires `MCP-Protocol-Version` and `Mcp-Method` on every modern *request* POST (`Mcp-Name` only for the methods that mirror `params.name` / `params.uri` / `params.taskId`, see `MCP_NAME_HEADER_SOURCE`) and names them in that order, so a request missing several is answered by the earliest. Notification POSTs are exempt: the presence half runs on requests only, so a modern-enveloped notification is dispatched even with no standard headers at all. The classifier\u2019s own header-mismatch cells (protocol-version, `Mcp-Method` mismatch) stay on the edge `era-classification` rung; this rung carries the entry-layer presence/`Mcp-Name` half \u2014 including the missing `MCP-Protocol-Version` cell, which cannot live on the edge rung without breaking body-primary classification. Evaluated before the capability gate, the factory call, and the `Mcp-Param-*` rung so a request that fails several rungs is answered by the standard-header rung first. The documented order (after method-registry 5 and request-params 6) is NOT the observed precedence: serveModern evaluates this rung immediately after the supported-revision gate, so a request that also fails a dispatch rung is answered here before the dispatch rungs (5\u20136) are consulted."
23810
23824
  },
23811
23825
  {
23812
23826
  rung: "client-capabilities",
@@ -24607,7 +24621,7 @@ var Protocol = class {
24607
24621
  return this._requestHandlers.get(method);
24608
24622
  }
24609
24623
  async _oncancel(notification) {
24610
- if (!notification.params.requestId) return;
24624
+ if (notification.params.requestId === void 0) return;
24611
24625
  this._requestHandlerAbortControllers.get(notification.params.requestId)?.abort(notification.params.reason);
24612
24626
  }
24613
24627
  _setupTimeout(messageId, timeout, maxTotalTimeout, onTimeout, resetTimeoutOnProgress = false) {
@@ -25006,19 +25020,20 @@ var Protocol = class {
25006
25020
  const cancel = (reason) => {
25007
25021
  if (responseReceived) return;
25008
25022
  this._progressHandlers.delete(messageId);
25009
- if (requestAbort === void 0) this._transport?.send(this._envelopeOutbound({
25010
- jsonrpc: "2.0",
25011
- method: "notifications/cancelled",
25012
- params: {
25013
- requestId: messageId,
25014
- reason: String(reason)
25015
- }
25016
- }), {
25017
- relatedRequestId,
25018
- resumptionToken,
25019
- onresumptiontoken
25020
- }).catch((error62) => this._onerror(/* @__PURE__ */ new Error(`Failed to send cancellation: ${error62}`)));
25021
- else requestAbort.abort();
25023
+ if (requestAbort === void 0) {
25024
+ if (request.method !== "initialize") this._transport?.send(this._envelopeOutbound({
25025
+ jsonrpc: "2.0",
25026
+ method: "notifications/cancelled",
25027
+ params: {
25028
+ requestId: messageId,
25029
+ reason: String(reason)
25030
+ }
25031
+ }), {
25032
+ relatedRequestId,
25033
+ resumptionToken,
25034
+ onresumptiontoken
25035
+ }).catch((error62) => this._onerror(/* @__PURE__ */ new Error(`Failed to send cancellation: ${error62}`)));
25036
+ } else requestAbort.abort();
25022
25037
  reject(reason instanceof SdkError ? reason : new SdkError(SdkErrorCode.RequestTimeout, String(reason)));
25023
25038
  };
25024
25039
  this._responseHandlers.set(messageId, (response) => {
@@ -25098,7 +25113,7 @@ var Protocol = class {
25098
25113
  jsonrpc: "2.0",
25099
25114
  ...notification
25100
25115
  });
25101
- if ((this._options?.debouncedNotificationMethods ?? []).includes(notification.method) && !notification.params && !options?.relatedRequestId) {
25116
+ if ((this._options?.debouncedNotificationMethods ?? []).includes(notification.method) && !notification.params && options?.relatedRequestId === void 0) {
25102
25117
  if (this._pendingDebouncedNotifications.has(notification.method)) return;
25103
25118
  this._pendingDebouncedNotifications.add(notification.method);
25104
25119
  Promise.resolve().then(() => {
@@ -25451,7 +25466,7 @@ var require_code$1 = /* @__PURE__ */ __commonJSMin(((exports) => {
25451
25466
  }
25452
25467
  exports._ = _;
25453
25468
  const plus = new _Code("+");
25454
- function str(strs, ...args) {
25469
+ function str2(strs, ...args) {
25455
25470
  const expr = [safeStringify(strs[0])];
25456
25471
  let i = 0;
25457
25472
  while (i < args.length) {
@@ -25462,7 +25477,7 @@ var require_code$1 = /* @__PURE__ */ __commonJSMin(((exports) => {
25462
25477
  optimize(expr);
25463
25478
  return new _Code(expr);
25464
25479
  }
25465
- exports.str = str;
25480
+ exports.str = str2;
25466
25481
  function addCodeArg(code, arg) {
25467
25482
  if (arg instanceof _Code) code.push(...arg._items);
25468
25483
  else if (arg instanceof Name) code.push(arg);
@@ -25495,7 +25510,7 @@ var require_code$1 = /* @__PURE__ */ __commonJSMin(((exports) => {
25495
25510
  if (typeof b == "string" && b[0] === '"' && !(a instanceof Name)) return `"${a}${b.slice(1)}`;
25496
25511
  }
25497
25512
  function strConcat(c1, c2) {
25498
- return c2.emptyStr() ? c1 : c1.emptyStr() ? c2 : str`${c1}${c2}`;
25513
+ return c2.emptyStr() ? c1 : c1.emptyStr() ? c2 : str2`${c1}${c2}`;
25499
25514
  }
25500
25515
  exports.strConcat = strConcat;
25501
25516
  function interpolate(x) {
@@ -26374,21 +26389,21 @@ var require_util = /* @__PURE__ */ __commonJSMin(((exports) => {
26374
26389
  return (0, codegen_1._)`${topSchemaRef}${schemaPath}${(0, codegen_1.getProperty)(keyword)}`;
26375
26390
  }
26376
26391
  exports.schemaRefOrVal = schemaRefOrVal;
26377
- function unescapeFragment(str) {
26378
- return unescapeJsonPointer(decodeURIComponent(str));
26392
+ function unescapeFragment(str2) {
26393
+ return unescapeJsonPointer(decodeURIComponent(str2));
26379
26394
  }
26380
26395
  exports.unescapeFragment = unescapeFragment;
26381
- function escapeFragment(str) {
26382
- return encodeURIComponent(escapeJsonPointer(str));
26396
+ function escapeFragment(str2) {
26397
+ return encodeURIComponent(escapeJsonPointer(str2));
26383
26398
  }
26384
26399
  exports.escapeFragment = escapeFragment;
26385
- function escapeJsonPointer(str) {
26386
- if (typeof str == "number") return `${str}`;
26387
- return str.replace(/~/g, "~0").replace(/\//g, "~1");
26400
+ function escapeJsonPointer(str2) {
26401
+ if (typeof str2 == "number") return `${str2}`;
26402
+ return str2.replace(/~/g, "~0").replace(/\//g, "~1");
26388
26403
  }
26389
26404
  exports.escapeJsonPointer = escapeJsonPointer;
26390
- function unescapeJsonPointer(str) {
26391
- return str.replace(/~1/g, "/").replace(/~0/g, "~");
26405
+ function unescapeJsonPointer(str2) {
26406
+ return str2.replace(/~1/g, "/").replace(/~0/g, "~");
26392
26407
  }
26393
26408
  exports.unescapeJsonPointer = unescapeJsonPointer;
26394
26409
  function eachItem(xs, f) {
@@ -27274,8 +27289,8 @@ var require_json_schema_traverse = /* @__PURE__ */ __commonJSMin(((exports, modu
27274
27289
  post(schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex);
27275
27290
  }
27276
27291
  }
27277
- function escapeJsonPtr(str) {
27278
- return str.replace(/~/g, "~0").replace(/\//g, "~1");
27292
+ function escapeJsonPtr(str2) {
27293
+ return str2.replace(/~/g, "~0").replace(/\//g, "~1");
27279
27294
  }
27280
27295
  }));
27281
27296
  var require_resolve = /* @__PURE__ */ __commonJSMin(((exports) => {
@@ -28167,9 +28182,9 @@ var require_utils = /* @__PURE__ */ __commonJSMin(((exports, module) => {
28167
28182
  isIPV6: false
28168
28183
  };
28169
28184
  }
28170
- function findToken(str, token) {
28185
+ function findToken(str2, token) {
28171
28186
  let ind = 0;
28172
- for (let i = 0; i < str.length; i++) if (str[i] === token) ind++;
28187
+ for (let i = 0; i < str2.length; i++) if (str2[i] === token) ind++;
28173
28188
  return ind;
28174
28189
  }
28175
28190
  function removeDotSegments(path) {
@@ -28684,7 +28699,7 @@ var require_core$3 = /* @__PURE__ */ __commonJSMin(((exports) => {
28684
28699
  const util_1 = require_util();
28685
28700
  const $dataRefSchema = require_data();
28686
28701
  const uri_1 = require_uri();
28687
- const defaultRegExp = (str, flags) => new RegExp(str, flags);
28702
+ const defaultRegExp = (str2, flags) => new RegExp(str2, flags);
28688
28703
  defaultRegExp.code = "new RegExp";
28689
28704
  const META_IGNORE_OPTIONS = [
28690
28705
  "removeAdditional",
@@ -29390,16 +29405,16 @@ var require_multipleOf = /* @__PURE__ */ __commonJSMin(((exports) => {
29390
29405
  }));
29391
29406
  var require_ucs2length = /* @__PURE__ */ __commonJSMin(((exports) => {
29392
29407
  Object.defineProperty(exports, "__esModule", { value: true });
29393
- function ucs2length(str) {
29394
- const len = str.length;
29408
+ function ucs2length(str2) {
29409
+ const len = str2.length;
29395
29410
  let length = 0;
29396
29411
  let pos2 = 0;
29397
29412
  let value;
29398
29413
  while (pos2 < len) {
29399
29414
  length++;
29400
- value = str.charCodeAt(pos2++);
29415
+ value = str2.charCodeAt(pos2++);
29401
29416
  if (value >= 55296 && value <= 56319 && pos2 < len) {
29402
- value = str.charCodeAt(pos2);
29417
+ value = str2.charCodeAt(pos2);
29403
29418
  if ((value & 64512) === 56320) pos2++;
29404
29419
  }
29405
29420
  }
@@ -32110,8 +32125,8 @@ var require_formats = /* @__PURE__ */ __commonJSMin(((exports) => {
32110
32125
  30,
32111
32126
  31
32112
32127
  ];
32113
- function date5(str) {
32114
- const matches = DATE.exec(str);
32128
+ function date5(str2) {
32129
+ const matches = DATE.exec(str2);
32115
32130
  if (!matches) return false;
32116
32131
  const year = +matches[1];
32117
32132
  const month = +matches[2];
@@ -32126,8 +32141,8 @@ var require_formats = /* @__PURE__ */ __commonJSMin(((exports) => {
32126
32141
  }
32127
32142
  const TIME = /^(\d\d):(\d\d):(\d\d(?:\.\d+)?)(z|([+-])(\d\d)(?::?(\d\d))?)?$/i;
32128
32143
  function getTime(strictTimeZone) {
32129
- return function time3(str) {
32130
- const matches = TIME.exec(str);
32144
+ return function time3(str2) {
32145
+ const matches = TIME.exec(str2);
32131
32146
  if (!matches) return false;
32132
32147
  const hr = +matches[1];
32133
32148
  const min = +matches[2];
@@ -32164,8 +32179,8 @@ var require_formats = /* @__PURE__ */ __commonJSMin(((exports) => {
32164
32179
  const DATE_TIME_SEPARATOR = /t|\s/i;
32165
32180
  function getDateTime(strictTimeZone) {
32166
32181
  const time3 = getTime(strictTimeZone);
32167
- return function date_time(str) {
32168
- const dateTime = str.split(DATE_TIME_SEPARATOR);
32182
+ return function date_time(str2) {
32183
+ const dateTime = str2.split(DATE_TIME_SEPARATOR);
32169
32184
  return dateTime.length === 2 && date5(dateTime[0]) && time3(dateTime[1]);
32170
32185
  };
32171
32186
  }
@@ -32186,13 +32201,13 @@ var require_formats = /* @__PURE__ */ __commonJSMin(((exports) => {
32186
32201
  }
32187
32202
  const NOT_URI_FRAGMENT = /\/|:/;
32188
32203
  const URI = /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i;
32189
- function uri(str) {
32190
- return NOT_URI_FRAGMENT.test(str) && URI.test(str);
32204
+ function uri(str2) {
32205
+ return NOT_URI_FRAGMENT.test(str2) && URI.test(str2);
32191
32206
  }
32192
32207
  const BYTE = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/gm;
32193
- function byte(str) {
32208
+ function byte(str2) {
32194
32209
  BYTE.lastIndex = 0;
32195
- return BYTE.test(str);
32210
+ return BYTE.test(str2);
32196
32211
  }
32197
32212
  const MIN_INT32 = -(2 ** 31);
32198
32213
  const MAX_INT32 = 2 ** 31 - 1;
@@ -32206,10 +32221,10 @@ var require_formats = /* @__PURE__ */ __commonJSMin(((exports) => {
32206
32221
  return true;
32207
32222
  }
32208
32223
  const Z_ANCHOR = /[^\\]\\Z/;
32209
- function regex(str) {
32210
- if (Z_ANCHOR.test(str)) return false;
32224
+ function regex(str2) {
32225
+ if (Z_ANCHOR.test(str2)) return false;
32211
32226
  try {
32212
- new RegExp(str);
32227
+ new RegExp(str2);
32213
32228
  return true;
32214
32229
  } catch (e) {
32215
32230
  return false;
@@ -32401,7 +32416,7 @@ var Ajv = import_ajv.Ajv;
32401
32416
  // ../../node_modules/@modelcontextprotocol/server/dist/shimsNode.mjs
32402
32417
  import process2 from "node:process";
32403
32418
 
32404
- // ../../node_modules/@modelcontextprotocol/server/dist/mcp-DXXb3Vv3.mjs
32419
+ // ../../node_modules/@modelcontextprotocol/server/dist/mcp-Dw2OlZ1f.mjs
32405
32420
  var COMPLETABLE_SYMBOL = /* @__PURE__ */ Symbol.for("mcp.completable");
32406
32421
  function isCompletable(schema) {
32407
32422
  return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
@@ -32594,6 +32609,9 @@ function notificationToServerEvent(method, uri) {
32594
32609
  };
32595
32610
  }
32596
32611
  }
32612
+ function supportsScopeChallengeResolver(transport) {
32613
+ return typeof transport === "object" && transport !== null && "setScopeChallengeResolver" in transport && typeof transport.setScopeChallengeResolver === "function";
32614
+ }
32597
32615
  var DEFAULT_LEGACY_SHIM_MAX_ROUNDS = 8;
32598
32616
  var DEFAULT_LEGACY_SHIM_ROUND_TIMEOUT_MS = 6e5;
32599
32617
  function resolveLegacyShimOptions(options) {
@@ -33404,6 +33422,7 @@ var McpServer = class {
33404
33422
  * ```
33405
33423
  */
33406
33424
  async connect(transport) {
33425
+ if (supportsScopeChallengeResolver(transport)) transport.setScopeChallengeResolver((context) => this.resolveScopeChallenge(context));
33407
33426
  return await this.server.connect(transport);
33408
33427
  }
33409
33428
  /**
@@ -33412,6 +33431,41 @@ var McpServer = class {
33412
33431
  async close() {
33413
33432
  await this.server.close();
33414
33433
  }
33434
+ /** @internal */
33435
+ resolveScopeChallenge = (context) => {
33436
+ switch (context.request.method) {
33437
+ case "tools/call": {
33438
+ const toolName = context.request.params?.name;
33439
+ if (typeof toolName !== "string") return;
33440
+ const tool = this._registeredTools[toolName];
33441
+ if (tool === void 0 || !tool.enabled) return;
33442
+ return tool.scopeChallenge?.(context);
33443
+ }
33444
+ case "resources/read": {
33445
+ const resourceUri = context.request.params?.uri;
33446
+ if (typeof resourceUri !== "string") return;
33447
+ let uri;
33448
+ try {
33449
+ uri = new URL(resourceUri);
33450
+ } catch {
33451
+ return;
33452
+ }
33453
+ const resource = this._registeredResources[uri.toString()];
33454
+ if (resource !== void 0) return resource.enabled ? resource.scopeChallenge?.(context) : void 0;
33455
+ for (const template of Object.values(this._registeredResourceTemplates)) if (template.resourceTemplate.uriTemplate.match(uri.toString())) return template.enabled ? template.scopeChallenge?.(context) : void 0;
33456
+ return;
33457
+ }
33458
+ case "prompts/get": {
33459
+ const promptName = context.request.params?.name;
33460
+ if (typeof promptName !== "string") return;
33461
+ const prompt = this._registeredPrompts[promptName];
33462
+ if (prompt === void 0 || !prompt.enabled) return;
33463
+ return prompt.scopeChallenge?.(context);
33464
+ }
33465
+ default:
33466
+ return;
33467
+ }
33468
+ };
33415
33469
  _toolHandlersInitialized = false;
33416
33470
  setToolRequestHandlers() {
33417
33471
  if (this._toolHandlersInitialized) return;
@@ -33578,7 +33632,10 @@ var McpServer = class {
33578
33632
  }
33579
33633
  for (const template of Object.values(this._registeredResourceTemplates)) {
33580
33634
  const variables = template.resourceTemplate.uriTemplate.match(uri.toString());
33581
- if (variables) return attachCacheHintFallback(await template.readCallback(uri, variables, ctx), template.cacheHint);
33635
+ if (variables) {
33636
+ if (!template.enabled) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Resource template ${template.resourceTemplate.uriTemplate} disabled`);
33637
+ return attachCacheHintFallback(await template.readCallback(uri, variables, ctx), template.cacheHint);
33638
+ }
33582
33639
  }
33583
33640
  throw new ResourceNotFoundError(request.params.uri);
33584
33641
  });
@@ -33609,36 +33666,32 @@ var McpServer = class {
33609
33666
  this._promptHandlersInitialized = true;
33610
33667
  }
33611
33668
  registerResource(name, uriOrTemplate, config2, readCallback) {
33612
- const cacheHint = config2.cacheHint;
33613
- let metadata = config2;
33614
- if (cacheHint !== void 0) {
33615
- assertValidCacheHint(cacheHint, `resource ${name}`);
33616
- const rest = { ...config2 };
33617
- delete rest.cacheHint;
33618
- metadata = rest;
33619
- }
33669
+ const { cacheHint, scopeChallenge, ...resourceMetadata } = config2;
33670
+ const metadata = resourceMetadata;
33671
+ if (cacheHint !== void 0) assertValidCacheHint(cacheHint, `resource ${name}`);
33620
33672
  if (typeof uriOrTemplate === "string") {
33621
33673
  if (this._registeredResources[uriOrTemplate]) throw new Error(`Resource ${uriOrTemplate} is already registered`);
33622
- const registeredResource = this._createRegisteredResource(name, config2.title, uriOrTemplate, metadata, readCallback);
33674
+ const registeredResource = this._createRegisteredResource(name, config2.title, uriOrTemplate, metadata, scopeChallenge, readCallback);
33623
33675
  if (cacheHint !== void 0) registeredResource.cacheHint = cacheHint;
33624
33676
  this.setResourceRequestHandlers();
33625
33677
  this.sendResourceListChanged();
33626
33678
  return registeredResource;
33627
33679
  } else {
33628
33680
  if (this._registeredResourceTemplates[name]) throw new Error(`Resource template ${name} is already registered`);
33629
- const registeredResourceTemplate = this._createRegisteredResourceTemplate(name, config2.title, uriOrTemplate, metadata, readCallback);
33681
+ const registeredResourceTemplate = this._createRegisteredResourceTemplate(name, config2.title, uriOrTemplate, metadata, scopeChallenge, readCallback);
33630
33682
  if (cacheHint !== void 0) registeredResourceTemplate.cacheHint = cacheHint;
33631
33683
  this.setResourceRequestHandlers();
33632
33684
  this.sendResourceListChanged();
33633
33685
  return registeredResourceTemplate;
33634
33686
  }
33635
33687
  }
33636
- _createRegisteredResource(name, title, uri, metadata, readCallback) {
33688
+ _createRegisteredResource(name, title, uri, metadata, scopeChallenge, readCallback) {
33637
33689
  const registeredResource = {
33638
33690
  name,
33639
33691
  title,
33640
33692
  metadata,
33641
33693
  readCallback,
33694
+ scopeChallenge,
33642
33695
  enabled: true,
33643
33696
  disable: () => registeredResource.update({ enabled: false }),
33644
33697
  enable: () => registeredResource.update({ enabled: true }),
@@ -33652,6 +33705,7 @@ var McpServer = class {
33652
33705
  if (updates.title !== void 0) registeredResource.title = updates.title;
33653
33706
  if (updates.metadata !== void 0) registeredResource.metadata = updates.metadata;
33654
33707
  if (updates.callback !== void 0) registeredResource.readCallback = updates.callback;
33708
+ if (updates.scopeChallenge !== void 0) registeredResource.scopeChallenge = updates.scopeChallenge === null ? void 0 : updates.scopeChallenge;
33655
33709
  if (updates.enabled !== void 0) registeredResource.enabled = updates.enabled;
33656
33710
  this.sendResourceListChanged();
33657
33711
  }
@@ -33659,12 +33713,13 @@ var McpServer = class {
33659
33713
  this._registeredResources[uri] = registeredResource;
33660
33714
  return registeredResource;
33661
33715
  }
33662
- _createRegisteredResourceTemplate(name, title, template, metadata, readCallback) {
33716
+ _createRegisteredResourceTemplate(name, title, template, metadata, scopeChallenge, readCallback) {
33663
33717
  const registeredResourceTemplate = {
33664
33718
  resourceTemplate: template,
33665
33719
  title,
33666
33720
  metadata,
33667
33721
  readCallback,
33722
+ scopeChallenge,
33668
33723
  enabled: true,
33669
33724
  disable: () => registeredResourceTemplate.update({ enabled: false }),
33670
33725
  enable: () => registeredResourceTemplate.update({ enabled: true }),
@@ -33678,6 +33733,7 @@ var McpServer = class {
33678
33733
  if (updates.template !== void 0) registeredResourceTemplate.resourceTemplate = updates.template;
33679
33734
  if (updates.metadata !== void 0) registeredResourceTemplate.metadata = updates.metadata;
33680
33735
  if (updates.callback !== void 0) registeredResourceTemplate.readCallback = updates.callback;
33736
+ if (updates.scopeChallenge !== void 0) registeredResourceTemplate.scopeChallenge = updates.scopeChallenge === null ? void 0 : updates.scopeChallenge;
33681
33737
  if (updates.enabled !== void 0) registeredResourceTemplate.enabled = updates.enabled;
33682
33738
  this.sendResourceListChanged();
33683
33739
  }
@@ -33687,7 +33743,7 @@ var McpServer = class {
33687
33743
  if (Array.isArray(variableNames) && variableNames.some((v) => !!template.completeCallback(v))) this.setCompletionRequestHandler();
33688
33744
  return registeredResourceTemplate;
33689
33745
  }
33690
- _createRegisteredPrompt(name, title, description, argsSchema, callback, icons, _meta) {
33746
+ _createRegisteredPrompt(name, title, description, argsSchema, callback, icons, scopeChallenge, _meta) {
33691
33747
  let currentArgsSchema = argsSchema;
33692
33748
  let currentCallback = callback;
33693
33749
  const registeredPrompt = {
@@ -33695,6 +33751,7 @@ var McpServer = class {
33695
33751
  description,
33696
33752
  argsSchema,
33697
33753
  icons,
33754
+ scopeChallenge,
33698
33755
  _meta,
33699
33756
  handler: createPromptHandler(name, argsSchema, callback),
33700
33757
  enabled: true,
@@ -33709,6 +33766,7 @@ var McpServer = class {
33709
33766
  if (updates.title !== void 0) registeredPrompt.title = updates.title;
33710
33767
  if (updates.description !== void 0) registeredPrompt.description = updates.description;
33711
33768
  if (updates.icons !== void 0) registeredPrompt.icons = updates.icons;
33769
+ if (updates.scopeChallenge !== void 0) registeredPrompt.scopeChallenge = updates.scopeChallenge === null ? void 0 : updates.scopeChallenge;
33712
33770
  if (updates._meta !== void 0) registeredPrompt._meta = updates._meta;
33713
33771
  let needsHandlerRegen = false;
33714
33772
  if (updates.argsSchema !== void 0) {
@@ -33736,7 +33794,7 @@ var McpServer = class {
33736
33794
  }
33737
33795
  return registeredPrompt;
33738
33796
  }
33739
- _createRegisteredTool(name, title, description, inputSchema, outputSchema, annotations, icons, execution, _meta, handler) {
33797
+ _createRegisteredTool(name, title, description, inputSchema, outputSchema, annotations, icons, execution, scopeChallenge, _meta, handler) {
33740
33798
  validateAndWarnToolName(name);
33741
33799
  if (inputSchema !== void 0) try {
33742
33800
  const json2 = standardSchemaToJsonSchema(inputSchema, "input");
@@ -33755,6 +33813,7 @@ var McpServer = class {
33755
33813
  annotations,
33756
33814
  icons,
33757
33815
  execution,
33816
+ scopeChallenge,
33758
33817
  _meta,
33759
33818
  handler,
33760
33819
  executor: createToolExecutor(inputSchema, handler),
@@ -33793,6 +33852,7 @@ var McpServer = class {
33793
33852
  }
33794
33853
  if (updates.annotations !== void 0) registeredTool.annotations = updates.annotations;
33795
33854
  if (updates.icons !== void 0) registeredTool.icons = updates.icons;
33855
+ if (updates.scopeChallenge !== void 0) registeredTool.scopeChallenge = updates.scopeChallenge === null ? void 0 : updates.scopeChallenge;
33796
33856
  if (updates._meta !== void 0) registeredTool._meta = updates._meta;
33797
33857
  if (updates.enabled !== void 0) registeredTool.enabled = updates.enabled;
33798
33858
  this.sendToolListChanged();
@@ -33805,13 +33865,13 @@ var McpServer = class {
33805
33865
  }
33806
33866
  registerTool(name, config2, cb) {
33807
33867
  if (this._registeredTools[name]) throw new Error(`Tool ${name} is already registered`);
33808
- const { title, description, inputSchema, outputSchema, annotations, icons, _meta } = config2;
33809
- return this._createRegisteredTool(name, title, description, normalizeRawShapeSchema(inputSchema), normalizeRawShapeSchema(outputSchema), annotations, icons, void 0, _meta, cb);
33868
+ const { title, description, inputSchema, outputSchema, annotations, icons, scopeChallenge, _meta } = config2;
33869
+ return this._createRegisteredTool(name, title, description, normalizeRawShapeSchema(inputSchema), normalizeRawShapeSchema(outputSchema), annotations, icons, void 0, scopeChallenge, _meta, cb);
33810
33870
  }
33811
33871
  registerPrompt(name, config2, cb) {
33812
33872
  if (this._registeredPrompts[name]) throw new Error(`Prompt ${name} is already registered`);
33813
- const { title, description, argsSchema, icons, _meta } = config2;
33814
- const registeredPrompt = this._createRegisteredPrompt(name, title, description, normalizeRawShapeSchema(argsSchema), cb, icons, _meta);
33873
+ const { title, description, argsSchema, icons, scopeChallenge, _meta } = config2;
33874
+ const registeredPrompt = this._createRegisteredPrompt(name, title, description, normalizeRawShapeSchema(argsSchema), cb, icons, scopeChallenge, _meta);
33815
33875
  this.setPromptRequestHandlers();
33816
33876
  this.sendPromptListChanged();
33817
33877
  return registeredPrompt;
@@ -33923,6 +33983,7 @@ function unwrapOptionalSchema(schema) {
33923
33983
  }
33924
33984
 
33925
33985
  // ../../node_modules/@modelcontextprotocol/server/dist/stdio.mjs
33986
+ var swallowsErrorsAfterClose = /* @__PURE__ */ Symbol("swallowsErrorsAfterClose");
33926
33987
  var StdioServerTransport = class {
33927
33988
  _readBuffer;
33928
33989
  _started = false;
@@ -33949,18 +34010,27 @@ var StdioServerTransport = class {
33949
34010
  this.onerror?.(error62);
33950
34011
  };
33951
34012
  _onstdouterror = (error62) => {
34013
+ if (this._closed) return;
33952
34014
  this.onerror?.(error62);
33953
34015
  this.close().catch(() => {
33954
34016
  });
33955
34017
  };
34018
+ _onstdinclose = () => {
34019
+ this.close().catch(() => {
34020
+ });
34021
+ };
33956
34022
  /**
33957
34023
  * Starts listening for messages on `stdin`.
33958
34024
  */
33959
34025
  async start() {
33960
34026
  if (this._started) throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");
33961
34027
  this._started = true;
34028
+ for (const listener of this._stdout.listeners("error")) if (listener[swallowsErrorsAfterClose]) this._stdout.off("error", listener);
34029
+ if (this._stdin.readableEnded || this._stdin.destroyed) setImmediate(this._onstdinclose);
33962
34030
  this._stdin.on("data", this._ondata);
33963
34031
  this._stdin.on("error", this._onerror);
34032
+ this._stdin.on("end", this._onstdinclose);
34033
+ this._stdin.on("close", this._onstdinclose);
33964
34034
  this._stdout.on("error", this._onstdouterror);
33965
34035
  }
33966
34036
  processReadBuffer() {
@@ -33977,7 +34047,9 @@ var StdioServerTransport = class {
33977
34047
  this._closed = true;
33978
34048
  this._stdin.off("data", this._ondata);
33979
34049
  this._stdin.off("error", this._onerror);
33980
- this._stdout.off("error", this._onstdouterror);
34050
+ this._stdin.off("end", this._onstdinclose);
34051
+ this._stdin.off("close", this._onstdinclose);
34052
+ this._onstdouterror[swallowsErrorsAfterClose] = true;
33981
34053
  if (this._stdin.listenerCount("data") === 0) this._stdin.pause();
33982
34054
  this._readBuffer.clear();
33983
34055
  this.onclose?.();
@@ -34254,6 +34326,7 @@ function serveStdio(factory, options = {}) {
34254
34326
  return;
34255
34327
  }
34256
34328
  if (state.era === "modern" && await tryServeListen(message)) return;
34329
+ if (isTornDown()) return;
34257
34330
  state.instance.channel.deliver(message);
34258
34331
  return;
34259
34332
  }
@@ -34320,6 +34393,7 @@ function serveStdio(factory, options = {}) {
34320
34393
  };
34321
34394
  }
34322
34395
  if (await tryServeListen(message)) return;
34396
+ if (isTornDown()) return;
34323
34397
  state.instance.channel.deliver(message, { classification: opening.classification });
34324
34398
  return;
34325
34399
  case "legacy": {
@@ -34406,6 +34480,9 @@ function toError(value) {
34406
34480
  return value instanceof Error ? value : new Error(String(value));
34407
34481
  }
34408
34482
 
34483
+ // ../../node_modules/@modelcontextprotocol/server/dist/index.mjs
34484
+ var DEFAULT_MAX_REQUEST_BODY_SIZE = 4 * 1024 * 1024;
34485
+
34409
34486
  // ../../node_modules/@chrischall/mcp-utils/dist/errors/index.js
34410
34487
  var McpToolError = class extends Error {
34411
34488
  /** Actionable remediation text, when one applies. */
@@ -35971,6 +36048,7 @@ async function diagnose(err) {
35971
36048
  const isAuthError = !isTransientError && AUTH_ERROR_PATTERN.test(errText);
35972
36049
  const isGridLimitError = GRID_LIMIT_ERROR_PATTERN.test(errText);
35973
36050
  const hint = isInvalidGrant ? INVALID_GRANT_HINT : isAuthError ? AUTH_HINT : isTransientError ? TRANSIENT_HINT : isGridLimitError ? GRID_LIMIT_HINT : "";
36051
+ if (!isAuthError && !isInvalidGrant) return errorResult(`${errText}${hint}`);
35974
36052
  try {
35975
36053
  const accounts = formatAccountList(await run(["auth", "list"]));
35976
36054
  return errorResult(`${errText}
@@ -36115,12 +36193,53 @@ function attachmentPreview(details) {
36115
36193
  var CONFIRM_SEND_INSTRUCTION = "Show this preview to the user verbatim and send only after they explicitly approve in chat. Then call again with confirmToken.";
36116
36194
  var CONFIRM_ACTION_INSTRUCTION = CONFIRM_TOKEN_INSTRUCTION;
36117
36195
  var CONFIRM_FALLBACK_DESCRIPTION = ' If the client cannot show that prompt (no MCP elicitation, e.g. claude.ai), a two-step flow applies instead: call WITHOUT confirmToken and nothing is sent or changed \u2014 the result has status "confirmation-required", the full preview and a confirmToken. Follow its instruction (by default: show the preview to the user verbatim and only after they explicitly approve it in chat, call again with the SAME arguments plus confirmToken). The tool re-reads what it would act on and refuses (DRAFT_CHANGED, with a fresh preview and token) if it changed; TOKEN_EXPIRED / TOKEN_REUSED / TOKEN_INVALID also do nothing. A server set to MCP_CONFIRM_MODE=refuse refuses instead.';
36196
+ function refusedInRun(what, via, does, instead) {
36197
+ return `${what} ${does} and is not available through ${via}. ${instead}`;
36198
+ }
36118
36199
  function gatedElsewhere(what, via, does, tool) {
36119
- return `${what} ${does} and is not available through ${via}. Use ${tool}, which asks the user to confirm.`;
36200
+ return refusedInRun(what, via, does, `Use ${tool}, which asks the user to confirm.`);
36120
36201
  }
36121
36202
  function hasCommandWord(args, words) {
36122
36203
  return args.find((a) => words.has(a.toLowerCase()));
36123
36204
  }
36205
+ function flagValue(args, name) {
36206
+ const flag = `--${name}`;
36207
+ for (let i = 0; i < args.length; i++) {
36208
+ const a = args[i];
36209
+ if (a === flag) return args[i + 1] ?? "";
36210
+ if (a.startsWith(`${flag}=`)) return a.slice(flag.length + 1);
36211
+ }
36212
+ return void 0;
36213
+ }
36214
+ var COMMENT_ADD_WORDS = /* @__PURE__ */ new Set(["create", "add", "new"]);
36215
+ var COMMENT_REPLY_WORDS = /* @__PURE__ */ new Set(["reply", "respond"]);
36216
+ function hasTrueFlag(args, flag) {
36217
+ const name = `--${flag}`;
36218
+ return args.some((a) => {
36219
+ const lower = a.toLowerCase();
36220
+ if (lower === name) return true;
36221
+ return lower.startsWith(`${name}=`) && lower.slice(name.length + 1) !== "false";
36222
+ });
36223
+ }
36224
+ function vetCommentsRun(service, subcommand, args) {
36225
+ if (subcommand.toLowerCase() !== "comments") return void 0;
36226
+ const reply = hasCommandWord(args, COMMENT_REPLY_WORDS);
36227
+ if (reply) {
36228
+ return gatedElsewhere(
36229
+ `gog ${service} comments ${reply.toLowerCase()}`,
36230
+ `gog_${service}_run`,
36231
+ "notifies the comment thread",
36232
+ `gog_${service}_comments_reply`
36233
+ );
36234
+ }
36235
+ const add = hasCommandWord(args, COMMENT_ADD_WORDS);
36236
+ return add ? gatedElsewhere(
36237
+ `gog ${service} comments ${add.toLowerCase()}`,
36238
+ `gog_${service}_run`,
36239
+ "notifies the file's owner and anyone it mentions",
36240
+ `gog_${service}_comments_add`
36241
+ ) : void 0;
36242
+ }
36124
36243
  async function requireDispatchConfirmation(ctx, options) {
36125
36244
  const { action, fallback } = options;
36126
36245
  const confirmation = {
@@ -36149,16 +36268,33 @@ function resultText(result) {
36149
36268
  // src/tools/api.ts
36150
36269
  var GMAIL_API_BLOCKED = /(?:\.send$|forwarding|filters\.create|filters\.update|delegates\.create)/i;
36151
36270
  var DISPATCH_API_BLOCKED = {
36152
- chat: [{ method: /(?:^|\.)spaces\.messages\.create$/i, does: "posts a Chat message", tool: "gog_chat_messages_send / gog_chat_dm_send" }],
36153
- drive: [{ method: /(?:^|\.)permissions\.(?:create|update)$/i, does: "grants access to a file", tool: "gog_drive_share" }],
36271
+ chat: [
36272
+ { method: /(?:^|\.)spaces\.messages\.create$/i, does: "posts a Chat message", tool: "gog_chat_messages_send / gog_chat_dm_send" },
36273
+ { method: /(?:^|\.)spaces\.(?:setup|members\.create)$/i, does: "adds people to a space", tool: "gog_chat_spaces_create" }
36274
+ ],
36275
+ drive: [
36276
+ { method: /(?:^|\.)permissions\.(?:create|update)$/i, does: "grants access to a file", tool: "gog_drive_share" },
36277
+ { method: /(?:^|\.)comments\.create$/i, does: "notifies the file's owner and anyone it mentions", tool: "gog_drive_comments_add / gog_docs_comments_add" },
36278
+ { method: /(?:^|\.)replies\.create$/i, does: "notifies the comment thread", tool: "gog_drive_comments_reply / gog_docs_comments_reply" }
36279
+ ],
36154
36280
  classroom: [
36155
36281
  { method: /(?:^|\.)courses\.announcements\.create$/i, does: "posts to a class", tool: "gog_classroom_announcements_create" },
36156
- { method: /(?:^|\.)invitations\.create$/i, does: "invites someone to a class", tool: "gog_classroom_invitations_create" }
36282
+ { method: /(?:^|\.)invitations\.create$/i, does: "invites someone to a class", tool: "gog_classroom_invitations_create" },
36283
+ { method: /(?:^|\.)courses\.students\.create$/i, does: "adds someone to a class", tool: "gog_classroom_students_add" },
36284
+ { method: /(?:^|\.)courses\.teachers\.create$/i, does: "gives someone teacher access to a class", tool: "gog_classroom_teachers_add" },
36285
+ { method: /(?:^|\.)courses\.coursework\.create$/i, does: "posts coursework to a class", tool: "gog_classroom_coursework_create" },
36286
+ { method: /(?:^|\.)studentsubmissions\.return$/i, does: "returns work to a student", tool: "gog_classroom_submissions_return" }
36157
36287
  ],
36158
36288
  calendar: [
36159
36289
  { method: /(?:^|\.)events\.(?:insert|import|quickadd)$/i, does: "can put an event on guests' calendars", tool: "gog_calendar_create" },
36160
- { method: /(?:^|\.)events\.(?:update|patch)$/i, does: "can change what guests see", tool: "gog_calendar_update / gog_calendar_respond" }
36161
- ]
36290
+ { method: /(?:^|\.)events\.(?:update|patch)$/i, does: "can change what guests see", tool: "gog_calendar_update / gog_calendar_respond" },
36291
+ { method: /(?:^|\.)events\.move$/i, does: "can email every guest", tool: "gog_calendar_move" }
36292
+ ],
36293
+ gmail: [
36294
+ { method: /(?:^|\.)settings\.sendas\.create$/i, does: "makes Google email the address and adds a sending identity", tool: "gog_gmail_sendas_create" },
36295
+ { method: /(?:^|\.)settings\.updatevacation$/i, does: "can turn on an auto-reply to every sender", tool: "gog_gmail_vacation_update" }
36296
+ ],
36297
+ script: [{ method: /(?:^|\.)scripts\.run$/i, does: "executes code with this account's authority", tool: "gog_appscript_run_function" }]
36162
36298
  };
36163
36299
  function refusedApiCall(api, method) {
36164
36300
  const name = api.trim().toLowerCase();
@@ -36169,6 +36305,14 @@ function refusedApiCall(api, method) {
36169
36305
  const hit = (Object.hasOwn(DISPATCH_API_BLOCKED, name) ? DISPATCH_API_BLOCKED[name] : []).find((b) => b.method.test(m));
36170
36306
  return hit ? gatedElsewhere(`${name} ${m}`, "gog_api_call", hit.does, hit.tool) : void 0;
36171
36307
  }
36308
+ function previewJson(text) {
36309
+ if (text.length > BODY_PREVIEW_MAX) return bodyPreview(text);
36310
+ try {
36311
+ return JSON.parse(text);
36312
+ } catch {
36313
+ return text;
36314
+ }
36315
+ }
36172
36316
  function registerApiTools(server) {
36173
36317
  server.registerTool("gog_api_list", {
36174
36318
  description: "List the Google Discovery APIs available for gog_api_call / gog_api_describe (name + version + title).",
@@ -36197,7 +36341,7 @@ function registerApiTools(server) {
36197
36341
  return runOrDiagnose(args, { account });
36198
36342
  });
36199
36343
  server.registerTool("gog_api_call", {
36200
- description: "Call any Discovery-described Google API method directly \u2014 an escape hatch for endpoints gog has no dedicated tool for. Find the exact api/version/method/params with gog_api_describe first. Read methods (GET/LIST) run as-is. Mutating methods (POST/PUT/PATCH/DELETE) are refused unless you set allowWrite=true \u2014 keep it false to preview, or set dryRun=true to print the intended request without sending it. Gmail send and forwarding methods (users.messages.send, users.drafts.send, forwarding/auto-forwarding, filters, delegates) are refused \u2014 use the dedicated gog_gmail_* tools, which ask the user to confirm. So are the other methods a dedicated tool asks about: Chat spaces.messages.create, Drive permissions.create/update, Classroom courses.announcements.create and invitations.create, and Calendar events.insert/import/quickAdd/update/patch.",
36344
+ description: "Call any Discovery-described Google API method directly \u2014 an escape hatch for endpoints gog has no dedicated tool for. Find the exact api/version/method/params with gog_api_describe first. Read methods (GET/LIST) run as-is. Mutating methods (POST/PUT/PATCH/DELETE) are refused unless you set allowWrite=true, and every write then asks the MCP host to show the user a confirmation prompt with the exact api/version/method/params/body before anything is sent; set dryRun=true to print the intended request without sending it (no prompt, no changes). Gmail send and forwarding methods (users.messages.send, users.drafts.send, forwarding/auto-forwarding, filters, delegates) are refused outright \u2014 use the dedicated gog_gmail_* tools, which ask the user to confirm. So are the other methods a dedicated tool asks about with a better preview: Chat spaces.messages.create, Drive permissions.create/update, Classroom courses.announcements.create and invitations.create, and Calendar events.insert/import/quickAdd/update/patch." + CONFIRM_FALLBACK_DESCRIPTION,
36201
36345
  annotations: { destructiveHint: true },
36202
36346
  inputSchema: external_exports.object({
36203
36347
  api: external_exports.string().describe("Discovery API name (e.g. drive, gmail, calendar)"),
@@ -36206,11 +36350,12 @@ function registerApiTools(server) {
36206
36350
  params: external_exports.string().optional().describe('Query/path parameters as a JSON object string (e.g. {"fileId":"abc","fields":"name"})'),
36207
36351
  body: external_exports.string().optional().describe("Request body as a JSON string (for write methods)"),
36208
36352
  scope: external_exports.string().optional().describe("Override the OAuth scope used for the call"),
36209
- allowWrite: external_exports.boolean().optional().describe("Required to invoke a mutating method (POST/PUT/PATCH/DELETE). Without it, gog refuses write methods. Leave unset for read-only calls."),
36210
- dryRun: external_exports.boolean().optional().describe("Print the intended request and exit without sending it (no changes made)"),
36211
- account: accountParam
36353
+ allowWrite: external_exports.boolean().optional().describe("Required to invoke a mutating method (POST/PUT/PATCH/DELETE); the user is asked to confirm the exact request first. Without it, gog refuses write methods. Leave unset for read-only calls."),
36354
+ dryRun: external_exports.boolean().optional().describe("Print the intended request and exit without sending it (no changes made, no confirmation prompt)"),
36355
+ account: accountParam,
36356
+ confirmToken: confirmTokenParam
36212
36357
  })
36213
- }, async ({ api, version: version2, method, params, body, scope, allowWrite, dryRun, account }) => {
36358
+ }, async ({ api, version: version2, method, params, body, scope, allowWrite, dryRun, account, confirmToken }, ctx) => {
36214
36359
  try {
36215
36360
  assertSafeForwardedArgs([api, version2, method]);
36216
36361
  const refusal = refusedApiCall(api, method);
@@ -36220,6 +36365,27 @@ function registerApiTools(server) {
36220
36365
  } catch (err) {
36221
36366
  return errorResult(errorText(err));
36222
36367
  }
36368
+ if (allowWrite && !dryRun) {
36369
+ const request = { api, version: version2, method, params, body, scope };
36370
+ const view = { api, version: version2, method };
36371
+ if (params !== void 0) view.params = previewJson(params);
36372
+ if (body !== void 0) view.body = previewJson(body);
36373
+ if (scope !== void 0) view.scope = scope;
36374
+ const confirmation = await requireDispatchConfirmation(ctx, {
36375
+ action: "api.call",
36376
+ message: `Review and confirm this raw Google API write (${api} ${version2} ${method}):`,
36377
+ confirmationLabel: "Confirm that this API method should be invoked with exactly these parameters.",
36378
+ details: view,
36379
+ unsupportedNote: "Set dryRun=true to see the request gog would send without sending it, or use the dedicated gog_* tool for this operation.",
36380
+ fallback: {
36381
+ tool: "gog_api_call",
36382
+ account,
36383
+ confirmToken,
36384
+ subject: () => ({ target: `${api}/${version2}/${method}`, payload: request, preview: view })
36385
+ }
36386
+ });
36387
+ if (confirmation) return confirmation;
36388
+ }
36223
36389
  const args = ["api", "call", pos(api), pos(version2), pos(method)];
36224
36390
  if (params) args.push(`--params=${params}`);
36225
36391
  if (body) args.push(`--body=${body}`);
@@ -36232,6 +36398,22 @@ function registerApiTools(server) {
36232
36398
  }
36233
36399
 
36234
36400
  // src/tools/appscript.ts
36401
+ function vetAppScriptRun(subcommand, _args) {
36402
+ return subcommand.toLowerCase() === "run" ? gatedElsewhere("gog appscript run", "gog_appscript_run", "executes code with this account's authority", "gog_appscript_run_function") : void 0;
36403
+ }
36404
+ function projectSnapshot(raw, scriptId) {
36405
+ let project;
36406
+ try {
36407
+ project = JSON.parse(raw)?.project;
36408
+ } catch {
36409
+ project = void 0;
36410
+ }
36411
+ return {
36412
+ scriptId,
36413
+ ...typeof project?.title === "string" ? { title: project.title } : {},
36414
+ ...typeof project?.updateTime === "string" ? { updateTime: project.updateTime } : {}
36415
+ };
36416
+ }
36235
36417
  function registerAppScriptTools(server) {
36236
36418
  const scriptIdParam = external_exports.string().describe(
36237
36419
  "Apps Script project ID \u2014 the long ID in script.google.com/\u2026/projects/<scriptId>/\u2026, NOT the Drive file ID of a container document"
@@ -36312,16 +36494,18 @@ function registerAppScriptTools(server) {
36312
36494
  return runOrDiagnose(args, { account });
36313
36495
  });
36314
36496
  server.registerTool("gog_appscript_run_function", {
36315
- description: "Execute a function in a deployed Apps Script project. TREAT THIS AS ARBITRARY CODE EXECUTION: the script runs with this Google account's authority and can send mail, edit Drive files or call external services, and the wrapper cannot tell a read from a write \u2014 read the code with gog_appscript_content first if you did not write it. Requires the project to be deployed as an API executable and to share the OAuth client with the calling credentials, otherwise Google refuses regardless of scopes. devMode runs the latest saved code instead of the deployed version, and only works if the account owns the script. This is NOT the escape hatch \u2014 gog_appscript_run is that." + apiEnableNote,
36497
+ description: "Execute a function in a deployed Apps Script project. TREAT THIS AS ARBITRARY CODE EXECUTION: the script runs with this Google account's authority and can send mail, edit Drive files or call external services, and the wrapper cannot tell a read from a write \u2014 read the code with gog_appscript_content first if you did not write it. Requires the project to be deployed as an API executable and to share the OAuth client with the calling credentials, otherwise Google refuses regardless of scopes. devMode runs the latest saved code instead of the deployed version, and only works if the account owns the script. This is NOT the escape hatch \u2014 gog_appscript_run is that. Because the wrapper cannot tell what the code will do, it reads the project and asks the MCP host to show the user a confirmation prompt with the project, the function and its arguments first; nothing runs unless they accept." + CONFIRM_FALLBACK_DESCRIPTION + apiEnableNote,
36316
36498
  annotations: { destructiveHint: true },
36317
36499
  inputSchema: external_exports.object({
36318
36500
  scriptId: scriptIdParam,
36319
36501
  functionName: external_exports.string().describe('Name of the function to call, e.g. "doWork"'),
36320
36502
  params: external_exports.string().optional().describe(`Function parameters as a JSON ARRAY of positional arguments, e.g. '["a", 1]' \u2014 not an object`),
36321
36503
  devMode: external_exports.boolean().optional().describe("Run the latest saved code rather than the deployed version (owner only)"),
36322
- account: accountParam
36504
+ account: accountParam,
36505
+ confirmToken: confirmTokenParam
36323
36506
  })
36324
- }, async ({ scriptId, functionName, params, devMode, account }) => {
36507
+ }, async ({ scriptId, functionName, params, devMode, account, confirmToken }, ctx) => {
36508
+ let parsedParams;
36325
36509
  if (params !== void 0) {
36326
36510
  let parsed;
36327
36511
  try {
@@ -36332,7 +36516,26 @@ function registerAppScriptTools(server) {
36332
36516
  if (!Array.isArray(parsed)) {
36333
36517
  throw new Error(`params must be a JSON ARRAY of positional arguments, e.g. '["a", 1]' \u2014 Apps Script takes positional arguments, not named ones. Received: ${params}`);
36334
36518
  }
36519
+ parsedParams = parsed;
36335
36520
  }
36521
+ const got = await runOrDiagnose(["appscript", "get", pos(scriptId)], { account });
36522
+ if (got.isError) return got;
36523
+ const { updateTime, ...project } = projectSnapshot(resultText(got), scriptId);
36524
+ const execution = { project, functionName, params: parsedParams, devMode: Boolean(devMode), runsAs: senderPreview(account) };
36525
+ const confirmation = await requireDispatchConfirmation(ctx, {
36526
+ action: "appscript.run-function",
36527
+ message: "Review and confirm running this Apps Script function with the account's full authority:",
36528
+ confirmationLabel: "Confirm that this code should run now.",
36529
+ details: execution,
36530
+ unsupportedNote: "Ask the user to run it themselves from the Apps Script editor.",
36531
+ fallback: {
36532
+ tool: "gog_appscript_run_function",
36533
+ account,
36534
+ confirmToken,
36535
+ subject: () => ({ target: `${scriptId}/${functionName}`, revision: updateTime, payload: execution, preview: execution })
36536
+ }
36537
+ });
36538
+ if (confirmation) return confirmation;
36336
36539
  const args = ["appscript", "run", pos(scriptId), pos(functionName)];
36337
36540
  if (params !== void 0) args.push(`--params=${params}`);
36338
36541
  if (devMode) args.push("--dev-mode");
@@ -36341,6 +36544,7 @@ function registerAppScriptTools(server) {
36341
36544
  registerRunTool(server, {
36342
36545
  service: "appscript",
36343
36546
  examples: '"get", "content", "deployments"',
36547
+ vet: vetAppScriptRun,
36344
36548
  note: "To execute a function, use gog_appscript_run_function \u2014 this tool is the generic escape hatch."
36345
36549
  });
36346
36550
  }
@@ -36480,21 +36684,47 @@ function registerAuthTools(server) {
36480
36684
  }
36481
36685
 
36482
36686
  // src/tools/calendar.ts
36483
- var CALENDAR_GATED = {
36484
- create: "gog_calendar_create",
36485
- add: "gog_calendar_create",
36486
- new: "gog_calendar_create",
36487
- update: "gog_calendar_update",
36488
- edit: "gog_calendar_update",
36489
- set: "gog_calendar_update",
36490
- respond: "gog_calendar_respond",
36491
- rsvp: "gog_calendar_respond",
36492
- reply: "gog_calendar_respond"
36687
+ var ASKS = (tool) => `Use ${tool}, which asks the user to confirm.`;
36688
+ var CALENDAR_REFUSED = {
36689
+ create: { does: "can change what guests see", instead: ASKS("gog_calendar_create") },
36690
+ add: { does: "can change what guests see", instead: ASKS("gog_calendar_create") },
36691
+ new: { does: "can change what guests see", instead: ASKS("gog_calendar_create") },
36692
+ update: { does: "can change what guests see", instead: ASKS("gog_calendar_update") },
36693
+ edit: { does: "can change what guests see", instead: ASKS("gog_calendar_update") },
36694
+ set: { does: "can change what guests see", instead: ASKS("gog_calendar_update") },
36695
+ respond: { does: "can change what guests see", instead: ASKS("gog_calendar_respond") },
36696
+ rsvp: { does: "can change what guests see", instead: ASKS("gog_calendar_respond") },
36697
+ reply: { does: "can change what guests see", instead: ASKS("gog_calendar_respond") },
36698
+ move: { does: "moves an event off guests' calendars (and can email them)", instead: ASKS("gog_calendar_move") },
36699
+ transfer: { does: "moves an event off guests' calendars (and can email them)", instead: ASKS("gog_calendar_move") },
36700
+ delete: { does: "removes an event from every guest's calendar (the whole series by default)", instead: ASKS("gog_calendar_delete") },
36701
+ del: { does: "removes an event from every guest's calendar (the whole series by default)", instead: ASKS("gog_calendar_delete") },
36702
+ rm: { does: "removes an event from every guest's calendar (the whole series by default)", instead: ASKS("gog_calendar_delete") },
36703
+ remove: { does: "removes an event from every guest's calendar (the whole series by default)", instead: ASKS("gog_calendar_delete") },
36704
+ "delete-calendar": { does: "deletes a calendar and every event on it", instead: ASKS("gog_calendar_delete_calendar") },
36705
+ "out-of-office": { does: "auto-declines invitations and notifies their organizers", instead: ASKS("gog_calendar_out_of_office") },
36706
+ ooo: { does: "auto-declines invitations and notifies their organizers", instead: ASKS("gog_calendar_out_of_office") }
36493
36707
  };
36494
- function vetCalendarRun(subcommand, _args) {
36708
+ function vetCalendarRun(subcommand, args) {
36495
36709
  const sub = subcommand.toLowerCase();
36496
- const tool = Object.hasOwn(CALENDAR_GATED, sub) ? CALENDAR_GATED[sub] : void 0;
36497
- return tool ? gatedElsewhere(`gog calendar ${sub}`, "gog_calendar_run", "can change what guests see", tool) : void 0;
36710
+ const what = `gog calendar ${sub}`;
36711
+ const via = "gog_calendar_run";
36712
+ if (Object.hasOwn(CALENDAR_REFUSED, sub)) {
36713
+ const { does, instead } = CALENDAR_REFUSED[sub];
36714
+ return refusedInRun(what, via, does, instead);
36715
+ }
36716
+ if (sub === "propose-time" && (flagValue(args, "decline") !== void 0 || flagValue(args, "comment") !== void 0)) {
36717
+ return gatedElsewhere(`${what} --decline`, via, "declines the event and notifies the organizer", "gog_calendar_respond");
36718
+ }
36719
+ if ((sub === "focus-time" || sub === "focus") && flagValue(args, "auto-decline")?.toLowerCase() !== "none") {
36720
+ return refusedInRun(
36721
+ what,
36722
+ via,
36723
+ "auto-declines invitations and notifies their organizers (gog defaults --auto-decline to all)",
36724
+ "Pass --auto-decline=none, or ask the user to create it from Google Calendar."
36725
+ );
36726
+ }
36727
+ return void 0;
36498
36728
  }
36499
36729
  function parseAttendees(value) {
36500
36730
  if (!value) return [];
@@ -36511,15 +36741,17 @@ function eventSnapshot(raw) {
36511
36741
  } catch {
36512
36742
  event = void 0;
36513
36743
  }
36514
- const str = (v) => typeof v === "string" ? v : void 0;
36744
+ const str2 = (v) => typeof v === "string" ? v : void 0;
36515
36745
  return {
36516
- summary: str(event?.summary),
36746
+ summary: str2(event?.summary),
36517
36747
  start: timeOf(event?.start),
36518
36748
  end: timeOf(event?.end),
36519
- organizer: str(event?.organizer?.email),
36749
+ organizer: str2(event?.organizer?.email),
36520
36750
  // Guests are the OTHER people: not this account's own attendee row, not rooms.
36521
36751
  guests: (Array.isArray(event?.attendees) ? event.attendees : []).filter((a) => a.self !== true && a.resource !== true && typeof a.email === "string").map((a) => a.email),
36522
- etag: str(event?.etag)
36752
+ // A series, or one instance of one: gog's delete --scope defaults to all.
36753
+ ...Array.isArray(event?.recurrence) && event.recurrence.length > 0 || typeof event?.recurringEventId === "string" ? { recurring: true } : {},
36754
+ etag: str2(event?.etag)
36523
36755
  };
36524
36756
  }
36525
36757
  async function readEvent(calendarId, eventId, account) {
@@ -36740,14 +36972,35 @@ function registerCalendarTools(server) {
36740
36972
  return runOrDiagnose(args, { account });
36741
36973
  });
36742
36974
  server.registerTool("gog_calendar_delete", {
36743
- description: "Delete a calendar event.",
36975
+ description: "Delete a calendar event. It disappears from every guest's calendar too, and for a recurring event gog deletes the WHOLE series, so when the event has guests or recurs this reads it and asks the MCP host to show the user a confirmation prompt with the event as it stands; a guest-free, one-off event is deleted without asking." + CONFIRM_FALLBACK_DESCRIPTION,
36744
36976
  annotations: { destructiveHint: true },
36745
36977
  inputSchema: external_exports.object({
36746
36978
  calendarId: external_exports.string().describe("Calendar ID"),
36747
36979
  eventId: external_exports.string().describe("Event ID"),
36748
- account: accountParam
36980
+ account: accountParam,
36981
+ confirmToken: confirmTokenParam
36749
36982
  })
36750
- }, async ({ calendarId, eventId, account }) => {
36983
+ }, async ({ calendarId, eventId, account, confirmToken }, ctx) => {
36984
+ const read = await readEvent(calendarId, eventId, account);
36985
+ if (read.error) return read.error;
36986
+ const { etag, ...event } = read.event;
36987
+ if (event.guests.length > 0 || event.recurring) {
36988
+ const view = { calendarId, eventId, event, scope: event.recurring ? "the whole recurring series" : "this event" };
36989
+ const confirmation = await requireDispatchConfirmation(ctx, {
36990
+ action: "calendar.delete",
36991
+ message: event.recurring ? "Review and confirm deleting this ENTIRE recurring series:" : "Review and confirm deleting this event from every guest's calendar:",
36992
+ confirmationLabel: "Confirm that this event should be deleted now.",
36993
+ details: view,
36994
+ unsupportedNote: "Ask the user to delete it from Google Calendar.",
36995
+ fallback: {
36996
+ tool: "gog_calendar_delete",
36997
+ account,
36998
+ confirmToken,
36999
+ subject: () => ({ target: `${calendarId}/${eventId}`, revision: etag, payload: view, preview: view })
37000
+ }
37001
+ });
37002
+ if (confirmation) return confirmation;
37003
+ }
36751
37004
  return runOrDiagnose(["calendar", "delete", pos(calendarId), pos(eventId), "--force"], { account });
36752
37005
  });
36753
37006
  server.registerTool("gog_calendar_respond", {
@@ -36869,8 +37122,14 @@ function inlineAttachmentArgs(flag, attachments, siblingArgs = []) {
36869
37122
 
36870
37123
  // src/tools/chat.ts
36871
37124
  var CHAT_SEND_WORDS = /* @__PURE__ */ new Set(["send", "create", "post"]);
37125
+ var CHAT_SPACE_CREATE_WORDS = /* @__PURE__ */ new Set(["create", "add", "new"]);
36872
37126
  function vetChatRun(subcommand, args) {
36873
37127
  const sub = subcommand.toLowerCase();
37128
+ if (sub === "spaces") {
37129
+ const word2 = hasCommandWord(args, CHAT_SPACE_CREATE_WORDS);
37130
+ const withMembers = args.some((a) => /^--members?(?:=|$)/i.test(a));
37131
+ return word2 && withMembers ? gatedElsewhere(`gog chat spaces ${word2.toLowerCase()} --member`, "gog_chat_run", "adds people to a space", "gog_chat_spaces_create") : void 0;
37132
+ }
36874
37133
  if (sub !== "messages" && sub !== "dm") return void 0;
36875
37134
  const word = hasCommandWord(args, CHAT_SEND_WORDS);
36876
37135
  if (!word) return void 0;
@@ -36921,16 +37180,34 @@ function registerChatTools(server) {
36921
37180
  return runOrDiagnose(args, { account });
36922
37181
  });
36923
37182
  server.registerTool("gog_chat_spaces_create", {
36924
- description: "Create a named Chat space, optionally seeding its membership. Members are added immediately and are notified \u2014 this is visible to other people the moment it runs, so confirm the member list before calling it." + workspaceOnlyNote,
37183
+ description: "Create a named Chat space, optionally seeding its membership. Members are added immediately and are notified, so with members this asks the MCP host to show the user a confirmation prompt with the space name and every member first; nothing is created unless they accept. A space with no members reaches nobody and is created without asking." + CONFIRM_FALLBACK_DESCRIPTION + workspaceOnlyNote,
36925
37184
  annotations: { destructiveHint: true },
36926
37185
  inputSchema: external_exports.object({
36927
37186
  displayName: external_exports.string().describe("Display name for the new space"),
36928
37187
  members: external_exports.array(external_exports.string()).optional().describe('Initial members, as email addresses or "users/..." resource names'),
36929
- account: accountParam
37188
+ account: accountParam,
37189
+ confirmToken: confirmTokenParam
36930
37190
  })
36931
- }, async ({ displayName, members: members2, account }) => {
37191
+ }, async ({ displayName, members: members2, account, confirmToken }, ctx) => {
36932
37192
  const args = ["chat", "spaces", "create", pos(displayName)];
36933
37193
  if (members2) for (const member of members2) args.push(`--member=${member}`);
37194
+ if (members2?.length) {
37195
+ const space = { displayName, members: members2 };
37196
+ const confirmation = await requireDispatchConfirmation(ctx, {
37197
+ action: "chat.space-create",
37198
+ message: "Review and confirm this Chat space \u2014 every member is added and notified:",
37199
+ confirmationLabel: "Confirm that these people should be added to a new space now.",
37200
+ details: space,
37201
+ unsupportedNote: "Create the space without members instead; the user can add people from Google Chat.",
37202
+ fallback: {
37203
+ tool: "gog_chat_spaces_create",
37204
+ account,
37205
+ confirmToken,
37206
+ subject: () => ({ target: displayName, payload: space, preview: space })
37207
+ }
37208
+ });
37209
+ if (confirmation) return confirmation;
37210
+ }
36934
37211
  return runOrDiagnose(args, { account });
36935
37212
  });
36936
37213
  server.registerTool("gog_chat_threads_list", {
@@ -37124,20 +37401,85 @@ function registerChatTools(server) {
37124
37401
 
37125
37402
  // src/tools/classroom.ts
37126
37403
  var CLASSROOM_CREATE_WORDS = /* @__PURE__ */ new Set(["create", "add", "new"]);
37127
- var CLASSROOM_GATED = {
37128
- announcements: { does: "posts to a class", tool: "gog_classroom_announcements_create" },
37129
- announcement: { does: "posts to a class", tool: "gog_classroom_announcements_create" },
37130
- ann: { does: "posts to a class", tool: "gog_classroom_announcements_create" },
37131
- invitations: { does: "invites someone to a class", tool: "gog_classroom_invitations_create" },
37132
- invitation: { does: "invites someone to a class", tool: "gog_classroom_invitations_create" },
37133
- invites: { does: "invites someone to a class", tool: "gog_classroom_invitations_create" }
37404
+ var CLASSROOM_DELETE_WORDS = /* @__PURE__ */ new Set(["delete", "rm", "del", "remove"]);
37405
+ var CLASSROOM_UPDATE_WORDS = /* @__PURE__ */ new Set(["update", "edit", "set"]);
37406
+ var CLASSROOM_RETURN_WORDS = /* @__PURE__ */ new Set(["return", "send"]);
37407
+ var CLASSROOM_ASSIGNEE_WORDS = /* @__PURE__ */ new Set(["assignees", "assign"]);
37408
+ var CLASSROOM_GROUPS = {
37409
+ courses: "courses",
37410
+ course: "courses",
37411
+ announcements: "announcements",
37412
+ announcement: "announcements",
37413
+ ann: "announcements",
37414
+ invitations: "invitations",
37415
+ invitation: "invitations",
37416
+ invites: "invitations",
37417
+ coursework: "coursework",
37418
+ work: "coursework",
37419
+ materials: "materials",
37420
+ material: "materials",
37421
+ students: "students",
37422
+ student: "students",
37423
+ teachers: "teachers",
37424
+ teacher: "teachers",
37425
+ submissions: "submissions",
37426
+ submission: "submissions",
37427
+ "guardian-invitations": "guardian-invitations",
37428
+ "guardian-invites": "guardian-invitations"
37134
37429
  };
37430
+ function publishesToStudents(args) {
37431
+ return flagValue(args, "state")?.toUpperCase() === "PUBLISHED" || flagValue(args, "scheduled") !== void 0;
37432
+ }
37433
+ function createsVisibleWork(args) {
37434
+ return flagValue(args, "state")?.toUpperCase() !== "DRAFT" || flagValue(args, "scheduled") !== void 0;
37435
+ }
37436
+ function widensAssignees(args) {
37437
+ return flagValue(args, "mode")?.toUpperCase() === "ALL_STUDENTS" || flagValue(args, "add-student") !== void 0;
37438
+ }
37135
37439
  function vetClassroomRun(subcommand, args) {
37136
37440
  const sub = subcommand.toLowerCase();
37137
- const gated = Object.hasOwn(CLASSROOM_GATED, sub) ? CLASSROOM_GATED[sub] : void 0;
37138
- if (!gated) return void 0;
37139
- const word = hasCommandWord(args, CLASSROOM_CREATE_WORDS);
37140
- return word ? gatedElsewhere(`gog classroom ${sub} ${word.toLowerCase()}`, "gog_classroom_run", gated.does, gated.tool) : void 0;
37441
+ if (!Object.hasOwn(CLASSROOM_GROUPS, sub)) return void 0;
37442
+ const group = CLASSROOM_GROUPS[sub];
37443
+ const via = "gog_classroom_run";
37444
+ const what = (word) => `gog classroom ${sub} ${word.toLowerCase()}`;
37445
+ const create = hasCommandWord(args, CLASSROOM_CREATE_WORDS);
37446
+ const update = hasCommandWord(args, CLASSROOM_UPDATE_WORDS);
37447
+ const remove = hasCommandWord(args, CLASSROOM_DELETE_WORDS);
37448
+ const widenedAssignees = () => {
37449
+ const word = hasCommandWord(args, CLASSROOM_ASSIGNEE_WORDS);
37450
+ return word && widensAssignees(args) ? refusedInRun(what(word), via, "shows it to more students", "Ask the user to change who it is assigned to from Classroom.") : void 0;
37451
+ };
37452
+ switch (group) {
37453
+ case "courses":
37454
+ return remove ? gatedElsewhere(what(remove), via, "deletes a course", "gog_classroom_courses_delete") : void 0;
37455
+ case "announcements":
37456
+ if (create) return gatedElsewhere(what(create), via, "posts to a class", "gog_classroom_announcements_create");
37457
+ if (update && publishesToStudents(args)) return gatedElsewhere(what(update), via, "publishes an announcement to a class", "gog_classroom_announcements_update");
37458
+ return widenedAssignees();
37459
+ case "invitations":
37460
+ return create ? gatedElsewhere(what(create), via, "invites someone to a class", "gog_classroom_invitations_create") : void 0;
37461
+ case "coursework":
37462
+ if (create && createsVisibleWork(args)) return gatedElsewhere(what(create), via, "posts coursework to a class", "gog_classroom_coursework_create");
37463
+ if (remove) return gatedElsewhere(what(remove), via, "deletes coursework and every submission to it", "gog_classroom_coursework_delete");
37464
+ if (update && publishesToStudents(args)) return gatedElsewhere(what(update), via, "publishes work to students", "gog_classroom_coursework_update");
37465
+ return widenedAssignees();
37466
+ case "materials":
37467
+ if (create && createsVisibleWork(args)) {
37468
+ return refusedInRun(what(create), via, "publishes material to students", "Create it with --state=DRAFT and no --scheduled; ask the user to publish it from Classroom.");
37469
+ }
37470
+ if (update && publishesToStudents(args)) return refusedInRun(what(update), via, "publishes material to students", "Ask the user to publish it from Classroom.");
37471
+ return void 0;
37472
+ case "students":
37473
+ return create ? gatedElsewhere(what(create), via, "enrols someone in a class", "gog_classroom_students_add") : void 0;
37474
+ case "teachers":
37475
+ return create ? gatedElsewhere(what(create), via, "gives someone a teacher's access to a class and its roster", "gog_classroom_teachers_add") : void 0;
37476
+ case "submissions": {
37477
+ const word = hasCommandWord(args, CLASSROOM_RETURN_WORDS);
37478
+ return word ? gatedElsewhere(what(word), via, "returns work to a student, who is notified", "gog_classroom_submissions_return") : void 0;
37479
+ }
37480
+ case "guardian-invitations":
37481
+ return create ? refusedInRun(what(create), via, "emails a guardian invitation", "Ask the user to invite the guardian from Classroom.") : void 0;
37482
+ }
37141
37483
  }
37142
37484
  async function readCourse(courseId, account, runner = runOrDiagnose) {
37143
37485
  const got = await runner(["classroom", "courses", "get", pos(courseId)], { account });
@@ -37156,6 +37498,52 @@ async function readCourse(courseId, account, runner = runOrDiagnose) {
37156
37498
  }
37157
37499
  };
37158
37500
  }
37501
+ function nested(raw, key) {
37502
+ try {
37503
+ const parsed = JSON.parse(raw);
37504
+ const inner = parsed?.[key];
37505
+ return inner && typeof inner === "object" ? inner : void 0;
37506
+ } catch {
37507
+ return void 0;
37508
+ }
37509
+ }
37510
+ var str = (v) => typeof v === "string" ? v : void 0;
37511
+ var num = (v) => typeof v === "number" ? v : void 0;
37512
+ async function readCoursework(courseId, courseworkId, account, runner = runOrDiagnose) {
37513
+ const got = await runner(["classroom", "coursework", "get", pos(courseId), pos(courseworkId)], { account });
37514
+ if (got.isError) return { error: got };
37515
+ const work = nested(resultText(got), "coursework");
37516
+ const title = str(work?.title);
37517
+ return { coursework: { id: courseworkId, ...title !== void 0 ? { title } : {} } };
37518
+ }
37519
+ async function readSubmission(courseId, courseworkId, submissionId, account, runner = runOrDiagnose) {
37520
+ const got = await runner(["classroom", "submissions", "get", pos(courseId), pos(courseworkId), pos(submissionId)], { account });
37521
+ if (got.isError) return { error: got };
37522
+ const sub = nested(resultText(got), "submission");
37523
+ const fields = {
37524
+ student: str(sub?.userId),
37525
+ state: str(sub?.state),
37526
+ draftGrade: num(sub?.draftGrade),
37527
+ assignedGrade: num(sub?.assignedGrade)
37528
+ };
37529
+ const updateTime = str(sub?.updateTime);
37530
+ return {
37531
+ submission: {
37532
+ id: submissionId,
37533
+ ...Object.fromEntries(Object.entries(fields).filter(([, v]) => v !== void 0))
37534
+ },
37535
+ ...updateTime !== void 0 ? { updateTime } : {}
37536
+ };
37537
+ }
37538
+ async function studentLabel(courseId, userId, account, runner = runOrDiagnose) {
37539
+ const got = await runner(["classroom", "students", "get", pos(courseId), pos(userId)], { account });
37540
+ if (got.isError) return userId;
37541
+ const profile = nested(resultText(got), "student")?.profile;
37542
+ const name = str(profile?.name?.fullName);
37543
+ const email3 = str(profile?.emailAddress);
37544
+ if (name && email3) return `${name} <${email3}>`;
37545
+ return name ?? email3 ?? userId;
37546
+ }
37159
37547
  function registerClassroomTools(server) {
37160
37548
  server.registerTool("gog_classroom_courses_list", {
37161
37549
  description: "List Google Classroom courses.",
@@ -37368,15 +37756,38 @@ function registerClassroomTools(server) {
37368
37756
  return runOrDiagnose(args, { account });
37369
37757
  });
37370
37758
  server.registerTool("gog_classroom_submissions_return", {
37371
- description: "Return a graded submission to the student.",
37759
+ description: "Return a graded submission to the student, who is notified and sees the grade. Reads the course, the coursework and the submission and asks the MCP host to show the user a confirmation prompt with the class, the assignment, the student and the grade being returned; nothing is returned unless they accept." + CONFIRM_FALLBACK_DESCRIPTION,
37372
37760
  annotations: { destructiveHint: true },
37373
37761
  inputSchema: external_exports.object({
37374
37762
  courseId: external_exports.string().describe("Course ID"),
37375
37763
  courseworkId: external_exports.string().describe("Coursework ID"),
37376
37764
  submissionId: external_exports.string().describe("Submission ID"),
37377
- account: accountParam
37765
+ account: accountParam,
37766
+ confirmToken: confirmTokenParam
37378
37767
  })
37379
- }, async ({ courseId, courseworkId, submissionId, account }) => {
37768
+ }, async ({ courseId, courseworkId, submissionId, account, confirmToken }, ctx) => {
37769
+ const course = await readCourse(courseId, account);
37770
+ if (course.error) return course.error;
37771
+ const work = await readCoursework(courseId, courseworkId, account);
37772
+ if (work.error) return work.error;
37773
+ const sub = await readSubmission(courseId, courseworkId, submissionId, account);
37774
+ if (sub.error) return sub.error;
37775
+ const submission = sub.submission.student ? { ...sub.submission, student: await studentLabel(courseId, sub.submission.student, account) } : sub.submission;
37776
+ const view = { course: course.course, coursework: work.coursework, submission };
37777
+ const confirmation = await requireDispatchConfirmation(ctx, {
37778
+ action: "classroom.submission-return",
37779
+ message: "Review and confirm returning this work \u2014 the student is notified and sees the grade:",
37780
+ confirmationLabel: "Confirm that this submission should be returned to the student now.",
37781
+ details: view,
37782
+ unsupportedNote: "Ask the user to return it from Classroom.",
37783
+ fallback: {
37784
+ tool: "gog_classroom_submissions_return",
37785
+ account,
37786
+ confirmToken,
37787
+ subject: () => ({ target: `${courseId}/${courseworkId}/${submissionId}`, revision: sub.updateTime, payload: view, preview: view })
37788
+ }
37789
+ });
37790
+ if (confirmation) return confirmation;
37380
37791
  return runOrDiagnose(["classroom", "submissions", "return", pos(courseId), pos(courseworkId), pos(submissionId)], { account });
37381
37792
  });
37382
37793
  server.registerTool("gog_classroom_submissions_turn_in", {
@@ -37438,13 +37849,13 @@ function registerClassroomTools(server) {
37438
37849
  return runOrDiagnose(["classroom", "announcements", "get", pos(courseId), pos(announcementId)], { account });
37439
37850
  });
37440
37851
  server.registerTool("gog_classroom_announcements_create", {
37441
- description: "Create an announcement in a Google Classroom course. Unless state is DRAFT (which students cannot see), this reads the course and asks the MCP host to show the user a confirmation prompt with the class, the full text and when it publishes; nothing is posted unless they accept. To stage one without asking, pass state DRAFT." + CONFIRM_FALLBACK_DESCRIPTION,
37852
+ description: "Create an announcement in a Google Classroom course. Unless state is DRAFT with no scheduled time (which students cannot see; a scheduled draft publishes itself), this reads the course and asks the MCP host to show the user a confirmation prompt with the class, the full text and when it publishes; nothing is posted unless they accept. To stage one without asking, pass state DRAFT and no scheduled time." + CONFIRM_FALLBACK_DESCRIPTION,
37442
37853
  annotations: { destructiveHint: true },
37443
37854
  inputSchema: external_exports.object({
37444
37855
  courseId: external_exports.string().describe("Course ID"),
37445
37856
  text: external_exports.string().describe("Announcement text"),
37446
- state: external_exports.enum(["PUBLISHED", "DRAFT"]).optional().describe("State (DRAFT is visible only to teachers and needs no confirmation)"),
37447
- scheduled: external_exports.string().optional().describe("Scheduled publish time"),
37857
+ state: external_exports.enum(["PUBLISHED", "DRAFT"]).optional().describe("State (an unscheduled DRAFT is visible only to teachers and needs no confirmation)"),
37858
+ scheduled: external_exports.string().optional().describe("Scheduled publish time (asks the user to confirm, even for a DRAFT)"),
37448
37859
  account: accountParam,
37449
37860
  confirmToken: confirmTokenParam
37450
37861
  })
@@ -37452,7 +37863,7 @@ function registerClassroomTools(server) {
37452
37863
  const args = ["classroom", "announcements", "create", pos(courseId), `--text=${text}`];
37453
37864
  if (state) args.push(`--state=${state}`);
37454
37865
  if (scheduled) args.push(`--scheduled=${scheduled}`);
37455
- if (state !== "DRAFT") {
37866
+ if (state !== "DRAFT" || scheduled) {
37456
37867
  const read = await readCourse(courseId, account);
37457
37868
  if (read.error) return read.error;
37458
37869
  const publishes = scheduled ? `at ${scheduled}` : "immediately";
@@ -37624,6 +38035,9 @@ function registerContactsTools(server) {
37624
38035
  }
37625
38036
 
37626
38037
  // src/tools/docs.ts
38038
+ function vetDocsRun(subcommand, args) {
38039
+ return vetCommentsRun("docs", subcommand, args);
38040
+ }
37627
38041
  function registerDocsTools(server) {
37628
38042
  server.registerTool("gog_docs_info", {
37629
38043
  description: "Get Google Doc metadata: title, ID, and other properties.",
@@ -37720,12 +38134,29 @@ function registerDocsTools(server) {
37720
38134
  }, async ({ docId, account }) => {
37721
38135
  return runOrDiagnose(["docs", "structure", pos(docId)], { account });
37722
38136
  });
37723
- registerRunTool(server, { service: "docs", examples: '"copy", "clear", "insert", "sed", "export"' });
38137
+ registerRunTool(server, { service: "docs", examples: '"copy", "clear", "insert", "sed", "export"', vet: vetDocsRun });
37724
38138
  }
37725
38139
 
37726
38140
  // src/tools/drive.ts
37727
- function vetDriveRun(subcommand, _args) {
37728
- return subcommand.toLowerCase() === "share" ? gatedElsewhere("gog drive share", "gog_drive_run", "grants access to a file", "gog_drive_share") : void 0;
38141
+ var DRIVE_DELETE_WORDS = /* @__PURE__ */ new Set(["delete", "rm", "del"]);
38142
+ function vetDriveRun(subcommand, args) {
38143
+ const sub = subcommand.toLowerCase();
38144
+ if (sub === "share") return gatedElsewhere("gog drive share", "gog_drive_run", "grants access to a file", "gog_drive_share");
38145
+ if (DRIVE_DELETE_WORDS.has(sub) && hasTrueFlag(args, "permanent")) {
38146
+ return gatedElsewhere(`gog drive ${sub} --permanent`, "gog_drive_run", "deletes a file for good, bypassing the trash", "gog_drive_delete");
38147
+ }
38148
+ if (sub === "bulk") {
38149
+ return gatedElsewhere(
38150
+ "gog drive bulk",
38151
+ "gog_drive_run",
38152
+ "rewrites sharing permissions across every matching file in a tree",
38153
+ "gog_drive_share (one file at a time)"
38154
+ );
38155
+ }
38156
+ if (sub === "unshare") {
38157
+ return refusedInRun("gog drive unshare", "gog_drive_run", "removes someone's access to a file", "Use gog_drive_unshare.");
38158
+ }
38159
+ return vetCommentsRun("drive", sub, args);
37729
38160
  }
37730
38161
  var GOOGLE_DOC_MIME = "application/vnd.google-apps.document";
37731
38162
  function shareTargetMeta(raw) {
@@ -37844,16 +38275,36 @@ function registerDriveTools(server) {
37844
38275
  return runOrDiagnose(["drive", "move", pos(fileId), `--parent=${parentId}`], { account });
37845
38276
  });
37846
38277
  server.registerTool("gog_drive_delete", {
37847
- description: "Move a Google Drive file to trash, or permanently delete it with permanent=true (irreversible).",
38278
+ description: "Move a Google Drive file to trash, or permanently delete it with permanent=true (irreversible). A permanent delete reads the file and asks the MCP host to show the user a confirmation prompt naming it first; nothing is deleted unless they accept. Moving to trash is recoverable and does not ask." + CONFIRM_FALLBACK_DESCRIPTION,
37848
38279
  annotations: { destructiveHint: true },
37849
38280
  inputSchema: external_exports.object({
37850
38281
  fileId: external_exports.string().describe("File ID to delete"),
37851
- permanent: external_exports.boolean().optional().describe("Permanently delete instead of moving to trash (irreversible)"),
37852
- account: accountParam
38282
+ permanent: external_exports.boolean().optional().describe("Permanently delete instead of moving to trash (irreversible; asks the user first)"),
38283
+ account: accountParam,
38284
+ confirmToken: confirmTokenParam
37853
38285
  })
37854
- }, async ({ fileId, permanent, account }) => {
38286
+ }, async ({ fileId, permanent, account, confirmToken }, ctx) => {
37855
38287
  const args = ["drive", "delete", pos(fileId)];
37856
- if (permanent) args.push("--permanent");
38288
+ if (permanent) {
38289
+ const got = await runOrDiagnose(["drive", "get", pos(fileId)], { account });
38290
+ if (got.isError) return got;
38291
+ const target = { file: { id: fileId, ...shareTargetMeta(resultText(got)) }, permanent: true };
38292
+ const confirmation = await requireDispatchConfirmation(ctx, {
38293
+ action: "drive.delete-permanent",
38294
+ message: "Review and confirm PERMANENTLY deleting this file \u2014 it skips the trash and cannot be recovered:",
38295
+ confirmationLabel: "Confirm that this file should be permanently deleted now.",
38296
+ details: target,
38297
+ unsupportedNote: "Move it to the trash instead (permanent=false); the user can empty the trash from Google Drive.",
38298
+ fallback: {
38299
+ tool: "gog_drive_delete",
38300
+ account,
38301
+ confirmToken,
38302
+ subject: () => ({ target: fileId, payload: target, preview: target })
38303
+ }
38304
+ });
38305
+ if (confirmation) return confirmation;
38306
+ args.push("--permanent");
38307
+ }
37857
38308
  args.push("--force");
37858
38309
  return runOrDiagnose(args, { account });
37859
38310
  });
@@ -38179,18 +38630,22 @@ function trustedDomains(account) {
38179
38630
  }
38180
38631
  function logGmailDispatch(tool, recipients, account) {
38181
38632
  const domains = trustedDomains(account);
38182
- const externalRecipients = recipients.filter((recipient) => {
38633
+ const externalDomains = /* @__PURE__ */ new Set();
38634
+ let externalRecipientCount = 0;
38635
+ for (const recipient of recipients) {
38183
38636
  const at = recipient.indexOf("@");
38184
- const domain2 = at > -1 ? recipient.slice(at + 1) : "";
38185
- return !domain2 || !domains.has(domain2);
38186
- });
38637
+ const domain2 = at > -1 ? recipient.slice(at + 1).toLowerCase() : "";
38638
+ if (domain2 && domains.has(domain2)) continue;
38639
+ externalRecipientCount += 1;
38640
+ externalDomains.add(domain2 || "(no domain)");
38641
+ }
38187
38642
  const event = {
38188
38643
  event: "gmail_dispatch",
38189
38644
  tool,
38190
38645
  recipientCount: recipients.length,
38191
- externalRecipientCount: externalRecipients.length,
38192
- hasExternalRecipients: externalRecipients.length > 0,
38193
- externalRecipients,
38646
+ externalRecipientCount,
38647
+ hasExternalRecipients: externalRecipientCount > 0,
38648
+ externalDomains: [...externalDomains].sort(),
38194
38649
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
38195
38650
  };
38196
38651
  process.stderr.write(`${JSON.stringify(event)}
@@ -38357,6 +38812,39 @@ async function sendReply(kind, toolName, messageId, account, flags, ctx, confirm
38357
38812
  return result;
38358
38813
  }
38359
38814
  var GMAIL_RUN_BLOCKED_SETTINGS = /* @__PURE__ */ new Set(["forwarding", "autoforward", "filters", "delegates"]);
38815
+ var GMAIL_DELETE_WORDS = /* @__PURE__ */ new Set(["delete", "rm", "del", "remove"]);
38816
+ var GMAIL_CREATE_WORDS = /* @__PURE__ */ new Set(["create", "add", "new"]);
38817
+ var GMAIL_UPDATE_WORDS = /* @__PURE__ */ new Set(["update", "edit", "set"]);
38818
+ var SENDAS = /* @__PURE__ */ new Set(["sendas"]);
38819
+ var VACATION = /* @__PURE__ */ new Set(["vacation"]);
38820
+ function vetGmailGatedRun(sub, args) {
38821
+ if (sub === "batch") {
38822
+ const word = hasCommandWord(args, GMAIL_DELETE_WORDS);
38823
+ return word ? gatedElsewhere(`gog gmail batch ${word.toLowerCase()}`, "gog_gmail_run", "deletes mail for good, bypassing the Trash", "gog_gmail_batch_delete") : void 0;
38824
+ }
38825
+ if (sub !== "settings" && sub !== "sendas" && sub !== "vacation") return void 0;
38826
+ const words = sub === "settings" ? args : [sub, ...args];
38827
+ if (hasCommandWord(words, SENDAS)) {
38828
+ const word = hasCommandWord(args, GMAIL_CREATE_WORDS);
38829
+ if (word) {
38830
+ return gatedElsewhere(
38831
+ `gog gmail sendas ${word.toLowerCase()}`,
38832
+ "gog_gmail_run",
38833
+ "makes Google email the address and adds a sending identity",
38834
+ "gog_gmail_sendas_create"
38835
+ );
38836
+ }
38837
+ }
38838
+ if (hasCommandWord(words, VACATION) && hasCommandWord(args, GMAIL_UPDATE_WORDS) && hasTrueFlag(args, "enable")) {
38839
+ return gatedElsewhere(
38840
+ "gog gmail vacation update --enable",
38841
+ "gog_gmail_run",
38842
+ "turns on an auto-reply to every sender",
38843
+ "gog_gmail_vacation_update"
38844
+ );
38845
+ }
38846
+ return void 0;
38847
+ }
38360
38848
  function vetGmailRun(subcommand, args) {
38361
38849
  if (subcommand === "autoreply") {
38362
38850
  return "gog gmail autoreply sends mail and is not available through gog_gmail_run. Use gog_gmail_autoreply, which asks the user to confirm.";
@@ -38364,6 +38852,8 @@ function vetGmailRun(subcommand, args) {
38364
38852
  if (GMAIL_RUN_BLOCKED_SETTINGS.has(subcommand)) {
38365
38853
  return `gog gmail ${subcommand} can forward or hand over mail and is not available through gog_gmail_run. Use the dedicated gog_gmail_* tool instead.`;
38366
38854
  }
38855
+ const gated = vetGmailGatedRun(subcommand.toLowerCase(), args);
38856
+ if (gated) return gated;
38367
38857
  if (subcommand === "settings") {
38368
38858
  const blocked = hasCommandWord(args, GMAIL_RUN_BLOCKED_SETTINGS);
38369
38859
  if (blocked) {
@@ -38575,6 +39065,13 @@ function countNonEmptyCells(getOutput) {
38575
39065
  }
38576
39066
 
38577
39067
  // src/tools/sheets.ts
39068
+ var DATASOURCE_ALIASES = /* @__PURE__ */ new Set(["datasource", "data-source", "data-sources", "connected-sheets"]);
39069
+ var DATASOURCE_BILLED = /* @__PURE__ */ new Set(["add", "update", "refresh"]);
39070
+ function vetSheetsRun(subcommand, args) {
39071
+ if (!DATASOURCE_ALIASES.has(subcommand.toLowerCase())) return void 0;
39072
+ const word = hasCommandWord(args, DATASOURCE_BILLED)?.toLowerCase();
39073
+ return word ? gatedElsewhere(`gog sheets datasource ${word}`, "gog_sheets_run", "runs a billed BigQuery job", `gog_sheets_datasource_${word}`) : void 0;
39074
+ }
38578
39075
  var cellValueParam = external_exports.union([external_exports.string(), external_exports.number(), external_exports.boolean(), external_exports.null()]);
38579
39076
  var dryRunParam = external_exports.boolean().optional().describe(
38580
39077
  "Preview the operation without modifying the sheet (gog --dry-run): reports the intended actions and exits without writing."
@@ -38690,7 +39187,7 @@ function registerSheetsTools(server) {
38690
39187
  }, async ({ spreadsheetId, find, replace, account }) => {
38691
39188
  return runOrDiagnose(["sheets", "find-replace", pos(spreadsheetId), pos(find), pos(replace)], { account });
38692
39189
  });
38693
- registerRunTool(server, { service: "sheets", examples: '"freeze", "add-tab", "rename-tab"' });
39190
+ registerRunTool(server, { service: "sheets", examples: '"freeze", "add-tab", "rename-tab"', vet: vetSheetsRun });
38694
39191
  }
38695
39192
 
38696
39193
  // src/tools/slides.ts
@@ -38854,7 +39351,7 @@ function registerTasksTools(server) {
38854
39351
  }
38855
39352
 
38856
39353
  // src/server.ts
38857
- var VERSION = true ? "4.5.0" : "0.0.0";
39354
+ var VERSION = true ? "4.5.2" : "0.0.0";
38858
39355
  var BASE_TOOL_REGISTRARS = [
38859
39356
  registerApiTools,
38860
39357
  registerAppScriptTools,
@@ -38944,7 +39441,7 @@ await runMcp({
38944
39441
  });
38945
39442
  /*! Bundled license information:
38946
39443
 
38947
- @modelcontextprotocol/server/dist/src-CX2iR2pK.mjs:
39444
+ @modelcontextprotocol/server/dist/src-D-y6h4N7.mjs:
38948
39445
  (*!
38949
39446
  * content-type
38950
39447
  * Copyright(c) 2015 Douglas Christopher Wilson