ofw-mcp 2.20.1 → 2.20.3
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/README.md +2 -1
- package/dist/bundle.js +518 -143
- package/dist/client.js +86 -69
- package/dist/index.js +1 -1
- package/dist/tools/calendar.js +40 -7
- package/mint.yaml +7 -0
- package/package.json +5 -5
- package/server.json +2 -2
package/dist/bundle.js
CHANGED
|
@@ -2335,11 +2335,23 @@ var require_websocket = __commonJS({
|
|
|
2335
2335
|
this._isServer = false;
|
|
2336
2336
|
this._redirects = 0;
|
|
2337
2337
|
if (protocols === void 0) {
|
|
2338
|
-
protocols
|
|
2338
|
+
if (!options || options.protocols === void 0) {
|
|
2339
|
+
protocols = [];
|
|
2340
|
+
} else if (Array.isArray(options.protocols)) {
|
|
2341
|
+
protocols = options.protocols;
|
|
2342
|
+
} else {
|
|
2343
|
+
protocols = [options.protocols];
|
|
2344
|
+
}
|
|
2339
2345
|
} else if (!Array.isArray(protocols)) {
|
|
2340
2346
|
if (typeof protocols === "object" && protocols !== null) {
|
|
2341
2347
|
options = protocols;
|
|
2342
|
-
protocols
|
|
2348
|
+
if (options.protocols === void 0) {
|
|
2349
|
+
protocols = [];
|
|
2350
|
+
} else if (Array.isArray(options.protocols)) {
|
|
2351
|
+
protocols = options.protocols;
|
|
2352
|
+
} else {
|
|
2353
|
+
protocols = [options.protocols];
|
|
2354
|
+
}
|
|
2343
2355
|
} else {
|
|
2344
2356
|
protocols = [protocols];
|
|
2345
2357
|
}
|
|
@@ -2536,7 +2548,6 @@ var require_websocket = __commonJS({
|
|
|
2536
2548
|
}
|
|
2537
2549
|
return;
|
|
2538
2550
|
}
|
|
2539
|
-
this._readyState = _WebSocket.CLOSING;
|
|
2540
2551
|
this._sender.close(code2, data, !this._isServer, (err) => {
|
|
2541
2552
|
if (err) return;
|
|
2542
2553
|
this._closeFrameSent = true;
|
|
@@ -2544,6 +2555,7 @@ var require_websocket = __commonJS({
|
|
|
2544
2555
|
this._socket.end();
|
|
2545
2556
|
}
|
|
2546
2557
|
});
|
|
2558
|
+
this._readyState = _WebSocket.CLOSING;
|
|
2547
2559
|
setCloseTimer(this);
|
|
2548
2560
|
}
|
|
2549
2561
|
/**
|
|
@@ -2768,6 +2780,7 @@ var require_websocket = __commonJS({
|
|
|
2768
2780
|
socketPath: void 0,
|
|
2769
2781
|
hostname: void 0,
|
|
2770
2782
|
protocol: void 0,
|
|
2783
|
+
protocols: void 0,
|
|
2771
2784
|
timeout: void 0,
|
|
2772
2785
|
method: "GET",
|
|
2773
2786
|
host: void 0,
|
|
@@ -21552,8 +21565,8 @@ function currencyCode2(_params) {
|
|
|
21552
21565
|
return _stringFormat(ZodCustomStringFormat, "currency_code", currencyCode, _params);
|
|
21553
21566
|
}
|
|
21554
21567
|
function hash(alg, params) {
|
|
21555
|
-
const
|
|
21556
|
-
const format = `${alg}_${
|
|
21568
|
+
const enc7 = params?.enc ?? "hex";
|
|
21569
|
+
const format = `${alg}_${enc7}`;
|
|
21557
21570
|
const regex = regexes_exports[format];
|
|
21558
21571
|
if (!regex)
|
|
21559
21572
|
throw new Error(`Unrecognized hash format: ${format}`);
|
|
@@ -24428,7 +24441,7 @@ var OAuthTokenRevocationRequestSchema = object({
|
|
|
24428
24441
|
token_type_hint: string2().optional()
|
|
24429
24442
|
}).strip();
|
|
24430
24443
|
|
|
24431
|
-
// node_modules/@modelcontextprotocol/server/dist/src-
|
|
24444
|
+
// node_modules/@modelcontextprotocol/server/dist/src-Cqbh3MYc.mjs
|
|
24432
24445
|
var BRANDS = /* @__PURE__ */ Symbol.for("mcp.sdk.errorBrands");
|
|
24433
24446
|
function stampErrorBrands(instance, ctor) {
|
|
24434
24447
|
const brands = /* @__PURE__ */ new Set();
|
|
@@ -26671,7 +26684,8 @@ function build() {
|
|
|
26671
26684
|
ListResourceTemplatesResultResponseSchema: wireResultResponse(ListResourceTemplatesResultSchema$1),
|
|
26672
26685
|
ReadResourceResultResponseSchema: wireResultResponse(union([ReadResourceResultSchema$1, InputRequiredResultSchema])),
|
|
26673
26686
|
CompleteResultResponseSchema: wireResultResponse(CompleteResultSchema$1),
|
|
26674
|
-
DiscoverResultResponseSchema: wireResultResponse(DiscoverResultSchema$1)
|
|
26687
|
+
DiscoverResultResponseSchema: wireResultResponse(DiscoverResultSchema$1),
|
|
26688
|
+
SubscriptionsListenResultResponseSchema: wireResultResponse(SubscriptionsListenResultSchema$1)
|
|
26675
26689
|
};
|
|
26676
26690
|
}
|
|
26677
26691
|
var memo2;
|
|
@@ -27179,6 +27193,9 @@ function isSpecRequestMethod(method) {
|
|
|
27179
27193
|
function isSpecNotificationMethod(method) {
|
|
27180
27194
|
return ALL_CODECS.some((codec2) => codec2.hasNotificationMethod(method));
|
|
27181
27195
|
}
|
|
27196
|
+
function isExtensionReusedRequestMethod(method) {
|
|
27197
|
+
return method === "tasks/get" || method === "tasks/cancel";
|
|
27198
|
+
}
|
|
27182
27199
|
var ALL_CODECS = [rev2025Codec, rev2026Codec];
|
|
27183
27200
|
function isPlainObject$3(value) {
|
|
27184
27201
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -28187,6 +28204,8 @@ var Protocol = class {
|
|
|
28187
28204
|
_transport;
|
|
28188
28205
|
_requestMessageId = 0;
|
|
28189
28206
|
_requestHandlers = /* @__PURE__ */ new Map();
|
|
28207
|
+
/** Methods registered with an explicit schema; the era gate in `_onrequest` reads it for the Tasks extension names. */
|
|
28208
|
+
_customSchemaRequestMethods = /* @__PURE__ */ new Set();
|
|
28190
28209
|
_requestHandlerAbortControllers = /* @__PURE__ */ new Map();
|
|
28191
28210
|
_notificationHandlers = /* @__PURE__ */ new Map();
|
|
28192
28211
|
_responseHandlers = /* @__PURE__ */ new Map();
|
|
@@ -28470,7 +28489,7 @@ var Protocol = class {
|
|
|
28470
28489
|
return;
|
|
28471
28490
|
}
|
|
28472
28491
|
}
|
|
28473
|
-
if (isSpecRequestMethod(request.method) && !codec2.hasRequestMethod(request.method)) {
|
|
28492
|
+
if (isSpecRequestMethod(request.method) && !codec2.hasRequestMethod(request.method) && !(isExtensionReusedRequestMethod(request.method) && this._customSchemaRequestMethods.has(request.method))) {
|
|
28474
28493
|
sendErrorResponse(ProtocolErrorCode.MethodNotFound, "Method not found");
|
|
28475
28494
|
return;
|
|
28476
28495
|
}
|
|
@@ -28603,8 +28622,11 @@ var Protocol = class {
|
|
|
28603
28622
|
}
|
|
28604
28623
|
request(request, schemaOrOptions, maybeOptions) {
|
|
28605
28624
|
const codec2 = this._resolveOutboundCodec(request.method);
|
|
28625
|
+
if (isStandardSchema(schemaOrOptions)) {
|
|
28626
|
+
if (!isExtensionReusedRequestMethod(request.method)) this._assertOutboundRequestInEra(codec2, request.method);
|
|
28627
|
+
return this._requestWithSchemaViaCodec(codec2, request, schemaOrOptions, maybeOptions);
|
|
28628
|
+
}
|
|
28606
28629
|
this._assertOutboundRequestInEra(codec2, request.method);
|
|
28607
|
-
if (isStandardSchema(schemaOrOptions)) return this._requestWithSchemaViaCodec(codec2, request, schemaOrOptions, maybeOptions);
|
|
28608
28630
|
const validate2 = codecResultValidator(codec2, request.method);
|
|
28609
28631
|
if (validate2 === void 0) throw new TypeError(`'${request.method}' is not a spec method; pass a result schema as the second argument to request().`);
|
|
28610
28632
|
return this._requestWithSchemaViaCodec(codec2, request, validate2, schemaOrOptions);
|
|
@@ -28848,6 +28870,8 @@ var Protocol = class {
|
|
|
28848
28870
|
return maybeHandler(parsed.data, ctx);
|
|
28849
28871
|
};
|
|
28850
28872
|
else throw new TypeError("setRequestHandler: handler is required");
|
|
28873
|
+
if (typeof schemasOrHandler === "function") this._customSchemaRequestMethods.delete(method);
|
|
28874
|
+
else this._customSchemaRequestMethods.add(method);
|
|
28851
28875
|
this._requestHandlers.set(method, this._wrapHandler(method, stored));
|
|
28852
28876
|
}
|
|
28853
28877
|
/**
|
|
@@ -28877,6 +28901,7 @@ var Protocol = class {
|
|
|
28877
28901
|
*/
|
|
28878
28902
|
removeRequestHandler(method) {
|
|
28879
28903
|
this._requestHandlers.delete(method);
|
|
28904
|
+
this._customSchemaRequestMethods.delete(method);
|
|
28880
28905
|
}
|
|
28881
28906
|
/**
|
|
28882
28907
|
* Asserts that a request handler has not already been set for the given method, in preparation for a new one being automatically installed.
|
|
@@ -36119,7 +36144,7 @@ var Ajv = import_ajv.Ajv;
|
|
|
36119
36144
|
// node_modules/@modelcontextprotocol/server/dist/shimsNode.mjs
|
|
36120
36145
|
import process2 from "node:process";
|
|
36121
36146
|
|
|
36122
|
-
// node_modules/@modelcontextprotocol/server/dist/mcp-
|
|
36147
|
+
// node_modules/@modelcontextprotocol/server/dist/mcp-DIH4cS6P.mjs
|
|
36123
36148
|
var COMPLETABLE_SYMBOL = /* @__PURE__ */ Symbol.for("mcp.completable");
|
|
36124
36149
|
function isCompletable(schema) {
|
|
36125
36150
|
return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
|
|
@@ -36184,7 +36209,7 @@ var StdioListenRouter = class {
|
|
|
36184
36209
|
_serverCapabilities;
|
|
36185
36210
|
/**
|
|
36186
36211
|
* The serving instance's identity, stamped onto the graceful-close
|
|
36187
|
-
* results' `_meta` (the spec's `
|
|
36212
|
+
* results' `_meta` (the spec's `SubscriptionsListenResultMetaObject` extends
|
|
36188
36213
|
* `ResultMetaObject`). Handed over together with the capabilities.
|
|
36189
36214
|
*/
|
|
36190
36215
|
_serverInfo;
|
|
@@ -36516,6 +36541,11 @@ var Server = class extends Protocol {
|
|
|
36516
36541
|
if (modernProtocolVersions(this._supportedProtocolVersions).length > 0) this.setRequestHandler("server/discover", () => this._ondiscover());
|
|
36517
36542
|
if (this._capabilities.logging) this._registerLoggingHandler();
|
|
36518
36543
|
}
|
|
36544
|
+
/** Attaches to the given transport; rejects while this instance is connected to another one. */
|
|
36545
|
+
async connect(transport) {
|
|
36546
|
+
if (this.transport !== void 0) throw new SdkError(SdkErrorCode.AlreadyConnected, "Use a separate Server instance per connection: this instance is already connected to a transport. To connect it to a new transport, call close() first.");
|
|
36547
|
+
await super.connect(transport);
|
|
36548
|
+
}
|
|
36519
36549
|
/**
|
|
36520
36550
|
* Registers the built-in `logging/setLevel` request handler.
|
|
36521
36551
|
*
|
|
@@ -37069,21 +37099,41 @@ var Server = class extends Protocol {
|
|
|
37069
37099
|
function discoverAdvertisedCapabilities(capabilities) {
|
|
37070
37100
|
return { ...capabilities };
|
|
37071
37101
|
}
|
|
37102
|
+
function toolInputElementCount(value, max) {
|
|
37103
|
+
let count = 0;
|
|
37104
|
+
const stack = [value];
|
|
37105
|
+
while (stack.length > 0) {
|
|
37106
|
+
const node2 = stack.pop();
|
|
37107
|
+
if (node2 === null || typeof node2 !== "object") continue;
|
|
37108
|
+
if (Array.isArray(node2)) for (const child of node2) {
|
|
37109
|
+
if (++count > max) return count;
|
|
37110
|
+
if (child !== null && typeof child === "object") stack.push(child);
|
|
37111
|
+
}
|
|
37112
|
+
else for (const key in node2) {
|
|
37113
|
+
if (!Object.prototype.hasOwnProperty.call(node2, key)) continue;
|
|
37114
|
+
if (++count > max) return count;
|
|
37115
|
+
const child = node2[key];
|
|
37116
|
+
if (child !== null && typeof child === "object") stack.push(child);
|
|
37117
|
+
}
|
|
37118
|
+
}
|
|
37119
|
+
return count;
|
|
37120
|
+
}
|
|
37121
|
+
function resolveMaxToolInputElements(value) {
|
|
37122
|
+
if (value === void 0 || value === Infinity) return void 0;
|
|
37123
|
+
if (typeof value !== "number" || Number.isNaN(value) || value < 1) throw new RangeError(`maxToolInputElements must be a number of at least 1, or Infinity, got ${String(value)}`);
|
|
37124
|
+
return value;
|
|
37125
|
+
}
|
|
37072
37126
|
var McpServer = class {
|
|
37073
37127
|
/**
|
|
37074
37128
|
* The underlying {@linkcode Server} instance, useful for advanced operations like sending notifications.
|
|
37075
37129
|
*/
|
|
37076
37130
|
server;
|
|
37131
|
+
_maxToolInputElements;
|
|
37077
37132
|
_registeredResources = {};
|
|
37078
37133
|
_registeredResourceTemplates = {};
|
|
37079
37134
|
_registeredTools = {};
|
|
37080
37135
|
_registeredPrompts = {};
|
|
37081
|
-
/**
|
|
37082
|
-
* Per-tool JSON-converted `inputSchema`, memoized so the SEP-2243
|
|
37083
|
-
* registration-time scan and the pre-dispatch validation step share one
|
|
37084
|
-
* conversion instead of paying it twice per request under the
|
|
37085
|
-
* per-request-factory `createMcpHandler` model.
|
|
37086
|
-
*/
|
|
37136
|
+
/** Per-tool JSON-converted `inputSchema`, filled on first use by `toolInputSchemaJson()`. */
|
|
37087
37137
|
_toolInputSchemaJson = {};
|
|
37088
37138
|
/**
|
|
37089
37139
|
* The JSON-serialized `inputSchema` of a registered tool, or `undefined`
|
|
@@ -37108,6 +37158,7 @@ var McpServer = class {
|
|
|
37108
37158
|
}
|
|
37109
37159
|
constructor(serverInfo, options) {
|
|
37110
37160
|
this.server = new Server(serverInfo, options);
|
|
37161
|
+
this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
|
|
37111
37162
|
if (options?.capabilities?.tools) this.setToolRequestHandlers();
|
|
37112
37163
|
if (options?.capabilities?.resources) this.setResourceRequestHandlers();
|
|
37113
37164
|
if (options?.capabilities?.prompts) this.setPromptRequestHandlers();
|
|
@@ -37180,7 +37231,7 @@ var McpServer = class {
|
|
|
37180
37231
|
name,
|
|
37181
37232
|
title: tool.title,
|
|
37182
37233
|
description: tool.description,
|
|
37183
|
-
inputSchema: tool.inputSchema ?
|
|
37234
|
+
inputSchema: tool.inputSchema ? convertListedInputSchema(name, tool.inputSchema) : EMPTY_OBJECT_JSON_SCHEMA,
|
|
37184
37235
|
annotations: tool.annotations,
|
|
37185
37236
|
icons: tool.icons,
|
|
37186
37237
|
execution: tool.execution,
|
|
@@ -37225,6 +37276,7 @@ var McpServer = class {
|
|
|
37225
37276
|
* Validates tool input arguments against the tool's input schema.
|
|
37226
37277
|
*/
|
|
37227
37278
|
async validateToolInput(tool, args, toolName) {
|
|
37279
|
+
if (this._maxToolInputElements !== void 0 && toolInputElementCount(args, this._maxToolInputElements) > this._maxToolInputElements) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Invalid arguments for tool ${toolName}: arguments contain more than the maximum of ${this._maxToolInputElements} elements`);
|
|
37228
37280
|
if (!tool.inputSchema) return;
|
|
37229
37281
|
const parseResult = await validateStandardSchema(tool.inputSchema, args ?? {});
|
|
37230
37282
|
if (!parseResult.success) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Input validation error: Invalid arguments for tool ${toolName}: ${parseResult.error}`);
|
|
@@ -37499,20 +37551,19 @@ var McpServer = class {
|
|
|
37499
37551
|
}
|
|
37500
37552
|
_createRegisteredTool(name, title, description, inputSchema, outputSchema, annotations, icons, execution, scopeChallenge, _meta, handler) {
|
|
37501
37553
|
validateAndWarnToolName(name);
|
|
37502
|
-
if (inputSchema !== void 0) try {
|
|
37503
|
-
const json2 = standardSchemaToJsonSchema(inputSchema, "input");
|
|
37504
|
-
this._toolInputSchemaJson[name] = json2;
|
|
37505
|
-
const scan = scanXMcpHeaderDeclarations(json2);
|
|
37506
|
-
if (!scan.valid) console.warn(`[mcp-sdk] tool '${name}' carries an invalid x-mcp-header declaration and will be excluded by conforming Streamable HTTP clients: ${scan.reason}`);
|
|
37507
|
-
} catch {
|
|
37508
|
-
}
|
|
37509
37554
|
let currentHandler = handler;
|
|
37555
|
+
let outputSchemaJson;
|
|
37510
37556
|
const registeredTool = {
|
|
37511
37557
|
title,
|
|
37512
37558
|
description,
|
|
37513
37559
|
inputSchema,
|
|
37514
37560
|
outputSchema,
|
|
37515
|
-
outputSchemaJson
|
|
37561
|
+
get outputSchemaJson() {
|
|
37562
|
+
return outputSchemaJson ??= convertOutputSchemaJson(registeredTool.outputSchema);
|
|
37563
|
+
},
|
|
37564
|
+
set outputSchemaJson(value) {
|
|
37565
|
+
outputSchemaJson = value;
|
|
37566
|
+
},
|
|
37516
37567
|
annotations,
|
|
37517
37568
|
icons,
|
|
37518
37569
|
execution,
|
|
@@ -37639,6 +37690,12 @@ var EMPTY_OBJECT_JSON_SCHEMA = {
|
|
|
37639
37690
|
type: "object",
|
|
37640
37691
|
properties: {}
|
|
37641
37692
|
};
|
|
37693
|
+
function convertListedInputSchema(name, inputSchema) {
|
|
37694
|
+
const json2 = standardSchemaToJsonSchema(inputSchema, "input");
|
|
37695
|
+
const scan = scanXMcpHeaderDeclarations(json2);
|
|
37696
|
+
if (!scan.valid) console.warn(`[mcp-sdk] tool '${name}' carries an invalid x-mcp-header declaration and will be excluded by conforming Streamable HTTP clients: ${scan.reason}`);
|
|
37697
|
+
return json2;
|
|
37698
|
+
}
|
|
37642
37699
|
function convertOutputSchemaJson(outputSchema) {
|
|
37643
37700
|
if (outputSchema === void 0) return void 0;
|
|
37644
37701
|
try {
|
|
@@ -37651,7 +37708,7 @@ function createPromptHandler(name, argsSchema, callback) {
|
|
|
37651
37708
|
if (argsSchema) {
|
|
37652
37709
|
const typedCallback = callback;
|
|
37653
37710
|
return async (args, ctx) => {
|
|
37654
|
-
const parseResult = await validateStandardSchema(argsSchema, args);
|
|
37711
|
+
const parseResult = await validateStandardSchema(argsSchema, args ?? {});
|
|
37655
37712
|
if (!parseResult.success) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Invalid arguments for prompt ${name}: ${parseResult.error}`);
|
|
37656
37713
|
return typedCallback(parseResult.data, ctx);
|
|
37657
37714
|
};
|
|
@@ -38402,6 +38459,7 @@ function escapeKey(key) {
|
|
|
38402
38459
|
var DEFAULT_REQUEST_KEY = "confirmation";
|
|
38403
38460
|
var DEFAULT_CONFIRMATION_LABEL = "Confirm this action should proceed.";
|
|
38404
38461
|
var UNSUPPORTED_NOTE = "Nothing was done because this client cannot show a confirmation prompt (it declares no MCP elicitation capability), and this action is never taken without one";
|
|
38462
|
+
var DISABLED_NOTE = "Nothing was done because confirmation prompts are turned off for this server, and this action is never taken without one";
|
|
38405
38463
|
var STATE_PREFIX = "mcpu.confirm.v1.";
|
|
38406
38464
|
function bindingKey(binding) {
|
|
38407
38465
|
if (binding.ttlSeconds !== void 0 && !(Number.isFinite(binding.ttlSeconds) && binding.ttlSeconds > 0)) {
|
|
@@ -38474,6 +38532,15 @@ ${JSON.stringify(preview, null, 2)}`,
|
|
|
38474
38532
|
};
|
|
38475
38533
|
const response = inputResponse(ctx.mcpReq.inputResponses, requestKey);
|
|
38476
38534
|
const accepted = acceptedContent(ctx.mcpReq.inputResponses, requestKey, confirmationSchema);
|
|
38535
|
+
if (options.elicitation === false) {
|
|
38536
|
+
return textResult({
|
|
38537
|
+
confirmed: false,
|
|
38538
|
+
dispatched: false,
|
|
38539
|
+
action: options.action,
|
|
38540
|
+
reason: "confirmation-unsupported",
|
|
38541
|
+
note: options.unsupportedNote ? `${DISABLED_NOTE}. ${options.unsupportedNote}` : `${DISABLED_NOTE}.`
|
|
38542
|
+
});
|
|
38543
|
+
}
|
|
38477
38544
|
if (response.kind === "missing") {
|
|
38478
38545
|
if (callerAcceptsFormElicitation(ctx) === false) {
|
|
38479
38546
|
return textResult({
|
|
@@ -38668,7 +38735,7 @@ async function tokenConfirmation(action, fb) {
|
|
|
38668
38735
|
}
|
|
38669
38736
|
async function requireConfirmationWithFallback(ctx, options) {
|
|
38670
38737
|
const { tokenFallback, ...confirmation } = options;
|
|
38671
|
-
if (tokenFallback && callerAcceptsFormElicitation(ctx) === false) {
|
|
38738
|
+
if (tokenFallback && (options.elicitation === false || callerAcceptsFormElicitation(ctx) === false)) {
|
|
38672
38739
|
return tokenConfirmation(options.action, tokenFallback);
|
|
38673
38740
|
}
|
|
38674
38741
|
return requireConfirmation(ctx, confirmation);
|
|
@@ -38830,6 +38897,20 @@ function readConfirmMode(env = process.env) {
|
|
|
38830
38897
|
}
|
|
38831
38898
|
return "refuse";
|
|
38832
38899
|
}
|
|
38900
|
+
function readConfirmElicitation(env = process.env) {
|
|
38901
|
+
const raw = readEnvVar("MCP_CONFIRM_ELICITATION", { env })?.trim().toLowerCase();
|
|
38902
|
+
if (!raw || raw === "on")
|
|
38903
|
+
return "on";
|
|
38904
|
+
if (raw === "off")
|
|
38905
|
+
return "off";
|
|
38906
|
+
const key = `elicitation:${raw}`;
|
|
38907
|
+
if (!warned.has(key)) {
|
|
38908
|
+
warned.add(key);
|
|
38909
|
+
process.stderr.write(`MCP_CONFIRM_ELICITATION="${raw}" is not one of on, off; treating it as on.
|
|
38910
|
+
`);
|
|
38911
|
+
}
|
|
38912
|
+
return "on";
|
|
38913
|
+
}
|
|
38833
38914
|
function readConfirmTtl(env) {
|
|
38834
38915
|
const raw = readEnvVar("MCP_CONFIRM_TTL_SECONDS", { env })?.trim();
|
|
38835
38916
|
if (!raw)
|
|
@@ -38874,6 +38955,7 @@ function spentTokenStoreFromEnv(env = process.env) {
|
|
|
38874
38955
|
}
|
|
38875
38956
|
var CONFIRM_TOKEN_AUTO_INSTRUCTION = "Nothing has been done yet. Review this preview; if it is what was intended, call again with the same arguments plus confirmToken. (This server runs with MCP_CONFIRM_MODE=auto, so the user's approval in chat is not required.)";
|
|
38876
38957
|
var REFUSE_HINT = "Set MCP_CONFIRM_MODE=ask-user on the server to allow two-step confirmation instead.";
|
|
38958
|
+
var ELICITATION_OFF_HINT = "MCP_CONFIRM_ELICITATION=off on the server turns confirmation prompts off.";
|
|
38877
38959
|
var BAD_TTL_HINT = "MCP_CONFIRM_TTL_SECONDS on the server is not a positive whole number of seconds; fix it to allow two-step confirmation.";
|
|
38878
38960
|
function boundArgs(args) {
|
|
38879
38961
|
if (args === null || typeof args !== "object" || Array.isArray(args) || !("confirmToken" in args))
|
|
@@ -38887,10 +38969,13 @@ function confirmationFromEnv(options) {
|
|
|
38887
38969
|
const spent = callerSpent ?? spentTokenStoreFromEnv(env);
|
|
38888
38970
|
const mode = readConfirmMode(env);
|
|
38889
38971
|
const ttlSeconds = readConfirmTtl(env);
|
|
38972
|
+
const elicitationOff = readConfirmElicitation(env) === "off";
|
|
38890
38973
|
const bound = args === void 0 ? void 0 : boundArgs(args);
|
|
38891
|
-
const
|
|
38974
|
+
const bindingAdded = bound === void 0 || rest.binding ? rest : { ...rest, binding: { key: confirmKeyFromEnv(env), args: bound, ttlSeconds: ttlSeconds ?? DEFAULT_TTL_SECONDS2 } };
|
|
38975
|
+
const confirmation = elicitationOff ? { ...bindingAdded, elicitation: false } : bindingAdded;
|
|
38892
38976
|
if (mode === "refuse" || ttlSeconds === void 0) {
|
|
38893
|
-
const
|
|
38977
|
+
const reason = mode === "refuse" ? REFUSE_HINT : BAD_TTL_HINT;
|
|
38978
|
+
const hint = elicitationOff ? `${ELICITATION_OFF_HINT} ${reason}` : reason;
|
|
38894
38979
|
return {
|
|
38895
38980
|
...confirmation,
|
|
38896
38981
|
unsupportedNote: confirmation.unsupportedNote ? `${confirmation.unsupportedNote} ${hint}` : hint
|
|
@@ -38999,7 +39084,10 @@ function surfaceToolHints(server) {
|
|
|
38999
39084
|
));
|
|
39000
39085
|
}
|
|
39001
39086
|
async function createMcpServer(opts) {
|
|
39002
|
-
const server = new McpServer({ name: opts.name, version: opts.version }, {
|
|
39087
|
+
const server = new McpServer({ name: opts.name, version: opts.version }, {
|
|
39088
|
+
supportedProtocolVersions: [...SERVER_PROTOCOL_VERSIONS],
|
|
39089
|
+
...opts.maxToolInputElements !== void 0 ? { maxToolInputElements: opts.maxToolInputElements } : {}
|
|
39090
|
+
});
|
|
39003
39091
|
if (opts.surfaceHints !== false)
|
|
39004
39092
|
surfaceToolHints(server);
|
|
39005
39093
|
if (opts.banner !== void 0) {
|
|
@@ -40327,6 +40415,60 @@ var KNOWN_CAPABILITIES = /* @__PURE__ */ new Set([
|
|
|
40327
40415
|
"graphql",
|
|
40328
40416
|
"write_cookies"
|
|
40329
40417
|
]);
|
|
40418
|
+
var ACCOUNT_KEY_FRAME = "account-key";
|
|
40419
|
+
var ACCOUNT_ATTEST_FRAME = "account-attest";
|
|
40420
|
+
var BRIDGE_ROLE_FRAME = "bridge-role";
|
|
40421
|
+
var BRIDGE_SERVE_FRAME = "bridge-serve";
|
|
40422
|
+
var ROOM_PING_FRAME = "room-ping";
|
|
40423
|
+
var ROOM_PONG_FRAME = "room-pong";
|
|
40424
|
+
var BRIDGE_ROLE_LABEL_MAX = 64;
|
|
40425
|
+
var ROOM_FRAME_ACCEPTS = Object.freeze({
|
|
40426
|
+
[BRIDGE_ROLE_FRAME]: BRIDGE_ROLE_FRAME,
|
|
40427
|
+
[BRIDGE_SERVE_FRAME]: BRIDGE_SERVE_FRAME,
|
|
40428
|
+
[ROOM_PING_FRAME]: ROOM_PING_FRAME,
|
|
40429
|
+
[ROOM_PONG_FRAME]: ROOM_PING_FRAME
|
|
40430
|
+
});
|
|
40431
|
+
|
|
40432
|
+
// node_modules/@fetchproxy/protocol/dist/mcp-id.js
|
|
40433
|
+
var ID_RE = /^([^:]+):([^:]+):([0-9a-f]{16})$/;
|
|
40434
|
+
function generateMcpId(serverName, version2) {
|
|
40435
|
+
if (serverName.includes(":")) {
|
|
40436
|
+
throw new Error(`serverName cannot contain ':': ${serverName}`);
|
|
40437
|
+
}
|
|
40438
|
+
if (version2.includes(":")) {
|
|
40439
|
+
throw new Error(`version cannot contain ':': ${version2}`);
|
|
40440
|
+
}
|
|
40441
|
+
const rand = randomHex(8);
|
|
40442
|
+
return `${serverName}:${version2}:${rand}`;
|
|
40443
|
+
}
|
|
40444
|
+
function isValidMcpId(id) {
|
|
40445
|
+
return typeof id === "string" && ID_RE.test(id);
|
|
40446
|
+
}
|
|
40447
|
+
function randomHex(bytes) {
|
|
40448
|
+
const arr = new Uint8Array(bytes);
|
|
40449
|
+
globalThis.crypto.getRandomValues(arr);
|
|
40450
|
+
return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
40451
|
+
}
|
|
40452
|
+
|
|
40453
|
+
// node_modules/@fetchproxy/protocol/dist/account-attest.js
|
|
40454
|
+
var ACCOUNT_ATTEST_CONSENTS = Object.freeze([
|
|
40455
|
+
"silent",
|
|
40456
|
+
"confirm",
|
|
40457
|
+
"confirm-each"
|
|
40458
|
+
]);
|
|
40459
|
+
var NO_SCOPE_DIGEST = "0".repeat(64);
|
|
40460
|
+
var ACCOUNT_ID_RE = /^[A-Za-z0-9_.\-]{1,128}$/;
|
|
40461
|
+
var HEX64_RE = /^[0-9a-f]{64}$/;
|
|
40462
|
+
var ACCOUNT_KID_RE = /^[0-9a-f]{16}$/;
|
|
40463
|
+
var enc2 = new TextEncoder();
|
|
40464
|
+
|
|
40465
|
+
// node_modules/@fetchproxy/protocol/dist/awaiting-approval.js
|
|
40466
|
+
var AWAITING_APPROVAL_REASON_PREFIX = "awaiting-approval:";
|
|
40467
|
+
function parseAwaitingApprovalReason(reason) {
|
|
40468
|
+
if (!reason.startsWith(AWAITING_APPROVAL_REASON_PREFIX))
|
|
40469
|
+
return null;
|
|
40470
|
+
return reason.slice(AWAITING_APPROVAL_REASON_PREFIX.length).trim();
|
|
40471
|
+
}
|
|
40330
40472
|
|
|
40331
40473
|
// node_modules/@fetchproxy/protocol/dist/capability-availability.js
|
|
40332
40474
|
var CAPABILITY_UNAVAILABLE_CODE = "capability_unavailable";
|
|
@@ -40352,27 +40494,6 @@ function parseUnsupportedCapabilityReason(reason) {
|
|
|
40352
40494
|
return rest.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
40353
40495
|
}
|
|
40354
40496
|
|
|
40355
|
-
// node_modules/@fetchproxy/protocol/dist/mcp-id.js
|
|
40356
|
-
var ID_RE = /^([^:]+):([^:]+):([0-9a-f]{16})$/;
|
|
40357
|
-
function generateMcpId(serverName, version2) {
|
|
40358
|
-
if (serverName.includes(":")) {
|
|
40359
|
-
throw new Error(`serverName cannot contain ':': ${serverName}`);
|
|
40360
|
-
}
|
|
40361
|
-
if (version2.includes(":")) {
|
|
40362
|
-
throw new Error(`version cannot contain ':': ${version2}`);
|
|
40363
|
-
}
|
|
40364
|
-
const rand = randomHex(8);
|
|
40365
|
-
return `${serverName}:${version2}:${rand}`;
|
|
40366
|
-
}
|
|
40367
|
-
function isValidMcpId(id) {
|
|
40368
|
-
return typeof id === "string" && ID_RE.test(id);
|
|
40369
|
-
}
|
|
40370
|
-
function randomHex(bytes) {
|
|
40371
|
-
const arr = new Uint8Array(bytes);
|
|
40372
|
-
globalThis.crypto.getRandomValues(arr);
|
|
40373
|
-
return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
40374
|
-
}
|
|
40375
|
-
|
|
40376
40497
|
// node_modules/@fetchproxy/protocol/dist/json-pointer.js
|
|
40377
40498
|
function matchesDeclaredKey(requested, declared) {
|
|
40378
40499
|
for (const decl of declared) {
|
|
@@ -40968,6 +41089,16 @@ function validateFrame(raw) {
|
|
|
40968
41089
|
return { type: "extension-disconnected" };
|
|
40969
41090
|
if (t === "peer-gone")
|
|
40970
41091
|
return validatePeerGone(raw);
|
|
41092
|
+
if (t === ACCOUNT_KEY_FRAME)
|
|
41093
|
+
return validateAccountKey(raw);
|
|
41094
|
+
if (t === ACCOUNT_ATTEST_FRAME)
|
|
41095
|
+
return validateAccountAttest(raw);
|
|
41096
|
+
if (t === BRIDGE_ROLE_FRAME)
|
|
41097
|
+
return validateBridgeRole(raw);
|
|
41098
|
+
if (t === BRIDGE_SERVE_FRAME || t === ROOM_PING_FRAME || t === ROOM_PONG_FRAME) {
|
|
41099
|
+
assertExactFields(raw, TYPE_ONLY_FIELDS, t);
|
|
41100
|
+
return { type: t };
|
|
41101
|
+
}
|
|
40971
41102
|
throw new ProtocolError3(`unknown frame type: ${String(t)}`);
|
|
40972
41103
|
}
|
|
40973
41104
|
function validateHello(raw) {
|
|
@@ -41171,6 +41302,165 @@ function validateHelloRejected(raw) {
|
|
|
41171
41302
|
}
|
|
41172
41303
|
return { type: "hello-rejected", mcpId: raw.mcpId, reason: raw.reason };
|
|
41173
41304
|
}
|
|
41305
|
+
var DISPLAY_FORBIDDEN_RE = /[\u0000-\u001f\u007f-\u009f\u200e\u200f\u202a-\u202e\u2066-\u2069]/;
|
|
41306
|
+
function assertExactFields(raw, allowed, label) {
|
|
41307
|
+
for (const k of Object.keys(raw)) {
|
|
41308
|
+
if (!allowed.includes(k)) {
|
|
41309
|
+
throw new ProtocolError3(`${label}: unexpected field ${JSON.stringify(k)}`);
|
|
41310
|
+
}
|
|
41311
|
+
}
|
|
41312
|
+
}
|
|
41313
|
+
function assertMatch(x, re, label, what) {
|
|
41314
|
+
assertString(x, label);
|
|
41315
|
+
if (!re.test(x))
|
|
41316
|
+
throw new ProtocolError3(`${label}: must be ${what}`);
|
|
41317
|
+
}
|
|
41318
|
+
function assertPositiveSafeInt(x, label) {
|
|
41319
|
+
if (typeof x !== "number" || !Number.isSafeInteger(x) || x <= 0) {
|
|
41320
|
+
throw new ProtocolError3(`${label}: expected positive safe integer`);
|
|
41321
|
+
}
|
|
41322
|
+
}
|
|
41323
|
+
function assertDisplayString(x, label, min, max) {
|
|
41324
|
+
assertString(x, label);
|
|
41325
|
+
if (x.length < min || x.length > max) {
|
|
41326
|
+
throw new ProtocolError3(`${label}: must be ${min}-${max} characters`);
|
|
41327
|
+
}
|
|
41328
|
+
if (DISPLAY_FORBIDDEN_RE.test(x)) {
|
|
41329
|
+
throw new ProtocolError3(`${label}: control or bidi-override character`);
|
|
41330
|
+
}
|
|
41331
|
+
}
|
|
41332
|
+
var ACCOUNT_KEY_FIELDS = [
|
|
41333
|
+
"type",
|
|
41334
|
+
"accountId",
|
|
41335
|
+
"slug",
|
|
41336
|
+
"displayName",
|
|
41337
|
+
"confirmedBy",
|
|
41338
|
+
"tokenId",
|
|
41339
|
+
"kid",
|
|
41340
|
+
"publicKey",
|
|
41341
|
+
"generation",
|
|
41342
|
+
"bridgedRegistrations"
|
|
41343
|
+
];
|
|
41344
|
+
function validateAccountKey(raw) {
|
|
41345
|
+
const L = "account-key";
|
|
41346
|
+
assertMatch(raw.accountId, ACCOUNT_ID_RE, `${L}.accountId`, "an account id");
|
|
41347
|
+
assertMatch(raw.slug, ACCOUNT_ID_RE, `${L}.slug`, "a slug");
|
|
41348
|
+
assertDisplayString(raw.displayName, `${L}.displayName`, 0, 128);
|
|
41349
|
+
assertDisplayString(raw.confirmedBy, `${L}.confirmedBy`, 1, 256);
|
|
41350
|
+
assertMatch(raw.tokenId, ACCOUNT_ID_RE, `${L}.tokenId`, "a token id");
|
|
41351
|
+
assertMatch(raw.kid, ACCOUNT_KID_RE, `${L}.kid`, "16 lowercase hex");
|
|
41352
|
+
assertBase64Bytes(raw.publicKey, `${L}.publicKey`, 32);
|
|
41353
|
+
assertPositiveSafeInt(raw.generation, `${L}.generation`);
|
|
41354
|
+
const n = raw.bridgedRegistrations;
|
|
41355
|
+
if (typeof n !== "number" || !Number.isSafeInteger(n) || n < 0) {
|
|
41356
|
+
throw new ProtocolError3(`${L}.bridgedRegistrations: expected non-negative safe integer`);
|
|
41357
|
+
}
|
|
41358
|
+
assertExactFields(raw, ACCOUNT_KEY_FIELDS, L);
|
|
41359
|
+
return {
|
|
41360
|
+
type: ACCOUNT_KEY_FRAME,
|
|
41361
|
+
accountId: raw.accountId,
|
|
41362
|
+
slug: raw.slug,
|
|
41363
|
+
displayName: raw.displayName,
|
|
41364
|
+
confirmedBy: raw.confirmedBy,
|
|
41365
|
+
tokenId: raw.tokenId,
|
|
41366
|
+
kid: raw.kid,
|
|
41367
|
+
publicKey: raw.publicKey,
|
|
41368
|
+
generation: raw.generation,
|
|
41369
|
+
bridgedRegistrations: n
|
|
41370
|
+
};
|
|
41371
|
+
}
|
|
41372
|
+
var ACCOUNT_ATTEST_FIELDS = [
|
|
41373
|
+
"type",
|
|
41374
|
+
"mcpId",
|
|
41375
|
+
"accountId",
|
|
41376
|
+
"generation",
|
|
41377
|
+
"tokenId",
|
|
41378
|
+
"kid",
|
|
41379
|
+
"registrationId",
|
|
41380
|
+
"slug",
|
|
41381
|
+
"identityHash",
|
|
41382
|
+
"identityEd25519Pub",
|
|
41383
|
+
"scopeDigest",
|
|
41384
|
+
"consent",
|
|
41385
|
+
"notAfter",
|
|
41386
|
+
"sig"
|
|
41387
|
+
];
|
|
41388
|
+
function validateAccountAttest(raw) {
|
|
41389
|
+
const L = "account-attest";
|
|
41390
|
+
if (!isValidMcpId(raw.mcpId))
|
|
41391
|
+
throw new ProtocolError3(`${L}.mcpId: invalid format`);
|
|
41392
|
+
assertMatch(raw.accountId, ACCOUNT_ID_RE, `${L}.accountId`, "an account id");
|
|
41393
|
+
assertPositiveSafeInt(raw.generation, `${L}.generation`);
|
|
41394
|
+
assertMatch(raw.tokenId, ACCOUNT_ID_RE, `${L}.tokenId`, "a token id");
|
|
41395
|
+
assertMatch(raw.kid, ACCOUNT_KID_RE, `${L}.kid`, "16 lowercase hex");
|
|
41396
|
+
assertMatch(raw.registrationId, ACCOUNT_ID_RE, `${L}.registrationId`, "a registration id");
|
|
41397
|
+
assertMatch(raw.slug, ACCOUNT_ID_RE, `${L}.slug`, "a slug");
|
|
41398
|
+
assertMatch(raw.identityHash, HEX64_RE, `${L}.identityHash`, "64 lowercase hex");
|
|
41399
|
+
assertBase64Bytes(raw.identityEd25519Pub, `${L}.identityEd25519Pub`, 32);
|
|
41400
|
+
assertMatch(raw.scopeDigest, HEX64_RE, `${L}.scopeDigest`, "64 lowercase hex");
|
|
41401
|
+
assertString(raw.consent, `${L}.consent`);
|
|
41402
|
+
const consent = raw.consent;
|
|
41403
|
+
const known = ACCOUNT_ATTEST_CONSENTS.find((c) => c === consent);
|
|
41404
|
+
if (known === void 0) {
|
|
41405
|
+
throw new ProtocolError3(`${L}.consent: must be one of ${ACCOUNT_ATTEST_CONSENTS.join(", ")}`);
|
|
41406
|
+
}
|
|
41407
|
+
assertPositiveSafeInt(raw.notAfter, `${L}.notAfter`);
|
|
41408
|
+
assertBase64Bytes(raw.sig, `${L}.sig`, 64);
|
|
41409
|
+
assertExactFields(raw, ACCOUNT_ATTEST_FIELDS, L);
|
|
41410
|
+
return {
|
|
41411
|
+
type: ACCOUNT_ATTEST_FRAME,
|
|
41412
|
+
mcpId: raw.mcpId,
|
|
41413
|
+
accountId: raw.accountId,
|
|
41414
|
+
generation: raw.generation,
|
|
41415
|
+
tokenId: raw.tokenId,
|
|
41416
|
+
kid: raw.kid,
|
|
41417
|
+
registrationId: raw.registrationId,
|
|
41418
|
+
slug: raw.slug,
|
|
41419
|
+
identityHash: raw.identityHash,
|
|
41420
|
+
identityEd25519Pub: raw.identityEd25519Pub,
|
|
41421
|
+
scopeDigest: raw.scopeDigest,
|
|
41422
|
+
consent: known,
|
|
41423
|
+
notAfter: raw.notAfter,
|
|
41424
|
+
sig: raw.sig
|
|
41425
|
+
};
|
|
41426
|
+
}
|
|
41427
|
+
var TYPE_ONLY_FIELDS = ["type"];
|
|
41428
|
+
var BRIDGE_ROLE_FIELDS = ["type", "role", "canServe", "serving"];
|
|
41429
|
+
var BRIDGE_ROLE_SERVING_FIELDS = ["label", "since"];
|
|
41430
|
+
function validateBridgeRole(raw) {
|
|
41431
|
+
const L = BRIDGE_ROLE_FRAME;
|
|
41432
|
+
const role = raw.role;
|
|
41433
|
+
if (role !== "serving" && role !== "standby") {
|
|
41434
|
+
throw new ProtocolError3(`${L}.role: must be one of serving, standby`);
|
|
41435
|
+
}
|
|
41436
|
+
const canServe = raw.canServe;
|
|
41437
|
+
assertBoolean(canServe, `${L}.canServe`);
|
|
41438
|
+
assertExactFields(raw, BRIDGE_ROLE_FIELDS, L);
|
|
41439
|
+
const serving = raw.serving;
|
|
41440
|
+
if (role === "serving") {
|
|
41441
|
+
if (serving !== void 0) {
|
|
41442
|
+
throw new ProtocolError3(`${L}.serving: must be absent when role is serving`);
|
|
41443
|
+
}
|
|
41444
|
+
return { type: BRIDGE_ROLE_FRAME, role, canServe };
|
|
41445
|
+
}
|
|
41446
|
+
if (serving === void 0) {
|
|
41447
|
+
throw new ProtocolError3(`${L}.serving: required when role is standby`);
|
|
41448
|
+
}
|
|
41449
|
+
assertObject(serving, `${L}.serving`);
|
|
41450
|
+
const label = serving.label;
|
|
41451
|
+
assertDisplayString(label, `${L}.serving.label`, 1, BRIDGE_ROLE_LABEL_MAX);
|
|
41452
|
+
const since = serving.since;
|
|
41453
|
+
if (typeof since !== "number" || !Number.isSafeInteger(since) || since < 0) {
|
|
41454
|
+
throw new ProtocolError3(`${L}.serving.since: expected non-negative safe integer (Unix ms)`);
|
|
41455
|
+
}
|
|
41456
|
+
assertExactFields(serving, BRIDGE_ROLE_SERVING_FIELDS, `${L}.serving`);
|
|
41457
|
+
return {
|
|
41458
|
+
type: BRIDGE_ROLE_FRAME,
|
|
41459
|
+
role,
|
|
41460
|
+
canServe,
|
|
41461
|
+
serving: { label, since }
|
|
41462
|
+
};
|
|
41463
|
+
}
|
|
41174
41464
|
function validateInnerFrame(raw) {
|
|
41175
41465
|
assertObject(raw, "inner");
|
|
41176
41466
|
const t = raw.type;
|
|
@@ -41638,10 +41928,10 @@ function validateInnerResponse(raw) {
|
|
|
41638
41928
|
}
|
|
41639
41929
|
|
|
41640
41930
|
// node_modules/@fetchproxy/protocol/dist/pair-code.js
|
|
41641
|
-
var
|
|
41931
|
+
var enc3 = new TextEncoder();
|
|
41642
41932
|
var PAIR_LABEL = "fetchproxy/4/pair";
|
|
41643
41933
|
async function pairTranscript(mcpIdentityPub, extIdentityPub, mcpNonce, extNonce, mcpSessionPub) {
|
|
41644
|
-
const label =
|
|
41934
|
+
const label = enc3.encode(PAIR_LABEL);
|
|
41645
41935
|
const parts = [mcpIdentityPub, extIdentityPub, mcpNonce, extNonce, mcpSessionPub];
|
|
41646
41936
|
const out = new Uint8Array(label.length + 1 + parts.reduce((n, p) => n + p.length, 0));
|
|
41647
41937
|
out.set(label, 0);
|
|
@@ -41662,7 +41952,7 @@ function digits(hash2) {
|
|
|
41662
41952
|
}
|
|
41663
41953
|
|
|
41664
41954
|
// node_modules/@fetchproxy/protocol/dist/seal.js
|
|
41665
|
-
var
|
|
41955
|
+
var enc4 = new TextEncoder();
|
|
41666
41956
|
var dec = new TextDecoder();
|
|
41667
41957
|
function randomIv() {
|
|
41668
41958
|
const iv = new Uint8Array(12);
|
|
@@ -41675,14 +41965,14 @@ function base64Length(byteLength) {
|
|
|
41675
41965
|
return Math.ceil(byteLength / 3) * 4;
|
|
41676
41966
|
}
|
|
41677
41967
|
function encodeInnerFrame(inner) {
|
|
41678
|
-
return
|
|
41968
|
+
return enc4.encode(JSON.stringify(inner));
|
|
41679
41969
|
}
|
|
41680
41970
|
function plaintextOf(inner) {
|
|
41681
41971
|
return inner instanceof Uint8Array ? inner : encodeInnerFrame(inner);
|
|
41682
41972
|
}
|
|
41683
41973
|
function sealedFrameWireBytes(mcpId, seq, inner) {
|
|
41684
41974
|
const plaintext = plaintextOf(inner).length;
|
|
41685
|
-
const envelope =
|
|
41975
|
+
const envelope = enc4.encode(JSON.stringify({ type: "frame", mcpId, seq, iv: "", ciphertext: "" })).length;
|
|
41686
41976
|
return envelope + IV_B64_BYTES + base64Length(plaintext + AES_GCM_TAG_BYTES);
|
|
41687
41977
|
}
|
|
41688
41978
|
var MAX_FRAME_BYTES = 42 * 1024 * 1024;
|
|
@@ -42022,14 +42312,23 @@ var FetchproxyHelloRejectedError = class extends Error {
|
|
|
42022
42312
|
platform;
|
|
42023
42313
|
/**
|
|
42024
42314
|
* #418: the remedy, when the reason is one this package knows how to
|
|
42025
|
-
* explain —
|
|
42026
|
-
*
|
|
42315
|
+
* explain — `unsupported-capability`, which blames the browser rather than
|
|
42316
|
+
* the MCP, and (D12) `awaiting-approval`, which says to approve in the
|
|
42317
|
+
* browser. `null` otherwise.
|
|
42027
42318
|
*/
|
|
42028
42319
|
hint;
|
|
42320
|
+
/**
|
|
42321
|
+
* D12: `true` only for an `awaiting-approval:` refusal — the extension has
|
|
42322
|
+
* queued an approval card and nobody is at the browser yet, so the same call
|
|
42323
|
+
* succeeds once the person approves. Every other refusal is the extension's
|
|
42324
|
+
* final answer, and retrying unchanged is refused the same way.
|
|
42325
|
+
*/
|
|
42326
|
+
retryable;
|
|
42029
42327
|
constructor(info) {
|
|
42030
42328
|
const unavailable = parseUnsupportedCapabilityReason(info.reason);
|
|
42329
|
+
const awaiting = parseAwaitingApprovalReason(info.reason);
|
|
42031
42330
|
const platform = info.platform ?? null;
|
|
42032
|
-
const hint = unavailable !== null ? `${platform ? `this browser (${platform})` : "this browser"} cannot serve any of the capabilities this MCP needs (${unavailable.join(", ")}) \u2014 ContextMint Bridge checked for the browser APIs and they are missing. Nothing is wrong with the MCP or your pairing, and updating will not change it: use this MCP from a browser that provides them (for example Chrome).` : null;
|
|
42331
|
+
const hint = awaiting !== null ? `The extension is waiting for you to approve this MCP` + (awaiting !== "" ? ` (${awaiting})` : "") + ` \u2014 open ContextMint Bridge in your browser, approve it there, then retry. Nothing is wrong with the MCP or your sign-in.` : unavailable !== null ? `${platform ? `this browser (${platform})` : "this browser"} cannot serve any of the capabilities this MCP needs (${unavailable.join(", ")}) \u2014 ContextMint Bridge checked for the browser APIs and they are missing. Nothing is wrong with the MCP or your pairing, and updating will not change it: use this MCP from a browser that provides them (for example Chrome).` : null;
|
|
42033
42332
|
super(`fetchproxy: the extension refused the connection for "${info.mcpId}": ${info.reason}. ` + (hint !== null ? hint : `This is the extension's own reason \u2014 it is not a timeout, and retrying unchanged will be refused the same way.`));
|
|
42034
42333
|
this.name = "FetchproxyHelloRejectedError";
|
|
42035
42334
|
this.mcpId = info.mcpId;
|
|
@@ -42037,6 +42336,7 @@ var FetchproxyHelloRejectedError = class extends Error {
|
|
|
42037
42336
|
this.unavailableCapabilities = unavailable ?? [];
|
|
42038
42337
|
this.platform = platform;
|
|
42039
42338
|
this.hint = hint;
|
|
42339
|
+
this.retryable = awaiting !== null;
|
|
42040
42340
|
Object.setPrototypeOf(this, new.target.prototype);
|
|
42041
42341
|
}
|
|
42042
42342
|
};
|
|
@@ -42589,7 +42889,7 @@ function originVerdict(origin, allowLocal) {
|
|
|
42589
42889
|
}
|
|
42590
42890
|
var HANDSHAKE_TIMEOUT_MS = 15e3;
|
|
42591
42891
|
var MAX_PAYLOAD_BYTES = MAX_FRAME_BYTES;
|
|
42592
|
-
var
|
|
42892
|
+
var enc5 = new TextEncoder();
|
|
42593
42893
|
var OWN_DECRYPT_FAILURES_BEFORE_REHANDSHAKE = 3;
|
|
42594
42894
|
async function startHost(opts) {
|
|
42595
42895
|
const allowLocalOrigins = envAllowsLocalOrigins();
|
|
@@ -42660,10 +42960,20 @@ async function startHost(opts) {
|
|
|
42660
42960
|
let resolveOwnSession;
|
|
42661
42961
|
let rejectOwnSession;
|
|
42662
42962
|
let ownSessionReady;
|
|
42963
|
+
let ownRetryableRefusal = false;
|
|
42964
|
+
let ownSessionSettled = false;
|
|
42663
42965
|
function resetSessionPromise() {
|
|
42966
|
+
ownRetryableRefusal = false;
|
|
42967
|
+
ownSessionSettled = false;
|
|
42664
42968
|
ownSessionReady = new Promise((resolve7, reject) => {
|
|
42665
|
-
resolveOwnSession =
|
|
42666
|
-
|
|
42969
|
+
resolveOwnSession = (st) => {
|
|
42970
|
+
ownSessionSettled = true;
|
|
42971
|
+
resolve7(st);
|
|
42972
|
+
};
|
|
42973
|
+
rejectOwnSession = (e) => {
|
|
42974
|
+
ownSessionSettled = true;
|
|
42975
|
+
reject(e);
|
|
42976
|
+
};
|
|
42667
42977
|
});
|
|
42668
42978
|
ownSessionReady.catch(() => {
|
|
42669
42979
|
});
|
|
@@ -42930,13 +43240,15 @@ async function startHost(opts) {
|
|
|
42930
43240
|
const extPub = fromB64(frame.extensionSessionPub);
|
|
42931
43241
|
const shared = await ecdhX25519(held.priv, extPub);
|
|
42932
43242
|
const salt = await transcriptHash(held.nonce, extNonce, held.pub, extPub);
|
|
42933
|
-
const key = await hkdfSha256(shared, salt,
|
|
43243
|
+
const key = await hkdfSha256(shared, salt, enc5.encode(HKDF_SESSION_INFO), 32);
|
|
42934
43244
|
if (extensionWs !== ws)
|
|
42935
43245
|
return;
|
|
42936
43246
|
ownSession = new SessionState(key);
|
|
42937
43247
|
ownSessionInfo = sessionInfoFromHello(verifiedHello);
|
|
42938
43248
|
ownDecryptFailures = 0;
|
|
42939
43249
|
ownPendingPairCode = null;
|
|
43250
|
+
if (ownRetryableRefusal)
|
|
43251
|
+
resetSessionPromise();
|
|
42940
43252
|
resolveOwnSession(ownSession);
|
|
42941
43253
|
} else {
|
|
42942
43254
|
const slot = peers.get(frame.mcpId);
|
|
@@ -43005,11 +43317,17 @@ async function startHost(opts) {
|
|
|
43005
43317
|
}
|
|
43006
43318
|
if (frame.type === "hello-rejected" && identified === "extension") {
|
|
43007
43319
|
if (frame.mcpId === opts.ownMcpId) {
|
|
43008
|
-
|
|
43320
|
+
const refusal = new FetchproxyHelloRejectedError({
|
|
43009
43321
|
mcpId: frame.mcpId,
|
|
43010
43322
|
reason: frame.reason,
|
|
43011
43323
|
platform: extensionHello?.platform ?? null
|
|
43012
|
-
})
|
|
43324
|
+
});
|
|
43325
|
+
if (ownRetryableRefusal)
|
|
43326
|
+
resetSessionPromise();
|
|
43327
|
+
const settlesPending = !ownSessionSettled;
|
|
43328
|
+
rejectOwnSession(refusal);
|
|
43329
|
+
if (refusal.retryable && settlesPending)
|
|
43330
|
+
ownRetryableRefusal = true;
|
|
43013
43331
|
} else {
|
|
43014
43332
|
const slot = peers.get(frame.mcpId);
|
|
43015
43333
|
if (slot?.helloFrame.accepts?.includes("hello-rejected")) {
|
|
@@ -43125,7 +43443,7 @@ async function startHost(opts) {
|
|
|
43125
43443
|
|
|
43126
43444
|
// node_modules/@fetchproxy/server/dist/peer.js
|
|
43127
43445
|
var PEER_DIAL_TIMEOUT_MS = 5e3;
|
|
43128
|
-
var
|
|
43446
|
+
var enc6 = new TextEncoder();
|
|
43129
43447
|
function notSentError() {
|
|
43130
43448
|
return new Error("fetchproxy: request not sent \u2014 the connection to the bridge host closed before it went out, so nothing reached the browser. It is safe to retry.");
|
|
43131
43449
|
}
|
|
@@ -43225,7 +43543,9 @@ async function startPeer(opts) {
|
|
|
43225
43543
|
let rejectFirstReady;
|
|
43226
43544
|
let sessionPromise;
|
|
43227
43545
|
let sessionPromiseSettled = false;
|
|
43546
|
+
let retryableRefusal = false;
|
|
43228
43547
|
function resetSessionPromise() {
|
|
43548
|
+
retryableRefusal = false;
|
|
43229
43549
|
sessionPromiseSettled = false;
|
|
43230
43550
|
sessionPromise = new Promise((resolve7, reject) => {
|
|
43231
43551
|
resolveFirstReady = (st) => {
|
|
@@ -43322,6 +43642,8 @@ async function startPeer(opts) {
|
|
|
43322
43642
|
raw = JSON.parse(data.toString());
|
|
43323
43643
|
const frame = validateFrame(raw);
|
|
43324
43644
|
if (frame.type === "hello" && frame.role === "extension") {
|
|
43645
|
+
if (retryableRefusal)
|
|
43646
|
+
resetSessionPromise();
|
|
43325
43647
|
extensionHello = frame;
|
|
43326
43648
|
const mintedKeypair = await generateSessionKeypair();
|
|
43327
43649
|
const mintedHello = await buildServerHello({
|
|
@@ -43351,6 +43673,8 @@ async function startPeer(opts) {
|
|
|
43351
43673
|
session = null;
|
|
43352
43674
|
if (sessionPromiseSettled)
|
|
43353
43675
|
resetSessionPromise();
|
|
43676
|
+
} else if (retryableRefusal) {
|
|
43677
|
+
resetSessionPromise();
|
|
43354
43678
|
}
|
|
43355
43679
|
extensionDisconnectListeners.forEach((cb) => cb());
|
|
43356
43680
|
return;
|
|
@@ -43372,7 +43696,7 @@ async function startPeer(opts) {
|
|
|
43372
43696
|
const extNonce = fromB64(authenticated.sessionNonce);
|
|
43373
43697
|
const shared = await ecdhX25519(held.priv, extPub);
|
|
43374
43698
|
const salt = await transcriptHash(held.nonce, extNonce, held.pub, extPub);
|
|
43375
|
-
const sessionKey = await hkdfSha256(shared, salt,
|
|
43699
|
+
const sessionKey = await hkdfSha256(shared, salt, enc6.encode(HKDF_SESSION_INFO), 32);
|
|
43376
43700
|
if (sessionEphemeral !== held) {
|
|
43377
43701
|
console.warn(`[fetchproxy] ${opts.serverName}: dropping a session derived against an ephemeral that was superseded while it was being derived`);
|
|
43378
43702
|
return;
|
|
@@ -43385,16 +43709,24 @@ async function startPeer(opts) {
|
|
|
43385
43709
|
if (isRenegotiation) {
|
|
43386
43710
|
renegotiateListeners.forEach((cb) => cb());
|
|
43387
43711
|
} else {
|
|
43712
|
+
if (retryableRefusal)
|
|
43713
|
+
resetSessionPromise();
|
|
43388
43714
|
resolveFirstReady(session);
|
|
43389
43715
|
}
|
|
43390
43716
|
return;
|
|
43391
43717
|
}
|
|
43392
43718
|
if (frame.type === "hello-rejected" && frame.mcpId === opts.mcpId) {
|
|
43393
|
-
|
|
43719
|
+
const refusal = new FetchproxyHelloRejectedError({
|
|
43394
43720
|
mcpId: frame.mcpId,
|
|
43395
43721
|
reason: frame.reason,
|
|
43396
43722
|
platform: extensionHello?.platform ?? null
|
|
43397
|
-
})
|
|
43723
|
+
});
|
|
43724
|
+
if (retryableRefusal)
|
|
43725
|
+
resetSessionPromise();
|
|
43726
|
+
const settlesPending = !sessionPromiseSettled;
|
|
43727
|
+
rejectFirstReady(refusal);
|
|
43728
|
+
if (refusal.retryable && settlesPending)
|
|
43729
|
+
retryableRefusal = true;
|
|
43398
43730
|
}
|
|
43399
43731
|
if (frame.type === "pair-pending" && frame.mcpId === opts.mcpId) {
|
|
43400
43732
|
const hello2 = extensionHello;
|
|
@@ -43558,8 +43890,9 @@ function classifyFetchError(error62, code2) {
|
|
|
43558
43890
|
|
|
43559
43891
|
// node_modules/@fetchproxy/server/dist/classify-bridge-error.js
|
|
43560
43892
|
function classifyBridgeError(err) {
|
|
43561
|
-
if (err instanceof FetchproxyHelloRejectedError)
|
|
43562
|
-
return "hello_rejected";
|
|
43893
|
+
if (err instanceof FetchproxyHelloRejectedError) {
|
|
43894
|
+
return err.retryable ? "awaiting_approval" : "hello_rejected";
|
|
43895
|
+
}
|
|
43563
43896
|
if (err instanceof FetchproxySessionNotReadyError)
|
|
43564
43897
|
return "session_not_ready";
|
|
43565
43898
|
if (err instanceof FetchproxyTimeoutError)
|
|
@@ -46330,7 +46663,7 @@ async function loginWithPassword(username, password) {
|
|
|
46330
46663
|
// package.json
|
|
46331
46664
|
var package_default = {
|
|
46332
46665
|
name: "ofw-mcp",
|
|
46333
|
-
version: "2.20.
|
|
46666
|
+
version: "2.20.3",
|
|
46334
46667
|
license: "MIT",
|
|
46335
46668
|
mcpName: "io.github.chrischall/ofw-mcp",
|
|
46336
46669
|
description: "OurFamilyWizard MCP server for Claude \u2014 developed and maintained by AI (Claude Code)",
|
|
@@ -46364,14 +46697,14 @@ var package_default = {
|
|
|
46364
46697
|
typecheck: "tsc -p tsconfig.json --noEmit"
|
|
46365
46698
|
},
|
|
46366
46699
|
dependencies: {
|
|
46367
|
-
"@chrischall/mcp-utils": "^2.
|
|
46368
|
-
"@fetchproxy/bootstrap": "^3.
|
|
46369
|
-
"@modelcontextprotocol/server": "^2.
|
|
46700
|
+
"@chrischall/mcp-utils": "^2.15.0",
|
|
46701
|
+
"@fetchproxy/bootstrap": "^3.6.0",
|
|
46702
|
+
"@modelcontextprotocol/server": "^2.3.0",
|
|
46370
46703
|
dotenv: "^18.0.0",
|
|
46371
46704
|
zod: "^4.6.5"
|
|
46372
46705
|
},
|
|
46373
46706
|
devDependencies: {
|
|
46374
|
-
"@modelcontextprotocol/client": "^2.
|
|
46707
|
+
"@modelcontextprotocol/client": "^2.3.0",
|
|
46375
46708
|
"@types/node": "^26.0.0",
|
|
46376
46709
|
"@vitest/coverage-v8": "^5.0.0",
|
|
46377
46710
|
esbuild: "^0.28.0",
|
|
@@ -46519,10 +46852,10 @@ var OFW_REFRESH_SENTINEL = "ofw";
|
|
|
46519
46852
|
async function throwIfEdgeBlocked(response, method, path) {
|
|
46520
46853
|
if (response.ok) return;
|
|
46521
46854
|
let edge = detectEdgeBlock({ headers: response.headers, status: response.status });
|
|
46522
|
-
if (edge === null && response.status === 429 && !/json/i.test(response.headers.get("content-type") ?? "")) {
|
|
46855
|
+
if (edge === null && (response.status === 401 || response.status === 429) && !/json/i.test(response.headers.get("content-type") ?? "")) {
|
|
46523
46856
|
let body = "";
|
|
46524
46857
|
try {
|
|
46525
|
-
body = await response.clone().text();
|
|
46858
|
+
body = await (response.status === 401 ? response.clone() : response).text();
|
|
46526
46859
|
} catch {
|
|
46527
46860
|
}
|
|
46528
46861
|
edge = detectEdgeBlock({ body, headers: response.headers, status: response.status });
|
|
@@ -46585,63 +46918,73 @@ var OFWClient = class {
|
|
|
46585
46918
|
return this.tokenManager;
|
|
46586
46919
|
}
|
|
46587
46920
|
async request(method, path, body) {
|
|
46588
|
-
|
|
46589
|
-
|
|
46590
|
-
|
|
46591
|
-
|
|
46592
|
-
|
|
46593
|
-
|
|
46921
|
+
return this.fetchAuthed(method, path, body, "application/json", async (response) => {
|
|
46922
|
+
const text = await response.text();
|
|
46923
|
+
if (debugLogEnabled()) {
|
|
46924
|
+
console.error(`[ofw-debug] response body: ${text || "<empty>"}`);
|
|
46925
|
+
}
|
|
46926
|
+
return text ? JSON.parse(text) : null;
|
|
46927
|
+
});
|
|
46594
46928
|
}
|
|
46595
46929
|
/** Like `request`, but returns the raw bytes plus Content-Type/-Disposition metadata. */
|
|
46596
46930
|
async requestBinary(method, path) {
|
|
46597
|
-
|
|
46598
|
-
return {
|
|
46931
|
+
return this.fetchAuthed(method, path, void 0, "application/octet-stream", async (response) => ({
|
|
46599
46932
|
body: Buffer.from(await response.arrayBuffer()),
|
|
46600
46933
|
contentType: response.headers.get("content-type"),
|
|
46601
46934
|
suggestedFileName: parseContentDispositionFilename(response.headers.get("content-disposition") ?? "") ?? null
|
|
46602
|
-
};
|
|
46935
|
+
}));
|
|
46603
46936
|
}
|
|
46604
46937
|
// Authenticated fetch for both JSON and binary callers. Auth (proactive
|
|
46605
46938
|
// refresh inside the skew window + one 401-replay, guarded against a
|
|
46606
46939
|
// double-refresh under concurrency) is delegated to the shared TokenManager's
|
|
46607
46940
|
// `withAuth`. The 429 wait-and-replay and the non-2xx → throw remain here.
|
|
46608
|
-
async fetchAuthed(method, path, body, accept) {
|
|
46941
|
+
async fetchAuthed(method, path, body, accept, consume) {
|
|
46609
46942
|
let attempt = 0;
|
|
46610
|
-
let
|
|
46611
|
-
|
|
46612
|
-
|
|
46613
|
-
|
|
46943
|
+
let result;
|
|
46944
|
+
const call = async (retry) => {
|
|
46945
|
+
let authAttempt = 0;
|
|
46946
|
+
return this.getTokenManager().withAuth((token) => {
|
|
46947
|
+
const firstAuthAttempt = authAttempt++ === 0;
|
|
46948
|
+
return this.fetchOnce(method, path, body, accept, token, async (response2) => {
|
|
46949
|
+
await throwIfEdgeBlocked(response2, method, path);
|
|
46950
|
+
if (response2.status === 401 && firstAuthAttempt) {
|
|
46951
|
+
await releaseBody(response2);
|
|
46952
|
+
return;
|
|
46953
|
+
}
|
|
46954
|
+
if (response2.status === 429) {
|
|
46955
|
+
await releaseBody(response2);
|
|
46956
|
+
return;
|
|
46957
|
+
}
|
|
46958
|
+
if (!response2.ok) {
|
|
46959
|
+
const errorBody = await response2.text();
|
|
46960
|
+
const edge = detectEdgeBlock({ body: errorBody, headers: response2.headers, status: response2.status });
|
|
46961
|
+
if (edge !== null) {
|
|
46962
|
+
throw new EdgeBlockedError(response2.status, edge.vendor, { service: "OurFamilyWizard", method, path });
|
|
46963
|
+
}
|
|
46964
|
+
const safeBody = redactSecrets(errorBody).replace(/\s+/g, " ").trim().slice(0, 4e3);
|
|
46965
|
+
throw new Error(
|
|
46966
|
+
`OFW API error: ${response2.status} ${response2.statusText} for ${method} ${path}` + (safeBody ? ` \u2014 ${safeBody}` : "")
|
|
46967
|
+
);
|
|
46968
|
+
}
|
|
46969
|
+
result = await consume(response2);
|
|
46970
|
+
}, retry || attempt++ > 0);
|
|
46971
|
+
});
|
|
46972
|
+
};
|
|
46973
|
+
const response = await call(false);
|
|
46614
46974
|
if (response.status === 429) {
|
|
46615
|
-
await releaseBody(response);
|
|
46616
46975
|
await new Promise((r) => setTimeout(r, 2e3));
|
|
46617
|
-
|
|
46618
|
-
(token) => this.fetchOnce(method, path, body, accept, token, true)
|
|
46619
|
-
);
|
|
46620
|
-
await throwIfEdgeBlocked(response, method, path);
|
|
46621
|
-
if (response.status === 429) {
|
|
46622
|
-
await releaseBody(response);
|
|
46976
|
+
if ((await call(true)).status === 429) {
|
|
46623
46977
|
throw new Error("Rate limited by OFW API");
|
|
46624
46978
|
}
|
|
46625
46979
|
}
|
|
46626
|
-
|
|
46627
|
-
const errorBody = await response.text();
|
|
46628
|
-
const edge = detectEdgeBlock({ body: errorBody, headers: response.headers, status: response.status });
|
|
46629
|
-
if (edge !== null) {
|
|
46630
|
-
throw new EdgeBlockedError(response.status, edge.vendor, { service: "OurFamilyWizard", method, path });
|
|
46631
|
-
}
|
|
46632
|
-
const safeBody = redactSecrets(errorBody).replace(/\s+/g, " ").trim().slice(0, 4e3);
|
|
46633
|
-
throw new Error(
|
|
46634
|
-
`OFW API error: ${response.status} ${response.statusText} for ${method} ${path}` + (safeBody ? ` \u2014 ${safeBody}` : "")
|
|
46635
|
-
);
|
|
46636
|
-
}
|
|
46637
|
-
return response;
|
|
46980
|
+
return result;
|
|
46638
46981
|
}
|
|
46639
46982
|
// A single OFW API fetch with the bearer token supplied by `withAuth`.
|
|
46640
46983
|
// Carries the per-request timeout (AbortController + setTimeout so vitest
|
|
46641
46984
|
// fake timers can drive it and we attach a clear error message) and the
|
|
46642
|
-
// OFW_DEBUG_LOG instrumentation.
|
|
46643
|
-
//
|
|
46644
|
-
async fetchOnce(method, path, body, accept, token, isRetry = false) {
|
|
46985
|
+
// OFW_DEBUG_LOG instrumentation. The handler completes body consumption or
|
|
46986
|
+
// release before this attempt returns its Response to `withAuth`.
|
|
46987
|
+
async fetchOnce(method, path, body, accept, token, handleResponse, isRetry = false) {
|
|
46645
46988
|
const isFormData = body instanceof FormData;
|
|
46646
46989
|
const headers = {
|
|
46647
46990
|
...OFW_PROTOCOL_HEADERS,
|
|
@@ -46661,22 +47004,31 @@ var OFWClient = class {
|
|
|
46661
47004
|
const ac = new AbortController();
|
|
46662
47005
|
const timer = setTimeout(() => ac.abort(), timeoutMs);
|
|
46663
47006
|
const startedAt = Date.now();
|
|
46664
|
-
|
|
47007
|
+
const signal = withAmbientCancellation(ac.signal);
|
|
47008
|
+
let onAbort;
|
|
47009
|
+
const aborted2 = new Promise((_resolve, reject) => {
|
|
47010
|
+
onAbort = () => reject(signal.reason);
|
|
47011
|
+
if (signal.aborted) onAbort();
|
|
47012
|
+
else signal.addEventListener("abort", onAbort, { once: true });
|
|
47013
|
+
});
|
|
46665
47014
|
try {
|
|
46666
|
-
|
|
46667
|
-
|
|
46668
|
-
|
|
46669
|
-
|
|
46670
|
-
|
|
46671
|
-
|
|
46672
|
-
|
|
46673
|
-
|
|
46674
|
-
|
|
46675
|
-
|
|
46676
|
-
|
|
46677
|
-
|
|
46678
|
-
|
|
46679
|
-
|
|
47015
|
+
return await Promise.race([aborted2, (async () => {
|
|
47016
|
+
signal.throwIfAborted();
|
|
47017
|
+
const response = await fetch(url2, {
|
|
47018
|
+
method,
|
|
47019
|
+
headers,
|
|
47020
|
+
// The caller's cancellation and our timeout both cover headers,
|
|
47021
|
+
// body reads and releases; only our controller diagnoses slowness.
|
|
47022
|
+
signal,
|
|
47023
|
+
...body !== void 0 ? { body: isFormData ? body : JSON.stringify(body) } : {}
|
|
47024
|
+
});
|
|
47025
|
+
if (debugLogEnabled()) {
|
|
47026
|
+
console.error(`[ofw-debug] \u2190 ${response.status} ${response.statusText} (${Date.now() - startedAt}ms)`);
|
|
47027
|
+
}
|
|
47028
|
+
await handleResponse(response);
|
|
47029
|
+
signal.throwIfAborted();
|
|
47030
|
+
return response;
|
|
47031
|
+
})()]);
|
|
46680
47032
|
} catch (err) {
|
|
46681
47033
|
const elapsed = Date.now() - startedAt;
|
|
46682
47034
|
if (ac.signal.aborted) {
|
|
@@ -46693,11 +47045,8 @@ var OFWClient = class {
|
|
|
46693
47045
|
throw err;
|
|
46694
47046
|
} finally {
|
|
46695
47047
|
clearTimeout(timer);
|
|
47048
|
+
signal.removeEventListener("abort", onAbort);
|
|
46696
47049
|
}
|
|
46697
|
-
if (debugLogEnabled()) {
|
|
46698
|
-
console.error(`[ofw-debug] \u2190 ${response.status} ${response.statusText} (${Date.now() - startedAt}ms)`);
|
|
46699
|
-
}
|
|
46700
|
-
return response;
|
|
46701
47050
|
}
|
|
46702
47051
|
};
|
|
46703
47052
|
var client = new OFWClient();
|
|
@@ -50942,7 +51291,7 @@ function registerCalendarTools(server, client2) {
|
|
|
50942
51291
|
});
|
|
50943
51292
|
});
|
|
50944
51293
|
if (allowWrites) server.registerTool("ofw_update_event", {
|
|
50945
|
-
description: "Update an existing OurFamilyWizard calendar event. Fetches the event, applies the given changes, and writes the merged result back (OFW has no partial update). A change to an event the co-parent can see (shared before or after the change) is confirmed first; the confirmation is bound to the event exactly as read, so if it changes on OFW in between (say the co-parent edited it) the update is refused instead of overwriting their edit. " + CONFIRM_NOTE,
|
|
51294
|
+
description: "Update an existing OurFamilyWizard calendar event. Fetches the event, applies the given changes, and writes the merged result back (OFW has no partial update). A change to an event the co-parent can see (shared before or after the change) is confirmed first; the confirmation is bound to the event exactly as read, so if it changes on OFW in between (say the co-parent edited it) the update is refused instead of overwriting their edit. If the write fails without a definitive answer, or lands but cannot be re-read to confirm it, the result is EVENT_UNCONFIRMED: the change may already be on OFW, so do NOT retry until ofw_list_events shows whether it landed. " + CONFIRM_NOTE,
|
|
50946
51295
|
annotations: { destructiveHint: true },
|
|
50947
51296
|
inputSchema: external_exports.object({
|
|
50948
51297
|
eventId: external_exports.string().describe("Event id \u2014 the `id` from ofw_list_events / eventRecurrenceId from ofw_create_event"),
|
|
@@ -50991,13 +51340,30 @@ function registerCalendarTools(server, client2) {
|
|
|
50991
51340
|
});
|
|
50992
51341
|
if (gate) return gate;
|
|
50993
51342
|
}
|
|
50994
|
-
|
|
50995
|
-
|
|
50996
|
-
|
|
50997
|
-
|
|
51343
|
+
try {
|
|
51344
|
+
await requestWrite(client2, "PUT", `/pub/v3/events/${id}`, payload);
|
|
51345
|
+
} catch (e) {
|
|
51346
|
+
if (!(e instanceof UnconfirmedWriteError)) throw e;
|
|
51347
|
+
return unconfirmedWriteResponse(e, {
|
|
51348
|
+
result: "EVENT_UNCONFIRMED",
|
|
51349
|
+
what: `update event ${eventId}`,
|
|
51350
|
+
checkWith: "ofw_list_events for this event and date range"
|
|
51351
|
+
});
|
|
51352
|
+
}
|
|
51353
|
+
try {
|
|
51354
|
+
const rawAfter = await client2.request("GET", `/pub/v3/events/${id}`);
|
|
51355
|
+
const event = parseLenient(eventDetailSchema, rawAfter, { label: "ofw-mcp", context: `GET /pub/v3/events/${eventId} (post-update)`, mode: "strict" });
|
|
51356
|
+
return jsonResponse({ note: "Event updated; returning re-fetched event state.", event });
|
|
51357
|
+
} catch (e) {
|
|
51358
|
+
return unconfirmedWriteResponse(new UnconfirmedWriteError(null, e), {
|
|
51359
|
+
result: "EVENT_UNCONFIRMED",
|
|
51360
|
+
what: `verify the update to event ${eventId}`,
|
|
51361
|
+
checkWith: "ofw_list_events for this event and date range"
|
|
51362
|
+
});
|
|
51363
|
+
}
|
|
50998
51364
|
});
|
|
50999
51365
|
if (allowWrites) server.registerTool("ofw_delete_event", {
|
|
51000
|
-
description: "Delete an OurFamilyWizard calendar event. Reads the event first; deleting one the co-parent can see is confirmed first, with a preview of exactly which event (title, date, time) is removed, and is refused if the event changed on OFW after that preview. " + CONFIRM_NOTE,
|
|
51366
|
+
description: "Delete an OurFamilyWizard calendar event. Reads the event first; deleting one the co-parent can see is confirmed first, with a preview of exactly which event (title, date, time) is removed, and is refused if the event changed on OFW after that preview. If the request fails without a definitive answer the result is EVENT_UNCONFIRMED: the event may already be gone, so do NOT retry until ofw_list_events shows whether it is still there. " + CONFIRM_NOTE,
|
|
51001
51367
|
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
|
|
51002
51368
|
inputSchema: external_exports.object({
|
|
51003
51369
|
eventId: external_exports.string().describe("Event id \u2014 the `id` from ofw_list_events / eventRecurrenceId from ofw_create_event"),
|
|
@@ -51030,7 +51396,16 @@ function registerCalendarTools(server, client2) {
|
|
|
51030
51396
|
});
|
|
51031
51397
|
if (gate) return gate;
|
|
51032
51398
|
}
|
|
51033
|
-
|
|
51399
|
+
try {
|
|
51400
|
+
await requestWrite(client2, "DELETE", `/pub/v3/events/${id}?includeFuture=${includeFuture}`);
|
|
51401
|
+
} catch (e) {
|
|
51402
|
+
if (!(e instanceof UnconfirmedWriteError)) throw e;
|
|
51403
|
+
return unconfirmedWriteResponse(e, {
|
|
51404
|
+
result: "EVENT_UNCONFIRMED",
|
|
51405
|
+
what: `delete event ${args.eventId}${includeFuture ? " and its future occurrences" : ""}`,
|
|
51406
|
+
checkWith: "ofw_list_events for this event and date range (including future occurrences if requested)"
|
|
51407
|
+
});
|
|
51408
|
+
}
|
|
51034
51409
|
return textResponse(`Event ${args.eventId} ("${current.title}") deleted`);
|
|
51035
51410
|
});
|
|
51036
51411
|
}
|
|
@@ -52206,7 +52581,7 @@ var tools = selectToolRegistrars({
|
|
|
52206
52581
|
});
|
|
52207
52582
|
await runMcp({
|
|
52208
52583
|
name: "ofw",
|
|
52209
|
-
version: "2.20.
|
|
52584
|
+
version: "2.20.3",
|
|
52210
52585
|
// x-release-please-version
|
|
52211
52586
|
deps: client,
|
|
52212
52587
|
tools,
|
|
@@ -52214,7 +52589,7 @@ await runMcp({
|
|
|
52214
52589
|
});
|
|
52215
52590
|
/*! Bundled license information:
|
|
52216
52591
|
|
|
52217
|
-
@modelcontextprotocol/server/dist/src-
|
|
52592
|
+
@modelcontextprotocol/server/dist/src-Cqbh3MYc.mjs:
|
|
52218
52593
|
(*!
|
|
52219
52594
|
* content-type
|
|
52220
52595
|
* Copyright(c) 2015 Douglas Christopher Wilson
|