honeybook-mcp 0.2.4 → 0.3.1

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": "0.2.4"
10
+ "version": "0.3.1"
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": "0.2.4",
18
+ "version": "0.3.1",
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": "0.2.4",
4
+ "version": "0.3.1",
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/dist/auth.js CHANGED
@@ -56,6 +56,7 @@
56
56
  // - Persistence (sessionStore.add) is the existing side effect; tests
57
57
  // verify the captured session round-trips through sessionStore.get.
58
58
  import { bootstrap } from '@fetchproxy/bootstrap';
59
+ import { classifyBridgeError } from '@fetchproxy/server';
59
60
  import pkg from '../package.json' with { type: 'json' };
60
61
  import { sessionStore, normalizeOrigin } from './sessions.js';
61
62
  /**
@@ -167,6 +168,11 @@ export async function captureSessionViaFetchproxy(opts) {
167
168
  });
168
169
  }
169
170
  catch (e) {
171
+ // SW eviction retry exhausted — surface library's typed `.hint` instead of the generic "open magic link" message.
172
+ if (classifyBridgeError(e) === 'bridge_down') {
173
+ const downErr = e;
174
+ throw new Error(`HoneyBook auth: fetchproxy bridge is down (extension service worker unreachable after retry). ${downErr.hint}`);
175
+ }
170
176
  const msg = e instanceof Error ? e.message : String(e);
171
177
  throw new Error(`HoneyBook auth: fetchproxy capture failed: ${msg} — ` +
172
178
  'open the vendor magic-link URL in Chrome (with the fetchproxy 0.3.0 extension installed), ' +
package/dist/bundle.js CHANGED
@@ -36133,6 +36133,52 @@ var FetchproxyHttpError = class extends Error {
36133
36133
  this.name = "FetchproxyHttpError";
36134
36134
  }
36135
36135
  };
36136
+ var FetchproxyBridgeDownError = class extends FetchproxyProtocolError {
36137
+ originalError;
36138
+ retryAttempted;
36139
+ op;
36140
+ url;
36141
+ /** 0.8.0+: bridge role at throw time; `null` if listen() hadn't bound yet. */
36142
+ role;
36143
+ /** 0.8.0+: bridge port at throw time (the same port `listen()` bound to). */
36144
+ port;
36145
+ hint;
36146
+ constructor(args) {
36147
+ const retryAttempted = args.retryAttempted ?? false;
36148
+ const op = args.op ?? "fetch";
36149
+ const retryClause = retryAttempted ? `Server already burned a one-shot lazy-revive retry; SW is still down. ` : `Server lazy-revive retry was disabled (bridgeReviveDelayMs unset/0). `;
36150
+ const hint = `the fetchproxy extension's service worker is not responding ("${args.originalError}"). Chrome evicts extension service workers after ~30s idle by default. ${retryClause}Wake it by clicking the fetchproxy extension toolbar icon, then retry. If it keeps happening, reload the extension from chrome://extensions.`;
36151
+ super(`fetchproxy bridge down during ${op}${args.url ? ` (${args.url})` : ""}. ${hint}`);
36152
+ this.name = "FetchproxyBridgeDownError";
36153
+ this.originalError = args.originalError;
36154
+ this.retryAttempted = retryAttempted;
36155
+ this.op = op;
36156
+ if (args.url !== void 0)
36157
+ this.url = args.url;
36158
+ this.role = args.role ?? null;
36159
+ this.port = args.port ?? 0;
36160
+ this.hint = hint;
36161
+ }
36162
+ };
36163
+ var FetchproxyTimeoutError = class extends FetchproxyProtocolError {
36164
+ url;
36165
+ timeoutMs;
36166
+ /** 0.8.0+: bridge role at throw time; `null` if listen() hadn't bound yet. */
36167
+ role;
36168
+ /** 0.8.0+: bridge port at throw time. */
36169
+ port;
36170
+ /** 0.8.0+: actual elapsed milliseconds when the timer won the race. */
36171
+ elapsedMs;
36172
+ constructor(args) {
36173
+ super(`fetchproxy: ${args.url} did not respond within ${args.timeoutMs}ms`);
36174
+ this.name = "FetchproxyTimeoutError";
36175
+ this.url = args.url;
36176
+ this.timeoutMs = args.timeoutMs;
36177
+ this.role = args.role ?? null;
36178
+ this.port = args.port ?? 0;
36179
+ this.elapsedMs = args.elapsedMs ?? args.timeoutMs;
36180
+ }
36181
+ };
36136
36182
  var SUBDOMAIN_LABEL_RE = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
36137
36183
  function assertSubdomainLabel(label) {
36138
36184
  if (!SUBDOMAIN_LABEL_RE.test(label)) {
@@ -36170,6 +36216,18 @@ var FetchproxyServer = class {
36170
36216
  hostHandle = null;
36171
36217
  peerHandle = null;
36172
36218
  nextRequestId = 1;
36219
+ // 0.8.0+: process-wide freshness counters surfaced via bridgeHealth().
36220
+ // Replaces the local copies every downstream MCP was rolling on top
36221
+ // of its own transport adapter — see realty-mcp cohort drift notes.
36222
+ // Updated by recordSuccess / recordFailure from fetch + capture paths.
36223
+ // `lastExtensionMessageAt` (#23 ask 4) is updated whenever any inner
36224
+ // frame from the extension arrives — gives extension-side liveness
36225
+ // distinct from per-call success/failure.
36226
+ lastSuccessAt = null;
36227
+ lastFailureAt = null;
36228
+ lastFailureReason = null;
36229
+ consecutiveFailures = 0;
36230
+ lastExtensionMessageAt = null;
36173
36231
  pending = /* @__PURE__ */ new Map();
36174
36232
  // Separate pending map for read_cookies so the response shape (cookies
36175
36233
  // string vs status/body) doesn't have to share a union type with fetch.
@@ -36238,6 +36296,12 @@ var FetchproxyServer = class {
36238
36296
  key: d.key,
36239
36297
  jsonPointer: d.jsonPointer
36240
36298
  })),
36299
+ // 0.8.0+: timer + lazy-revive default to ON. Every realty MCP
36300
+ // adapter was about to set these to the same numbers anyway; the
36301
+ // back-door is `0` (explicit opt-out) if a caller genuinely wants
36302
+ // the legacy hang-forever / fail-once-on-SW-eviction behavior.
36303
+ fetchTimeoutMs: opts.fetchTimeoutMs ?? 3e4,
36304
+ bridgeReviveDelayMs: opts.bridgeReviveDelayMs ?? 2e3,
36241
36305
  identityDir: opts.identityDir,
36242
36306
  onPairCode: opts.onPairCode
36243
36307
  };
@@ -36373,7 +36437,7 @@ var FetchproxyServer = class {
36373
36437
  }
36374
36438
  }
36375
36439
  pairingErrorMessage(code) {
36376
- return `fetchproxy: pairing required for ${this.opts.serverName} \u2014 open the fetchproxy extension popup in Chrome and approve the pair request. Verify the pair code matches: ${code}`;
36440
+ return `fetchproxy transport error: pairing required for ${this.opts.serverName}. Tell the user to open the Transporter browser extension popup and approve the pair request. The pair code is: ${code} \u2014 display this code to the user so they can verify it matches.`;
36377
36441
  }
36378
36442
  /**
36379
36443
  * Raw single-shot fetch through the bridge. Most callers should prefer
@@ -36394,8 +36458,71 @@ var FetchproxyServer = class {
36394
36458
  const pendingCode = this.currentPendingPairCode();
36395
36459
  if (pendingCode !== null) {
36396
36460
  const error51 = this.pairingErrorMessage(pendingCode);
36397
- return { ok: false, error: error51, kind: classifyFetchError(error51) };
36461
+ return {
36462
+ ok: false,
36463
+ error: error51,
36464
+ kind: classifyFetchError(error51),
36465
+ retryAttempted: false
36466
+ };
36467
+ }
36468
+ const first = await this._fetchOnceWithTimeout(init);
36469
+ const reviveMs = this.opts.bridgeReviveDelayMs;
36470
+ let final = first;
36471
+ if (!first.ok && first.kind === "content_script_unreachable" && reviveMs !== void 0 && reviveMs > 0) {
36472
+ await new Promise((r) => setTimeout(r, reviveMs));
36473
+ const second = await this._fetchOnceWithTimeout(init);
36474
+ if (second.ok)
36475
+ this.recordSuccess();
36476
+ else
36477
+ this.recordFailure(`${second.kind ?? "other"}: ${second.error}`);
36478
+ return { ...second, retryAttempted: true };
36398
36479
  }
36480
+ if (first.ok)
36481
+ this.recordSuccess();
36482
+ else
36483
+ this.recordFailure(`${first.kind ?? "other"}: ${first.error}`);
36484
+ return { ...first, retryAttempted: false };
36485
+ }
36486
+ /**
36487
+ * 0.8.0+: snapshot of the bridge's process-wide freshness counters,
36488
+ * suitable for surfacing through a downstream MCP's healthcheck tool.
36489
+ * Counters reset on a success (consecutiveFailures), accumulate
36490
+ * across the process lifetime otherwise. Replaces the per-MCP
36491
+ * duplication the realty cohort had been rolling in their adapters.
36492
+ * `lastExtensionMessageAt` is updated whenever ANY inner frame
36493
+ * arrives from the extension — gives extension-side liveness
36494
+ * distinct from server-side success/failure of the user-visible
36495
+ * call (addresses #23 ask 4).
36496
+ */
36497
+ bridgeHealth() {
36498
+ return {
36499
+ role: this.role,
36500
+ port: this.opts.port,
36501
+ serverVersion: this.opts.version,
36502
+ fetchTimeoutMs: this.opts.fetchTimeoutMs ?? 0,
36503
+ bridgeReviveDelayMs: this.opts.bridgeReviveDelayMs ?? 0,
36504
+ lastSuccessAt: this.lastSuccessAt,
36505
+ lastFailureAt: this.lastFailureAt,
36506
+ lastFailureReason: this.lastFailureReason,
36507
+ consecutiveFailures: this.consecutiveFailures,
36508
+ lastExtensionMessageAt: this.lastExtensionMessageAt
36509
+ };
36510
+ }
36511
+ recordSuccess() {
36512
+ this.lastSuccessAt = Date.now();
36513
+ this.consecutiveFailures = 0;
36514
+ }
36515
+ recordFailure(reason) {
36516
+ this.lastFailureAt = Date.now();
36517
+ this.lastFailureReason = reason;
36518
+ this.consecutiveFailures += 1;
36519
+ }
36520
+ /**
36521
+ * Single bridge round-trip, wrapped by `fetchTimeoutMs` when set.
36522
+ * On timeout returns the `{ok:false, kind:'timeout'}` envelope —
36523
+ * the throwing surface is the convenience methods.
36524
+ */
36525
+ async _fetchOnceWithTimeout(init) {
36399
36526
  const id = this.nextRequestId++;
36400
36527
  const inner = { type: "request", id, op: "fetch", init };
36401
36528
  const pending = new Promise((resolve) => {
@@ -36406,7 +36533,61 @@ var FetchproxyServer = class {
36406
36533
  } else if (this.peerHandle) {
36407
36534
  await this.peerHandle.sendInner(inner);
36408
36535
  }
36409
- return pending;
36536
+ const timeoutMs = this.opts.fetchTimeoutMs;
36537
+ if (timeoutMs === void 0 || timeoutMs <= 0)
36538
+ return pending;
36539
+ let timer;
36540
+ const start = Date.now();
36541
+ try {
36542
+ return await Promise.race([
36543
+ pending,
36544
+ new Promise((resolve) => {
36545
+ timer = setTimeout(() => {
36546
+ this.pending.delete(id);
36547
+ const elapsedMs = Date.now() - start;
36548
+ const error51 = `fetchproxy: ${init.url} did not respond within ${timeoutMs}ms`;
36549
+ resolve({
36550
+ ok: false,
36551
+ error: error51,
36552
+ kind: "timeout",
36553
+ retryAttempted: false,
36554
+ elapsedMs
36555
+ });
36556
+ }, timeoutMs);
36557
+ })
36558
+ ]);
36559
+ } finally {
36560
+ if (timer)
36561
+ clearTimeout(timer);
36562
+ }
36563
+ }
36564
+ /**
36565
+ * Map an `ok:false` fetch result to its typed throwable. Centralizes
36566
+ * the kind-to-error-class switch so `request()` and (via the same
36567
+ * logic re-implemented inline) `captureRequestHeader()` agree on what
36568
+ * to throw.
36569
+ */
36570
+ _typedErrorFor(result, url2, op, retryAttempted) {
36571
+ if (result.kind === "timeout") {
36572
+ return new FetchproxyTimeoutError({
36573
+ url: url2,
36574
+ timeoutMs: this.opts.fetchTimeoutMs ?? 0,
36575
+ role: this.role,
36576
+ port: this.opts.port,
36577
+ elapsedMs: result.elapsedMs
36578
+ });
36579
+ }
36580
+ if (result.kind === "content_script_unreachable") {
36581
+ return new FetchproxyBridgeDownError({
36582
+ originalError: result.error,
36583
+ retryAttempted,
36584
+ op,
36585
+ url: url2,
36586
+ role: this.role,
36587
+ port: this.opts.port
36588
+ });
36589
+ }
36590
+ return new FetchproxyProtocolError(result.error);
36410
36591
  }
36411
36592
  /**
36412
36593
  * Convenience wrapper around `fetch()`. Builds the URL from a path
@@ -36429,8 +36610,18 @@ var FetchproxyServer = class {
36429
36610
  if (opts.subdomain !== void 0)
36430
36611
  assertSubdomainLabel(opts.subdomain);
36431
36612
  const baseDomain = this.resolveBaseDomain(opts.domain);
36432
- const host = opts.subdomain ? `${opts.subdomain}.${baseDomain}` : baseDomain;
36433
- const url2 = path.startsWith("http://") || path.startsWith("https://") ? path : `https://${host}${path}`;
36613
+ const isAbsolute = path.startsWith("http://") || path.startsWith("https://");
36614
+ let host;
36615
+ if (isAbsolute) {
36616
+ try {
36617
+ host = new URL(path).host;
36618
+ } catch {
36619
+ throw new Error(`FetchproxyServer.request: absolute path is not a valid URL: ${JSON.stringify(path)}`);
36620
+ }
36621
+ } else {
36622
+ host = opts.subdomain ? `${opts.subdomain}.${baseDomain}` : baseDomain;
36623
+ }
36624
+ const url2 = isAbsolute ? path : `https://${host}${path}`;
36434
36625
  assertUrlInDomains("request url", url2, this.opts.domains);
36435
36626
  const init = {
36436
36627
  url: url2,
@@ -36441,7 +36632,7 @@ var FetchproxyServer = class {
36441
36632
  };
36442
36633
  const result = await this.fetch(init);
36443
36634
  if (!result.ok) {
36444
- throw new FetchproxyProtocolError(result.error);
36635
+ throw this._typedErrorFor(result, init.url, "fetch", result.retryAttempted ?? false);
36445
36636
  }
36446
36637
  const response = {
36447
36638
  status: result.status,
@@ -36651,10 +36842,73 @@ var FetchproxyServer = class {
36651
36842
  }
36652
36843
  await this.ensureConnected();
36653
36844
  this.throwIfPendingPair();
36654
- const declared = this.opts.captureHeaders.find((d) => d.urlPattern === opts.urlPattern && d.headerName === opts.headerName);
36655
- if (!declared) {
36656
- throw new Error(`FetchproxyServer.captureRequestHeader: (urlPattern=${JSON.stringify(opts.urlPattern)}, headerName=${JSON.stringify(opts.headerName)}) not declared in captureHeaders`);
36845
+ const decls = this.opts.captureHeaders;
36846
+ let resolved;
36847
+ if (opts?.urlPattern !== void 0 && opts?.headerName !== void 0) {
36848
+ const found = decls.find((d) => d.urlPattern === opts.urlPattern && d.headerName === opts.headerName);
36849
+ if (!found) {
36850
+ throw new Error(`FetchproxyServer.captureRequestHeader: (urlPattern=${JSON.stringify(opts.urlPattern)}, headerName=${JSON.stringify(opts.headerName)}) not declared in captureHeaders`);
36851
+ }
36852
+ resolved = found;
36853
+ } else if (opts?.urlPattern === void 0 && opts?.headerName === void 0) {
36854
+ if (decls.length === 0) {
36855
+ throw new Error("FetchproxyServer.captureRequestHeader: no captureHeaders declared on this server \u2014 declare at least one entry in FetchproxyServerOpts.captureHeaders, or pass {urlPattern, headerName} explicitly");
36856
+ }
36857
+ if (decls.length > 1) {
36858
+ const list = decls.map((d) => `${JSON.stringify(d.urlPattern)}/${JSON.stringify(d.headerName)}`).join(", ");
36859
+ throw new Error(`FetchproxyServer.captureRequestHeader: multiple captureHeaders declared (${decls.length}: ${list}); pass {urlPattern, headerName} to disambiguate`);
36860
+ }
36861
+ resolved = decls[0];
36862
+ } else {
36863
+ throw new Error("FetchproxyServer.captureRequestHeader: pass both urlPattern AND headerName, or neither (which defaults to the single declared entry)");
36657
36864
  }
36865
+ const callOpts = { ...resolved, ...opts?.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {} };
36866
+ try {
36867
+ const result = await this._captureRequestHeaderOnce(callOpts);
36868
+ this.recordSuccess();
36869
+ return result;
36870
+ } catch (err) {
36871
+ const swDown = err instanceof FetchproxyProtocolError && classifyFetchError(err.message) === "content_script_unreachable";
36872
+ if (!swDown) {
36873
+ this.recordFailure(`capture_request_header: ${err.message ?? String(err)}`);
36874
+ throw err;
36875
+ }
36876
+ const reviveMs = this.opts.bridgeReviveDelayMs ?? 0;
36877
+ if (reviveMs > 0) {
36878
+ await new Promise((r) => setTimeout(r, reviveMs));
36879
+ try {
36880
+ const result = await this._captureRequestHeaderOnce(callOpts);
36881
+ this.recordSuccess();
36882
+ return result;
36883
+ } catch (retryErr) {
36884
+ const stillDown = retryErr instanceof FetchproxyProtocolError && classifyFetchError(retryErr.message) === "content_script_unreachable";
36885
+ if (!stillDown) {
36886
+ this.recordFailure(`capture_request_header: ${retryErr.message ?? String(retryErr)}`);
36887
+ throw retryErr;
36888
+ }
36889
+ this.recordFailure(`capture_request_header bridge-down: ${retryErr.message}`);
36890
+ throw new FetchproxyBridgeDownError({
36891
+ originalError: retryErr.message,
36892
+ retryAttempted: true,
36893
+ op: "capture_request_header",
36894
+ url: resolved.urlPattern,
36895
+ role: this.role,
36896
+ port: this.opts.port
36897
+ });
36898
+ }
36899
+ }
36900
+ this.recordFailure(`capture_request_header bridge-down: ${err.message}`);
36901
+ throw new FetchproxyBridgeDownError({
36902
+ originalError: err.message,
36903
+ retryAttempted: false,
36904
+ op: "capture_request_header",
36905
+ url: resolved.urlPattern,
36906
+ role: this.role,
36907
+ port: this.opts.port
36908
+ });
36909
+ }
36910
+ }
36911
+ async _captureRequestHeaderOnce(opts) {
36658
36912
  const id = this.nextRequestId++;
36659
36913
  const inner = {
36660
36914
  type: "request",
@@ -36763,18 +37017,35 @@ var FetchproxyServer = class {
36763
37017
  onInner(inner) {
36764
37018
  if (inner.type !== "response")
36765
37019
  return;
37020
+ this.lastExtensionMessageAt = Date.now();
36766
37021
  const fetchCb = this.pending.get(inner.id);
36767
37022
  if (fetchCb) {
36768
37023
  this.pending.delete(inner.id);
36769
37024
  if (inner.ok) {
36770
37025
  if (inner.op === void 0 || inner.op === "fetch") {
36771
- fetchCb({ ok: true, status: inner.status, url: inner.url, body: inner.body });
37026
+ fetchCb({
37027
+ ok: true,
37028
+ status: inner.status,
37029
+ url: inner.url,
37030
+ body: inner.body,
37031
+ retryAttempted: false
37032
+ });
36772
37033
  } else {
36773
37034
  const error51 = `unexpected ${inner.op} response on fetch awaiter`;
36774
- fetchCb({ ok: false, error: error51, kind: classifyFetchError(error51) });
37035
+ fetchCb({
37036
+ ok: false,
37037
+ error: error51,
37038
+ kind: classifyFetchError(error51),
37039
+ retryAttempted: false
37040
+ });
36775
37041
  }
36776
37042
  } else {
36777
- fetchCb({ ok: false, error: inner.error, kind: classifyFetchError(inner.error) });
37043
+ fetchCb({
37044
+ ok: false,
37045
+ error: inner.error,
37046
+ kind: classifyFetchError(inner.error),
37047
+ retryAttempted: false
37048
+ });
36778
37049
  }
36779
37050
  return;
36780
37051
  }
@@ -36844,7 +37115,12 @@ var FetchproxyServer = class {
36844
37115
  rejectAllPending(reason = "extension disconnected") {
36845
37116
  const err = new FetchproxyProtocolError(reason);
36846
37117
  for (const cb of this.pending.values()) {
36847
- cb({ ok: false, error: err.message, kind: classifyFetchError(err.message) });
37118
+ cb({
37119
+ ok: false,
37120
+ error: err.message,
37121
+ kind: classifyFetchError(err.message),
37122
+ retryAttempted: false
37123
+ });
36848
37124
  }
36849
37125
  this.pending.clear();
36850
37126
  for (const cb of this.pendingReadCookies.values()) {
@@ -36909,6 +37185,19 @@ var FetchproxyServer = class {
36909
37185
  }
36910
37186
  };
36911
37187
 
37188
+ // node_modules/@fetchproxy/server/dist/classify-bridge-error.js
37189
+ function classifyBridgeError(err) {
37190
+ if (err instanceof FetchproxyTimeoutError)
37191
+ return "timeout";
37192
+ if (err instanceof FetchproxyBridgeDownError)
37193
+ return "bridge_down";
37194
+ if (err instanceof FetchproxyHttpError)
37195
+ return "http";
37196
+ if (err instanceof FetchproxyProtocolError)
37197
+ return "protocol";
37198
+ return "other";
37199
+ }
37200
+
36912
37201
  // node_modules/@fetchproxy/bootstrap/dist/index.js
36913
37202
  var defaultFactory = (opts) => new FetchproxyServer(opts);
36914
37203
  async function bootstrap(opts) {
@@ -36963,7 +37252,11 @@ async function bootstrap(opts) {
36963
37252
  key: p.storageKey,
36964
37253
  jsonPointer: p.jsonPointer
36965
37254
  })),
36966
- onPairCode: opts.onPairCode
37255
+ onPairCode: opts.onPairCode,
37256
+ // 0.8.0+ pass-through. Only forwarded when the caller set them;
37257
+ // unset → server defaults apply (30000 / 2000 in 0.8.0).
37258
+ ...opts.fetchTimeoutMs !== void 0 ? { fetchTimeoutMs: opts.fetchTimeoutMs } : {},
37259
+ ...opts.bridgeReviveDelayMs !== void 0 ? { bridgeReviveDelayMs: opts.bridgeReviveDelayMs } : {}
36967
37260
  });
36968
37261
  const storageDomainOpts = {};
36969
37262
  if (opts.storageDomain !== void 0)
@@ -37066,7 +37359,7 @@ var BootstrapDisabledError = class extends Error {
37066
37359
  // package.json
37067
37360
  var package_default = {
37068
37361
  name: "honeybook-mcp",
37069
- version: "0.2.4",
37362
+ version: "0.3.1",
37070
37363
  mcpName: "io.github.chrischall/honeybook-mcp",
37071
37364
  description: "HoneyBook client-portal MCP server for Claude",
37072
37365
  author: "Claude Code (AI) <https://www.anthropic.com/claude>",
@@ -37106,7 +37399,8 @@ var package_default = {
37106
37399
  "test:watch": "vitest"
37107
37400
  },
37108
37401
  dependencies: {
37109
- "@fetchproxy/bootstrap": "^0.6.0",
37402
+ "@fetchproxy/bootstrap": "^0.8.0",
37403
+ "@fetchproxy/server": "^0.8.0",
37110
37404
  "@modelcontextprotocol/sdk": "^1.29.0",
37111
37405
  dotenv: "^17.4.2",
37112
37406
  zod: "^4.4.3"
@@ -37207,6 +37501,12 @@ async function captureSessionViaFetchproxy(opts) {
37207
37501
  }
37208
37502
  });
37209
37503
  } catch (e) {
37504
+ if (classifyBridgeError(e) === "bridge_down") {
37505
+ const downErr = e;
37506
+ throw new Error(
37507
+ `HoneyBook auth: fetchproxy bridge is down (extension service worker unreachable after retry). ${downErr.hint}`
37508
+ );
37509
+ }
37210
37510
  const msg = e instanceof Error ? e.message : String(e);
37211
37511
  throw new Error(
37212
37512
  `HoneyBook auth: fetchproxy capture failed: ${msg} \u2014 open the vendor magic-link URL in Chrome (with the fetchproxy 0.3.0 extension installed), then retry.`
@@ -37732,7 +38032,7 @@ try {
37732
38032
  }
37733
38033
  var server = new McpServer({
37734
38034
  name: "honeybook-mcp",
37735
- version: "0.2.4"
38035
+ version: "0.3.1"
37736
38036
  // x-release-please-version
37737
38037
  });
37738
38038
  registerSessionTools(server);
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ import { registerContractTools } from './tools/contracts.js';
18
18
  import { registerInvoiceTools } from './tools/invoices.js';
19
19
  const server = new McpServer({
20
20
  name: 'honeybook-mcp',
21
- version: '0.2.4', // x-release-please-version
21
+ version: '0.3.1', // x-release-please-version
22
22
  });
23
23
  registerSessionTools(server);
24
24
  registerWorkspaceFileTools(server);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "honeybook-mcp",
3
- "version": "0.2.4",
3
+ "version": "0.3.1",
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>",
@@ -40,7 +40,8 @@
40
40
  "test:watch": "vitest"
41
41
  },
42
42
  "dependencies": {
43
- "@fetchproxy/bootstrap": "^0.6.0",
43
+ "@fetchproxy/bootstrap": "^0.8.0",
44
+ "@fetchproxy/server": "^0.8.0",
44
45
  "@modelcontextprotocol/sdk": "^1.29.0",
45
46
  "dotenv": "^17.4.2",
46
47
  "zod": "^4.4.3"
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": "0.2.4",
9
+ "version": "0.3.1",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "honeybook-mcp",
14
- "version": "0.2.4",
14
+ "version": "0.3.1",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },