@leadbay/mcp 0.32.1 → 0.32.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Changelog — @leadbay/mcp
2
2
 
3
+ ## 0.32.4 — 2026-09-01
4
+
5
+ `leadbay_account_status.notifications` was permanently `[]` on the hosted server
6
+ (product#4009). Same shape as product#4005: `buildServerFromClient` builds every
7
+ hosted server without a `notificationsInbox`, `BuildServerOptions` makes it
8
+ optional, so it compiled and failed silently.
9
+
10
+ **Not fixed by wiring the inbox, because the inbox cannot exist there.** It is
11
+ fed by a WS listener whose ticket (`GET /auth/ws`) is per-account, which is
12
+ meaningless on a multi-tenant process, and the streamable transport builds a
13
+ fresh `Server` per request so nothing would survive to be cached. Porting it
14
+ would be the same mistake in a third place.
15
+
16
+ `GET /notifications` is already per-account and already durable. On hosted the
17
+ ledger IS the inbox, so `account_status` reads it on demand when no inbox is
18
+ wired. Stdio is unchanged and still free — the WS listener already has the
19
+ answer, and the ledger is not called.
20
+
21
+ - `fetchTerminalNotifications(client)` in `notifications/catch-up.ts` returns
22
+ terminal, unseen entries directly. `isTerminalUnseen` is extracted so inbox
23
+ seeding and the inbox-less read cannot disagree about what counts.
24
+ - A notifications failure resolves to `[]` rather than throwing. `account_status`
25
+ is the daily entry point; a ledger hiccup must not take the check-in down.
26
+ - **Deliberately not done: `_meta.notifications` still does not ride hosted tool
27
+ responses.** Reviving it would mean a `GET /notifications` per tool call to
28
+ decorate every response. The cost lands on the check-in entry point only,
29
+ which is where the daily-rhythm channel is actually read.
30
+
3
31
  ## 0.32.0 — 2026-09-01
4
32
 
5
33
  A poll-budget timeout stops being an error (product#4007). The import wizard's
package/dist/bin.js CHANGED
@@ -5568,6 +5568,28 @@ var init_inbox = __esm({
5568
5568
  });
5569
5569
 
5570
5570
  // ../core/dist/notifications/catch-up.js
5571
+ function isTerminalUnseen(n) {
5572
+ if (!n.bulk_progress)
5573
+ return false;
5574
+ if (n.in_progress)
5575
+ return false;
5576
+ if (n.first_seen_at)
5577
+ return false;
5578
+ return true;
5579
+ }
5580
+ async function fetchTerminalNotifications(client, opts = {}) {
5581
+ try {
5582
+ const page = await client.listNotifications({
5583
+ archived: false,
5584
+ page: 0,
5585
+ count: opts.count ?? DEFAULT_COUNT
5586
+ });
5587
+ return page.items.filter(isTerminalUnseen).map(toInboxEntry);
5588
+ } catch (err) {
5589
+ opts.logger?.warn?.(`notifications.fetch_terminal failed: ${err?.message ?? err?.code ?? err}`);
5590
+ return [];
5591
+ }
5592
+ }
5571
5593
  async function catchUpNotifications(client, inbox, opts = {}) {
5572
5594
  const count = opts.count ?? DEFAULT_COUNT;
5573
5595
  let added = 0;
@@ -5578,11 +5600,7 @@ async function catchUpNotifications(client, inbox, opts = {}) {
5578
5600
  count
5579
5601
  });
5580
5602
  for (const n of page.items) {
5581
- if (!n.bulk_progress)
5582
- continue;
5583
- if (n.in_progress)
5584
- continue;
5585
- if (n.first_seen_at)
5603
+ if (!isTerminalUnseen(n))
5586
5604
  continue;
5587
5605
  const sizeBefore = inbox.size();
5588
5606
  inbox.record(n);
@@ -5599,6 +5617,7 @@ var DEFAULT_COUNT;
5599
5617
  var init_catch_up = __esm({
5600
5618
  "../core/dist/notifications/catch-up.js"() {
5601
5619
  "use strict";
5620
+ init_revise_hint();
5602
5621
  DEFAULT_COUNT = 50;
5603
5622
  }
5604
5623
  });
@@ -20718,6 +20737,7 @@ var init_account_status = __esm({
20718
20737
  "../core/dist/composite/account-status.js"() {
20719
20738
  "use strict";
20720
20739
  init_agent_memory();
20740
+ init_catch_up();
20721
20741
  init_credits_helpers();
20722
20742
  init_tool_descriptions_generated();
20723
20743
  accountStatus = {
@@ -20839,6 +20859,8 @@ var init_account_status = __esm({
20839
20859
  ctx?.logger?.warn?.(`account_status: quota_status failed: ${err?.message ?? err?.code ?? err}`);
20840
20860
  }
20841
20861
  }
20862
+ const inbox = ctx?.notificationsInbox;
20863
+ const notifications = inbox ? inbox.list() : await fetchTerminalNotifications(client, { logger: ctx?.logger });
20842
20864
  const lensId = me.last_requested_lens ?? null;
20843
20865
  const lensAsked = typeof ctx?.triggered_by === "string" && /\b(lens|lenses|audience|targeting|segment|filter)\b/i.test(ctx.triggered_by);
20844
20866
  let last_requested_lens_name = null;
@@ -20879,13 +20901,12 @@ var init_account_status = __esm({
20879
20901
  // on /me are intentionally NOT surfaced — they're defunct (see
20880
20902
  // SHAPE-DRIFT.md probe round 4).
20881
20903
  quota,
20882
- // Inbox of terminal bulk-progress notifications. Same shape the MCP
20883
- // server attaches to `_meta.notifications` on every tool response —
20884
- // duplicated here as a top-level field so the agent's daily-rhythm
20885
- // check-in (this composite) sees them without having to read _meta.
20886
- // Empty array when the WS listener isn't wired (OpenClaw, tests) OR
20887
- // when nothing has completed since the last ack.
20888
- notifications: ctx?.notificationsInbox?.list() ?? [],
20904
+ // Terminal bulk-progress notifications. Same shape the MCP server
20905
+ // attaches to `_meta.notifications` on every tool response — carried
20906
+ // here as a top-level field so the agent's daily-rhythm check-in (this
20907
+ // composite) sees them without reading _meta. See the read above for
20908
+ // why hosted takes a different path to the same list.
20909
+ notifications,
20889
20910
  // Non-null ONLY when the quota_status call failed. The agent must treat
20890
20911
  // this as "could not read quota" — NOT as zero usage, and NOT as a broken
20891
20912
  // login (the token just authenticated /users/me above). product#3761.
@@ -32940,7 +32961,7 @@ var OAUTH_BASE_URLS = {
32940
32961
  fr: "https://staging.api.leadbay.app"
32941
32962
  }
32942
32963
  };
32943
- var VERSION = "0.32.1";
32964
+ var VERSION = "0.32.4";
32944
32965
  var HELP = `
32945
32966
  leadbay-mcp ${VERSION} \u2014 Leadbay Model Context Protocol server
32946
32967
 
@@ -8101,9 +8101,82 @@ var COMPOSITE_FILE_TOOL_NAMES = /* @__PURE__ */ new Set([
8101
8101
  "leadbay_tour_plan"
8102
8102
  ]);
8103
8103
 
8104
+ // ../core/dist/notifications/revise-hint.js
8105
+ var HINT_BULK_ENRICH = "Contact enrichment just finished. Revise any prior output that named these leads' contacts (outreach drafts, contact lists, recommended-lead lists with contact_count, NEXT STEPS asking the user to wait for emails / phones). Re-fetch contacts via leadbay_get_contacts for the affected leads.";
8106
+ var HINT_BULK_QUALIFY = "Lead qualification just finished. Revise any prior lead list / ranking / outreach shortlist that depended on ai_agent_lead_score for these leads \u2014 today's leads, top-of-inbox, followups maps, prepare-outreach shortlists. Re-pull qualification answers via leadbay_research_lead_by_id or re-rank via leadbay_pull_leads.";
8107
+ var HINT_IMPORT = "CSV / CRM import just finished. Revise any prior output that referenced 'leads available' before the import landed \u2014 lead lists pulled from the affected lens, 'what's new today', followup planning. Re-pull the affected lens via leadbay_pull_leads / leadbay_pull_followups.";
8108
+ var HINT_OTHER = "Background work just completed. If you referenced its subject in prior output, re-fetch the affected data and revise.";
8109
+ function reviseHintFor(kind) {
8110
+ switch (kind) {
8111
+ case "bulk_enrich":
8112
+ return HINT_BULK_ENRICH;
8113
+ case "bulk_qualify":
8114
+ return HINT_BULK_QUALIFY;
8115
+ case "import":
8116
+ return HINT_IMPORT;
8117
+ default:
8118
+ return HINT_OTHER;
8119
+ }
8120
+ }
8121
+ function inferKind(n) {
8122
+ if (n.links.some((l) => l.type === "bulk_enrichment"))
8123
+ return "bulk_enrich";
8124
+ if (n.file_import_id)
8125
+ return "import";
8126
+ if (n.bulk_progress)
8127
+ return "bulk_qualify";
8128
+ return "other";
8129
+ }
8130
+ function anchorIdFor(n, kind) {
8131
+ if (kind === "bulk_enrich") {
8132
+ const link = n.links.find((l) => l.type === "bulk_enrichment");
8133
+ return link ? String(link.id) : null;
8134
+ }
8135
+ if (kind === "import")
8136
+ return n.file_import_id;
8137
+ return null;
8138
+ }
8139
+ function toInboxEntry(n) {
8140
+ const kind = inferKind(n);
8141
+ return {
8142
+ notification_id: n.id,
8143
+ kind,
8144
+ anchor_id: anchorIdFor(n, kind),
8145
+ title: n.title,
8146
+ bulk_progress: n.bulk_progress,
8147
+ completed_at: n.updated_at,
8148
+ revise_hint: reviseHintFor(kind)
8149
+ };
8150
+ }
8151
+
8104
8152
  // ../core/dist/notifications/inbox.js
8105
8153
  var DEFAULT_TTL_MS = 24 * 60 * 60 * 1e3;
8106
8154
 
8155
+ // ../core/dist/notifications/catch-up.js
8156
+ var DEFAULT_COUNT = 50;
8157
+ function isTerminalUnseen(n) {
8158
+ if (!n.bulk_progress)
8159
+ return false;
8160
+ if (n.in_progress)
8161
+ return false;
8162
+ if (n.first_seen_at)
8163
+ return false;
8164
+ return true;
8165
+ }
8166
+ async function fetchTerminalNotifications(client, opts = {}) {
8167
+ try {
8168
+ const page = await client.listNotifications({
8169
+ archived: false,
8170
+ page: 0,
8171
+ count: opts.count ?? DEFAULT_COUNT
8172
+ });
8173
+ return page.items.filter(isTerminalUnseen).map(toInboxEntry);
8174
+ } catch (err) {
8175
+ opts.logger?.warn?.(`notifications.fetch_terminal failed: ${err?.message ?? err?.code ?? err}`);
8176
+ return [];
8177
+ }
8178
+ }
8179
+
8107
8180
  // ../core/dist/tool-descriptions.generated.js
8108
8181
  var leadbay_account_history = `## WHEN TO USE
8109
8182
 
@@ -22490,6 +22563,8 @@ var accountStatus = {
22490
22563
  ctx?.logger?.warn?.(`account_status: quota_status failed: ${err?.message ?? err?.code ?? err}`);
22491
22564
  }
22492
22565
  }
22566
+ const inbox = ctx?.notificationsInbox;
22567
+ const notifications = inbox ? inbox.list() : await fetchTerminalNotifications(client, { logger: ctx?.logger });
22493
22568
  const lensId = me.last_requested_lens ?? null;
22494
22569
  const lensAsked = typeof ctx?.triggered_by === "string" && /\b(lens|lenses|audience|targeting|segment|filter)\b/i.test(ctx.triggered_by);
22495
22570
  let last_requested_lens_name = null;
@@ -22530,13 +22605,12 @@ var accountStatus = {
22530
22605
  // on /me are intentionally NOT surfaced — they're defunct (see
22531
22606
  // SHAPE-DRIFT.md probe round 4).
22532
22607
  quota,
22533
- // Inbox of terminal bulk-progress notifications. Same shape the MCP
22534
- // server attaches to `_meta.notifications` on every tool response —
22535
- // duplicated here as a top-level field so the agent's daily-rhythm
22536
- // check-in (this composite) sees them without having to read _meta.
22537
- // Empty array when the WS listener isn't wired (OpenClaw, tests) OR
22538
- // when nothing has completed since the last ack.
22539
- notifications: ctx?.notificationsInbox?.list() ?? [],
22608
+ // Terminal bulk-progress notifications. Same shape the MCP server
22609
+ // attaches to `_meta.notifications` on every tool response — carried
22610
+ // here as a top-level field so the agent's daily-rhythm check-in (this
22611
+ // composite) sees them without reading _meta. See the read above for
22612
+ // why hosted takes a different path to the same list.
22613
+ notifications,
22540
22614
  // Non-null ONLY when the quota_status call failed. The agent must treat
22541
22615
  // this as "could not read quota" — NOT as zero usage, and NOT as a broken
22542
22616
  // login (the token just authenticated /users/me above). product#3761.
@@ -22550,7 +22624,7 @@ var accountStatus = {
22550
22624
 
22551
22625
  // ../core/dist/composite/bulk-qualify-leads.js
22552
22626
  var PAGE_SIZE = 50;
22553
- var DEFAULT_COUNT = 10;
22627
+ var DEFAULT_COUNT2 = 10;
22554
22628
  var MAX_COUNT = 25;
22555
22629
  var DEFAULT_PER_LEAD_BUDGET_MS = 9e4;
22556
22630
  var DEFAULT_TOTAL_BUDGET_MS2 = 5 * 6e4;
@@ -22598,7 +22672,7 @@ var bulkQualifyLeads = {
22598
22672
  properties: {
22599
22673
  count: {
22600
22674
  type: "number",
22601
- description: `How many fresh leads to qualify (default ${DEFAULT_COUNT}, max ${MAX_COUNT})`
22675
+ description: `How many fresh leads to qualify (default ${DEFAULT_COUNT2}, max ${MAX_COUNT})`
22602
22676
  },
22603
22677
  leadIds: {
22604
22678
  type: "array",
@@ -22689,7 +22763,7 @@ var bulkQualifyLeads = {
22689
22763
  ]
22690
22764
  },
22691
22765
  execute: async (client, params, ctx) => {
22692
- const wantCount = Math.min(params.count ?? DEFAULT_COUNT, MAX_COUNT);
22766
+ const wantCount = Math.min(params.count ?? DEFAULT_COUNT2, MAX_COUNT);
22693
22767
  const perLeadBudget = params.per_lead_budget_ms ?? DEFAULT_PER_LEAD_BUDGET_MS;
22694
22768
  const totalBudget = params.total_budget_ms ?? DEFAULT_TOTAL_BUDGET_MS2;
22695
22769
  const totalDeadline = Date.now() + totalBudget;
@@ -29473,7 +29547,7 @@ function parseWriteEnv(env = process.env) {
29473
29547
  }
29474
29548
 
29475
29549
  // src/http-server.ts
29476
- var VERSION = true ? "0.32.1" : "0.0.0-dev";
29550
+ var VERSION = true ? "0.32.4" : "0.0.0-dev";
29477
29551
  var PORT = Number(process.env.PORT ?? 8080);
29478
29552
  var HOST = process.env.HOST ?? "0.0.0.0";
29479
29553
  var logger = {
@@ -1804,7 +1804,7 @@ var init_installer_gui = __esm({
1804
1804
  init_install_dxt();
1805
1805
  init_install_shared();
1806
1806
  init_oauth();
1807
- VERSION = true ? "0.32.1" : "0.0.0-dev";
1807
+ VERSION = true ? "0.32.4" : "0.0.0-dev";
1808
1808
  MESSAGES = {
1809
1809
  en: {
1810
1810
  installer: {
@@ -1067,7 +1067,7 @@ async function oauthLogin(opts) {
1067
1067
  }
1068
1068
 
1069
1069
  // installer/installer-gui.ts
1070
- var VERSION = true ? "0.32.1" : "0.0.0-dev";
1070
+ var VERSION = true ? "0.32.4" : "0.0.0-dev";
1071
1071
  var MESSAGES = {
1072
1072
  en: {
1073
1073
  installer: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leadbay/mcp",
3
- "version": "0.32.1",
3
+ "version": "0.32.4",
4
4
  "mcpName": "io.github.leadbay/leadbay-mcp",
5
5
  "description": "Model Context Protocol (MCP) server for Leadbay — AI lead discovery, qualification, and enrichment for Claude Desktop, Cursor, and Claude Code.",
6
6
  "type": "module",