honeybook-mcp 1.2.3 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "metadata": {
9
9
  "description": "HoneyBook client-portal tools for Claude Code",
10
- "version": "1.2.3"
10
+ "version": "1.2.5"
11
11
  },
12
12
  "plugins": [
13
13
  {
@@ -15,7 +15,7 @@
15
15
  "displayName": "HoneyBook",
16
16
  "source": "./",
17
17
  "description": "HoneyBook client-portal MCP for Claude — view wedding-vendor contracts and invoices via MCP",
18
- "version": "1.2.3",
18
+ "version": "1.2.5",
19
19
  "author": {
20
20
  "name": "Chris Chall"
21
21
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "honeybook",
3
3
  "displayName": "HoneyBook",
4
- "version": "1.2.3",
4
+ "version": "1.2.5",
5
5
  "description": "HoneyBook client-portal MCP for Claude — view wedding-vendor contracts and invoices via MCP",
6
6
  "author": {
7
7
  "name": "Chris Chall",
package/README.md CHANGED
@@ -160,7 +160,8 @@ Until you confirm it only previews the recipients, subject and body — see [Con
160
160
 
161
161
  | variable | default | |
162
162
  |---|---|---|
163
- | `MCP_CONFIRM_MODE` | `ask-user` | What a write does on a client that cannot show a confirmation prompt (claude.ai, Claude Desktop). `ask-user`: two steps — the first call does nothing and returns a preview plus a token, and the model must get your approval in chat before calling again with it. `auto`: the same two steps, but the model may use the token after reviewing the preview itself. `refuse`: writes are refused on such clients. A client that can show prompts (Claude Code) always gets the real prompt. An unrecognised value is treated as `refuse`. |
163
+ | `MCP_CONFIRM_MODE` | `ask-user` | What a write does on a client that cannot show a confirmation prompt (claude.ai, Claude Desktop). `ask-user`: two steps — the first call does nothing and returns a preview plus a token, and the model must get your approval in chat before calling again with it. `auto`: the same two steps, but the model may use the token after reviewing the preview itself. `refuse`: writes are refused on such clients. A client that can show prompts (Claude Code) always gets the real prompt, unless `MCP_CONFIRM_ELICITATION=off`. An unrecognised value is treated as `refuse`. |
164
+ | `MCP_CONFIRM_ELICITATION` | `on` | `off` never sends a confirmation prompt, so every client gets the `MCP_CONFIRM_MODE` path. Set it for a client that declares it can show prompts but never does (the gated call hangs — opencode 2.0.x). Any other value stays `on`, with a stderr warning. |
164
165
  | `MCP_CONFIRM_TTL_SECONDS` | `600` | How long a token stays valid. |
165
166
  | `MCP_CONFIRM_SECRET` | random per process | Signing key; set it only if tokens must survive a server restart. |
166
167
 
package/dist/bundle.js CHANGED
@@ -20692,8 +20692,8 @@ var require_schemas2 = __commonJS({
20692
20692
  return core._stringFormat(exports.ZodCustomStringFormat, "currency_code", regexes.currencyCode, _params);
20693
20693
  }
20694
20694
  function hash2(alg, params) {
20695
- const enc6 = params?.enc ?? "hex";
20696
- const format = `${alg}_${enc6}`;
20695
+ const enc7 = params?.enc ?? "hex";
20696
+ const format = `${alg}_${enc7}`;
20697
20697
  const regex = core.regexes[format];
20698
20698
  if (!regex)
20699
20699
  throw new Error(`Unrecognized hash format: ${format}`);
@@ -25603,11 +25603,23 @@ var require_websocket = __commonJS({
25603
25603
  this._isServer = false;
25604
25604
  this._redirects = 0;
25605
25605
  if (protocols === void 0) {
25606
- protocols = [];
25606
+ if (!options || options.protocols === void 0) {
25607
+ protocols = [];
25608
+ } else if (Array.isArray(options.protocols)) {
25609
+ protocols = options.protocols;
25610
+ } else {
25611
+ protocols = [options.protocols];
25612
+ }
25607
25613
  } else if (!Array.isArray(protocols)) {
25608
25614
  if (typeof protocols === "object" && protocols !== null) {
25609
25615
  options = protocols;
25610
- protocols = [];
25616
+ if (options.protocols === void 0) {
25617
+ protocols = [];
25618
+ } else if (Array.isArray(options.protocols)) {
25619
+ protocols = options.protocols;
25620
+ } else {
25621
+ protocols = [options.protocols];
25622
+ }
25611
25623
  } else {
25612
25624
  protocols = [protocols];
25613
25625
  }
@@ -25804,7 +25816,6 @@ var require_websocket = __commonJS({
25804
25816
  }
25805
25817
  return;
25806
25818
  }
25807
- this._readyState = _WebSocket.CLOSING;
25808
25819
  this._sender.close(code2, data, !this._isServer, (err) => {
25809
25820
  if (err) return;
25810
25821
  this._closeFrameSent = true;
@@ -25812,6 +25823,7 @@ var require_websocket = __commonJS({
25812
25823
  this._socket.end();
25813
25824
  }
25814
25825
  });
25826
+ this._readyState = _WebSocket.CLOSING;
25815
25827
  setCloseTimer(this);
25816
25828
  }
25817
25829
  /**
@@ -26036,6 +26048,7 @@ var require_websocket = __commonJS({
26036
26048
  socketPath: void 0,
26037
26049
  hostname: void 0,
26038
26050
  protocol: void 0,
26051
+ protocols: void 0,
26039
26052
  timeout: void 0,
26040
26053
  method: "GET",
26041
26054
  host: void 0,
@@ -28038,7 +28051,7 @@ var OAuthTokenRevocationRequestSchema = z.object({
28038
28051
  token_type_hint: z.string().optional()
28039
28052
  }).strip();
28040
28053
 
28041
- // node_modules/@modelcontextprotocol/server/dist/src-BHSMhZ_W.mjs
28054
+ // node_modules/@modelcontextprotocol/server/dist/src-Cqbh3MYc.mjs
28042
28055
  var z2 = __toESM(require_v4(), 1);
28043
28056
  var BRANDS = /* @__PURE__ */ Symbol.for("mcp.sdk.errorBrands");
28044
28057
  function stampErrorBrands(instance, ctor) {
@@ -30282,7 +30295,8 @@ function build() {
30282
30295
  ListResourceTemplatesResultResponseSchema: wireResultResponse(ListResourceTemplatesResultSchema$1),
30283
30296
  ReadResourceResultResponseSchema: wireResultResponse(z2.union([ReadResourceResultSchema$1, InputRequiredResultSchema])),
30284
30297
  CompleteResultResponseSchema: wireResultResponse(CompleteResultSchema$1),
30285
- DiscoverResultResponseSchema: wireResultResponse(DiscoverResultSchema$1)
30298
+ DiscoverResultResponseSchema: wireResultResponse(DiscoverResultSchema$1),
30299
+ SubscriptionsListenResultResponseSchema: wireResultResponse(SubscriptionsListenResultSchema$1)
30286
30300
  };
30287
30301
  }
30288
30302
  var memo;
@@ -30790,6 +30804,9 @@ function isSpecRequestMethod(method) {
30790
30804
  function isSpecNotificationMethod(method) {
30791
30805
  return ALL_CODECS.some((codec2) => codec2.hasNotificationMethod(method));
30792
30806
  }
30807
+ function isExtensionReusedRequestMethod(method) {
30808
+ return method === "tasks/get" || method === "tasks/cancel";
30809
+ }
30793
30810
  var ALL_CODECS = [rev2025Codec, rev2026Codec];
30794
30811
  function isPlainObject$3(value) {
30795
30812
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -31798,6 +31815,8 @@ var Protocol = class {
31798
31815
  _transport;
31799
31816
  _requestMessageId = 0;
31800
31817
  _requestHandlers = /* @__PURE__ */ new Map();
31818
+ /** Methods registered with an explicit schema; the era gate in `_onrequest` reads it for the Tasks extension names. */
31819
+ _customSchemaRequestMethods = /* @__PURE__ */ new Set();
31801
31820
  _requestHandlerAbortControllers = /* @__PURE__ */ new Map();
31802
31821
  _notificationHandlers = /* @__PURE__ */ new Map();
31803
31822
  _responseHandlers = /* @__PURE__ */ new Map();
@@ -32081,7 +32100,7 @@ var Protocol = class {
32081
32100
  return;
32082
32101
  }
32083
32102
  }
32084
- if (isSpecRequestMethod(request.method) && !codec2.hasRequestMethod(request.method)) {
32103
+ if (isSpecRequestMethod(request.method) && !codec2.hasRequestMethod(request.method) && !(isExtensionReusedRequestMethod(request.method) && this._customSchemaRequestMethods.has(request.method))) {
32085
32104
  sendErrorResponse(ProtocolErrorCode.MethodNotFound, "Method not found");
32086
32105
  return;
32087
32106
  }
@@ -32214,8 +32233,11 @@ var Protocol = class {
32214
32233
  }
32215
32234
  request(request, schemaOrOptions, maybeOptions) {
32216
32235
  const codec2 = this._resolveOutboundCodec(request.method);
32236
+ if (isStandardSchema(schemaOrOptions)) {
32237
+ if (!isExtensionReusedRequestMethod(request.method)) this._assertOutboundRequestInEra(codec2, request.method);
32238
+ return this._requestWithSchemaViaCodec(codec2, request, schemaOrOptions, maybeOptions);
32239
+ }
32217
32240
  this._assertOutboundRequestInEra(codec2, request.method);
32218
- if (isStandardSchema(schemaOrOptions)) return this._requestWithSchemaViaCodec(codec2, request, schemaOrOptions, maybeOptions);
32219
32241
  const validate2 = codecResultValidator(codec2, request.method);
32220
32242
  if (validate2 === void 0) throw new TypeError(`'${request.method}' is not a spec method; pass a result schema as the second argument to request().`);
32221
32243
  return this._requestWithSchemaViaCodec(codec2, request, validate2, schemaOrOptions);
@@ -32459,6 +32481,8 @@ var Protocol = class {
32459
32481
  return maybeHandler(parsed.data, ctx);
32460
32482
  };
32461
32483
  else throw new TypeError("setRequestHandler: handler is required");
32484
+ if (typeof schemasOrHandler === "function") this._customSchemaRequestMethods.delete(method);
32485
+ else this._customSchemaRequestMethods.add(method);
32462
32486
  this._requestHandlers.set(method, this._wrapHandler(method, stored));
32463
32487
  }
32464
32488
  /**
@@ -32488,6 +32512,7 @@ var Protocol = class {
32488
32512
  */
32489
32513
  removeRequestHandler(method) {
32490
32514
  this._requestHandlers.delete(method);
32515
+ this._customSchemaRequestMethods.delete(method);
32491
32516
  }
32492
32517
  /**
32493
32518
  * Asserts that a request handler has not already been set for the given method, in preparation for a new one being automatically installed.
@@ -39730,7 +39755,7 @@ var Ajv = import_ajv.Ajv;
39730
39755
  // node_modules/@modelcontextprotocol/server/dist/shimsNode.mjs
39731
39756
  import process2 from "node:process";
39732
39757
 
39733
- // node_modules/@modelcontextprotocol/server/dist/mcp-DYuW2ZSs.mjs
39758
+ // node_modules/@modelcontextprotocol/server/dist/mcp-DIH4cS6P.mjs
39734
39759
  var COMPLETABLE_SYMBOL = /* @__PURE__ */ Symbol.for("mcp.completable");
39735
39760
  function isCompletable(schema) {
39736
39761
  return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
@@ -39795,7 +39820,7 @@ var StdioListenRouter = class {
39795
39820
  _serverCapabilities;
39796
39821
  /**
39797
39822
  * The serving instance's identity, stamped onto the graceful-close
39798
- * results' `_meta` (the spec's `SubscriptionsListenResultMeta` extends
39823
+ * results' `_meta` (the spec's `SubscriptionsListenResultMetaObject` extends
39799
39824
  * `ResultMetaObject`). Handed over together with the capabilities.
39800
39825
  */
39801
39826
  _serverInfo;
@@ -40127,6 +40152,11 @@ var Server = class extends Protocol {
40127
40152
  if (modernProtocolVersions(this._supportedProtocolVersions).length > 0) this.setRequestHandler("server/discover", () => this._ondiscover());
40128
40153
  if (this._capabilities.logging) this._registerLoggingHandler();
40129
40154
  }
40155
+ /** Attaches to the given transport; rejects while this instance is connected to another one. */
40156
+ async connect(transport) {
40157
+ 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.");
40158
+ await super.connect(transport);
40159
+ }
40130
40160
  /**
40131
40161
  * Registers the built-in `logging/setLevel` request handler.
40132
40162
  *
@@ -40680,21 +40710,41 @@ var Server = class extends Protocol {
40680
40710
  function discoverAdvertisedCapabilities(capabilities) {
40681
40711
  return { ...capabilities };
40682
40712
  }
40713
+ function toolInputElementCount(value, max) {
40714
+ let count = 0;
40715
+ const stack = [value];
40716
+ while (stack.length > 0) {
40717
+ const node2 = stack.pop();
40718
+ if (node2 === null || typeof node2 !== "object") continue;
40719
+ if (Array.isArray(node2)) for (const child of node2) {
40720
+ if (++count > max) return count;
40721
+ if (child !== null && typeof child === "object") stack.push(child);
40722
+ }
40723
+ else for (const key in node2) {
40724
+ if (!Object.prototype.hasOwnProperty.call(node2, key)) continue;
40725
+ if (++count > max) return count;
40726
+ const child = node2[key];
40727
+ if (child !== null && typeof child === "object") stack.push(child);
40728
+ }
40729
+ }
40730
+ return count;
40731
+ }
40732
+ function resolveMaxToolInputElements(value) {
40733
+ if (value === void 0 || value === Infinity) return void 0;
40734
+ 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)}`);
40735
+ return value;
40736
+ }
40683
40737
  var McpServer = class {
40684
40738
  /**
40685
40739
  * The underlying {@linkcode Server} instance, useful for advanced operations like sending notifications.
40686
40740
  */
40687
40741
  server;
40742
+ _maxToolInputElements;
40688
40743
  _registeredResources = {};
40689
40744
  _registeredResourceTemplates = {};
40690
40745
  _registeredTools = {};
40691
40746
  _registeredPrompts = {};
40692
- /**
40693
- * Per-tool JSON-converted `inputSchema`, memoized so the SEP-2243
40694
- * registration-time scan and the pre-dispatch validation step share one
40695
- * conversion instead of paying it twice per request under the
40696
- * per-request-factory `createMcpHandler` model.
40697
- */
40747
+ /** Per-tool JSON-converted `inputSchema`, filled on first use by `toolInputSchemaJson()`. */
40698
40748
  _toolInputSchemaJson = {};
40699
40749
  /**
40700
40750
  * The JSON-serialized `inputSchema` of a registered tool, or `undefined`
@@ -40719,6 +40769,7 @@ var McpServer = class {
40719
40769
  }
40720
40770
  constructor(serverInfo, options) {
40721
40771
  this.server = new Server(serverInfo, options);
40772
+ this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
40722
40773
  if (options?.capabilities?.tools) this.setToolRequestHandlers();
40723
40774
  if (options?.capabilities?.resources) this.setResourceRequestHandlers();
40724
40775
  if (options?.capabilities?.prompts) this.setPromptRequestHandlers();
@@ -40791,7 +40842,7 @@ var McpServer = class {
40791
40842
  name,
40792
40843
  title: tool.title,
40793
40844
  description: tool.description,
40794
- inputSchema: tool.inputSchema ? standardSchemaToJsonSchema(tool.inputSchema, "input") : EMPTY_OBJECT_JSON_SCHEMA,
40845
+ inputSchema: tool.inputSchema ? convertListedInputSchema(name, tool.inputSchema) : EMPTY_OBJECT_JSON_SCHEMA,
40795
40846
  annotations: tool.annotations,
40796
40847
  icons: tool.icons,
40797
40848
  execution: tool.execution,
@@ -40836,6 +40887,7 @@ var McpServer = class {
40836
40887
  * Validates tool input arguments against the tool's input schema.
40837
40888
  */
40838
40889
  async validateToolInput(tool, args, toolName) {
40890
+ 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`);
40839
40891
  if (!tool.inputSchema) return;
40840
40892
  const parseResult = await validateStandardSchema(tool.inputSchema, args ?? {});
40841
40893
  if (!parseResult.success) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Input validation error: Invalid arguments for tool ${toolName}: ${parseResult.error}`);
@@ -41110,20 +41162,19 @@ var McpServer = class {
41110
41162
  }
41111
41163
  _createRegisteredTool(name, title, description, inputSchema, outputSchema, annotations, icons, execution, scopeChallenge, _meta, handler) {
41112
41164
  validateAndWarnToolName(name);
41113
- if (inputSchema !== void 0) try {
41114
- const json2 = standardSchemaToJsonSchema(inputSchema, "input");
41115
- this._toolInputSchemaJson[name] = json2;
41116
- const scan = scanXMcpHeaderDeclarations(json2);
41117
- 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}`);
41118
- } catch {
41119
- }
41120
41165
  let currentHandler = handler;
41166
+ let outputSchemaJson;
41121
41167
  const registeredTool = {
41122
41168
  title,
41123
41169
  description,
41124
41170
  inputSchema,
41125
41171
  outputSchema,
41126
- outputSchemaJson: convertOutputSchemaJson(outputSchema),
41172
+ get outputSchemaJson() {
41173
+ return outputSchemaJson ??= convertOutputSchemaJson(registeredTool.outputSchema);
41174
+ },
41175
+ set outputSchemaJson(value) {
41176
+ outputSchemaJson = value;
41177
+ },
41127
41178
  annotations,
41128
41179
  icons,
41129
41180
  execution,
@@ -41250,6 +41301,12 @@ var EMPTY_OBJECT_JSON_SCHEMA = {
41250
41301
  type: "object",
41251
41302
  properties: {}
41252
41303
  };
41304
+ function convertListedInputSchema(name, inputSchema) {
41305
+ const json2 = standardSchemaToJsonSchema(inputSchema, "input");
41306
+ const scan = scanXMcpHeaderDeclarations(json2);
41307
+ 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}`);
41308
+ return json2;
41309
+ }
41253
41310
  function convertOutputSchemaJson(outputSchema) {
41254
41311
  if (outputSchema === void 0) return void 0;
41255
41312
  try {
@@ -41262,7 +41319,7 @@ function createPromptHandler(name, argsSchema, callback) {
41262
41319
  if (argsSchema) {
41263
41320
  const typedCallback = callback;
41264
41321
  return async (args, ctx) => {
41265
- const parseResult = await validateStandardSchema(argsSchema, args);
41322
+ const parseResult = await validateStandardSchema(argsSchema, args ?? {});
41266
41323
  if (!parseResult.success) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Invalid arguments for prompt ${name}: ${parseResult.error}`);
41267
41324
  return typedCallback(parseResult.data, ctx);
41268
41325
  };
@@ -59619,8 +59676,8 @@ function currencyCode2(_params) {
59619
59676
  return _stringFormat(ZodCustomStringFormat, "currency_code", currencyCode, _params);
59620
59677
  }
59621
59678
  function hash(alg, params) {
59622
- const enc6 = params?.enc ?? "hex";
59623
- const format = `${alg}_${enc6}`;
59679
+ const enc7 = params?.enc ?? "hex";
59680
+ const format = `${alg}_${enc7}`;
59624
59681
  const regex = regexes_exports[format];
59625
59682
  if (!regex)
59626
59683
  throw new Error(`Unrecognized hash format: ${format}`);
@@ -61657,6 +61714,7 @@ function escapeKey(key) {
61657
61714
  var DEFAULT_REQUEST_KEY = "confirmation";
61658
61715
  var DEFAULT_CONFIRMATION_LABEL = "Confirm this action should proceed.";
61659
61716
  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";
61717
+ var DISABLED_NOTE = "Nothing was done because confirmation prompts are turned off for this server, and this action is never taken without one";
61660
61718
  var STATE_PREFIX = "mcpu.confirm.v1.";
61661
61719
  function bindingKey(binding) {
61662
61720
  if (binding.ttlSeconds !== void 0 && !(Number.isFinite(binding.ttlSeconds) && binding.ttlSeconds > 0)) {
@@ -61729,6 +61787,15 @@ ${JSON.stringify(preview, null, 2)}`,
61729
61787
  };
61730
61788
  const response = inputResponse(ctx.mcpReq.inputResponses, requestKey);
61731
61789
  const accepted = acceptedContent(ctx.mcpReq.inputResponses, requestKey, confirmationSchema);
61790
+ if (options.elicitation === false) {
61791
+ return textResult({
61792
+ confirmed: false,
61793
+ dispatched: false,
61794
+ action: options.action,
61795
+ reason: "confirmation-unsupported",
61796
+ note: options.unsupportedNote ? `${DISABLED_NOTE}. ${options.unsupportedNote}` : `${DISABLED_NOTE}.`
61797
+ });
61798
+ }
61732
61799
  if (response.kind === "missing") {
61733
61800
  if (callerAcceptsFormElicitation(ctx) === false) {
61734
61801
  return textResult({
@@ -61923,7 +61990,7 @@ async function tokenConfirmation(action, fb) {
61923
61990
  }
61924
61991
  async function requireConfirmationWithFallback(ctx, options) {
61925
61992
  const { tokenFallback, ...confirmation } = options;
61926
- if (tokenFallback && callerAcceptsFormElicitation(ctx) === false) {
61993
+ if (tokenFallback && (options.elicitation === false || callerAcceptsFormElicitation(ctx) === false)) {
61927
61994
  return tokenConfirmation(options.action, tokenFallback);
61928
61995
  }
61929
61996
  return requireConfirmation(ctx, confirmation);
@@ -62074,6 +62141,20 @@ function readConfirmMode(env = process.env) {
62074
62141
  }
62075
62142
  return "refuse";
62076
62143
  }
62144
+ function readConfirmElicitation(env = process.env) {
62145
+ const raw = readEnvVar("MCP_CONFIRM_ELICITATION", { env })?.trim().toLowerCase();
62146
+ if (!raw || raw === "on")
62147
+ return "on";
62148
+ if (raw === "off")
62149
+ return "off";
62150
+ const key = `elicitation:${raw}`;
62151
+ if (!warned.has(key)) {
62152
+ warned.add(key);
62153
+ process.stderr.write(`MCP_CONFIRM_ELICITATION="${raw}" is not one of on, off; treating it as on.
62154
+ `);
62155
+ }
62156
+ return "on";
62157
+ }
62077
62158
  function readConfirmTtl(env) {
62078
62159
  const raw = readEnvVar("MCP_CONFIRM_TTL_SECONDS", { env })?.trim();
62079
62160
  if (!raw)
@@ -62118,6 +62199,7 @@ function spentTokenStoreFromEnv(env = process.env) {
62118
62199
  }
62119
62200
  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.)";
62120
62201
  var REFUSE_HINT = "Set MCP_CONFIRM_MODE=ask-user on the server to allow two-step confirmation instead.";
62202
+ var ELICITATION_OFF_HINT = "MCP_CONFIRM_ELICITATION=off on the server turns confirmation prompts off.";
62121
62203
  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.";
62122
62204
  function boundArgs(args) {
62123
62205
  if (args === null || typeof args !== "object" || Array.isArray(args) || !("confirmToken" in args))
@@ -62131,10 +62213,13 @@ function confirmationFromEnv(options) {
62131
62213
  const spent = callerSpent ?? spentTokenStoreFromEnv(env);
62132
62214
  const mode = readConfirmMode(env);
62133
62215
  const ttlSeconds = readConfirmTtl(env);
62216
+ const elicitationOff = readConfirmElicitation(env) === "off";
62134
62217
  const bound = args === void 0 ? void 0 : boundArgs(args);
62135
- const confirmation = bound === void 0 || rest.binding ? rest : { ...rest, binding: { key: confirmKeyFromEnv(env), args: bound, ttlSeconds: ttlSeconds ?? DEFAULT_TTL_SECONDS2 } };
62218
+ const bindingAdded = bound === void 0 || rest.binding ? rest : { ...rest, binding: { key: confirmKeyFromEnv(env), args: bound, ttlSeconds: ttlSeconds ?? DEFAULT_TTL_SECONDS2 } };
62219
+ const confirmation = elicitationOff ? { ...bindingAdded, elicitation: false } : bindingAdded;
62136
62220
  if (mode === "refuse" || ttlSeconds === void 0) {
62137
- const hint = mode === "refuse" ? REFUSE_HINT : BAD_TTL_HINT;
62221
+ const reason = mode === "refuse" ? REFUSE_HINT : BAD_TTL_HINT;
62222
+ const hint = elicitationOff ? `${ELICITATION_OFF_HINT} ${reason}` : reason;
62138
62223
  return {
62139
62224
  ...confirmation,
62140
62225
  unsupportedNote: confirmation.unsupportedNote ? `${confirmation.unsupportedNote} ${hint}` : hint
@@ -62243,7 +62328,10 @@ function surfaceToolHints(server) {
62243
62328
  ));
62244
62329
  }
62245
62330
  async function createMcpServer(opts) {
62246
- const server = new McpServer({ name: opts.name, version: opts.version }, { supportedProtocolVersions: [...SERVER_PROTOCOL_VERSIONS] });
62331
+ const server = new McpServer({ name: opts.name, version: opts.version }, {
62332
+ supportedProtocolVersions: [...SERVER_PROTOCOL_VERSIONS],
62333
+ ...opts.maxToolInputElements !== void 0 ? { maxToolInputElements: opts.maxToolInputElements } : {}
62334
+ });
62247
62335
  if (opts.surfaceHints !== false)
62248
62336
  surfaceToolHints(server);
62249
62337
  if (opts.banner !== void 0) {
@@ -63313,6 +63401,60 @@ var KNOWN_CAPABILITIES = /* @__PURE__ */ new Set([
63313
63401
  "graphql",
63314
63402
  "write_cookies"
63315
63403
  ]);
63404
+ var ACCOUNT_KEY_FRAME = "account-key";
63405
+ var ACCOUNT_ATTEST_FRAME = "account-attest";
63406
+ var BRIDGE_ROLE_FRAME = "bridge-role";
63407
+ var BRIDGE_SERVE_FRAME = "bridge-serve";
63408
+ var ROOM_PING_FRAME = "room-ping";
63409
+ var ROOM_PONG_FRAME = "room-pong";
63410
+ var BRIDGE_ROLE_LABEL_MAX = 64;
63411
+ var ROOM_FRAME_ACCEPTS = Object.freeze({
63412
+ [BRIDGE_ROLE_FRAME]: BRIDGE_ROLE_FRAME,
63413
+ [BRIDGE_SERVE_FRAME]: BRIDGE_SERVE_FRAME,
63414
+ [ROOM_PING_FRAME]: ROOM_PING_FRAME,
63415
+ [ROOM_PONG_FRAME]: ROOM_PING_FRAME
63416
+ });
63417
+
63418
+ // node_modules/@fetchproxy/protocol/dist/mcp-id.js
63419
+ var ID_RE = /^([^:]+):([^:]+):([0-9a-f]{16})$/;
63420
+ function generateMcpId(serverName, version2) {
63421
+ if (serverName.includes(":")) {
63422
+ throw new Error(`serverName cannot contain ':': ${serverName}`);
63423
+ }
63424
+ if (version2.includes(":")) {
63425
+ throw new Error(`version cannot contain ':': ${version2}`);
63426
+ }
63427
+ const rand = randomHex(8);
63428
+ return `${serverName}:${version2}:${rand}`;
63429
+ }
63430
+ function isValidMcpId(id) {
63431
+ return typeof id === "string" && ID_RE.test(id);
63432
+ }
63433
+ function randomHex(bytes) {
63434
+ const arr2 = new Uint8Array(bytes);
63435
+ globalThis.crypto.getRandomValues(arr2);
63436
+ return Array.from(arr2, (b) => b.toString(16).padStart(2, "0")).join("");
63437
+ }
63438
+
63439
+ // node_modules/@fetchproxy/protocol/dist/account-attest.js
63440
+ var ACCOUNT_ATTEST_CONSENTS = Object.freeze([
63441
+ "silent",
63442
+ "confirm",
63443
+ "confirm-each"
63444
+ ]);
63445
+ var NO_SCOPE_DIGEST = "0".repeat(64);
63446
+ var ACCOUNT_ID_RE = /^[A-Za-z0-9_.\-]{1,128}$/;
63447
+ var HEX64_RE = /^[0-9a-f]{64}$/;
63448
+ var ACCOUNT_KID_RE = /^[0-9a-f]{16}$/;
63449
+ var enc2 = new TextEncoder();
63450
+
63451
+ // node_modules/@fetchproxy/protocol/dist/awaiting-approval.js
63452
+ var AWAITING_APPROVAL_REASON_PREFIX = "awaiting-approval:";
63453
+ function parseAwaitingApprovalReason(reason) {
63454
+ if (!reason.startsWith(AWAITING_APPROVAL_REASON_PREFIX))
63455
+ return null;
63456
+ return reason.slice(AWAITING_APPROVAL_REASON_PREFIX.length).trim();
63457
+ }
63316
63458
 
63317
63459
  // node_modules/@fetchproxy/protocol/dist/capability-availability.js
63318
63460
  var CAPABILITY_UNAVAILABLE_CODE = "capability_unavailable";
@@ -63338,27 +63480,6 @@ function parseUnsupportedCapabilityReason(reason) {
63338
63480
  return rest.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
63339
63481
  }
63340
63482
 
63341
- // node_modules/@fetchproxy/protocol/dist/mcp-id.js
63342
- var ID_RE = /^([^:]+):([^:]+):([0-9a-f]{16})$/;
63343
- function generateMcpId(serverName, version2) {
63344
- if (serverName.includes(":")) {
63345
- throw new Error(`serverName cannot contain ':': ${serverName}`);
63346
- }
63347
- if (version2.includes(":")) {
63348
- throw new Error(`version cannot contain ':': ${version2}`);
63349
- }
63350
- const rand = randomHex(8);
63351
- return `${serverName}:${version2}:${rand}`;
63352
- }
63353
- function isValidMcpId(id) {
63354
- return typeof id === "string" && ID_RE.test(id);
63355
- }
63356
- function randomHex(bytes) {
63357
- const arr2 = new Uint8Array(bytes);
63358
- globalThis.crypto.getRandomValues(arr2);
63359
- return Array.from(arr2, (b) => b.toString(16).padStart(2, "0")).join("");
63360
- }
63361
-
63362
63483
  // node_modules/@fetchproxy/protocol/dist/json-pointer.js
63363
63484
  function matchesDeclaredKey(requested, declared) {
63364
63485
  for (const decl of declared) {
@@ -63954,6 +64075,16 @@ function validateFrame(raw) {
63954
64075
  return { type: "extension-disconnected" };
63955
64076
  if (t === "peer-gone")
63956
64077
  return validatePeerGone(raw);
64078
+ if (t === ACCOUNT_KEY_FRAME)
64079
+ return validateAccountKey(raw);
64080
+ if (t === ACCOUNT_ATTEST_FRAME)
64081
+ return validateAccountAttest(raw);
64082
+ if (t === BRIDGE_ROLE_FRAME)
64083
+ return validateBridgeRole(raw);
64084
+ if (t === BRIDGE_SERVE_FRAME || t === ROOM_PING_FRAME || t === ROOM_PONG_FRAME) {
64085
+ assertExactFields(raw, TYPE_ONLY_FIELDS, t);
64086
+ return { type: t };
64087
+ }
63957
64088
  throw new ProtocolError3(`unknown frame type: ${String(t)}`);
63958
64089
  }
63959
64090
  function validateHello(raw) {
@@ -64157,6 +64288,165 @@ function validateHelloRejected(raw) {
64157
64288
  }
64158
64289
  return { type: "hello-rejected", mcpId: raw.mcpId, reason: raw.reason };
64159
64290
  }
64291
+ var DISPLAY_FORBIDDEN_RE = /[\u0000-\u001f\u007f-\u009f\u200e\u200f\u202a-\u202e\u2066-\u2069]/;
64292
+ function assertExactFields(raw, allowed, label) {
64293
+ for (const k of Object.keys(raw)) {
64294
+ if (!allowed.includes(k)) {
64295
+ throw new ProtocolError3(`${label}: unexpected field ${JSON.stringify(k)}`);
64296
+ }
64297
+ }
64298
+ }
64299
+ function assertMatch(x, re, label, what) {
64300
+ assertString(x, label);
64301
+ if (!re.test(x))
64302
+ throw new ProtocolError3(`${label}: must be ${what}`);
64303
+ }
64304
+ function assertPositiveSafeInt(x, label) {
64305
+ if (typeof x !== "number" || !Number.isSafeInteger(x) || x <= 0) {
64306
+ throw new ProtocolError3(`${label}: expected positive safe integer`);
64307
+ }
64308
+ }
64309
+ function assertDisplayString(x, label, min, max) {
64310
+ assertString(x, label);
64311
+ if (x.length < min || x.length > max) {
64312
+ throw new ProtocolError3(`${label}: must be ${min}-${max} characters`);
64313
+ }
64314
+ if (DISPLAY_FORBIDDEN_RE.test(x)) {
64315
+ throw new ProtocolError3(`${label}: control or bidi-override character`);
64316
+ }
64317
+ }
64318
+ var ACCOUNT_KEY_FIELDS = [
64319
+ "type",
64320
+ "accountId",
64321
+ "slug",
64322
+ "displayName",
64323
+ "confirmedBy",
64324
+ "tokenId",
64325
+ "kid",
64326
+ "publicKey",
64327
+ "generation",
64328
+ "bridgedRegistrations"
64329
+ ];
64330
+ function validateAccountKey(raw) {
64331
+ const L = "account-key";
64332
+ assertMatch(raw.accountId, ACCOUNT_ID_RE, `${L}.accountId`, "an account id");
64333
+ assertMatch(raw.slug, ACCOUNT_ID_RE, `${L}.slug`, "a slug");
64334
+ assertDisplayString(raw.displayName, `${L}.displayName`, 0, 128);
64335
+ assertDisplayString(raw.confirmedBy, `${L}.confirmedBy`, 1, 256);
64336
+ assertMatch(raw.tokenId, ACCOUNT_ID_RE, `${L}.tokenId`, "a token id");
64337
+ assertMatch(raw.kid, ACCOUNT_KID_RE, `${L}.kid`, "16 lowercase hex");
64338
+ assertBase64Bytes(raw.publicKey, `${L}.publicKey`, 32);
64339
+ assertPositiveSafeInt(raw.generation, `${L}.generation`);
64340
+ const n = raw.bridgedRegistrations;
64341
+ if (typeof n !== "number" || !Number.isSafeInteger(n) || n < 0) {
64342
+ throw new ProtocolError3(`${L}.bridgedRegistrations: expected non-negative safe integer`);
64343
+ }
64344
+ assertExactFields(raw, ACCOUNT_KEY_FIELDS, L);
64345
+ return {
64346
+ type: ACCOUNT_KEY_FRAME,
64347
+ accountId: raw.accountId,
64348
+ slug: raw.slug,
64349
+ displayName: raw.displayName,
64350
+ confirmedBy: raw.confirmedBy,
64351
+ tokenId: raw.tokenId,
64352
+ kid: raw.kid,
64353
+ publicKey: raw.publicKey,
64354
+ generation: raw.generation,
64355
+ bridgedRegistrations: n
64356
+ };
64357
+ }
64358
+ var ACCOUNT_ATTEST_FIELDS = [
64359
+ "type",
64360
+ "mcpId",
64361
+ "accountId",
64362
+ "generation",
64363
+ "tokenId",
64364
+ "kid",
64365
+ "registrationId",
64366
+ "slug",
64367
+ "identityHash",
64368
+ "identityEd25519Pub",
64369
+ "scopeDigest",
64370
+ "consent",
64371
+ "notAfter",
64372
+ "sig"
64373
+ ];
64374
+ function validateAccountAttest(raw) {
64375
+ const L = "account-attest";
64376
+ if (!isValidMcpId(raw.mcpId))
64377
+ throw new ProtocolError3(`${L}.mcpId: invalid format`);
64378
+ assertMatch(raw.accountId, ACCOUNT_ID_RE, `${L}.accountId`, "an account id");
64379
+ assertPositiveSafeInt(raw.generation, `${L}.generation`);
64380
+ assertMatch(raw.tokenId, ACCOUNT_ID_RE, `${L}.tokenId`, "a token id");
64381
+ assertMatch(raw.kid, ACCOUNT_KID_RE, `${L}.kid`, "16 lowercase hex");
64382
+ assertMatch(raw.registrationId, ACCOUNT_ID_RE, `${L}.registrationId`, "a registration id");
64383
+ assertMatch(raw.slug, ACCOUNT_ID_RE, `${L}.slug`, "a slug");
64384
+ assertMatch(raw.identityHash, HEX64_RE, `${L}.identityHash`, "64 lowercase hex");
64385
+ assertBase64Bytes(raw.identityEd25519Pub, `${L}.identityEd25519Pub`, 32);
64386
+ assertMatch(raw.scopeDigest, HEX64_RE, `${L}.scopeDigest`, "64 lowercase hex");
64387
+ assertString(raw.consent, `${L}.consent`);
64388
+ const consent = raw.consent;
64389
+ const known = ACCOUNT_ATTEST_CONSENTS.find((c) => c === consent);
64390
+ if (known === void 0) {
64391
+ throw new ProtocolError3(`${L}.consent: must be one of ${ACCOUNT_ATTEST_CONSENTS.join(", ")}`);
64392
+ }
64393
+ assertPositiveSafeInt(raw.notAfter, `${L}.notAfter`);
64394
+ assertBase64Bytes(raw.sig, `${L}.sig`, 64);
64395
+ assertExactFields(raw, ACCOUNT_ATTEST_FIELDS, L);
64396
+ return {
64397
+ type: ACCOUNT_ATTEST_FRAME,
64398
+ mcpId: raw.mcpId,
64399
+ accountId: raw.accountId,
64400
+ generation: raw.generation,
64401
+ tokenId: raw.tokenId,
64402
+ kid: raw.kid,
64403
+ registrationId: raw.registrationId,
64404
+ slug: raw.slug,
64405
+ identityHash: raw.identityHash,
64406
+ identityEd25519Pub: raw.identityEd25519Pub,
64407
+ scopeDigest: raw.scopeDigest,
64408
+ consent: known,
64409
+ notAfter: raw.notAfter,
64410
+ sig: raw.sig
64411
+ };
64412
+ }
64413
+ var TYPE_ONLY_FIELDS = ["type"];
64414
+ var BRIDGE_ROLE_FIELDS = ["type", "role", "canServe", "serving"];
64415
+ var BRIDGE_ROLE_SERVING_FIELDS = ["label", "since"];
64416
+ function validateBridgeRole(raw) {
64417
+ const L = BRIDGE_ROLE_FRAME;
64418
+ const role = raw.role;
64419
+ if (role !== "serving" && role !== "standby") {
64420
+ throw new ProtocolError3(`${L}.role: must be one of serving, standby`);
64421
+ }
64422
+ const canServe = raw.canServe;
64423
+ assertBoolean(canServe, `${L}.canServe`);
64424
+ assertExactFields(raw, BRIDGE_ROLE_FIELDS, L);
64425
+ const serving = raw.serving;
64426
+ if (role === "serving") {
64427
+ if (serving !== void 0) {
64428
+ throw new ProtocolError3(`${L}.serving: must be absent when role is serving`);
64429
+ }
64430
+ return { type: BRIDGE_ROLE_FRAME, role, canServe };
64431
+ }
64432
+ if (serving === void 0) {
64433
+ throw new ProtocolError3(`${L}.serving: required when role is standby`);
64434
+ }
64435
+ assertObject(serving, `${L}.serving`);
64436
+ const label = serving.label;
64437
+ assertDisplayString(label, `${L}.serving.label`, 1, BRIDGE_ROLE_LABEL_MAX);
64438
+ const since = serving.since;
64439
+ if (typeof since !== "number" || !Number.isSafeInteger(since) || since < 0) {
64440
+ throw new ProtocolError3(`${L}.serving.since: expected non-negative safe integer (Unix ms)`);
64441
+ }
64442
+ assertExactFields(serving, BRIDGE_ROLE_SERVING_FIELDS, `${L}.serving`);
64443
+ return {
64444
+ type: BRIDGE_ROLE_FRAME,
64445
+ role,
64446
+ canServe,
64447
+ serving: { label, since }
64448
+ };
64449
+ }
64160
64450
  function validateInnerFrame(raw) {
64161
64451
  assertObject(raw, "inner");
64162
64452
  const t = raw.type;
@@ -64624,10 +64914,10 @@ function validateInnerResponse(raw) {
64624
64914
  }
64625
64915
 
64626
64916
  // node_modules/@fetchproxy/protocol/dist/pair-code.js
64627
- var enc2 = new TextEncoder();
64917
+ var enc3 = new TextEncoder();
64628
64918
  var PAIR_LABEL = "fetchproxy/4/pair";
64629
64919
  async function pairTranscript(mcpIdentityPub, extIdentityPub, mcpNonce, extNonce, mcpSessionPub) {
64630
- const label = enc2.encode(PAIR_LABEL);
64920
+ const label = enc3.encode(PAIR_LABEL);
64631
64921
  const parts = [mcpIdentityPub, extIdentityPub, mcpNonce, extNonce, mcpSessionPub];
64632
64922
  const out = new Uint8Array(label.length + 1 + parts.reduce((n, p) => n + p.length, 0));
64633
64923
  out.set(label, 0);
@@ -64648,7 +64938,7 @@ function digits(hash2) {
64648
64938
  }
64649
64939
 
64650
64940
  // node_modules/@fetchproxy/protocol/dist/seal.js
64651
- var enc3 = new TextEncoder();
64941
+ var enc4 = new TextEncoder();
64652
64942
  var dec = new TextDecoder();
64653
64943
  function randomIv() {
64654
64944
  const iv = new Uint8Array(12);
@@ -64661,14 +64951,14 @@ function base64Length(byteLength) {
64661
64951
  return Math.ceil(byteLength / 3) * 4;
64662
64952
  }
64663
64953
  function encodeInnerFrame(inner) {
64664
- return enc3.encode(JSON.stringify(inner));
64954
+ return enc4.encode(JSON.stringify(inner));
64665
64955
  }
64666
64956
  function plaintextOf(inner) {
64667
64957
  return inner instanceof Uint8Array ? inner : encodeInnerFrame(inner);
64668
64958
  }
64669
64959
  function sealedFrameWireBytes(mcpId, seq, inner) {
64670
64960
  const plaintext = plaintextOf(inner).length;
64671
- const envelope = enc3.encode(JSON.stringify({ type: "frame", mcpId, seq, iv: "", ciphertext: "" })).length;
64961
+ const envelope = enc4.encode(JSON.stringify({ type: "frame", mcpId, seq, iv: "", ciphertext: "" })).length;
64672
64962
  return envelope + IV_B64_BYTES + base64Length(plaintext + AES_GCM_TAG_BYTES);
64673
64963
  }
64674
64964
  var MAX_FRAME_BYTES = 42 * 1024 * 1024;
@@ -65008,14 +65298,23 @@ var FetchproxyHelloRejectedError = class extends Error {
65008
65298
  platform;
65009
65299
  /**
65010
65300
  * #418: the remedy, when the reason is one this package knows how to
65011
- * explain — today only `unsupported-capability`, which blames the browser
65012
- * rather than the MCP. `null` otherwise.
65301
+ * explain — `unsupported-capability`, which blames the browser rather than
65302
+ * the MCP, and (D12) `awaiting-approval`, which says to approve in the
65303
+ * browser. `null` otherwise.
65013
65304
  */
65014
65305
  hint;
65306
+ /**
65307
+ * D12: `true` only for an `awaiting-approval:` refusal — the extension has
65308
+ * queued an approval card and nobody is at the browser yet, so the same call
65309
+ * succeeds once the person approves. Every other refusal is the extension's
65310
+ * final answer, and retrying unchanged is refused the same way.
65311
+ */
65312
+ retryable;
65015
65313
  constructor(info) {
65016
65314
  const unavailable = parseUnsupportedCapabilityReason(info.reason);
65315
+ const awaiting = parseAwaitingApprovalReason(info.reason);
65017
65316
  const platform = info.platform ?? null;
65018
- 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;
65317
+ 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;
65019
65318
  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.`));
65020
65319
  this.name = "FetchproxyHelloRejectedError";
65021
65320
  this.mcpId = info.mcpId;
@@ -65023,6 +65322,7 @@ var FetchproxyHelloRejectedError = class extends Error {
65023
65322
  this.unavailableCapabilities = unavailable ?? [];
65024
65323
  this.platform = platform;
65025
65324
  this.hint = hint;
65325
+ this.retryable = awaiting !== null;
65026
65326
  Object.setPrototypeOf(this, new.target.prototype);
65027
65327
  }
65028
65328
  };
@@ -65575,7 +65875,7 @@ function originVerdict(origin, allowLocal) {
65575
65875
  }
65576
65876
  var HANDSHAKE_TIMEOUT_MS = 15e3;
65577
65877
  var MAX_PAYLOAD_BYTES = MAX_FRAME_BYTES;
65578
- var enc4 = new TextEncoder();
65878
+ var enc5 = new TextEncoder();
65579
65879
  var OWN_DECRYPT_FAILURES_BEFORE_REHANDSHAKE = 3;
65580
65880
  async function startHost(opts) {
65581
65881
  const allowLocalOrigins = envAllowsLocalOrigins();
@@ -65646,10 +65946,20 @@ async function startHost(opts) {
65646
65946
  let resolveOwnSession;
65647
65947
  let rejectOwnSession;
65648
65948
  let ownSessionReady;
65949
+ let ownRetryableRefusal = false;
65950
+ let ownSessionSettled = false;
65649
65951
  function resetSessionPromise() {
65952
+ ownRetryableRefusal = false;
65953
+ ownSessionSettled = false;
65650
65954
  ownSessionReady = new Promise((resolve2, reject) => {
65651
- resolveOwnSession = resolve2;
65652
- rejectOwnSession = reject;
65955
+ resolveOwnSession = (st) => {
65956
+ ownSessionSettled = true;
65957
+ resolve2(st);
65958
+ };
65959
+ rejectOwnSession = (e) => {
65960
+ ownSessionSettled = true;
65961
+ reject(e);
65962
+ };
65653
65963
  });
65654
65964
  ownSessionReady.catch(() => {
65655
65965
  });
@@ -65916,13 +66226,15 @@ async function startHost(opts) {
65916
66226
  const extPub = fromB64(frame.extensionSessionPub);
65917
66227
  const shared = await ecdhX25519(held.priv, extPub);
65918
66228
  const salt = await transcriptHash(held.nonce, extNonce, held.pub, extPub);
65919
- const key = await hkdfSha256(shared, salt, enc4.encode(HKDF_SESSION_INFO), 32);
66229
+ const key = await hkdfSha256(shared, salt, enc5.encode(HKDF_SESSION_INFO), 32);
65920
66230
  if (extensionWs !== ws)
65921
66231
  return;
65922
66232
  ownSession = new SessionState(key);
65923
66233
  ownSessionInfo = sessionInfoFromHello(verifiedHello);
65924
66234
  ownDecryptFailures = 0;
65925
66235
  ownPendingPairCode = null;
66236
+ if (ownRetryableRefusal)
66237
+ resetSessionPromise();
65926
66238
  resolveOwnSession(ownSession);
65927
66239
  } else {
65928
66240
  const slot = peers.get(frame.mcpId);
@@ -65991,11 +66303,17 @@ async function startHost(opts) {
65991
66303
  }
65992
66304
  if (frame.type === "hello-rejected" && identified === "extension") {
65993
66305
  if (frame.mcpId === opts.ownMcpId) {
65994
- rejectOwnSession(new FetchproxyHelloRejectedError({
66306
+ const refusal = new FetchproxyHelloRejectedError({
65995
66307
  mcpId: frame.mcpId,
65996
66308
  reason: frame.reason,
65997
66309
  platform: extensionHello?.platform ?? null
65998
- }));
66310
+ });
66311
+ if (ownRetryableRefusal)
66312
+ resetSessionPromise();
66313
+ const settlesPending = !ownSessionSettled;
66314
+ rejectOwnSession(refusal);
66315
+ if (refusal.retryable && settlesPending)
66316
+ ownRetryableRefusal = true;
65999
66317
  } else {
66000
66318
  const slot = peers.get(frame.mcpId);
66001
66319
  if (slot?.helloFrame.accepts?.includes("hello-rejected")) {
@@ -66111,7 +66429,7 @@ async function startHost(opts) {
66111
66429
 
66112
66430
  // node_modules/@fetchproxy/server/dist/peer.js
66113
66431
  var PEER_DIAL_TIMEOUT_MS = 5e3;
66114
- var enc5 = new TextEncoder();
66432
+ var enc6 = new TextEncoder();
66115
66433
  function notSentError() {
66116
66434
  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.");
66117
66435
  }
@@ -66211,7 +66529,9 @@ async function startPeer(opts) {
66211
66529
  let rejectFirstReady;
66212
66530
  let sessionPromise;
66213
66531
  let sessionPromiseSettled = false;
66532
+ let retryableRefusal = false;
66214
66533
  function resetSessionPromise() {
66534
+ retryableRefusal = false;
66215
66535
  sessionPromiseSettled = false;
66216
66536
  sessionPromise = new Promise((resolve2, reject) => {
66217
66537
  resolveFirstReady = (st) => {
@@ -66308,6 +66628,8 @@ async function startPeer(opts) {
66308
66628
  raw = JSON.parse(data.toString());
66309
66629
  const frame = validateFrame(raw);
66310
66630
  if (frame.type === "hello" && frame.role === "extension") {
66631
+ if (retryableRefusal)
66632
+ resetSessionPromise();
66311
66633
  extensionHello = frame;
66312
66634
  const mintedKeypair = await generateSessionKeypair();
66313
66635
  const mintedHello = await buildServerHello({
@@ -66337,6 +66659,8 @@ async function startPeer(opts) {
66337
66659
  session = null;
66338
66660
  if (sessionPromiseSettled)
66339
66661
  resetSessionPromise();
66662
+ } else if (retryableRefusal) {
66663
+ resetSessionPromise();
66340
66664
  }
66341
66665
  extensionDisconnectListeners.forEach((cb) => cb());
66342
66666
  return;
@@ -66358,7 +66682,7 @@ async function startPeer(opts) {
66358
66682
  const extNonce = fromB64(authenticated.sessionNonce);
66359
66683
  const shared = await ecdhX25519(held.priv, extPub);
66360
66684
  const salt = await transcriptHash(held.nonce, extNonce, held.pub, extPub);
66361
- const sessionKey = await hkdfSha256(shared, salt, enc5.encode(HKDF_SESSION_INFO), 32);
66685
+ const sessionKey = await hkdfSha256(shared, salt, enc6.encode(HKDF_SESSION_INFO), 32);
66362
66686
  if (sessionEphemeral !== held) {
66363
66687
  console.warn(`[fetchproxy] ${opts.serverName}: dropping a session derived against an ephemeral that was superseded while it was being derived`);
66364
66688
  return;
@@ -66371,16 +66695,24 @@ async function startPeer(opts) {
66371
66695
  if (isRenegotiation) {
66372
66696
  renegotiateListeners.forEach((cb) => cb());
66373
66697
  } else {
66698
+ if (retryableRefusal)
66699
+ resetSessionPromise();
66374
66700
  resolveFirstReady(session);
66375
66701
  }
66376
66702
  return;
66377
66703
  }
66378
66704
  if (frame.type === "hello-rejected" && frame.mcpId === opts.mcpId) {
66379
- rejectFirstReady(new FetchproxyHelloRejectedError({
66705
+ const refusal = new FetchproxyHelloRejectedError({
66380
66706
  mcpId: frame.mcpId,
66381
66707
  reason: frame.reason,
66382
66708
  platform: extensionHello?.platform ?? null
66383
- }));
66709
+ });
66710
+ if (retryableRefusal)
66711
+ resetSessionPromise();
66712
+ const settlesPending = !sessionPromiseSettled;
66713
+ rejectFirstReady(refusal);
66714
+ if (refusal.retryable && settlesPending)
66715
+ retryableRefusal = true;
66384
66716
  }
66385
66717
  if (frame.type === "pair-pending" && frame.mcpId === opts.mcpId) {
66386
66718
  const hello2 = extensionHello;
@@ -66544,8 +66876,9 @@ function classifyFetchError(error62, code2) {
66544
66876
 
66545
66877
  // node_modules/@fetchproxy/server/dist/classify-bridge-error.js
66546
66878
  function classifyBridgeError(err) {
66547
- if (err instanceof FetchproxyHelloRejectedError)
66548
- return "hello_rejected";
66879
+ if (err instanceof FetchproxyHelloRejectedError) {
66880
+ return err.retryable ? "awaiting_approval" : "hello_rejected";
66881
+ }
66549
66882
  if (err instanceof FetchproxySessionNotReadyError)
66550
66883
  return "session_not_ready";
66551
66884
  if (err instanceof FetchproxyTimeoutError)
@@ -69330,7 +69663,7 @@ function isBrowserCapabilityGap(e) {
69330
69663
  // package.json
69331
69664
  var package_default = {
69332
69665
  name: "honeybook-mcp",
69333
- version: "1.2.3",
69666
+ version: "1.2.5",
69334
69667
  mcpName: "io.github.chrischall/honeybook-mcp",
69335
69668
  description: "HoneyBook client-portal MCP server for Claude",
69336
69669
  author: "Claude Code (AI) <https://www.anthropic.com/claude>",
@@ -69374,15 +69707,15 @@ var package_default = {
69374
69707
  typecheck: "tsc -p tsconfig.json --noEmit"
69375
69708
  },
69376
69709
  dependencies: {
69377
- "@chrischall/mcp-utils": "^2.13.0",
69378
- "@fetchproxy/bootstrap": "^3.4.1",
69379
- "@fetchproxy/server": "^3.4.1",
69380
- "@modelcontextprotocol/server": "^2.2.0",
69710
+ "@chrischall/mcp-utils": "^2.15.0",
69711
+ "@fetchproxy/bootstrap": "^3.6.0",
69712
+ "@fetchproxy/server": "^3.6.0",
69713
+ "@modelcontextprotocol/server": "^2.3.0",
69381
69714
  dotenv: "^18.0.2",
69382
69715
  zod: "^4.6.5"
69383
69716
  },
69384
69717
  devDependencies: {
69385
- "@modelcontextprotocol/client": "^2.2.0",
69718
+ "@modelcontextprotocol/client": "^2.3.0",
69386
69719
  "@types/node": "^26.0.0",
69387
69720
  "@vitest/coverage-v8": "^5.0.0",
69388
69721
  esbuild: "^0.28.0",
@@ -71261,7 +71594,7 @@ var __dirname = dirname3(fileURLToPath(import.meta.url));
71261
71594
  await loadDotenvSafely({ path: join9(__dirname, "..", ".env"), override: false });
71262
71595
  await runMcp({
71263
71596
  name: "honeybook-mcp",
71264
- version: "1.2.3",
71597
+ version: "1.2.5",
71265
71598
  // x-release-please-version
71266
71599
  tools: [
71267
71600
  registerSessionTools,
@@ -71283,7 +71616,7 @@ await runMcp({
71283
71616
  });
71284
71617
  /*! Bundled license information:
71285
71618
 
71286
- @modelcontextprotocol/server/dist/src-BHSMhZ_W.mjs:
71619
+ @modelcontextprotocol/server/dist/src-Cqbh3MYc.mjs:
71287
71620
  (*!
71288
71621
  * content-type
71289
71622
  * Copyright(c) 2015 Douglas Christopher Wilson
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ import { registerAttachmentTools } from './tools/attachments.js';
20
20
  import { registerPaymentTools } from './tools/payments.js';
21
21
  await runMcp({
22
22
  name: 'honeybook-mcp',
23
- version: '1.2.3', // x-release-please-version
23
+ version: '1.2.5', // x-release-please-version
24
24
  tools: [
25
25
  registerSessionTools,
26
26
  registerFlowTools,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "honeybook-mcp",
3
- "version": "1.2.3",
3
+ "version": "1.2.5",
4
4
  "mcpName": "io.github.chrischall/honeybook-mcp",
5
5
  "description": "HoneyBook client-portal MCP server for Claude",
6
6
  "author": "Claude Code (AI) <https://www.anthropic.com/claude>",
@@ -44,15 +44,15 @@
44
44
  "typecheck": "tsc -p tsconfig.json --noEmit"
45
45
  },
46
46
  "dependencies": {
47
- "@chrischall/mcp-utils": "^2.13.0",
48
- "@fetchproxy/bootstrap": "^3.4.1",
49
- "@fetchproxy/server": "^3.4.1",
50
- "@modelcontextprotocol/server": "^2.2.0",
47
+ "@chrischall/mcp-utils": "^2.15.0",
48
+ "@fetchproxy/bootstrap": "^3.6.0",
49
+ "@fetchproxy/server": "^3.6.0",
50
+ "@modelcontextprotocol/server": "^2.3.0",
51
51
  "dotenv": "^18.0.2",
52
52
  "zod": "^4.6.5"
53
53
  },
54
54
  "devDependencies": {
55
- "@modelcontextprotocol/client": "^2.2.0",
55
+ "@modelcontextprotocol/client": "^2.3.0",
56
56
  "@types/node": "^26.0.0",
57
57
  "@vitest/coverage-v8": "^5.0.0",
58
58
  "esbuild": "^0.28.0",
package/server.json CHANGED
@@ -6,12 +6,12 @@
6
6
  "url": "https://github.com/chrischall/honeybook-mcp",
7
7
  "source": "github"
8
8
  },
9
- "version": "1.2.3",
9
+ "version": "1.2.5",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "honeybook-mcp",
14
- "version": "1.2.3",
14
+ "version": "1.2.5",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },