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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/dist/index.js +659 -162
- package/dist/lib.js +619 -142
- package/manifest.json +7 -7
- package/package.json +3 -3
- package/server.json +2 -2
- package/src/dispatch-confirmation.ts +63 -3
- package/src/gmail-dispatch-guard.ts +19 -12
- package/src/lib.ts +6 -2
- package/src/tools/api.ts +74 -8
- package/src/tools/appscript.ts +63 -2
- package/src/tools/calendar.ts +83 -13
- package/src/tools/chat.ts +35 -4
- package/src/tools/classroom.ts +254 -25
- package/src/tools/docs.ts +7 -1
- package/src/tools/drive.ts +82 -10
- package/src/tools/gmail.ts +37 -1
- package/src/tools/sheets.ts +16 -1
- package/src/tools/utils.ts +10 -4
- package/tests/gmail-dispatch-guard.test.ts +24 -8
- package/tests/tools/api.test.ts +130 -5
- package/tests/tools/appscript.test.ts +6 -2
- package/tests/tools/dispatch-gates-more.test.ts +447 -0
- package/tests/tools/dispatch-gates.test.ts +52 -1
- package/tests/tools/docs.test.ts +5 -6
- package/tests/tools/drive.test.ts +2 -5
- package/tests/tools/run-vets-more.test.ts +269 -0
- package/tests/tools/run-vets.test.ts +158 -4
- package/tests/tools/sheets.test.ts +10 -11
- package/tests/tools/utils.test.ts +38 -41
package/dist/lib.js
CHANGED
|
@@ -838,14 +838,14 @@ function promiseAllObject(promisesObj) {
|
|
|
838
838
|
}
|
|
839
839
|
function randomString(length = 10) {
|
|
840
840
|
const chars = "abcdefghijklmnopqrstuvwxyz";
|
|
841
|
-
let
|
|
841
|
+
let str2 = "";
|
|
842
842
|
for (let i = 0; i < length; i++) {
|
|
843
|
-
|
|
843
|
+
str2 += chars[Math.floor(Math.random() * chars.length)];
|
|
844
844
|
}
|
|
845
|
-
return
|
|
845
|
+
return str2;
|
|
846
846
|
}
|
|
847
|
-
function esc(
|
|
848
|
-
return JSON.stringify(
|
|
847
|
+
function esc(str2) {
|
|
848
|
+
return JSON.stringify(str2);
|
|
849
849
|
}
|
|
850
850
|
function slugify(input2) {
|
|
851
851
|
return input2.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -959,8 +959,8 @@ var primitiveTypes = /* @__PURE__ */ new Set([
|
|
|
959
959
|
"symbol",
|
|
960
960
|
"undefined"
|
|
961
961
|
]);
|
|
962
|
-
function escapeRegex(
|
|
963
|
-
return
|
|
962
|
+
function escapeRegex(str2) {
|
|
963
|
+
return str2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
964
964
|
}
|
|
965
965
|
function clone(inst, def, params) {
|
|
966
966
|
const cl = new inst._zod.constr(def ?? inst._zod.def);
|
|
@@ -1214,13 +1214,13 @@ function getSizableOrigin(input2) {
|
|
|
1214
1214
|
return "unknown";
|
|
1215
1215
|
}
|
|
1216
1216
|
var highSurrogate = /[\uD800-\uDBFF]/;
|
|
1217
|
-
function codePointLength(
|
|
1218
|
-
const units =
|
|
1219
|
-
if (!highSurrogate.test(
|
|
1217
|
+
function codePointLength(str2) {
|
|
1218
|
+
const units = str2.length;
|
|
1219
|
+
if (!highSurrogate.test(str2))
|
|
1220
1220
|
return units;
|
|
1221
1221
|
let count = units;
|
|
1222
1222
|
for (let i = 0; i < units - 1; i++) {
|
|
1223
|
-
if ((
|
|
1223
|
+
if ((str2.charCodeAt(i) & 64512) === 55296 && (str2.charCodeAt(i + 1) & 64512) === 56320) {
|
|
1224
1224
|
count--;
|
|
1225
1225
|
i++;
|
|
1226
1226
|
}
|
|
@@ -19783,7 +19783,7 @@ function declaredDialect(schema, remedy) {
|
|
|
19783
19783
|
throw new Error(`JSON Schema declares an unsupported dialect ("$schema": "${schema.$schema.slice(0, 200)}"). The default validator supports JSON Schema 2020-12, 2019-09, draft-07, and draft-06; ${remedy}`);
|
|
19784
19784
|
}
|
|
19785
19785
|
|
|
19786
|
-
// ../../node_modules/@modelcontextprotocol/core/dist/auth-
|
|
19786
|
+
// ../../node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core/dist/auth-CGP0BDVq.mjs
|
|
19787
19787
|
var LATEST_PROTOCOL_VERSION = "2025-11-25";
|
|
19788
19788
|
var SUPPORTED_PROTOCOL_VERSIONS = [
|
|
19789
19789
|
LATEST_PROTOCOL_VERSION,
|
|
@@ -20620,7 +20620,8 @@ var OAuthMetadataSchema = looseObject({
|
|
|
20620
20620
|
introspection_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
|
|
20621
20621
|
code_challenge_methods_supported: array(string2()).optional(),
|
|
20622
20622
|
client_id_metadata_document_supported: boolean2().optional(),
|
|
20623
|
-
authorization_response_iss_parameter_supported: boolean2().optional().catch(void 0)
|
|
20623
|
+
authorization_response_iss_parameter_supported: boolean2().optional().catch(void 0),
|
|
20624
|
+
dpop_signing_alg_values_supported: array(string2()).optional()
|
|
20624
20625
|
});
|
|
20625
20626
|
var OpenIdProviderMetadataSchema = looseObject({
|
|
20626
20627
|
issuer: string2(),
|
|
@@ -20721,7 +20722,7 @@ var OAuthTokenRevocationRequestSchema = object({
|
|
|
20721
20722
|
token_type_hint: string2().optional()
|
|
20722
20723
|
}).strip();
|
|
20723
20724
|
|
|
20724
|
-
// ../../node_modules/@modelcontextprotocol/server/dist/src-
|
|
20725
|
+
// ../../node_modules/@modelcontextprotocol/server/dist/src-D-y6h4N7.mjs
|
|
20725
20726
|
var BRANDS = /* @__PURE__ */ Symbol.for("mcp.sdk.errorBrands");
|
|
20726
20727
|
function stampErrorBrands(instance, ctor) {
|
|
20727
20728
|
const brands = /* @__PURE__ */ new Set();
|
|
@@ -20835,8 +20836,18 @@ var SdkError = class extends Error {
|
|
|
20835
20836
|
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)`");
|
|
20836
20837
|
return brandedHasInstance(this, value);
|
|
20837
20838
|
}
|
|
20838
|
-
|
|
20839
|
-
|
|
20839
|
+
/**
|
|
20840
|
+
* @param code - Stable string code identifying the failure ({@linkcode SdkErrorCode}).
|
|
20841
|
+
* @param message - Human-readable description.
|
|
20842
|
+
* @param data - Optional structured payload (for example the HTTP status carried by
|
|
20843
|
+
* {@linkcode SdkHttpError}). Opaque to the SDK: a `cause` key inside `data` is not
|
|
20844
|
+
* promoted to `Error.cause`.
|
|
20845
|
+
* @param options - Standard `ErrorOptions`, forwarded to `Error`. Pass the underlying
|
|
20846
|
+
* failure as `{ cause }` so it is reachable through the `Error.cause` chain that
|
|
20847
|
+
* loggers and error trackers walk.
|
|
20848
|
+
*/
|
|
20849
|
+
constructor(code, message, data, options) {
|
|
20850
|
+
super(message, options);
|
|
20840
20851
|
this.code = code;
|
|
20841
20852
|
this.data = data;
|
|
20842
20853
|
this.name = "SdkError";
|
|
@@ -20847,8 +20858,11 @@ var SdkHttpError = class extends SdkError {
|
|
|
20847
20858
|
static {
|
|
20848
20859
|
Object.defineProperty(this, "mcpBrand", { value: "mcp.SdkHttpError" });
|
|
20849
20860
|
}
|
|
20850
|
-
|
|
20851
|
-
|
|
20861
|
+
/**
|
|
20862
|
+
* @param options - Standard `ErrorOptions`, forwarded to `Error` (see {@linkcode SdkError}).
|
|
20863
|
+
*/
|
|
20864
|
+
constructor(code, message, data, options) {
|
|
20865
|
+
super(code, message, data, options);
|
|
20852
20866
|
this.name = "SdkHttpError";
|
|
20853
20867
|
}
|
|
20854
20868
|
get status() {
|
|
@@ -23689,7 +23703,7 @@ var INBOUND_VALIDATION_LADDER = [
|
|
|
23689
23703
|
evaluatedAt: "pre-dispatch",
|
|
23690
23704
|
codes: [HEADER_MISMATCH_ERROR_CODE],
|
|
23691
23705
|
conformance: ["http-header-validation"],
|
|
23692
|
-
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."
|
|
23706
|
+
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."
|
|
23693
23707
|
},
|
|
23694
23708
|
{
|
|
23695
23709
|
rung: "client-capabilities",
|
|
@@ -24438,7 +24452,7 @@ var Protocol = class {
|
|
|
24438
24452
|
return this._requestHandlers.get(method);
|
|
24439
24453
|
}
|
|
24440
24454
|
async _oncancel(notification) {
|
|
24441
|
-
if (
|
|
24455
|
+
if (notification.params.requestId === void 0) return;
|
|
24442
24456
|
this._requestHandlerAbortControllers.get(notification.params.requestId)?.abort(notification.params.reason);
|
|
24443
24457
|
}
|
|
24444
24458
|
_setupTimeout(messageId, timeout, maxTotalTimeout, onTimeout, resetTimeoutOnProgress = false) {
|
|
@@ -24837,19 +24851,20 @@ var Protocol = class {
|
|
|
24837
24851
|
const cancel = (reason) => {
|
|
24838
24852
|
if (responseReceived) return;
|
|
24839
24853
|
this._progressHandlers.delete(messageId);
|
|
24840
|
-
if (requestAbort === void 0)
|
|
24841
|
-
|
|
24842
|
-
|
|
24843
|
-
|
|
24844
|
-
|
|
24845
|
-
|
|
24846
|
-
|
|
24847
|
-
|
|
24848
|
-
|
|
24849
|
-
|
|
24850
|
-
|
|
24851
|
-
|
|
24852
|
-
|
|
24854
|
+
if (requestAbort === void 0) {
|
|
24855
|
+
if (request.method !== "initialize") this._transport?.send(this._envelopeOutbound({
|
|
24856
|
+
jsonrpc: "2.0",
|
|
24857
|
+
method: "notifications/cancelled",
|
|
24858
|
+
params: {
|
|
24859
|
+
requestId: messageId,
|
|
24860
|
+
reason: String(reason)
|
|
24861
|
+
}
|
|
24862
|
+
}), {
|
|
24863
|
+
relatedRequestId,
|
|
24864
|
+
resumptionToken,
|
|
24865
|
+
onresumptiontoken
|
|
24866
|
+
}).catch((error62) => this._onerror(/* @__PURE__ */ new Error(`Failed to send cancellation: ${error62}`)));
|
|
24867
|
+
} else requestAbort.abort();
|
|
24853
24868
|
reject(reason instanceof SdkError ? reason : new SdkError(SdkErrorCode.RequestTimeout, String(reason)));
|
|
24854
24869
|
};
|
|
24855
24870
|
this._responseHandlers.set(messageId, (response) => {
|
|
@@ -24929,7 +24944,7 @@ var Protocol = class {
|
|
|
24929
24944
|
jsonrpc: "2.0",
|
|
24930
24945
|
...notification
|
|
24931
24946
|
});
|
|
24932
|
-
if ((this._options?.debouncedNotificationMethods ?? []).includes(notification.method) && !notification.params &&
|
|
24947
|
+
if ((this._options?.debouncedNotificationMethods ?? []).includes(notification.method) && !notification.params && options?.relatedRequestId === void 0) {
|
|
24933
24948
|
if (this._pendingDebouncedNotifications.has(notification.method)) return;
|
|
24934
24949
|
this._pendingDebouncedNotifications.add(notification.method);
|
|
24935
24950
|
Promise.resolve().then(() => {
|
|
@@ -25182,7 +25197,7 @@ var require_code$1 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
25182
25197
|
}
|
|
25183
25198
|
exports._ = _;
|
|
25184
25199
|
const plus = new _Code("+");
|
|
25185
|
-
function
|
|
25200
|
+
function str2(strs, ...args) {
|
|
25186
25201
|
const expr = [safeStringify(strs[0])];
|
|
25187
25202
|
let i = 0;
|
|
25188
25203
|
while (i < args.length) {
|
|
@@ -25193,7 +25208,7 @@ var require_code$1 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
25193
25208
|
optimize(expr);
|
|
25194
25209
|
return new _Code(expr);
|
|
25195
25210
|
}
|
|
25196
|
-
exports.str =
|
|
25211
|
+
exports.str = str2;
|
|
25197
25212
|
function addCodeArg(code, arg) {
|
|
25198
25213
|
if (arg instanceof _Code) code.push(...arg._items);
|
|
25199
25214
|
else if (arg instanceof Name) code.push(arg);
|
|
@@ -25226,7 +25241,7 @@ var require_code$1 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
25226
25241
|
if (typeof b == "string" && b[0] === '"' && !(a instanceof Name)) return `"${a}${b.slice(1)}`;
|
|
25227
25242
|
}
|
|
25228
25243
|
function strConcat(c1, c2) {
|
|
25229
|
-
return c2.emptyStr() ? c1 : c1.emptyStr() ? c2 :
|
|
25244
|
+
return c2.emptyStr() ? c1 : c1.emptyStr() ? c2 : str2`${c1}${c2}`;
|
|
25230
25245
|
}
|
|
25231
25246
|
exports.strConcat = strConcat;
|
|
25232
25247
|
function interpolate(x) {
|
|
@@ -26105,21 +26120,21 @@ var require_util = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
26105
26120
|
return (0, codegen_1._)`${topSchemaRef}${schemaPath}${(0, codegen_1.getProperty)(keyword)}`;
|
|
26106
26121
|
}
|
|
26107
26122
|
exports.schemaRefOrVal = schemaRefOrVal;
|
|
26108
|
-
function unescapeFragment(
|
|
26109
|
-
return unescapeJsonPointer(decodeURIComponent(
|
|
26123
|
+
function unescapeFragment(str2) {
|
|
26124
|
+
return unescapeJsonPointer(decodeURIComponent(str2));
|
|
26110
26125
|
}
|
|
26111
26126
|
exports.unescapeFragment = unescapeFragment;
|
|
26112
|
-
function escapeFragment(
|
|
26113
|
-
return encodeURIComponent(escapeJsonPointer(
|
|
26127
|
+
function escapeFragment(str2) {
|
|
26128
|
+
return encodeURIComponent(escapeJsonPointer(str2));
|
|
26114
26129
|
}
|
|
26115
26130
|
exports.escapeFragment = escapeFragment;
|
|
26116
|
-
function escapeJsonPointer(
|
|
26117
|
-
if (typeof
|
|
26118
|
-
return
|
|
26131
|
+
function escapeJsonPointer(str2) {
|
|
26132
|
+
if (typeof str2 == "number") return `${str2}`;
|
|
26133
|
+
return str2.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
26119
26134
|
}
|
|
26120
26135
|
exports.escapeJsonPointer = escapeJsonPointer;
|
|
26121
|
-
function unescapeJsonPointer(
|
|
26122
|
-
return
|
|
26136
|
+
function unescapeJsonPointer(str2) {
|
|
26137
|
+
return str2.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
26123
26138
|
}
|
|
26124
26139
|
exports.unescapeJsonPointer = unescapeJsonPointer;
|
|
26125
26140
|
function eachItem(xs, f) {
|
|
@@ -27005,8 +27020,8 @@ var require_json_schema_traverse = /* @__PURE__ */ __commonJSMin(((exports, modu
|
|
|
27005
27020
|
post(schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex);
|
|
27006
27021
|
}
|
|
27007
27022
|
}
|
|
27008
|
-
function escapeJsonPtr(
|
|
27009
|
-
return
|
|
27023
|
+
function escapeJsonPtr(str2) {
|
|
27024
|
+
return str2.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
27010
27025
|
}
|
|
27011
27026
|
}));
|
|
27012
27027
|
var require_resolve = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
@@ -27898,9 +27913,9 @@ var require_utils = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
27898
27913
|
isIPV6: false
|
|
27899
27914
|
};
|
|
27900
27915
|
}
|
|
27901
|
-
function findToken(
|
|
27916
|
+
function findToken(str2, token) {
|
|
27902
27917
|
let ind = 0;
|
|
27903
|
-
for (let i = 0; i <
|
|
27918
|
+
for (let i = 0; i < str2.length; i++) if (str2[i] === token) ind++;
|
|
27904
27919
|
return ind;
|
|
27905
27920
|
}
|
|
27906
27921
|
function removeDotSegments(path) {
|
|
@@ -28415,7 +28430,7 @@ var require_core$3 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
28415
28430
|
const util_1 = require_util();
|
|
28416
28431
|
const $dataRefSchema = require_data();
|
|
28417
28432
|
const uri_1 = require_uri();
|
|
28418
|
-
const defaultRegExp = (
|
|
28433
|
+
const defaultRegExp = (str2, flags) => new RegExp(str2, flags);
|
|
28419
28434
|
defaultRegExp.code = "new RegExp";
|
|
28420
28435
|
const META_IGNORE_OPTIONS = [
|
|
28421
28436
|
"removeAdditional",
|
|
@@ -29121,16 +29136,16 @@ var require_multipleOf = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
29121
29136
|
}));
|
|
29122
29137
|
var require_ucs2length = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
29123
29138
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29124
|
-
function ucs2length(
|
|
29125
|
-
const len =
|
|
29139
|
+
function ucs2length(str2) {
|
|
29140
|
+
const len = str2.length;
|
|
29126
29141
|
let length = 0;
|
|
29127
29142
|
let pos2 = 0;
|
|
29128
29143
|
let value;
|
|
29129
29144
|
while (pos2 < len) {
|
|
29130
29145
|
length++;
|
|
29131
|
-
value =
|
|
29146
|
+
value = str2.charCodeAt(pos2++);
|
|
29132
29147
|
if (value >= 55296 && value <= 56319 && pos2 < len) {
|
|
29133
|
-
value =
|
|
29148
|
+
value = str2.charCodeAt(pos2);
|
|
29134
29149
|
if ((value & 64512) === 56320) pos2++;
|
|
29135
29150
|
}
|
|
29136
29151
|
}
|
|
@@ -31841,8 +31856,8 @@ var require_formats = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
31841
31856
|
30,
|
|
31842
31857
|
31
|
|
31843
31858
|
];
|
|
31844
|
-
function date5(
|
|
31845
|
-
const matches = DATE.exec(
|
|
31859
|
+
function date5(str2) {
|
|
31860
|
+
const matches = DATE.exec(str2);
|
|
31846
31861
|
if (!matches) return false;
|
|
31847
31862
|
const year = +matches[1];
|
|
31848
31863
|
const month = +matches[2];
|
|
@@ -31857,8 +31872,8 @@ var require_formats = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
31857
31872
|
}
|
|
31858
31873
|
const TIME = /^(\d\d):(\d\d):(\d\d(?:\.\d+)?)(z|([+-])(\d\d)(?::?(\d\d))?)?$/i;
|
|
31859
31874
|
function getTime(strictTimeZone) {
|
|
31860
|
-
return function time3(
|
|
31861
|
-
const matches = TIME.exec(
|
|
31875
|
+
return function time3(str2) {
|
|
31876
|
+
const matches = TIME.exec(str2);
|
|
31862
31877
|
if (!matches) return false;
|
|
31863
31878
|
const hr = +matches[1];
|
|
31864
31879
|
const min = +matches[2];
|
|
@@ -31895,8 +31910,8 @@ var require_formats = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
31895
31910
|
const DATE_TIME_SEPARATOR = /t|\s/i;
|
|
31896
31911
|
function getDateTime(strictTimeZone) {
|
|
31897
31912
|
const time3 = getTime(strictTimeZone);
|
|
31898
|
-
return function date_time(
|
|
31899
|
-
const dateTime =
|
|
31913
|
+
return function date_time(str2) {
|
|
31914
|
+
const dateTime = str2.split(DATE_TIME_SEPARATOR);
|
|
31900
31915
|
return dateTime.length === 2 && date5(dateTime[0]) && time3(dateTime[1]);
|
|
31901
31916
|
};
|
|
31902
31917
|
}
|
|
@@ -31917,13 +31932,13 @@ var require_formats = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
31917
31932
|
}
|
|
31918
31933
|
const NOT_URI_FRAGMENT = /\/|:/;
|
|
31919
31934
|
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;
|
|
31920
|
-
function uri(
|
|
31921
|
-
return NOT_URI_FRAGMENT.test(
|
|
31935
|
+
function uri(str2) {
|
|
31936
|
+
return NOT_URI_FRAGMENT.test(str2) && URI.test(str2);
|
|
31922
31937
|
}
|
|
31923
31938
|
const BYTE = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/gm;
|
|
31924
|
-
function byte(
|
|
31939
|
+
function byte(str2) {
|
|
31925
31940
|
BYTE.lastIndex = 0;
|
|
31926
|
-
return BYTE.test(
|
|
31941
|
+
return BYTE.test(str2);
|
|
31927
31942
|
}
|
|
31928
31943
|
const MIN_INT32 = -(2 ** 31);
|
|
31929
31944
|
const MAX_INT32 = 2 ** 31 - 1;
|
|
@@ -31937,10 +31952,10 @@ var require_formats = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
31937
31952
|
return true;
|
|
31938
31953
|
}
|
|
31939
31954
|
const Z_ANCHOR = /[^\\]\\Z/;
|
|
31940
|
-
function regex(
|
|
31941
|
-
if (Z_ANCHOR.test(
|
|
31955
|
+
function regex(str2) {
|
|
31956
|
+
if (Z_ANCHOR.test(str2)) return false;
|
|
31942
31957
|
try {
|
|
31943
|
-
new RegExp(
|
|
31958
|
+
new RegExp(str2);
|
|
31944
31959
|
return true;
|
|
31945
31960
|
} catch (e) {
|
|
31946
31961
|
return false;
|
|
@@ -32129,7 +32144,7 @@ var AjvJsonSchemaValidator = class {
|
|
|
32129
32144
|
};
|
|
32130
32145
|
var Ajv = import_ajv.Ajv;
|
|
32131
32146
|
|
|
32132
|
-
// ../../node_modules/@modelcontextprotocol/server/dist/mcp-
|
|
32147
|
+
// ../../node_modules/@modelcontextprotocol/server/dist/mcp-Dw2OlZ1f.mjs
|
|
32133
32148
|
var MAX_TIMER_DELAY_MS = 2 ** 31 - 1;
|
|
32134
32149
|
var DEFAULT_LEGACY_SHIM_MAX_ROUNDS = 8;
|
|
32135
32150
|
var DEFAULT_LEGACY_SHIM_ROUND_TIMEOUT_MS = 6e5;
|
|
@@ -32880,6 +32895,9 @@ function discoverAdvertisedCapabilities(capabilities) {
|
|
|
32880
32895
|
return { ...capabilities };
|
|
32881
32896
|
}
|
|
32882
32897
|
|
|
32898
|
+
// ../../node_modules/@modelcontextprotocol/server/dist/index.mjs
|
|
32899
|
+
var DEFAULT_MAX_REQUEST_BODY_SIZE = 4 * 1024 * 1024;
|
|
32900
|
+
|
|
32883
32901
|
// ../../node_modules/@chrischall/mcp-utils/dist/errors/index.js
|
|
32884
32902
|
var BEARER_RE = /(bearer\s+)[A-Za-z0-9._~+/=-]{8,}/gi;
|
|
32885
32903
|
var JWT_RE = /\b[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{8,}\b/g;
|
|
@@ -34327,6 +34345,7 @@ async function diagnose(err) {
|
|
|
34327
34345
|
const isAuthError = !isTransientError && AUTH_ERROR_PATTERN.test(errText);
|
|
34328
34346
|
const isGridLimitError = GRID_LIMIT_ERROR_PATTERN.test(errText);
|
|
34329
34347
|
const hint = isInvalidGrant ? INVALID_GRANT_HINT : isAuthError ? AUTH_HINT : isTransientError ? TRANSIENT_HINT : isGridLimitError ? GRID_LIMIT_HINT : "";
|
|
34348
|
+
if (!isAuthError && !isInvalidGrant) return errorResult(`${errText}${hint}`);
|
|
34330
34349
|
try {
|
|
34331
34350
|
const accounts = formatAccountList(await run(["auth", "list"]));
|
|
34332
34351
|
return errorResult(`${errText}
|
|
@@ -34471,12 +34490,53 @@ function attachmentPreview(details) {
|
|
|
34471
34490
|
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.";
|
|
34472
34491
|
var CONFIRM_ACTION_INSTRUCTION = CONFIRM_TOKEN_INSTRUCTION;
|
|
34473
34492
|
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.';
|
|
34493
|
+
function refusedInRun(what, via, does, instead) {
|
|
34494
|
+
return `${what} ${does} and is not available through ${via}. ${instead}`;
|
|
34495
|
+
}
|
|
34474
34496
|
function gatedElsewhere(what, via, does, tool) {
|
|
34475
|
-
return
|
|
34497
|
+
return refusedInRun(what, via, does, `Use ${tool}, which asks the user to confirm.`);
|
|
34476
34498
|
}
|
|
34477
34499
|
function hasCommandWord(args, words) {
|
|
34478
34500
|
return args.find((a) => words.has(a.toLowerCase()));
|
|
34479
34501
|
}
|
|
34502
|
+
function flagValue(args, name) {
|
|
34503
|
+
const flag = `--${name}`;
|
|
34504
|
+
for (let i = 0; i < args.length; i++) {
|
|
34505
|
+
const a = args[i];
|
|
34506
|
+
if (a === flag) return args[i + 1] ?? "";
|
|
34507
|
+
if (a.startsWith(`${flag}=`)) return a.slice(flag.length + 1);
|
|
34508
|
+
}
|
|
34509
|
+
return void 0;
|
|
34510
|
+
}
|
|
34511
|
+
var COMMENT_ADD_WORDS = /* @__PURE__ */ new Set(["create", "add", "new"]);
|
|
34512
|
+
var COMMENT_REPLY_WORDS = /* @__PURE__ */ new Set(["reply", "respond"]);
|
|
34513
|
+
function hasTrueFlag(args, flag) {
|
|
34514
|
+
const name = `--${flag}`;
|
|
34515
|
+
return args.some((a) => {
|
|
34516
|
+
const lower = a.toLowerCase();
|
|
34517
|
+
if (lower === name) return true;
|
|
34518
|
+
return lower.startsWith(`${name}=`) && lower.slice(name.length + 1) !== "false";
|
|
34519
|
+
});
|
|
34520
|
+
}
|
|
34521
|
+
function vetCommentsRun(service, subcommand, args) {
|
|
34522
|
+
if (subcommand.toLowerCase() !== "comments") return void 0;
|
|
34523
|
+
const reply = hasCommandWord(args, COMMENT_REPLY_WORDS);
|
|
34524
|
+
if (reply) {
|
|
34525
|
+
return gatedElsewhere(
|
|
34526
|
+
`gog ${service} comments ${reply.toLowerCase()}`,
|
|
34527
|
+
`gog_${service}_run`,
|
|
34528
|
+
"notifies the comment thread",
|
|
34529
|
+
`gog_${service}_comments_reply`
|
|
34530
|
+
);
|
|
34531
|
+
}
|
|
34532
|
+
const add = hasCommandWord(args, COMMENT_ADD_WORDS);
|
|
34533
|
+
return add ? gatedElsewhere(
|
|
34534
|
+
`gog ${service} comments ${add.toLowerCase()}`,
|
|
34535
|
+
`gog_${service}_run`,
|
|
34536
|
+
"notifies the file's owner and anyone it mentions",
|
|
34537
|
+
`gog_${service}_comments_add`
|
|
34538
|
+
) : void 0;
|
|
34539
|
+
}
|
|
34480
34540
|
async function requireDispatchConfirmation(ctx, options) {
|
|
34481
34541
|
const { action, fallback } = options;
|
|
34482
34542
|
const confirmation = {
|
|
@@ -34505,16 +34565,33 @@ function resultText(result) {
|
|
|
34505
34565
|
// src/tools/api.ts
|
|
34506
34566
|
var GMAIL_API_BLOCKED = /(?:\.send$|forwarding|filters\.create|filters\.update|delegates\.create)/i;
|
|
34507
34567
|
var DISPATCH_API_BLOCKED = {
|
|
34508
|
-
chat: [
|
|
34509
|
-
|
|
34568
|
+
chat: [
|
|
34569
|
+
{ method: /(?:^|\.)spaces\.messages\.create$/i, does: "posts a Chat message", tool: "gog_chat_messages_send / gog_chat_dm_send" },
|
|
34570
|
+
{ method: /(?:^|\.)spaces\.(?:setup|members\.create)$/i, does: "adds people to a space", tool: "gog_chat_spaces_create" }
|
|
34571
|
+
],
|
|
34572
|
+
drive: [
|
|
34573
|
+
{ method: /(?:^|\.)permissions\.(?:create|update)$/i, does: "grants access to a file", tool: "gog_drive_share" },
|
|
34574
|
+
{ method: /(?:^|\.)comments\.create$/i, does: "notifies the file's owner and anyone it mentions", tool: "gog_drive_comments_add / gog_docs_comments_add" },
|
|
34575
|
+
{ method: /(?:^|\.)replies\.create$/i, does: "notifies the comment thread", tool: "gog_drive_comments_reply / gog_docs_comments_reply" }
|
|
34576
|
+
],
|
|
34510
34577
|
classroom: [
|
|
34511
34578
|
{ method: /(?:^|\.)courses\.announcements\.create$/i, does: "posts to a class", tool: "gog_classroom_announcements_create" },
|
|
34512
|
-
{ method: /(?:^|\.)invitations\.create$/i, does: "invites someone to a class", tool: "gog_classroom_invitations_create" }
|
|
34579
|
+
{ method: /(?:^|\.)invitations\.create$/i, does: "invites someone to a class", tool: "gog_classroom_invitations_create" },
|
|
34580
|
+
{ method: /(?:^|\.)courses\.students\.create$/i, does: "adds someone to a class", tool: "gog_classroom_students_add" },
|
|
34581
|
+
{ method: /(?:^|\.)courses\.teachers\.create$/i, does: "gives someone teacher access to a class", tool: "gog_classroom_teachers_add" },
|
|
34582
|
+
{ method: /(?:^|\.)courses\.coursework\.create$/i, does: "posts coursework to a class", tool: "gog_classroom_coursework_create" },
|
|
34583
|
+
{ method: /(?:^|\.)studentsubmissions\.return$/i, does: "returns work to a student", tool: "gog_classroom_submissions_return" }
|
|
34513
34584
|
],
|
|
34514
34585
|
calendar: [
|
|
34515
34586
|
{ method: /(?:^|\.)events\.(?:insert|import|quickadd)$/i, does: "can put an event on guests' calendars", tool: "gog_calendar_create" },
|
|
34516
|
-
{ method: /(?:^|\.)events\.(?:update|patch)$/i, does: "can change what guests see", tool: "gog_calendar_update / gog_calendar_respond" }
|
|
34517
|
-
|
|
34587
|
+
{ method: /(?:^|\.)events\.(?:update|patch)$/i, does: "can change what guests see", tool: "gog_calendar_update / gog_calendar_respond" },
|
|
34588
|
+
{ method: /(?:^|\.)events\.move$/i, does: "can email every guest", tool: "gog_calendar_move" }
|
|
34589
|
+
],
|
|
34590
|
+
gmail: [
|
|
34591
|
+
{ method: /(?:^|\.)settings\.sendas\.create$/i, does: "makes Google email the address and adds a sending identity", tool: "gog_gmail_sendas_create" },
|
|
34592
|
+
{ method: /(?:^|\.)settings\.updatevacation$/i, does: "can turn on an auto-reply to every sender", tool: "gog_gmail_vacation_update" }
|
|
34593
|
+
],
|
|
34594
|
+
script: [{ method: /(?:^|\.)scripts\.run$/i, does: "executes code with this account's authority", tool: "gog_appscript_run_function" }]
|
|
34518
34595
|
};
|
|
34519
34596
|
function refusedApiCall(api, method) {
|
|
34520
34597
|
const name = api.trim().toLowerCase();
|
|
@@ -34525,6 +34602,14 @@ function refusedApiCall(api, method) {
|
|
|
34525
34602
|
const hit = (Object.hasOwn(DISPATCH_API_BLOCKED, name) ? DISPATCH_API_BLOCKED[name] : []).find((b) => b.method.test(m));
|
|
34526
34603
|
return hit ? gatedElsewhere(`${name} ${m}`, "gog_api_call", hit.does, hit.tool) : void 0;
|
|
34527
34604
|
}
|
|
34605
|
+
function previewJson(text) {
|
|
34606
|
+
if (text.length > BODY_PREVIEW_MAX) return bodyPreview(text);
|
|
34607
|
+
try {
|
|
34608
|
+
return JSON.parse(text);
|
|
34609
|
+
} catch {
|
|
34610
|
+
return text;
|
|
34611
|
+
}
|
|
34612
|
+
}
|
|
34528
34613
|
function registerApiTools(server) {
|
|
34529
34614
|
server.registerTool("gog_api_list", {
|
|
34530
34615
|
description: "List the Google Discovery APIs available for gog_api_call / gog_api_describe (name + version + title).",
|
|
@@ -34553,7 +34638,7 @@ function registerApiTools(server) {
|
|
|
34553
34638
|
return runOrDiagnose(args, { account });
|
|
34554
34639
|
});
|
|
34555
34640
|
server.registerTool("gog_api_call", {
|
|
34556
|
-
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
|
|
34641
|
+
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,
|
|
34557
34642
|
annotations: { destructiveHint: true },
|
|
34558
34643
|
inputSchema: external_exports.object({
|
|
34559
34644
|
api: external_exports.string().describe("Discovery API name (e.g. drive, gmail, calendar)"),
|
|
@@ -34562,11 +34647,12 @@ function registerApiTools(server) {
|
|
|
34562
34647
|
params: external_exports.string().optional().describe('Query/path parameters as a JSON object string (e.g. {"fileId":"abc","fields":"name"})'),
|
|
34563
34648
|
body: external_exports.string().optional().describe("Request body as a JSON string (for write methods)"),
|
|
34564
34649
|
scope: external_exports.string().optional().describe("Override the OAuth scope used for the call"),
|
|
34565
|
-
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."),
|
|
34566
|
-
dryRun: external_exports.boolean().optional().describe("Print the intended request and exit without sending it (no changes made)"),
|
|
34567
|
-
account: accountParam
|
|
34650
|
+
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."),
|
|
34651
|
+
dryRun: external_exports.boolean().optional().describe("Print the intended request and exit without sending it (no changes made, no confirmation prompt)"),
|
|
34652
|
+
account: accountParam,
|
|
34653
|
+
confirmToken: confirmTokenParam
|
|
34568
34654
|
})
|
|
34569
|
-
}, async ({ api, version: version2, method, params, body, scope, allowWrite, dryRun, account }) => {
|
|
34655
|
+
}, async ({ api, version: version2, method, params, body, scope, allowWrite, dryRun, account, confirmToken }, ctx) => {
|
|
34570
34656
|
try {
|
|
34571
34657
|
assertSafeForwardedArgs([api, version2, method]);
|
|
34572
34658
|
const refusal = refusedApiCall(api, method);
|
|
@@ -34576,6 +34662,27 @@ function registerApiTools(server) {
|
|
|
34576
34662
|
} catch (err) {
|
|
34577
34663
|
return errorResult(errorText(err));
|
|
34578
34664
|
}
|
|
34665
|
+
if (allowWrite && !dryRun) {
|
|
34666
|
+
const request = { api, version: version2, method, params, body, scope };
|
|
34667
|
+
const view = { api, version: version2, method };
|
|
34668
|
+
if (params !== void 0) view.params = previewJson(params);
|
|
34669
|
+
if (body !== void 0) view.body = previewJson(body);
|
|
34670
|
+
if (scope !== void 0) view.scope = scope;
|
|
34671
|
+
const confirmation = await requireDispatchConfirmation(ctx, {
|
|
34672
|
+
action: "api.call",
|
|
34673
|
+
message: `Review and confirm this raw Google API write (${api} ${version2} ${method}):`,
|
|
34674
|
+
confirmationLabel: "Confirm that this API method should be invoked with exactly these parameters.",
|
|
34675
|
+
details: view,
|
|
34676
|
+
unsupportedNote: "Set dryRun=true to see the request gog would send without sending it, or use the dedicated gog_* tool for this operation.",
|
|
34677
|
+
fallback: {
|
|
34678
|
+
tool: "gog_api_call",
|
|
34679
|
+
account,
|
|
34680
|
+
confirmToken,
|
|
34681
|
+
subject: () => ({ target: `${api}/${version2}/${method}`, payload: request, preview: view })
|
|
34682
|
+
}
|
|
34683
|
+
});
|
|
34684
|
+
if (confirmation) return confirmation;
|
|
34685
|
+
}
|
|
34579
34686
|
const args = ["api", "call", pos(api), pos(version2), pos(method)];
|
|
34580
34687
|
if (params) args.push(`--params=${params}`);
|
|
34581
34688
|
if (body) args.push(`--body=${body}`);
|
|
@@ -34588,6 +34695,22 @@ function registerApiTools(server) {
|
|
|
34588
34695
|
}
|
|
34589
34696
|
|
|
34590
34697
|
// src/tools/appscript.ts
|
|
34698
|
+
function vetAppScriptRun(subcommand, _args) {
|
|
34699
|
+
return subcommand.toLowerCase() === "run" ? gatedElsewhere("gog appscript run", "gog_appscript_run", "executes code with this account's authority", "gog_appscript_run_function") : void 0;
|
|
34700
|
+
}
|
|
34701
|
+
function projectSnapshot(raw, scriptId) {
|
|
34702
|
+
let project;
|
|
34703
|
+
try {
|
|
34704
|
+
project = JSON.parse(raw)?.project;
|
|
34705
|
+
} catch {
|
|
34706
|
+
project = void 0;
|
|
34707
|
+
}
|
|
34708
|
+
return {
|
|
34709
|
+
scriptId,
|
|
34710
|
+
...typeof project?.title === "string" ? { title: project.title } : {},
|
|
34711
|
+
...typeof project?.updateTime === "string" ? { updateTime: project.updateTime } : {}
|
|
34712
|
+
};
|
|
34713
|
+
}
|
|
34591
34714
|
function registerAppScriptTools(server) {
|
|
34592
34715
|
const scriptIdParam = external_exports.string().describe(
|
|
34593
34716
|
"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"
|
|
@@ -34668,16 +34791,18 @@ function registerAppScriptTools(server) {
|
|
|
34668
34791
|
return runOrDiagnose(args, { account });
|
|
34669
34792
|
});
|
|
34670
34793
|
server.registerTool("gog_appscript_run_function", {
|
|
34671
|
-
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,
|
|
34794
|
+
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,
|
|
34672
34795
|
annotations: { destructiveHint: true },
|
|
34673
34796
|
inputSchema: external_exports.object({
|
|
34674
34797
|
scriptId: scriptIdParam,
|
|
34675
34798
|
functionName: external_exports.string().describe('Name of the function to call, e.g. "doWork"'),
|
|
34676
34799
|
params: external_exports.string().optional().describe(`Function parameters as a JSON ARRAY of positional arguments, e.g. '["a", 1]' \u2014 not an object`),
|
|
34677
34800
|
devMode: external_exports.boolean().optional().describe("Run the latest saved code rather than the deployed version (owner only)"),
|
|
34678
|
-
account: accountParam
|
|
34801
|
+
account: accountParam,
|
|
34802
|
+
confirmToken: confirmTokenParam
|
|
34679
34803
|
})
|
|
34680
|
-
}, async ({ scriptId, functionName, params, devMode, account }) => {
|
|
34804
|
+
}, async ({ scriptId, functionName, params, devMode, account, confirmToken }, ctx) => {
|
|
34805
|
+
let parsedParams;
|
|
34681
34806
|
if (params !== void 0) {
|
|
34682
34807
|
let parsed;
|
|
34683
34808
|
try {
|
|
@@ -34688,7 +34813,26 @@ function registerAppScriptTools(server) {
|
|
|
34688
34813
|
if (!Array.isArray(parsed)) {
|
|
34689
34814
|
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}`);
|
|
34690
34815
|
}
|
|
34816
|
+
parsedParams = parsed;
|
|
34691
34817
|
}
|
|
34818
|
+
const got = await runOrDiagnose(["appscript", "get", pos(scriptId)], { account });
|
|
34819
|
+
if (got.isError) return got;
|
|
34820
|
+
const { updateTime, ...project } = projectSnapshot(resultText(got), scriptId);
|
|
34821
|
+
const execution = { project, functionName, params: parsedParams, devMode: Boolean(devMode), runsAs: senderPreview(account) };
|
|
34822
|
+
const confirmation = await requireDispatchConfirmation(ctx, {
|
|
34823
|
+
action: "appscript.run-function",
|
|
34824
|
+
message: "Review and confirm running this Apps Script function with the account's full authority:",
|
|
34825
|
+
confirmationLabel: "Confirm that this code should run now.",
|
|
34826
|
+
details: execution,
|
|
34827
|
+
unsupportedNote: "Ask the user to run it themselves from the Apps Script editor.",
|
|
34828
|
+
fallback: {
|
|
34829
|
+
tool: "gog_appscript_run_function",
|
|
34830
|
+
account,
|
|
34831
|
+
confirmToken,
|
|
34832
|
+
subject: () => ({ target: `${scriptId}/${functionName}`, revision: updateTime, payload: execution, preview: execution })
|
|
34833
|
+
}
|
|
34834
|
+
});
|
|
34835
|
+
if (confirmation) return confirmation;
|
|
34692
34836
|
const args = ["appscript", "run", pos(scriptId), pos(functionName)];
|
|
34693
34837
|
if (params !== void 0) args.push(`--params=${params}`);
|
|
34694
34838
|
if (devMode) args.push("--dev-mode");
|
|
@@ -34697,6 +34841,7 @@ function registerAppScriptTools(server) {
|
|
|
34697
34841
|
registerRunTool(server, {
|
|
34698
34842
|
service: "appscript",
|
|
34699
34843
|
examples: '"get", "content", "deployments"',
|
|
34844
|
+
vet: vetAppScriptRun,
|
|
34700
34845
|
note: "To execute a function, use gog_appscript_run_function \u2014 this tool is the generic escape hatch."
|
|
34701
34846
|
});
|
|
34702
34847
|
}
|
|
@@ -34839,21 +34984,47 @@ function authToolsFor(defaultServices) {
|
|
|
34839
34984
|
}
|
|
34840
34985
|
|
|
34841
34986
|
// src/tools/calendar.ts
|
|
34842
|
-
var
|
|
34843
|
-
|
|
34844
|
-
|
|
34845
|
-
|
|
34846
|
-
|
|
34847
|
-
|
|
34848
|
-
|
|
34849
|
-
|
|
34850
|
-
|
|
34851
|
-
|
|
34987
|
+
var ASKS = (tool) => `Use ${tool}, which asks the user to confirm.`;
|
|
34988
|
+
var CALENDAR_REFUSED = {
|
|
34989
|
+
create: { does: "can change what guests see", instead: ASKS("gog_calendar_create") },
|
|
34990
|
+
add: { does: "can change what guests see", instead: ASKS("gog_calendar_create") },
|
|
34991
|
+
new: { does: "can change what guests see", instead: ASKS("gog_calendar_create") },
|
|
34992
|
+
update: { does: "can change what guests see", instead: ASKS("gog_calendar_update") },
|
|
34993
|
+
edit: { does: "can change what guests see", instead: ASKS("gog_calendar_update") },
|
|
34994
|
+
set: { does: "can change what guests see", instead: ASKS("gog_calendar_update") },
|
|
34995
|
+
respond: { does: "can change what guests see", instead: ASKS("gog_calendar_respond") },
|
|
34996
|
+
rsvp: { does: "can change what guests see", instead: ASKS("gog_calendar_respond") },
|
|
34997
|
+
reply: { does: "can change what guests see", instead: ASKS("gog_calendar_respond") },
|
|
34998
|
+
move: { does: "moves an event off guests' calendars (and can email them)", instead: ASKS("gog_calendar_move") },
|
|
34999
|
+
transfer: { does: "moves an event off guests' calendars (and can email them)", instead: ASKS("gog_calendar_move") },
|
|
35000
|
+
delete: { does: "removes an event from every guest's calendar (the whole series by default)", instead: ASKS("gog_calendar_delete") },
|
|
35001
|
+
del: { does: "removes an event from every guest's calendar (the whole series by default)", instead: ASKS("gog_calendar_delete") },
|
|
35002
|
+
rm: { does: "removes an event from every guest's calendar (the whole series by default)", instead: ASKS("gog_calendar_delete") },
|
|
35003
|
+
remove: { does: "removes an event from every guest's calendar (the whole series by default)", instead: ASKS("gog_calendar_delete") },
|
|
35004
|
+
"delete-calendar": { does: "deletes a calendar and every event on it", instead: ASKS("gog_calendar_delete_calendar") },
|
|
35005
|
+
"out-of-office": { does: "auto-declines invitations and notifies their organizers", instead: ASKS("gog_calendar_out_of_office") },
|
|
35006
|
+
ooo: { does: "auto-declines invitations and notifies their organizers", instead: ASKS("gog_calendar_out_of_office") }
|
|
34852
35007
|
};
|
|
34853
|
-
function vetCalendarRun(subcommand,
|
|
35008
|
+
function vetCalendarRun(subcommand, args) {
|
|
34854
35009
|
const sub = subcommand.toLowerCase();
|
|
34855
|
-
const
|
|
34856
|
-
|
|
35010
|
+
const what = `gog calendar ${sub}`;
|
|
35011
|
+
const via = "gog_calendar_run";
|
|
35012
|
+
if (Object.hasOwn(CALENDAR_REFUSED, sub)) {
|
|
35013
|
+
const { does, instead } = CALENDAR_REFUSED[sub];
|
|
35014
|
+
return refusedInRun(what, via, does, instead);
|
|
35015
|
+
}
|
|
35016
|
+
if (sub === "propose-time" && (flagValue(args, "decline") !== void 0 || flagValue(args, "comment") !== void 0)) {
|
|
35017
|
+
return gatedElsewhere(`${what} --decline`, via, "declines the event and notifies the organizer", "gog_calendar_respond");
|
|
35018
|
+
}
|
|
35019
|
+
if ((sub === "focus-time" || sub === "focus") && flagValue(args, "auto-decline")?.toLowerCase() !== "none") {
|
|
35020
|
+
return refusedInRun(
|
|
35021
|
+
what,
|
|
35022
|
+
via,
|
|
35023
|
+
"auto-declines invitations and notifies their organizers (gog defaults --auto-decline to all)",
|
|
35024
|
+
"Pass --auto-decline=none, or ask the user to create it from Google Calendar."
|
|
35025
|
+
);
|
|
35026
|
+
}
|
|
35027
|
+
return void 0;
|
|
34857
35028
|
}
|
|
34858
35029
|
function parseAttendees(value) {
|
|
34859
35030
|
if (!value) return [];
|
|
@@ -34870,15 +35041,17 @@ function eventSnapshot(raw) {
|
|
|
34870
35041
|
} catch {
|
|
34871
35042
|
event = void 0;
|
|
34872
35043
|
}
|
|
34873
|
-
const
|
|
35044
|
+
const str2 = (v) => typeof v === "string" ? v : void 0;
|
|
34874
35045
|
return {
|
|
34875
|
-
summary:
|
|
35046
|
+
summary: str2(event?.summary),
|
|
34876
35047
|
start: timeOf(event?.start),
|
|
34877
35048
|
end: timeOf(event?.end),
|
|
34878
|
-
organizer:
|
|
35049
|
+
organizer: str2(event?.organizer?.email),
|
|
34879
35050
|
// Guests are the OTHER people: not this account's own attendee row, not rooms.
|
|
34880
35051
|
guests: (Array.isArray(event?.attendees) ? event.attendees : []).filter((a) => a.self !== true && a.resource !== true && typeof a.email === "string").map((a) => a.email),
|
|
34881
|
-
|
|
35052
|
+
// A series, or one instance of one: gog's delete --scope defaults to all.
|
|
35053
|
+
...Array.isArray(event?.recurrence) && event.recurrence.length > 0 || typeof event?.recurringEventId === "string" ? { recurring: true } : {},
|
|
35054
|
+
etag: str2(event?.etag)
|
|
34882
35055
|
};
|
|
34883
35056
|
}
|
|
34884
35057
|
async function readEvent(calendarId, eventId, account) {
|
|
@@ -35099,14 +35272,35 @@ function registerCalendarTools(server) {
|
|
|
35099
35272
|
return runOrDiagnose(args, { account });
|
|
35100
35273
|
});
|
|
35101
35274
|
server.registerTool("gog_calendar_delete", {
|
|
35102
|
-
description: "Delete a calendar event.",
|
|
35275
|
+
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,
|
|
35103
35276
|
annotations: { destructiveHint: true },
|
|
35104
35277
|
inputSchema: external_exports.object({
|
|
35105
35278
|
calendarId: external_exports.string().describe("Calendar ID"),
|
|
35106
35279
|
eventId: external_exports.string().describe("Event ID"),
|
|
35107
|
-
account: accountParam
|
|
35280
|
+
account: accountParam,
|
|
35281
|
+
confirmToken: confirmTokenParam
|
|
35108
35282
|
})
|
|
35109
|
-
}, async ({ calendarId, eventId, account }) => {
|
|
35283
|
+
}, async ({ calendarId, eventId, account, confirmToken }, ctx) => {
|
|
35284
|
+
const read = await readEvent(calendarId, eventId, account);
|
|
35285
|
+
if (read.error) return read.error;
|
|
35286
|
+
const { etag, ...event } = read.event;
|
|
35287
|
+
if (event.guests.length > 0 || event.recurring) {
|
|
35288
|
+
const view = { calendarId, eventId, event, scope: event.recurring ? "the whole recurring series" : "this event" };
|
|
35289
|
+
const confirmation = await requireDispatchConfirmation(ctx, {
|
|
35290
|
+
action: "calendar.delete",
|
|
35291
|
+
message: event.recurring ? "Review and confirm deleting this ENTIRE recurring series:" : "Review and confirm deleting this event from every guest's calendar:",
|
|
35292
|
+
confirmationLabel: "Confirm that this event should be deleted now.",
|
|
35293
|
+
details: view,
|
|
35294
|
+
unsupportedNote: "Ask the user to delete it from Google Calendar.",
|
|
35295
|
+
fallback: {
|
|
35296
|
+
tool: "gog_calendar_delete",
|
|
35297
|
+
account,
|
|
35298
|
+
confirmToken,
|
|
35299
|
+
subject: () => ({ target: `${calendarId}/${eventId}`, revision: etag, payload: view, preview: view })
|
|
35300
|
+
}
|
|
35301
|
+
});
|
|
35302
|
+
if (confirmation) return confirmation;
|
|
35303
|
+
}
|
|
35110
35304
|
return runOrDiagnose(["calendar", "delete", pos(calendarId), pos(eventId), "--force"], { account });
|
|
35111
35305
|
});
|
|
35112
35306
|
server.registerTool("gog_calendar_respond", {
|
|
@@ -35228,8 +35422,14 @@ function inlineAttachmentArgs(flag, attachments, siblingArgs = []) {
|
|
|
35228
35422
|
|
|
35229
35423
|
// src/tools/chat.ts
|
|
35230
35424
|
var CHAT_SEND_WORDS = /* @__PURE__ */ new Set(["send", "create", "post"]);
|
|
35425
|
+
var CHAT_SPACE_CREATE_WORDS = /* @__PURE__ */ new Set(["create", "add", "new"]);
|
|
35231
35426
|
function vetChatRun(subcommand, args) {
|
|
35232
35427
|
const sub = subcommand.toLowerCase();
|
|
35428
|
+
if (sub === "spaces") {
|
|
35429
|
+
const word2 = hasCommandWord(args, CHAT_SPACE_CREATE_WORDS);
|
|
35430
|
+
const withMembers = args.some((a) => /^--members?(?:=|$)/i.test(a));
|
|
35431
|
+
return word2 && withMembers ? gatedElsewhere(`gog chat spaces ${word2.toLowerCase()} --member`, "gog_chat_run", "adds people to a space", "gog_chat_spaces_create") : void 0;
|
|
35432
|
+
}
|
|
35233
35433
|
if (sub !== "messages" && sub !== "dm") return void 0;
|
|
35234
35434
|
const word = hasCommandWord(args, CHAT_SEND_WORDS);
|
|
35235
35435
|
if (!word) return void 0;
|
|
@@ -35280,16 +35480,34 @@ function registerChatTools(server) {
|
|
|
35280
35480
|
return runOrDiagnose(args, { account });
|
|
35281
35481
|
});
|
|
35282
35482
|
server.registerTool("gog_chat_spaces_create", {
|
|
35283
|
-
description: "Create a named Chat space, optionally seeding its membership. Members are added immediately and are notified
|
|
35483
|
+
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,
|
|
35284
35484
|
annotations: { destructiveHint: true },
|
|
35285
35485
|
inputSchema: external_exports.object({
|
|
35286
35486
|
displayName: external_exports.string().describe("Display name for the new space"),
|
|
35287
35487
|
members: external_exports.array(external_exports.string()).optional().describe('Initial members, as email addresses or "users/..." resource names'),
|
|
35288
|
-
account: accountParam
|
|
35488
|
+
account: accountParam,
|
|
35489
|
+
confirmToken: confirmTokenParam
|
|
35289
35490
|
})
|
|
35290
|
-
}, async ({ displayName, members: members2, account }) => {
|
|
35491
|
+
}, async ({ displayName, members: members2, account, confirmToken }, ctx) => {
|
|
35291
35492
|
const args = ["chat", "spaces", "create", pos(displayName)];
|
|
35292
35493
|
if (members2) for (const member of members2) args.push(`--member=${member}`);
|
|
35494
|
+
if (members2?.length) {
|
|
35495
|
+
const space = { displayName, members: members2 };
|
|
35496
|
+
const confirmation = await requireDispatchConfirmation(ctx, {
|
|
35497
|
+
action: "chat.space-create",
|
|
35498
|
+
message: "Review and confirm this Chat space \u2014 every member is added and notified:",
|
|
35499
|
+
confirmationLabel: "Confirm that these people should be added to a new space now.",
|
|
35500
|
+
details: space,
|
|
35501
|
+
unsupportedNote: "Create the space without members instead; the user can add people from Google Chat.",
|
|
35502
|
+
fallback: {
|
|
35503
|
+
tool: "gog_chat_spaces_create",
|
|
35504
|
+
account,
|
|
35505
|
+
confirmToken,
|
|
35506
|
+
subject: () => ({ target: displayName, payload: space, preview: space })
|
|
35507
|
+
}
|
|
35508
|
+
});
|
|
35509
|
+
if (confirmation) return confirmation;
|
|
35510
|
+
}
|
|
35293
35511
|
return runOrDiagnose(args, { account });
|
|
35294
35512
|
});
|
|
35295
35513
|
server.registerTool("gog_chat_threads_list", {
|
|
@@ -35483,20 +35701,85 @@ function registerChatTools(server) {
|
|
|
35483
35701
|
|
|
35484
35702
|
// src/tools/classroom.ts
|
|
35485
35703
|
var CLASSROOM_CREATE_WORDS = /* @__PURE__ */ new Set(["create", "add", "new"]);
|
|
35486
|
-
var
|
|
35487
|
-
|
|
35488
|
-
|
|
35489
|
-
|
|
35490
|
-
|
|
35491
|
-
|
|
35492
|
-
|
|
35704
|
+
var CLASSROOM_DELETE_WORDS = /* @__PURE__ */ new Set(["delete", "rm", "del", "remove"]);
|
|
35705
|
+
var CLASSROOM_UPDATE_WORDS = /* @__PURE__ */ new Set(["update", "edit", "set"]);
|
|
35706
|
+
var CLASSROOM_RETURN_WORDS = /* @__PURE__ */ new Set(["return", "send"]);
|
|
35707
|
+
var CLASSROOM_ASSIGNEE_WORDS = /* @__PURE__ */ new Set(["assignees", "assign"]);
|
|
35708
|
+
var CLASSROOM_GROUPS = {
|
|
35709
|
+
courses: "courses",
|
|
35710
|
+
course: "courses",
|
|
35711
|
+
announcements: "announcements",
|
|
35712
|
+
announcement: "announcements",
|
|
35713
|
+
ann: "announcements",
|
|
35714
|
+
invitations: "invitations",
|
|
35715
|
+
invitation: "invitations",
|
|
35716
|
+
invites: "invitations",
|
|
35717
|
+
coursework: "coursework",
|
|
35718
|
+
work: "coursework",
|
|
35719
|
+
materials: "materials",
|
|
35720
|
+
material: "materials",
|
|
35721
|
+
students: "students",
|
|
35722
|
+
student: "students",
|
|
35723
|
+
teachers: "teachers",
|
|
35724
|
+
teacher: "teachers",
|
|
35725
|
+
submissions: "submissions",
|
|
35726
|
+
submission: "submissions",
|
|
35727
|
+
"guardian-invitations": "guardian-invitations",
|
|
35728
|
+
"guardian-invites": "guardian-invitations"
|
|
35493
35729
|
};
|
|
35730
|
+
function publishesToStudents(args) {
|
|
35731
|
+
return flagValue(args, "state")?.toUpperCase() === "PUBLISHED" || flagValue(args, "scheduled") !== void 0;
|
|
35732
|
+
}
|
|
35733
|
+
function createsVisibleWork(args) {
|
|
35734
|
+
return flagValue(args, "state")?.toUpperCase() !== "DRAFT" || flagValue(args, "scheduled") !== void 0;
|
|
35735
|
+
}
|
|
35736
|
+
function widensAssignees(args) {
|
|
35737
|
+
return flagValue(args, "mode")?.toUpperCase() === "ALL_STUDENTS" || flagValue(args, "add-student") !== void 0;
|
|
35738
|
+
}
|
|
35494
35739
|
function vetClassroomRun(subcommand, args) {
|
|
35495
35740
|
const sub = subcommand.toLowerCase();
|
|
35496
|
-
|
|
35497
|
-
|
|
35498
|
-
const
|
|
35499
|
-
|
|
35741
|
+
if (!Object.hasOwn(CLASSROOM_GROUPS, sub)) return void 0;
|
|
35742
|
+
const group = CLASSROOM_GROUPS[sub];
|
|
35743
|
+
const via = "gog_classroom_run";
|
|
35744
|
+
const what = (word) => `gog classroom ${sub} ${word.toLowerCase()}`;
|
|
35745
|
+
const create = hasCommandWord(args, CLASSROOM_CREATE_WORDS);
|
|
35746
|
+
const update = hasCommandWord(args, CLASSROOM_UPDATE_WORDS);
|
|
35747
|
+
const remove = hasCommandWord(args, CLASSROOM_DELETE_WORDS);
|
|
35748
|
+
const widenedAssignees = () => {
|
|
35749
|
+
const word = hasCommandWord(args, CLASSROOM_ASSIGNEE_WORDS);
|
|
35750
|
+
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;
|
|
35751
|
+
};
|
|
35752
|
+
switch (group) {
|
|
35753
|
+
case "courses":
|
|
35754
|
+
return remove ? gatedElsewhere(what(remove), via, "deletes a course", "gog_classroom_courses_delete") : void 0;
|
|
35755
|
+
case "announcements":
|
|
35756
|
+
if (create) return gatedElsewhere(what(create), via, "posts to a class", "gog_classroom_announcements_create");
|
|
35757
|
+
if (update && publishesToStudents(args)) return gatedElsewhere(what(update), via, "publishes an announcement to a class", "gog_classroom_announcements_update");
|
|
35758
|
+
return widenedAssignees();
|
|
35759
|
+
case "invitations":
|
|
35760
|
+
return create ? gatedElsewhere(what(create), via, "invites someone to a class", "gog_classroom_invitations_create") : void 0;
|
|
35761
|
+
case "coursework":
|
|
35762
|
+
if (create && createsVisibleWork(args)) return gatedElsewhere(what(create), via, "posts coursework to a class", "gog_classroom_coursework_create");
|
|
35763
|
+
if (remove) return gatedElsewhere(what(remove), via, "deletes coursework and every submission to it", "gog_classroom_coursework_delete");
|
|
35764
|
+
if (update && publishesToStudents(args)) return gatedElsewhere(what(update), via, "publishes work to students", "gog_classroom_coursework_update");
|
|
35765
|
+
return widenedAssignees();
|
|
35766
|
+
case "materials":
|
|
35767
|
+
if (create && createsVisibleWork(args)) {
|
|
35768
|
+
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.");
|
|
35769
|
+
}
|
|
35770
|
+
if (update && publishesToStudents(args)) return refusedInRun(what(update), via, "publishes material to students", "Ask the user to publish it from Classroom.");
|
|
35771
|
+
return void 0;
|
|
35772
|
+
case "students":
|
|
35773
|
+
return create ? gatedElsewhere(what(create), via, "enrols someone in a class", "gog_classroom_students_add") : void 0;
|
|
35774
|
+
case "teachers":
|
|
35775
|
+
return create ? gatedElsewhere(what(create), via, "gives someone a teacher's access to a class and its roster", "gog_classroom_teachers_add") : void 0;
|
|
35776
|
+
case "submissions": {
|
|
35777
|
+
const word = hasCommandWord(args, CLASSROOM_RETURN_WORDS);
|
|
35778
|
+
return word ? gatedElsewhere(what(word), via, "returns work to a student, who is notified", "gog_classroom_submissions_return") : void 0;
|
|
35779
|
+
}
|
|
35780
|
+
case "guardian-invitations":
|
|
35781
|
+
return create ? refusedInRun(what(create), via, "emails a guardian invitation", "Ask the user to invite the guardian from Classroom.") : void 0;
|
|
35782
|
+
}
|
|
35500
35783
|
}
|
|
35501
35784
|
async function readCourse(courseId, account, runner = runOrDiagnose) {
|
|
35502
35785
|
const got = await runner(["classroom", "courses", "get", pos(courseId)], { account });
|
|
@@ -35515,6 +35798,63 @@ async function readCourse(courseId, account, runner = runOrDiagnose) {
|
|
|
35515
35798
|
}
|
|
35516
35799
|
};
|
|
35517
35800
|
}
|
|
35801
|
+
function nested(raw, key) {
|
|
35802
|
+
try {
|
|
35803
|
+
const parsed = JSON.parse(raw);
|
|
35804
|
+
const inner = parsed?.[key];
|
|
35805
|
+
return inner && typeof inner === "object" ? inner : void 0;
|
|
35806
|
+
} catch {
|
|
35807
|
+
return void 0;
|
|
35808
|
+
}
|
|
35809
|
+
}
|
|
35810
|
+
var str = (v) => typeof v === "string" ? v : void 0;
|
|
35811
|
+
var num = (v) => typeof v === "number" ? v : void 0;
|
|
35812
|
+
async function readCoursework(courseId, courseworkId, account, runner = runOrDiagnose) {
|
|
35813
|
+
const got = await runner(["classroom", "coursework", "get", pos(courseId), pos(courseworkId)], { account });
|
|
35814
|
+
if (got.isError) return { error: got };
|
|
35815
|
+
const work = nested(resultText(got), "coursework");
|
|
35816
|
+
const title = str(work?.title);
|
|
35817
|
+
return { coursework: { id: courseworkId, ...title !== void 0 ? { title } : {} } };
|
|
35818
|
+
}
|
|
35819
|
+
async function readClassroomWork(kind, courseId, itemId, account, runner = runOrDiagnose) {
|
|
35820
|
+
const got = await runner(["classroom", kind, "get", pos(courseId), pos(itemId)], { account });
|
|
35821
|
+
if (got.isError) return { error: got };
|
|
35822
|
+
const item = nested(resultText(got), kind === "announcements" ? "announcement" : "coursework");
|
|
35823
|
+
const work = { id: itemId };
|
|
35824
|
+
for (const key of ["text", "title", "description", "state", "updateTime"]) {
|
|
35825
|
+
const value = str(item?.[key]);
|
|
35826
|
+
if (value !== void 0) work[key] = value;
|
|
35827
|
+
}
|
|
35828
|
+
return { work };
|
|
35829
|
+
}
|
|
35830
|
+
async function readSubmission(courseId, courseworkId, submissionId, account, runner = runOrDiagnose) {
|
|
35831
|
+
const got = await runner(["classroom", "submissions", "get", pos(courseId), pos(courseworkId), pos(submissionId)], { account });
|
|
35832
|
+
if (got.isError) return { error: got };
|
|
35833
|
+
const sub = nested(resultText(got), "submission");
|
|
35834
|
+
const fields = {
|
|
35835
|
+
student: str(sub?.userId),
|
|
35836
|
+
state: str(sub?.state),
|
|
35837
|
+
draftGrade: num(sub?.draftGrade),
|
|
35838
|
+
assignedGrade: num(sub?.assignedGrade)
|
|
35839
|
+
};
|
|
35840
|
+
const updateTime = str(sub?.updateTime);
|
|
35841
|
+
return {
|
|
35842
|
+
submission: {
|
|
35843
|
+
id: submissionId,
|
|
35844
|
+
...Object.fromEntries(Object.entries(fields).filter(([, v]) => v !== void 0))
|
|
35845
|
+
},
|
|
35846
|
+
...updateTime !== void 0 ? { updateTime } : {}
|
|
35847
|
+
};
|
|
35848
|
+
}
|
|
35849
|
+
async function studentLabel(courseId, userId, account, runner = runOrDiagnose) {
|
|
35850
|
+
const got = await runner(["classroom", "students", "get", pos(courseId), pos(userId)], { account });
|
|
35851
|
+
if (got.isError) return userId;
|
|
35852
|
+
const profile = nested(resultText(got), "student")?.profile;
|
|
35853
|
+
const name = str(profile?.name?.fullName);
|
|
35854
|
+
const email3 = str(profile?.emailAddress);
|
|
35855
|
+
if (name && email3) return `${name} <${email3}>`;
|
|
35856
|
+
return name ?? email3 ?? userId;
|
|
35857
|
+
}
|
|
35518
35858
|
function registerClassroomTools(server) {
|
|
35519
35859
|
server.registerTool("gog_classroom_courses_list", {
|
|
35520
35860
|
description: "List Google Classroom courses.",
|
|
@@ -35727,15 +36067,38 @@ function registerClassroomTools(server) {
|
|
|
35727
36067
|
return runOrDiagnose(args, { account });
|
|
35728
36068
|
});
|
|
35729
36069
|
server.registerTool("gog_classroom_submissions_return", {
|
|
35730
|
-
description: "Return a graded submission to the student.",
|
|
36070
|
+
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,
|
|
35731
36071
|
annotations: { destructiveHint: true },
|
|
35732
36072
|
inputSchema: external_exports.object({
|
|
35733
36073
|
courseId: external_exports.string().describe("Course ID"),
|
|
35734
36074
|
courseworkId: external_exports.string().describe("Coursework ID"),
|
|
35735
36075
|
submissionId: external_exports.string().describe("Submission ID"),
|
|
35736
|
-
account: accountParam
|
|
36076
|
+
account: accountParam,
|
|
36077
|
+
confirmToken: confirmTokenParam
|
|
35737
36078
|
})
|
|
35738
|
-
}, async ({ courseId, courseworkId, submissionId, account }) => {
|
|
36079
|
+
}, async ({ courseId, courseworkId, submissionId, account, confirmToken }, ctx) => {
|
|
36080
|
+
const course = await readCourse(courseId, account);
|
|
36081
|
+
if (course.error) return course.error;
|
|
36082
|
+
const work = await readCoursework(courseId, courseworkId, account);
|
|
36083
|
+
if (work.error) return work.error;
|
|
36084
|
+
const sub = await readSubmission(courseId, courseworkId, submissionId, account);
|
|
36085
|
+
if (sub.error) return sub.error;
|
|
36086
|
+
const submission = sub.submission.student ? { ...sub.submission, student: await studentLabel(courseId, sub.submission.student, account) } : sub.submission;
|
|
36087
|
+
const view = { course: course.course, coursework: work.coursework, submission };
|
|
36088
|
+
const confirmation = await requireDispatchConfirmation(ctx, {
|
|
36089
|
+
action: "classroom.submission-return",
|
|
36090
|
+
message: "Review and confirm returning this work \u2014 the student is notified and sees the grade:",
|
|
36091
|
+
confirmationLabel: "Confirm that this submission should be returned to the student now.",
|
|
36092
|
+
details: view,
|
|
36093
|
+
unsupportedNote: "Ask the user to return it from Classroom.",
|
|
36094
|
+
fallback: {
|
|
36095
|
+
tool: "gog_classroom_submissions_return",
|
|
36096
|
+
account,
|
|
36097
|
+
confirmToken,
|
|
36098
|
+
subject: () => ({ target: `${courseId}/${courseworkId}/${submissionId}`, revision: sub.updateTime, payload: view, preview: view })
|
|
36099
|
+
}
|
|
36100
|
+
});
|
|
36101
|
+
if (confirmation) return confirmation;
|
|
35739
36102
|
return runOrDiagnose(["classroom", "submissions", "return", pos(courseId), pos(courseworkId), pos(submissionId)], { account });
|
|
35740
36103
|
});
|
|
35741
36104
|
server.registerTool("gog_classroom_submissions_turn_in", {
|
|
@@ -35797,13 +36160,13 @@ function registerClassroomTools(server) {
|
|
|
35797
36160
|
return runOrDiagnose(["classroom", "announcements", "get", pos(courseId), pos(announcementId)], { account });
|
|
35798
36161
|
});
|
|
35799
36162
|
server.registerTool("gog_classroom_announcements_create", {
|
|
35800
|
-
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,
|
|
36163
|
+
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,
|
|
35801
36164
|
annotations: { destructiveHint: true },
|
|
35802
36165
|
inputSchema: external_exports.object({
|
|
35803
36166
|
courseId: external_exports.string().describe("Course ID"),
|
|
35804
36167
|
text: external_exports.string().describe("Announcement text"),
|
|
35805
|
-
state: external_exports.enum(["PUBLISHED", "DRAFT"]).optional().describe("State (DRAFT is visible only to teachers and needs no confirmation)"),
|
|
35806
|
-
scheduled: external_exports.string().optional().describe("Scheduled publish time"),
|
|
36168
|
+
state: external_exports.enum(["PUBLISHED", "DRAFT"]).optional().describe("State (an unscheduled DRAFT is visible only to teachers and needs no confirmation)"),
|
|
36169
|
+
scheduled: external_exports.string().optional().describe("Scheduled publish time (asks the user to confirm, even for a DRAFT)"),
|
|
35807
36170
|
account: accountParam,
|
|
35808
36171
|
confirmToken: confirmTokenParam
|
|
35809
36172
|
})
|
|
@@ -35811,7 +36174,7 @@ function registerClassroomTools(server) {
|
|
|
35811
36174
|
const args = ["classroom", "announcements", "create", pos(courseId), `--text=${text}`];
|
|
35812
36175
|
if (state) args.push(`--state=${state}`);
|
|
35813
36176
|
if (scheduled) args.push(`--scheduled=${scheduled}`);
|
|
35814
|
-
if (state !== "DRAFT") {
|
|
36177
|
+
if (state !== "DRAFT" || scheduled) {
|
|
35815
36178
|
const read = await readCourse(courseId, account);
|
|
35816
36179
|
if (read.error) return read.error;
|
|
35817
36180
|
const publishes = scheduled ? `at ${scheduled}` : "immediately";
|
|
@@ -35983,6 +36346,9 @@ function registerContactsTools(server) {
|
|
|
35983
36346
|
}
|
|
35984
36347
|
|
|
35985
36348
|
// src/tools/docs.ts
|
|
36349
|
+
function vetDocsRun(subcommand, args) {
|
|
36350
|
+
return vetCommentsRun("docs", subcommand, args);
|
|
36351
|
+
}
|
|
35986
36352
|
function registerDocsTools(server) {
|
|
35987
36353
|
server.registerTool("gog_docs_info", {
|
|
35988
36354
|
description: "Get Google Doc metadata: title, ID, and other properties.",
|
|
@@ -36079,12 +36445,29 @@ function registerDocsTools(server) {
|
|
|
36079
36445
|
}, async ({ docId, account }) => {
|
|
36080
36446
|
return runOrDiagnose(["docs", "structure", pos(docId)], { account });
|
|
36081
36447
|
});
|
|
36082
|
-
registerRunTool(server, { service: "docs", examples: '"copy", "clear", "insert", "sed", "export"' });
|
|
36448
|
+
registerRunTool(server, { service: "docs", examples: '"copy", "clear", "insert", "sed", "export"', vet: vetDocsRun });
|
|
36083
36449
|
}
|
|
36084
36450
|
|
|
36085
36451
|
// src/tools/drive.ts
|
|
36086
|
-
|
|
36087
|
-
|
|
36452
|
+
var DRIVE_DELETE_WORDS = /* @__PURE__ */ new Set(["delete", "rm", "del"]);
|
|
36453
|
+
function vetDriveRun(subcommand, args) {
|
|
36454
|
+
const sub = subcommand.toLowerCase();
|
|
36455
|
+
if (sub === "share") return gatedElsewhere("gog drive share", "gog_drive_run", "grants access to a file", "gog_drive_share");
|
|
36456
|
+
if (DRIVE_DELETE_WORDS.has(sub) && hasTrueFlag(args, "permanent")) {
|
|
36457
|
+
return gatedElsewhere(`gog drive ${sub} --permanent`, "gog_drive_run", "deletes a file for good, bypassing the trash", "gog_drive_delete");
|
|
36458
|
+
}
|
|
36459
|
+
if (sub === "bulk") {
|
|
36460
|
+
return gatedElsewhere(
|
|
36461
|
+
"gog drive bulk",
|
|
36462
|
+
"gog_drive_run",
|
|
36463
|
+
"rewrites sharing permissions across every matching file in a tree",
|
|
36464
|
+
"gog_drive_share (one file at a time)"
|
|
36465
|
+
);
|
|
36466
|
+
}
|
|
36467
|
+
if (sub === "unshare") {
|
|
36468
|
+
return refusedInRun("gog drive unshare", "gog_drive_run", "removes someone's access to a file", "Use gog_drive_unshare.");
|
|
36469
|
+
}
|
|
36470
|
+
return vetCommentsRun("drive", sub, args);
|
|
36088
36471
|
}
|
|
36089
36472
|
var GOOGLE_DOC_MIME = "application/vnd.google-apps.document";
|
|
36090
36473
|
function shareTargetMeta(raw) {
|
|
@@ -36095,6 +36478,26 @@ function shareTargetMeta(raw) {
|
|
|
36095
36478
|
return {};
|
|
36096
36479
|
}
|
|
36097
36480
|
}
|
|
36481
|
+
function commentSnapshot(raw) {
|
|
36482
|
+
let comment;
|
|
36483
|
+
try {
|
|
36484
|
+
const parsed = JSON.parse(raw);
|
|
36485
|
+
comment = parsed?.comment ?? parsed ?? void 0;
|
|
36486
|
+
} catch {
|
|
36487
|
+
comment = void 0;
|
|
36488
|
+
}
|
|
36489
|
+
const name = typeof comment?.author?.displayName === "string" ? comment.author.displayName : void 0;
|
|
36490
|
+
const email3 = typeof comment?.author?.emailAddress === "string" ? comment.author.emailAddress : void 0;
|
|
36491
|
+
const author = name && email3 ? `${name} <${email3}>` : name ?? email3;
|
|
36492
|
+
return {
|
|
36493
|
+
...author ? { author } : {},
|
|
36494
|
+
...typeof comment?.content === "string" ? { content: comment.content } : {},
|
|
36495
|
+
...typeof comment?.resolved === "boolean" ? { resolved: comment.resolved } : {}
|
|
36496
|
+
};
|
|
36497
|
+
}
|
|
36498
|
+
function commentMentions(text) {
|
|
36499
|
+
return [...new Set(text.match(/(?<=[+@])[\w.+-]+@[\w-]+(?:\.[\w-]+)+/g) ?? [])];
|
|
36500
|
+
}
|
|
36098
36501
|
function fileMeta(raw) {
|
|
36099
36502
|
const parsed = JSON.parse(raw);
|
|
36100
36503
|
const f = parsed.file ?? parsed;
|
|
@@ -36203,16 +36606,36 @@ function registerDriveTools(server) {
|
|
|
36203
36606
|
return runOrDiagnose(["drive", "move", pos(fileId), `--parent=${parentId}`], { account });
|
|
36204
36607
|
});
|
|
36205
36608
|
server.registerTool("gog_drive_delete", {
|
|
36206
|
-
description: "Move a Google Drive file to trash, or permanently delete it with permanent=true (irreversible).",
|
|
36609
|
+
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,
|
|
36207
36610
|
annotations: { destructiveHint: true },
|
|
36208
36611
|
inputSchema: external_exports.object({
|
|
36209
36612
|
fileId: external_exports.string().describe("File ID to delete"),
|
|
36210
|
-
permanent: external_exports.boolean().optional().describe("Permanently delete instead of moving to trash (irreversible)"),
|
|
36211
|
-
account: accountParam
|
|
36613
|
+
permanent: external_exports.boolean().optional().describe("Permanently delete instead of moving to trash (irreversible; asks the user first)"),
|
|
36614
|
+
account: accountParam,
|
|
36615
|
+
confirmToken: confirmTokenParam
|
|
36212
36616
|
})
|
|
36213
|
-
}, async ({ fileId, permanent, account }) => {
|
|
36617
|
+
}, async ({ fileId, permanent, account, confirmToken }, ctx) => {
|
|
36214
36618
|
const args = ["drive", "delete", pos(fileId)];
|
|
36215
|
-
if (permanent)
|
|
36619
|
+
if (permanent) {
|
|
36620
|
+
const got = await runOrDiagnose(["drive", "get", pos(fileId)], { account });
|
|
36621
|
+
if (got.isError) return got;
|
|
36622
|
+
const target = { file: { id: fileId, ...shareTargetMeta(resultText(got)) }, permanent: true };
|
|
36623
|
+
const confirmation = await requireDispatchConfirmation(ctx, {
|
|
36624
|
+
action: "drive.delete-permanent",
|
|
36625
|
+
message: "Review and confirm PERMANENTLY deleting this file \u2014 it skips the trash and cannot be recovered:",
|
|
36626
|
+
confirmationLabel: "Confirm that this file should be permanently deleted now.",
|
|
36627
|
+
details: target,
|
|
36628
|
+
unsupportedNote: "Move it to the trash instead (permanent=false); the user can empty the trash from Google Drive.",
|
|
36629
|
+
fallback: {
|
|
36630
|
+
tool: "gog_drive_delete",
|
|
36631
|
+
account,
|
|
36632
|
+
confirmToken,
|
|
36633
|
+
subject: () => ({ target: fileId, payload: target, preview: target })
|
|
36634
|
+
}
|
|
36635
|
+
});
|
|
36636
|
+
if (confirmation) return confirmation;
|
|
36637
|
+
args.push("--permanent");
|
|
36638
|
+
}
|
|
36216
36639
|
args.push("--force");
|
|
36217
36640
|
return runOrDiagnose(args, { account });
|
|
36218
36641
|
});
|
|
@@ -36538,18 +36961,22 @@ function trustedDomains(account) {
|
|
|
36538
36961
|
}
|
|
36539
36962
|
function logGmailDispatch(tool, recipients, account) {
|
|
36540
36963
|
const domains = trustedDomains(account);
|
|
36541
|
-
const
|
|
36964
|
+
const externalDomains = /* @__PURE__ */ new Set();
|
|
36965
|
+
let externalRecipientCount = 0;
|
|
36966
|
+
for (const recipient of recipients) {
|
|
36542
36967
|
const at = recipient.indexOf("@");
|
|
36543
|
-
const domain2 = at > -1 ? recipient.slice(at + 1) : "";
|
|
36544
|
-
|
|
36545
|
-
|
|
36968
|
+
const domain2 = at > -1 ? recipient.slice(at + 1).toLowerCase() : "";
|
|
36969
|
+
if (domain2 && domains.has(domain2)) continue;
|
|
36970
|
+
externalRecipientCount += 1;
|
|
36971
|
+
externalDomains.add(domain2 || "(no domain)");
|
|
36972
|
+
}
|
|
36546
36973
|
const event = {
|
|
36547
36974
|
event: "gmail_dispatch",
|
|
36548
36975
|
tool,
|
|
36549
36976
|
recipientCount: recipients.length,
|
|
36550
|
-
externalRecipientCount
|
|
36551
|
-
hasExternalRecipients:
|
|
36552
|
-
|
|
36977
|
+
externalRecipientCount,
|
|
36978
|
+
hasExternalRecipients: externalRecipientCount > 0,
|
|
36979
|
+
externalDomains: [...externalDomains].sort(),
|
|
36553
36980
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
36554
36981
|
};
|
|
36555
36982
|
process.stderr.write(`${JSON.stringify(event)}
|
|
@@ -36716,6 +37143,39 @@ async function sendReply(kind, toolName, messageId, account, flags, ctx, confirm
|
|
|
36716
37143
|
return result;
|
|
36717
37144
|
}
|
|
36718
37145
|
var GMAIL_RUN_BLOCKED_SETTINGS = /* @__PURE__ */ new Set(["forwarding", "autoforward", "filters", "delegates"]);
|
|
37146
|
+
var GMAIL_DELETE_WORDS = /* @__PURE__ */ new Set(["delete", "rm", "del", "remove"]);
|
|
37147
|
+
var GMAIL_CREATE_WORDS = /* @__PURE__ */ new Set(["create", "add", "new"]);
|
|
37148
|
+
var GMAIL_UPDATE_WORDS = /* @__PURE__ */ new Set(["update", "edit", "set"]);
|
|
37149
|
+
var SENDAS = /* @__PURE__ */ new Set(["sendas"]);
|
|
37150
|
+
var VACATION = /* @__PURE__ */ new Set(["vacation"]);
|
|
37151
|
+
function vetGmailGatedRun(sub, args) {
|
|
37152
|
+
if (sub === "batch") {
|
|
37153
|
+
const word = hasCommandWord(args, GMAIL_DELETE_WORDS);
|
|
37154
|
+
return word ? gatedElsewhere(`gog gmail batch ${word.toLowerCase()}`, "gog_gmail_run", "deletes mail for good, bypassing the Trash", "gog_gmail_batch_delete") : void 0;
|
|
37155
|
+
}
|
|
37156
|
+
if (sub !== "settings" && sub !== "sendas" && sub !== "vacation") return void 0;
|
|
37157
|
+
const words = sub === "settings" ? args : [sub, ...args];
|
|
37158
|
+
if (hasCommandWord(words, SENDAS)) {
|
|
37159
|
+
const word = hasCommandWord(args, GMAIL_CREATE_WORDS);
|
|
37160
|
+
if (word) {
|
|
37161
|
+
return gatedElsewhere(
|
|
37162
|
+
`gog gmail sendas ${word.toLowerCase()}`,
|
|
37163
|
+
"gog_gmail_run",
|
|
37164
|
+
"makes Google email the address and adds a sending identity",
|
|
37165
|
+
"gog_gmail_sendas_create"
|
|
37166
|
+
);
|
|
37167
|
+
}
|
|
37168
|
+
}
|
|
37169
|
+
if (hasCommandWord(words, VACATION) && hasCommandWord(args, GMAIL_UPDATE_WORDS) && hasTrueFlag(args, "enable")) {
|
|
37170
|
+
return gatedElsewhere(
|
|
37171
|
+
"gog gmail vacation update --enable",
|
|
37172
|
+
"gog_gmail_run",
|
|
37173
|
+
"turns on an auto-reply to every sender",
|
|
37174
|
+
"gog_gmail_vacation_update"
|
|
37175
|
+
);
|
|
37176
|
+
}
|
|
37177
|
+
return void 0;
|
|
37178
|
+
}
|
|
36719
37179
|
function vetGmailRun(subcommand, args) {
|
|
36720
37180
|
if (subcommand === "autoreply") {
|
|
36721
37181
|
return "gog gmail autoreply sends mail and is not available through gog_gmail_run. Use gog_gmail_autoreply, which asks the user to confirm.";
|
|
@@ -36723,6 +37183,8 @@ function vetGmailRun(subcommand, args) {
|
|
|
36723
37183
|
if (GMAIL_RUN_BLOCKED_SETTINGS.has(subcommand)) {
|
|
36724
37184
|
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.`;
|
|
36725
37185
|
}
|
|
37186
|
+
const gated = vetGmailGatedRun(subcommand.toLowerCase(), args);
|
|
37187
|
+
if (gated) return gated;
|
|
36726
37188
|
if (subcommand === "settings") {
|
|
36727
37189
|
const blocked = hasCommandWord(args, GMAIL_RUN_BLOCKED_SETTINGS);
|
|
36728
37190
|
if (blocked) {
|
|
@@ -36934,6 +37396,13 @@ function countNonEmptyCells(getOutput) {
|
|
|
36934
37396
|
}
|
|
36935
37397
|
|
|
36936
37398
|
// src/tools/sheets.ts
|
|
37399
|
+
var DATASOURCE_ALIASES = /* @__PURE__ */ new Set(["datasource", "data-source", "data-sources", "connected-sheets"]);
|
|
37400
|
+
var DATASOURCE_BILLED = /* @__PURE__ */ new Set(["add", "update", "refresh"]);
|
|
37401
|
+
function vetSheetsRun(subcommand, args) {
|
|
37402
|
+
if (!DATASOURCE_ALIASES.has(subcommand.toLowerCase())) return void 0;
|
|
37403
|
+
const word = hasCommandWord(args, DATASOURCE_BILLED)?.toLowerCase();
|
|
37404
|
+
return word ? gatedElsewhere(`gog sheets datasource ${word}`, "gog_sheets_run", "runs a billed BigQuery job", `gog_sheets_datasource_${word}`) : void 0;
|
|
37405
|
+
}
|
|
36937
37406
|
var cellValueParam = external_exports.union([external_exports.string(), external_exports.number(), external_exports.boolean(), external_exports.null()]);
|
|
36938
37407
|
var dryRunParam = external_exports.boolean().optional().describe(
|
|
36939
37408
|
"Preview the operation without modifying the sheet (gog --dry-run): reports the intended actions and exits without writing."
|
|
@@ -37049,7 +37518,7 @@ function registerSheetsTools(server) {
|
|
|
37049
37518
|
}, async ({ spreadsheetId, find, replace, account }) => {
|
|
37050
37519
|
return runOrDiagnose(["sheets", "find-replace", pos(spreadsheetId), pos(find), pos(replace)], { account });
|
|
37051
37520
|
});
|
|
37052
|
-
registerRunTool(server, { service: "sheets", examples: '"freeze", "add-tab", "rename-tab"' });
|
|
37521
|
+
registerRunTool(server, { service: "sheets", examples: '"freeze", "add-tab", "rename-tab"', vet: vetSheetsRun });
|
|
37053
37522
|
}
|
|
37054
37523
|
|
|
37055
37524
|
// src/tools/slides.ts
|
|
@@ -37213,7 +37682,7 @@ function registerTasksTools(server) {
|
|
|
37213
37682
|
}
|
|
37214
37683
|
|
|
37215
37684
|
// src/server.ts
|
|
37216
|
-
var VERSION = true ? "4.5.
|
|
37685
|
+
var VERSION = true ? "4.5.2" : "0.0.0";
|
|
37217
37686
|
var BASE_TOOL_REGISTRARS = [
|
|
37218
37687
|
registerApiTools,
|
|
37219
37688
|
registerAppScriptTools,
|
|
@@ -37515,6 +37984,8 @@ export {
|
|
|
37515
37984
|
blobStoreFromEnv,
|
|
37516
37985
|
bodyPreview,
|
|
37517
37986
|
bootstrapGogAuth,
|
|
37987
|
+
commentMentions,
|
|
37988
|
+
commentSnapshot,
|
|
37518
37989
|
confineAtFile,
|
|
37519
37990
|
confinePath,
|
|
37520
37991
|
confinePaths,
|
|
@@ -37523,6 +37994,7 @@ export {
|
|
|
37523
37994
|
defaultFileRoot,
|
|
37524
37995
|
diagnose,
|
|
37525
37996
|
errorText,
|
|
37997
|
+
eventSnapshot,
|
|
37526
37998
|
extractEmails,
|
|
37527
37999
|
fetchGmailPages,
|
|
37528
38000
|
fileRoots,
|
|
@@ -37537,11 +38009,14 @@ export {
|
|
|
37537
38009
|
pageAliasParam,
|
|
37538
38010
|
pageTokenParam,
|
|
37539
38011
|
paginationParams,
|
|
38012
|
+
parseMetadataHeaders,
|
|
37540
38013
|
payloadArg,
|
|
37541
38014
|
pos,
|
|
37542
38015
|
prepareDownloadRoot,
|
|
37543
38016
|
pushPaginationFlags,
|
|
38017
|
+
readClassroomWork,
|
|
37544
38018
|
readCourse,
|
|
38019
|
+
readCoursework,
|
|
37545
38020
|
registerApiTools,
|
|
37546
38021
|
registerAppScriptTools,
|
|
37547
38022
|
registerAuthTools,
|
|
@@ -37566,12 +38041,14 @@ export {
|
|
|
37566
38041
|
runBinary,
|
|
37567
38042
|
runOrDiagnose,
|
|
37568
38043
|
senderPreview,
|
|
38044
|
+
shareTargetMeta,
|
|
37569
38045
|
stripConsumedPageToken,
|
|
38046
|
+
studentLabel,
|
|
37570
38047
|
uploadToBlobStore
|
|
37571
38048
|
};
|
|
37572
38049
|
/*! Bundled license information:
|
|
37573
38050
|
|
|
37574
|
-
@modelcontextprotocol/server/dist/src-
|
|
38051
|
+
@modelcontextprotocol/server/dist/src-D-y6h4N7.mjs:
|
|
37575
38052
|
(*!
|
|
37576
38053
|
* content-type
|
|
37577
38054
|
* Copyright(c) 2015 Douglas Christopher Wilson
|