@leadbay/mcp 0.23.8 → 0.23.10
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 +14 -0
- package/README.md +5 -5
- package/dist/bin.js +90 -40
- package/dist/http-server.js +109 -37
- package/dist/installer-electron.js +1 -1
- package/dist/installer-gui.js +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog — @leadbay/mcp
|
|
2
2
|
|
|
3
|
+
## 0.23.10 — 2026-07-01
|
|
4
|
+
|
|
5
|
+
A freshly-created lens no longer reads as "empty" (product#3833).
|
|
6
|
+
|
|
7
|
+
- **`leadbay_new_lens`** — creating a lens with criteria queues an asynchronous backend wishlist rebuild, so an immediate `leadbay_pull_leads` can read empty for a few seconds while it computes. The `created` result now carries `computing_wishlist: true` and a "leads stream in — pull in ~30s" message so the agent waits instead of reporting an empty lens. A criteria-less clone inherits the base lens's leads immediately (`computing_wishlist: false`).
|
|
8
|
+
- **`leadbay_pull_leads`** — on an EMPTY page where the backend reports the lens is still computing (`computing_wishlist`/`computing_scores`), `next_steps` now carries a single "Re-pull in ~30s" option (`kind: repull_computing`) instead of `null`, so the agent renders a wait-and-retry widget rather than "no leads." An empty page with nothing computing still returns `null` (a genuinely empty / over-narrow lens — no fabricated leads).
|
|
9
|
+
- Confirmed against `leadbay/backend` (`POST /lenses/:id/filter` → `queueRefreshJob` → `RefreshLens`) and a live probe on `api-us`: a bare clone shows leads instantly; a filtered clone shows `computing_wishlist: true` then settles within ~1–30s.
|
|
10
|
+
|
|
11
|
+
## 0.23.9 — 2026-06-27
|
|
12
|
+
|
|
13
|
+
MCP data plane now targets backend **/1.6** (was /1.5).
|
|
14
|
+
|
|
15
|
+
- **`client`** — every request path is built from a single `API_VERSION = "1.6"` constant (exported as `API_PREFIX`). `LeadbayClient` (request / requestVoid / requestRawBinary + mock-mode paths) and `bin.ts`'s login probe all reference it, so future backend version bumps are a one-line change. Verified live on `api-us` before shipping: `/1.6` mirrors `/1.5` across the full route surface probed (monitor, lenses, auth/login, kpi, geo) — identical status on every call. Tool-description prose and route-doc comments updated to /1.6 to match.
|
|
16
|
+
|
|
3
17
|
## 0.23.8 — 2026-06-26
|
|
4
18
|
|
|
5
19
|
Installer no longer hangs in Claude Cowork / headless terminals (product#3805).
|
package/README.md
CHANGED
|
@@ -143,11 +143,11 @@ To rotate the local MCP credential, re-run `npx -y @leadbay/mcp install --oauth`
|
|
|
143
143
|
### Install via the Claude Code plugin marketplace
|
|
144
144
|
|
|
145
145
|
```text
|
|
146
|
-
/plugin marketplace add leadbay/
|
|
146
|
+
/plugin marketplace add leadbay/mcp
|
|
147
147
|
```
|
|
148
148
|
|
|
149
149
|
```text
|
|
150
|
-
/plugin install leadbay@leadbay-
|
|
150
|
+
/plugin install leadbay@leadbay-mcp
|
|
151
151
|
```
|
|
152
152
|
|
|
153
153
|
Claude Code prompts for Leadbay auth/config through the plugin's `userConfig`. This is equivalent to the npm/CLI install above.
|
|
@@ -157,13 +157,13 @@ The plugin install gives you **two surfaces in one shot**:
|
|
|
157
157
|
1. **The MCP server** — registered via the plugin's `mcpServers.leadbay` block (boots `@leadbay/mcp` over stdio). This exposes the `leadbay_*` tools to the agent.
|
|
158
158
|
2. **Six auto-discovered Claude Code skills** under `skills/` — `leadbay_daily_check_in`, `leadbay_research_a_domain`, `leadbay_import_file`, `leadbay_log_outreach`, `leadbay_qualify_top_n`, `leadbay_refine_audience`. These auto-trigger on natural-language matches against each skill's description ("get me leadbay leads today", "research acme.com", etc.) and dispatch to the MCP tools above by name. Each `SKILL.md` is generated by `@leadbay/promptforge` from the same `.md.tmpl` source as the MCP prompt, so the two surfaces never drift.
|
|
159
159
|
|
|
160
|
-
You can verify the skills installed by running `/skill list` after install. To uninstall everything, `/plugin uninstall leadbay@leadbay-
|
|
160
|
+
You can verify the skills installed by running `/skill list` after install. To uninstall everything, `/plugin uninstall leadbay@leadbay-mcp` removes the MCP server registration **and** the skills together.
|
|
161
161
|
|
|
162
162
|
### Claude Desktop
|
|
163
163
|
|
|
164
164
|
The guided installer writes the local `mcpServers.leadbay` entry in `claude_desktop_config.json` with `npx -y @leadbay/mcp@latest`, like the Linux flow. Restart Claude Desktop after install.
|
|
165
165
|
|
|
166
|
-
The `.dxt` / `.mcpb` bundle from [Releases](https://github.com/leadbay/
|
|
166
|
+
The `.dxt` / `.mcpb` bundle from [Releases](https://github.com/leadbay/mcp/releases/latest) remains available as an alternative install path.
|
|
167
167
|
|
|
168
168
|
### `npm install -g` says "EACCES" / "permission denied"
|
|
169
169
|
|
|
@@ -551,7 +551,7 @@ The user's literal text replaces `verification.ref` in the outreach record, and
|
|
|
551
551
|
|
|
552
552
|
## 7. Upgrade & rotation
|
|
553
553
|
|
|
554
|
-
**Upgrade**: the guided installer pins `@leadbay/mcp@latest`, so each MCP session already picks up the newest published version — just restart the client. (If you hand-pinned a specific version in your config, change it to `@latest` or the version you want, then restart.) **0.3.0 enables composite write tools by default** — see [MIGRATION.md](./MIGRATION.md). See also the [changelog](https://github.com/leadbay/
|
|
554
|
+
**Upgrade**: the guided installer pins `@leadbay/mcp@latest`, so each MCP session already picks up the newest published version — just restart the client. (If you hand-pinned a specific version in your config, change it to `@latest` or the version you want, then restart.) **0.3.0 enables composite write tools by default** — see [MIGRATION.md](./MIGRATION.md). See also the [changelog](https://github.com/leadbay/mcp/releases).
|
|
555
555
|
|
|
556
556
|
**Rotate local credential**: re-run `npx -y @leadbay/mcp@latest install --oauth` (or `login --oauth`) — the new credential replaces the old one in your MCP client config.
|
|
557
557
|
|
package/dist/bin.js
CHANGED
|
@@ -68,7 +68,7 @@ async function resolveRegion(email, password, startWith = "us") {
|
|
|
68
68
|
const baseUrl = REGIONS[region];
|
|
69
69
|
const body = JSON.stringify({ email, password });
|
|
70
70
|
try {
|
|
71
|
-
const res = await httpsRequest("POST", `${baseUrl}/
|
|
71
|
+
const res = await httpsRequest("POST", `${baseUrl}${API_PREFIX}/auth/login`, { "Content-Type": "application/json" }, body);
|
|
72
72
|
if (res.status === 200) {
|
|
73
73
|
const parsed = JSON.parse(res.body);
|
|
74
74
|
if (parsed?.token) {
|
|
@@ -159,7 +159,7 @@ function parseRetryAfter(value) {
|
|
|
159
159
|
}
|
|
160
160
|
return null;
|
|
161
161
|
}
|
|
162
|
-
var LENS_CACHE_TTL_MS, TASTE_CACHE_TTL_MS, ME_CACHE_TTL_MS, MAX_CONCURRENT, REGIONS, _mockFixtures, _mockJournal, LeadbayClient;
|
|
162
|
+
var LENS_CACHE_TTL_MS, TASTE_CACHE_TTL_MS, ME_CACHE_TTL_MS, MAX_CONCURRENT, REGIONS, API_VERSION, API_PREFIX, _mockFixtures, _mockJournal, LeadbayClient;
|
|
163
163
|
var init_client = __esm({
|
|
164
164
|
"../core/dist/client.js"() {
|
|
165
165
|
"use strict";
|
|
@@ -171,6 +171,8 @@ var init_client = __esm({
|
|
|
171
171
|
us: "https://api-us.leadbay.app",
|
|
172
172
|
fr: "https://api-fr.leadbay.app"
|
|
173
173
|
};
|
|
174
|
+
API_VERSION = "1.6";
|
|
175
|
+
API_PREFIX = `/${API_VERSION}`;
|
|
174
176
|
_mockFixtures = null;
|
|
175
177
|
_mockJournal = [];
|
|
176
178
|
LeadbayClient = class {
|
|
@@ -313,7 +315,7 @@ var init_client = __esm({
|
|
|
313
315
|
const retryOn401 = opts?.retryOn401 !== false;
|
|
314
316
|
await this.acquireSemaphore();
|
|
315
317
|
try {
|
|
316
|
-
const url = `${this._baseUrl}
|
|
318
|
+
const url = `${this._baseUrl}${API_PREFIX}${path}`;
|
|
317
319
|
const headers = {
|
|
318
320
|
Authorization: `Bearer ${this.token}`
|
|
319
321
|
};
|
|
@@ -348,7 +350,7 @@ var init_client = __esm({
|
|
|
348
350
|
}
|
|
349
351
|
await this.acquireSemaphore();
|
|
350
352
|
try {
|
|
351
|
-
const url = `${this._baseUrl}
|
|
353
|
+
const url = `${this._baseUrl}${API_PREFIX}${path}`;
|
|
352
354
|
const headers = {
|
|
353
355
|
Authorization: `Bearer ${this.token}`
|
|
354
356
|
};
|
|
@@ -373,7 +375,7 @@ var init_client = __esm({
|
|
|
373
375
|
// serialized body (string for text payloads such as CSV; Buffer for binary
|
|
374
376
|
// uploads). Auth, semaphore, error mapping, _lastMeta, and mock-mode all
|
|
375
377
|
// mirror request() exactly. Used by leadbay_import_leads to upload CSVs to
|
|
376
|
-
// the wizard at POST /1.
|
|
378
|
+
// the wizard at POST /1.6/imports.
|
|
377
379
|
async requestRawBinary(method, path, contentType, body) {
|
|
378
380
|
if (process.env.LEADBAY_MOCK === "1") {
|
|
379
381
|
return this.mockRequestBinary(method, path, contentType, body);
|
|
@@ -383,7 +385,7 @@ var init_client = __esm({
|
|
|
383
385
|
}
|
|
384
386
|
await this.acquireSemaphore();
|
|
385
387
|
try {
|
|
386
|
-
const url = `${this._baseUrl}
|
|
388
|
+
const url = `${this._baseUrl}${API_PREFIX}${path}`;
|
|
387
389
|
const headers = {
|
|
388
390
|
Authorization: `Bearer ${this.token}`,
|
|
389
391
|
"Content-Type": contentType
|
|
@@ -407,7 +409,7 @@ var init_client = __esm({
|
|
|
407
409
|
}
|
|
408
410
|
}
|
|
409
411
|
mockRequest(method, path, body) {
|
|
410
|
-
const fullPath =
|
|
412
|
+
const fullPath = `${API_PREFIX}${path}`;
|
|
411
413
|
this._lastMeta = {
|
|
412
414
|
region: this._region,
|
|
413
415
|
endpoint: `${method} ${path}`,
|
|
@@ -430,7 +432,7 @@ var init_client = __esm({
|
|
|
430
432
|
};
|
|
431
433
|
}
|
|
432
434
|
mockRequestBinary(method, path, contentType, body) {
|
|
433
|
-
const fullPath =
|
|
435
|
+
const fullPath = `${API_PREFIX}${path}`;
|
|
434
436
|
this._lastMeta = {
|
|
435
437
|
region: this._region,
|
|
436
438
|
endpoint: `${method} ${path}`,
|
|
@@ -5695,7 +5697,7 @@ WHEN TO USE: at the start of a session to know what the agent can/can't do, afte
|
|
|
5695
5697
|
|
|
5696
5698
|
WHEN NOT TO USE: as a pre-flight gate before bulk ops \u2014 operations themselves return 429; this tool is for context, not gating. And: a recent quota snapshot showing "exhausted" is NOT a reason to refuse a write call when the user has just topped up \u2014 re-call this tool first, then proceed.
|
|
5697
5699
|
`;
|
|
5698
|
-
leadbay_acknowledge_notification = `Acknowledge a Leadbay notification \u2014 i.e. tell the MCP and the backend "I've seen this and acted on it." Wraps \`POST /1.
|
|
5700
|
+
leadbay_acknowledge_notification = `Acknowledge a Leadbay notification \u2014 i.e. tell the MCP and the backend "I've seen this and acted on it." Wraps \`POST /1.6/notifications/{id}/seen\` (default) or \`/archive\` (when \`archive:true\`) and drops the entry from the local inbox so subsequent \`_meta.notifications\` payloads stop carrying it.
|
|
5699
5701
|
|
|
5700
5702
|
**When to call.** After you read an entry from \`_meta.notifications\` or \`account_status.notifications\` and have revised whatever prior output the just-finished background work might have made stale (outreach drafts, lead lists, "available leads" claims, followup plans). Mark-seen tells the human team's pipeline you handled this and prevents the notification from re-surfacing on every subsequent tool response.
|
|
5701
5703
|
|
|
@@ -6305,7 +6307,7 @@ WHEN NOT TO USE: from agent flow \u2014 leadbay_adjust_audience handles the draf
|
|
|
6305
6307
|
|
|
6306
6308
|
This tool MUTATES state. The caller (agent or human-in-the-loop) is responsible for confirming intent before invocation; the MCP server does not soft-prompt for confirmation. See \`annotations.destructiveHint\`.
|
|
6307
6309
|
`;
|
|
6308
|
-
leadbay_create_topup_link = `Generate a one-shot Stripe checkout session for an AI-credits top-up. Wraps \`POST /1.
|
|
6310
|
+
leadbay_create_topup_link = `Generate a one-shot Stripe checkout session for an AI-credits top-up. Wraps \`POST /1.6/stripe/topup_checkout\` \u2192 \`{url}\`. Returns a fresh Stripe-hosted URL (~1 hour TTL); creating one does NOT charge the user \u2014 payment happens only after the user opens the URL and completes checkout in their browser.
|
|
6309
6311
|
|
|
6310
6312
|
**When a quota window is hit, offer top-up as the FIRST option.** A top-up clears the throttle immediately (no need to wait for the daily/weekly/monthly window reset). The flow:
|
|
6311
6313
|
|
|
@@ -7409,8 +7411,9 @@ On \`preview\` (default \u2014 NOTHING created yet): show the lens that WILL be
|
|
|
7409
7411
|
created (name + resolved sectors/sizes as chips) and ASK the user to confirm
|
|
7410
7412
|
via ask_user_input_v0 ("Create this lens?" / "Change something"). Only on
|
|
7411
7413
|
"yes" re-call with confirm:true. On \`created\`: confirm "Created **<name>**."
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
+
(if \`computing_wishlist:true\`, add that leads stream in \u2014 pull in ~30s, don't
|
|
7415
|
+
report "empty"). On \`ambiguous_sectors\` / \`ambiguous_locations\`: surface the
|
|
7416
|
+
candidates to pick from.
|
|
7414
7417
|
|
|
7415
7418
|
---
|
|
7416
7419
|
|
|
@@ -7424,6 +7427,8 @@ Create a brand-new lens (saved audience) and apply its sector/size criteria. Clo
|
|
|
7424
7427
|
|
|
7425
7428
|
**Does not switch the active lens.** The new lens is created but the user stays on their current one. Offer \`leadbay_my_lenses(switchToLensId=<new id>)\` as a next step if they want to start pulling from it.
|
|
7426
7429
|
|
|
7430
|
+
**Leads compute asynchronously.** When the lens has criteria, applying the filter kicks off a backend wishlist rebuild \u2014 the \`created\` result carries \`computing_wishlist:true\`. An immediate \`leadbay_pull_leads\` may read empty for a few seconds while it computes; that lens is *warming up*, not empty. Wait ~30s before the first pull (or offer the user a re-pull). A criteria-less clone inherits the base lens's leads right away (\`computing_wishlist:false\`).
|
|
7431
|
+
|
|
7427
7432
|
WHEN TO USE: when the user wants a NEW lens. Canonical phrasings: "create a lens called X", "make a new audience for Y", "set up a lens for <sector>".
|
|
7428
7433
|
|
|
7429
7434
|
WHEN NOT TO USE: to EDIT an existing lens \u2014 use \`leadbay_adjust_audience\` (pass \`lensName\` to target one by name). Not for listing/switching (\`leadbay_my_lenses\`) or topping up (\`leadbay_extend_lens\`).
|
|
@@ -7477,19 +7482,25 @@ User picks \u2192 call the matching \`Calls\` tool. Constraints: 2\u20134 mutual
|
|
|
7477
7482
|
Pick the rows that fit. On \`created\`, the switch + pull rows are the natural
|
|
7478
7483
|
follow-ups. On \`ambiguous_sectors\`, the only move is to pick a sector and re-call.
|
|
7479
7484
|
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
|
|
|
7486
|
-
|
|
7487
|
-
| \`
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
|
|
7485
|
+
**\`created\` with \`computing_wishlist: true\`** \u2014 the new lens's leads are being
|
|
7486
|
+
(re)computed asynchronously. Do NOT fire an immediate \`leadbay_pull_leads\` and
|
|
7487
|
+
report "empty" \u2014 the lens is warming up, not empty. Tell the user the lens was
|
|
7488
|
+
created and its leads are streaming in, and offer to pull in ~30s.
|
|
7489
|
+
|
|
7490
|
+
| Observation | Suggest | Calls |
|
|
7491
|
+
|-----------------------------------------|------------------------------------------|--------------------------------------------------------|
|
|
7492
|
+
| \`preview\` (not yet created) | "Yes, create this lens" | \`leadbay_new_lens(...same args..., confirm=true)\` |
|
|
7493
|
+
| \`preview\` (not yet created) | "Change the sectors/size first" | (re-ask the user, then \`leadbay_new_lens\` with new args) |
|
|
7494
|
+
| Lens created, \`computing_wishlist=true\` | "Give it ~30s, then pull leads (the wishlist is still computing)" | \`leadbay_my_lenses(switchToLensId=<new id>)\` then \`leadbay_pull_leads()\` after ~30s |
|
|
7495
|
+
| Lens created (no criteria) | "Switch to it and pull leads" | \`leadbay_my_lenses(switchToLensId=<new id>)\` then \`leadbay_pull_leads()\` |
|
|
7496
|
+
| Lens created | "Refine the audience further" | \`leadbay_adjust_audience(lensName=<new name>, ...)\` |
|
|
7497
|
+
| Lens created | "Leave it; keep my current lens active" | (no call) |
|
|
7498
|
+
| \`ambiguous_sectors\` | "Pick the right sector and create" | \`leadbay_new_lens(name=..., sectors=[<chosen id>])\` |
|
|
7499
|
+
|
|
7500
|
+
If nothing fits, default to "switch to the new lens and pull leads in ~30s
|
|
7501
|
+
(the wishlist may still be computing)" \u2014 never invent a tool that doesn't exist.
|
|
7491
7502
|
`;
|
|
7492
|
-
leadbay_open_billing_portal = `Generate a one-shot Stripe customer-portal URL. Wraps \`GET /1.
|
|
7503
|
+
leadbay_open_billing_portal = `Generate a one-shot Stripe customer-portal URL. Wraps \`GET /1.6/stripe/portal\` \u2192 \`{url}\`. Returns a fresh Stripe-hosted URL the user can open to manage their existing Leadbay subscription: change plan tier, swap payment method, view invoices. The agent does NOT make subscription changes itself \u2014 it surfaces the URL and lets the user act.
|
|
7493
7504
|
|
|
7494
7505
|
Sibling of \`leadbay_create_topup_link\`. Use cases differ:
|
|
7495
7506
|
|
|
@@ -7767,7 +7778,7 @@ table. Detail + status priority below.
|
|
|
7767
7778
|
|
|
7768
7779
|
Pull KNOWN leads from the user's Monitor view \u2014 the re-engagement entry point. Use when the user asks "what should I follow up on", "leads I haven't contacted", "leads in [city]", "before my trip", or any phrasing implying pre-existing pipeline context. For NEW leads from Discover, use \`leadbay_pull_leads\`.
|
|
7769
7780
|
|
|
7770
|
-
Backend: wraps \`GET /1.
|
|
7781
|
+
Backend: wraps \`GET /1.6/monitor?personal=&liked=&filtered=&count=&page=\` plus, when \`set_filter\` is supplied, a preceding \`POST /1.6/monitor/filter\`. The Monitor filter is a single \`FilterItem\` per user \u2014 refreshing restores it.
|
|
7771
7782
|
|
|
7772
7783
|
**Filter mechanism \u2014 store-then-apply.** Pass \`set_filter: { criteria: FilterCriterion[] }\` to overwrite the server-stored filter, then the composite re-fetches with \`filtered:true\`. \`FilterCriterion\` is the backend's \`anyOf\` over 10 typed criteria: \`size\`, \`keywords\`, \`sector_ids\`, \`location_ids\`, \`custom_field\`(\`_comparison\`), \`yc\`, \`liked\`, \`last_action\` (MonitorActionType enum), \`last_action_date\` (with \`last_days\`).
|
|
7773
7784
|
|
|
@@ -7949,7 +7960,8 @@ Examples that should NOT invoke this tool (sound similar, route elsewhere):
|
|
|
7949
7960
|
|
|
7950
7961
|
## RENDER (quick)
|
|
7951
7962
|
|
|
7952
|
-
3-col markdown table
|
|
7963
|
+
3-col markdown table in the order the tool returns them (the Discover-tab
|
|
7964
|
+
order \u2014 do NOT re-sort by score) \u2014 DO NOT print the numeric
|
|
7953
7965
|
score. Col 1 = inline-code 10-segment bar (\`\u25B0\` firmographic, \`\u2756\` AI
|
|
7954
7966
|
booster cap at the right end of the filled run, \`\u25B1\` empty;
|
|
7955
7967
|
filled=round(score/10), ai=round(avg_boost/3.3)) + \`<br>\` + linked
|
|
@@ -7976,7 +7988,7 @@ The active lens can change between calls (5-min cache + backend \`last_requested
|
|
|
7976
7988
|
|
|
7977
7989
|
## RENDERING \u2014 markdown table, three columns, score-bar driven
|
|
7978
7990
|
|
|
7979
|
-
Present the response as a markdown table
|
|
7991
|
+
Present the response as a markdown table **in the exact order the tool returned the leads** \u2014 this is the Discover-tab order (the backend orders by new-today first, then status, then score). Do **not** re-sort the rows (in particular, do NOT re-order by \`score\`); render them top-to-bottom as received so the list matches what the user sees in the Leadbay UI. Exactly three columns. Do not summarize in prose. Do not show the numeric score anywhere.
|
|
7980
7992
|
|
|
7981
7993
|
## Score-bar (10-segment, inline-code wrapped)
|
|
7982
7994
|
|
|
@@ -8082,6 +8094,7 @@ Pick 2\u20133 items below based on what was actually observed in the response. T
|
|
|
8082
8094
|
| Top row has phone but no email | "Show [Contact]'s call details + a 60-second opener" | leadbay_prepare_outreach(leadId) |
|
|
8083
8095
|
| Top row has contacts but no phone/email | "Order contact enrichment to surface email/phone first" | leadbay_enrich_titles(...) or leadbay_prepare_outreach(leadId, enrich:true) |
|
|
8084
8096
|
| \`computing_scores == true\` or \`computing_wishlist == true\` | "Scores are still being computed \u2014 re-pull in ~30s" | leadbay_pull_leads (retry with same lensId) |
|
|
8097
|
+
| Batch is EMPTY and \`computing_wishlist\`/\`computing_scores == true\` (e.g. a just-created lens) | render the \`next_steps\` widget \u2014 it carries "Re-pull in ~30s" (first) + "Refine audience". Do NOT report "no leads": the lens is warming up, not empty | leadbay_pull_leads (retry with same lensId after ~30s) |
|
|
8085
8098
|
| User wants a narrower / wider audience | "Adjust the lens filters (sector / size)" | leadbay_adjust_audience(...) |
|
|
8086
8099
|
| Phase 4 research was run (\`research_lead_by_id\` called) AND top contacts lack direct email/phone | "Enrich contacts on [Lead1], [Lead2] to get direct emails and phone numbers" | leadbay_enrich_contacts(leadId, contactId) \u2014 ONE call per contact (the tool takes a single leadId + contactId, never a list) |
|
|
8087
8100
|
If nothing in the menu applies cleanly, suggest only "pull next page" and "research a specific lead in depth" \u2014 never invent a tool that doesn't exist.
|
|
@@ -11411,7 +11424,7 @@ async function pollRecordsToTerminal(client, importId, budgetMs, expectedRowCoun
|
|
|
11411
11424
|
}
|
|
11412
11425
|
}
|
|
11413
11426
|
if (!exhaustedPagination) {
|
|
11414
|
-
throw client.makeError("IMPORT_PAGINATION_RUNAWAY", `Records pagination exceeded ${maxPagesPerPoll} pages`, `importId=${importId}. Please file a bug at https://github.com/leadbay/
|
|
11427
|
+
throw client.makeError("IMPORT_PAGINATION_RUNAWAY", `Records pagination exceeded ${maxPagesPerPoll} pages`, `importId=${importId}. Please file a bug at https://github.com/leadbay/mcp/issues.`, `GET /imports/${importId}/records`);
|
|
11415
11428
|
}
|
|
11416
11429
|
const snapshot = { total, transient };
|
|
11417
11430
|
const settled = transient === 0;
|
|
@@ -14472,9 +14485,27 @@ function summarise(responses) {
|
|
|
14472
14485
|
return { answered, total, avg_qualification_boost: avg, best_response_excerpt: excerpt };
|
|
14473
14486
|
}
|
|
14474
14487
|
function buildPullLeadsNextSteps(args) {
|
|
14475
|
-
const { leadCount, hasMore, nextPage } = args;
|
|
14476
|
-
if (leadCount <= 0)
|
|
14488
|
+
const { leadCount, hasMore, nextPage, computingWishlist, computingScores } = args;
|
|
14489
|
+
if (leadCount <= 0) {
|
|
14490
|
+
if (computingWishlist || computingScores) {
|
|
14491
|
+
return {
|
|
14492
|
+
question: "This lens is still warming up. What next?",
|
|
14493
|
+
options: [
|
|
14494
|
+
{
|
|
14495
|
+
label: "Re-pull in ~30s",
|
|
14496
|
+
description: "Leads are still being computed for this lens \u2014 wait ~30s, then pull again to see them.",
|
|
14497
|
+
kind: "repull_computing"
|
|
14498
|
+
},
|
|
14499
|
+
{
|
|
14500
|
+
label: "Refine audience",
|
|
14501
|
+
description: "Adjust the lens audience / filters (sector, size, prompt) \u2014 useful if it's coming back sparse.",
|
|
14502
|
+
kind: "refine_audience"
|
|
14503
|
+
}
|
|
14504
|
+
]
|
|
14505
|
+
};
|
|
14506
|
+
}
|
|
14477
14507
|
return null;
|
|
14508
|
+
}
|
|
14478
14509
|
const options = [];
|
|
14479
14510
|
options.push({
|
|
14480
14511
|
label: "Triage board",
|
|
@@ -14572,7 +14603,7 @@ var init_pull_leads = __esm({
|
|
|
14572
14603
|
},
|
|
14573
14604
|
next_steps: {
|
|
14574
14605
|
type: ["object", "null"],
|
|
14575
|
-
description: "Ready-made NEXT STEPS for the host's choice widget. Each option has a SHORT `label` (\u22645 words, fits AskUserQuestion's label cap on Claude cowork/Claude Code) and a full `description`. For AskUserQuestion (cowork/Claude Code) pass each option as {label, description}. For ask_user_input_v0 (Claude chat/ChatGPT, string-only options) use the `description` as the option string. Use these VERBATIM, in order \u2014 do NOT re-derive, reword, or render as prose when a widget tool exists. options[0] is the artifact offer (build the lead triage board) whenever the batch is non-empty. null only when the batch is empty.",
|
|
14606
|
+
description: "Ready-made NEXT STEPS for the host's choice widget. Each option has a SHORT `label` (\u22645 words, fits AskUserQuestion's label cap on Claude cowork/Claude Code) and a full `description`. For AskUserQuestion (cowork/Claude Code) pass each option as {label, description}. For ask_user_input_v0 (Claude chat/ChatGPT, string-only options) use the `description` as the option string. Use these VERBATIM, in order \u2014 do NOT re-derive, reword, or render as prose when a widget tool exists. options[0] is the artifact offer (build the lead triage board) whenever the batch is non-empty. When the batch is empty but the lens is still computing (computing_wishlist/computing_scores true), this carries a 'Re-pull in ~30s' option (kind:repull_computing) plus 'Refine audience' \u2014 render the widget so the user waits rather than seeing 'no leads.' null only when the batch is empty AND nothing is computing (a genuinely empty / over-narrow lens).",
|
|
14576
14607
|
properties: {
|
|
14577
14608
|
question: { type: "string" },
|
|
14578
14609
|
options: {
|
|
@@ -14663,7 +14694,13 @@ var init_pull_leads = __esm({
|
|
|
14663
14694
|
const hasMore = currentPage < totalPages - 1;
|
|
14664
14695
|
const nextPage = hasMore ? currentPage + 1 : null;
|
|
14665
14696
|
const leadCount = res.items.length;
|
|
14666
|
-
const nextSteps = buildPullLeadsNextSteps({
|
|
14697
|
+
const nextSteps = buildPullLeadsNextSteps({
|
|
14698
|
+
leadCount,
|
|
14699
|
+
hasMore,
|
|
14700
|
+
nextPage,
|
|
14701
|
+
computingWishlist: res.computing_wishlist,
|
|
14702
|
+
computingScores: res.computing_scores
|
|
14703
|
+
});
|
|
14667
14704
|
return withAgentMemoryMeta(client, {
|
|
14668
14705
|
lens: { id: lensId },
|
|
14669
14706
|
leads: res.items.map((lead) => ({
|
|
@@ -21816,6 +21853,10 @@ var init_new_lens = __esm({
|
|
|
21816
21853
|
items: { type: "object" }
|
|
21817
21854
|
},
|
|
21818
21855
|
filter_applied: { type: "object", description: "On 'created': the FilterPayload POSTed to the new lens." },
|
|
21856
|
+
computing_wishlist: {
|
|
21857
|
+
type: "boolean",
|
|
21858
|
+
description: "On 'created': true when the lens has criteria and its wishlist is (re)computing asynchronously \u2014 an immediate leadbay_pull_leads may read empty; wait ~30s. False for a criteria-less clone (it inherits the base lens's leads immediately)."
|
|
21859
|
+
},
|
|
21819
21860
|
message: { type: "string" },
|
|
21820
21861
|
_meta: { type: "object" }
|
|
21821
21862
|
},
|
|
@@ -21922,7 +21963,13 @@ var init_new_lens = __esm({
|
|
|
21922
21963
|
status: "created",
|
|
21923
21964
|
lens: { id: created.id, name: created.name },
|
|
21924
21965
|
filter_applied: merged,
|
|
21925
|
-
|
|
21966
|
+
// Applying the filter queued a backend wishlist refresh (#3833). The lens
|
|
21967
|
+
// leads are (re)computed asynchronously, so an immediate pull_leads can
|
|
21968
|
+
// read empty for a few seconds. Signal that here (flag-independent — the
|
|
21969
|
+
// backend's own computing_wishlist can lag right after create) so the
|
|
21970
|
+
// agent waits ~30s instead of reporting an empty lens.
|
|
21971
|
+
computing_wishlist: hasCriteria,
|
|
21972
|
+
message: hasCriteria ? `Created "${created.name}". Leads stream in asynchronously \u2014 call leadbay_pull_leads in ~30s to see them (an immediate pull may show an empty lens while the wishlist computes).` : `Created "${created.name}".`,
|
|
21926
21973
|
_meta: { region: client.region }
|
|
21927
21974
|
};
|
|
21928
21975
|
}
|
|
@@ -22669,6 +22716,8 @@ var init_artifact_kit = __esm({
|
|
|
22669
22716
|
// ../core/dist/index.js
|
|
22670
22717
|
var dist_exports = {};
|
|
22671
22718
|
__export(dist_exports, {
|
|
22719
|
+
API_PREFIX: () => API_PREFIX,
|
|
22720
|
+
API_VERSION: () => API_VERSION,
|
|
22672
22721
|
AgentMemoryCaptureInputSchema: () => AgentMemoryCaptureInputSchema,
|
|
22673
22722
|
AgentMemoryEntrySchema: () => AgentMemoryEntrySchema,
|
|
22674
22723
|
AgentMemoryInjectionError: () => AgentMemoryInjectionError,
|
|
@@ -23219,7 +23268,7 @@ Call \`leadbay_pull_leads\` on the resolved lens. **Capture \`response.lens.id\`
|
|
|
23219
23268
|
|
|
23220
23269
|
## RENDERING \u2014 markdown table, three columns, score-bar driven
|
|
23221
23270
|
|
|
23222
|
-
Present the response as a markdown table
|
|
23271
|
+
Present the response as a markdown table **in the exact order the tool returned the leads** \u2014 this is the Discover-tab order (the backend orders by new-today first, then status, then score). Do **not** re-sort the rows (in particular, do NOT re-order by \`score\`); render them top-to-bottom as received so the list matches what the user sees in the Leadbay UI. Exactly three columns. Do not summarize in prose. Do not show the numeric score anywhere.
|
|
23223
23272
|
|
|
23224
23273
|
## Score-bar (10-segment, inline-code wrapped)
|
|
23225
23274
|
|
|
@@ -23418,7 +23467,7 @@ If the prompt's body and the tool's RENDERING appear to conflict, the tool's REN
|
|
|
23418
23467
|
|
|
23419
23468
|
## RENDERING \u2014 markdown table, three columns, score-bar driven
|
|
23420
23469
|
|
|
23421
|
-
Present the response as a markdown table
|
|
23470
|
+
Present the response as a markdown table **in the exact order the tool returned the leads** \u2014 this is the Discover-tab order (the backend orders by new-today first, then status, then score). Do **not** re-sort the rows (in particular, do NOT re-order by \`score\`); render them top-to-bottom as received so the list matches what the user sees in the Leadbay UI. Exactly three columns. Do not summarize in prose. Do not show the numeric score anywhere.
|
|
23422
23471
|
|
|
23423
23472
|
## Score-bar (10-segment, inline-code wrapped)
|
|
23424
23473
|
|
|
@@ -23548,6 +23597,7 @@ Pick 2\u20133 items below based on what was actually observed in the response. T
|
|
|
23548
23597
|
| Top row has phone but no email | "Show [Contact]'s call details + a 60-second opener" | leadbay_prepare_outreach(leadId) |
|
|
23549
23598
|
| Top row has contacts but no phone/email | "Order contact enrichment to surface email/phone first" | leadbay_enrich_titles(...) or leadbay_prepare_outreach(leadId, enrich:true) |
|
|
23550
23599
|
| \`computing_scores == true\` or \`computing_wishlist == true\` | "Scores are still being computed \u2014 re-pull in ~30s" | leadbay_pull_leads (retry with same lensId) |
|
|
23600
|
+
| Batch is EMPTY and \`computing_wishlist\`/\`computing_scores == true\` (e.g. a just-created lens) | render the \`next_steps\` widget \u2014 it carries "Re-pull in ~30s" (first) + "Refine audience". Do NOT report "no leads": the lens is warming up, not empty | leadbay_pull_leads (retry with same lensId after ~30s) |
|
|
23551
23601
|
| User wants a narrower / wider audience | "Adjust the lens filters (sector / size)" | leadbay_adjust_audience(...) |
|
|
23552
23602
|
| Phase 4 research was run (\`research_lead_by_id\` called) AND top contacts lack direct email/phone | "Enrich contacts on [Lead1], [Lead2] to get direct emails and phone numbers" | leadbay_enrich_contacts(leadId, contactId) \u2014 ONE call per contact (the tool takes a single leadId + contactId, never a list) |
|
|
23553
23603
|
If nothing in the menu applies cleanly, suggest only "pull next page" and "research a specific lead in depth" \u2014 never invent a tool that doesn't exist.
|
|
@@ -24062,7 +24112,7 @@ When \`bulk_qualify_leads\` returns, surface results in two parts.
|
|
|
24062
24112
|
|
|
24063
24113
|
## RENDERING \u2014 markdown table, three columns, score-bar driven
|
|
24064
24114
|
|
|
24065
|
-
Present the response as a markdown table
|
|
24115
|
+
Present the response as a markdown table **in the exact order the tool returned the leads** \u2014 this is the Discover-tab order (the backend orders by new-today first, then status, then score). Do **not** re-sort the rows (in particular, do NOT re-order by \`score\`); render them top-to-bottom as received so the list matches what the user sees in the Leadbay UI. Exactly three columns. Do not summarize in prose. Do not show the numeric score anywhere.
|
|
24066
24116
|
|
|
24067
24117
|
## Score-bar (10-segment, inline-code wrapped)
|
|
24068
24118
|
|
|
@@ -25170,7 +25220,7 @@ function getCachedUpdateInfo() {
|
|
|
25170
25220
|
function getInFlightCheck() {
|
|
25171
25221
|
return inFlightCheck;
|
|
25172
25222
|
}
|
|
25173
|
-
var RELEASES_LATEST_URL = "https://api.github.com/repos/leadbay/
|
|
25223
|
+
var RELEASES_LATEST_URL = "https://api.github.com/repos/leadbay/mcp/releases/latest";
|
|
25174
25224
|
var CHECK_THROTTLE_MS = 24 * 60 * 60 * 1e3;
|
|
25175
25225
|
var FETCH_TIMEOUT_MS = 5e3;
|
|
25176
25226
|
var USER_AGENT = "leadbay-mcp-update-check";
|
|
@@ -27717,7 +27767,7 @@ var OAUTH_BASE_URLS = {
|
|
|
27717
27767
|
fr: "https://staging.api.leadbay.app"
|
|
27718
27768
|
}
|
|
27719
27769
|
};
|
|
27720
|
-
var VERSION = "0.23.
|
|
27770
|
+
var VERSION = "0.23.10";
|
|
27721
27771
|
var HELP = `
|
|
27722
27772
|
leadbay-mcp ${VERSION} \u2014 Leadbay Model Context Protocol server
|
|
27723
27773
|
|
|
@@ -27784,7 +27834,7 @@ EXAMPLE Claude Desktop config (~/Library/Application Support/Claude/claude_deskt
|
|
|
27784
27834
|
}
|
|
27785
27835
|
|
|
27786
27836
|
DOCS
|
|
27787
|
-
https://github.com/leadbay/
|
|
27837
|
+
https://github.com/leadbay/mcp#readme
|
|
27788
27838
|
`.trim();
|
|
27789
27839
|
function makeStderrLogger(level) {
|
|
27790
27840
|
const rank = { debug: 0, info: 1, error: 2 };
|
|
@@ -28518,7 +28568,7 @@ async function loginAt(baseUrl, email, password) {
|
|
|
28518
28568
|
const https2 = await import("https");
|
|
28519
28569
|
return await new Promise((resolve, reject) => {
|
|
28520
28570
|
const body = JSON.stringify({ email, password });
|
|
28521
|
-
const u = new URL(baseUrl +
|
|
28571
|
+
const u = new URL(baseUrl + `${API_PREFIX}/auth/login`);
|
|
28522
28572
|
const r = https2.request(
|
|
28523
28573
|
{
|
|
28524
28574
|
hostname: u.hostname,
|
package/dist/http-server.js
CHANGED
|
@@ -88,7 +88,7 @@ Call \`leadbay_pull_leads\` on the resolved lens. **Capture \`response.lens.id\`
|
|
|
88
88
|
|
|
89
89
|
## RENDERING \u2014 markdown table, three columns, score-bar driven
|
|
90
90
|
|
|
91
|
-
Present the response as a markdown table
|
|
91
|
+
Present the response as a markdown table **in the exact order the tool returned the leads** \u2014 this is the Discover-tab order (the backend orders by new-today first, then status, then score). Do **not** re-sort the rows (in particular, do NOT re-order by \`score\`); render them top-to-bottom as received so the list matches what the user sees in the Leadbay UI. Exactly three columns. Do not summarize in prose. Do not show the numeric score anywhere.
|
|
92
92
|
|
|
93
93
|
## Score-bar (10-segment, inline-code wrapped)
|
|
94
94
|
|
|
@@ -287,7 +287,7 @@ If the prompt's body and the tool's RENDERING appear to conflict, the tool's REN
|
|
|
287
287
|
|
|
288
288
|
## RENDERING \u2014 markdown table, three columns, score-bar driven
|
|
289
289
|
|
|
290
|
-
Present the response as a markdown table
|
|
290
|
+
Present the response as a markdown table **in the exact order the tool returned the leads** \u2014 this is the Discover-tab order (the backend orders by new-today first, then status, then score). Do **not** re-sort the rows (in particular, do NOT re-order by \`score\`); render them top-to-bottom as received so the list matches what the user sees in the Leadbay UI. Exactly three columns. Do not summarize in prose. Do not show the numeric score anywhere.
|
|
291
291
|
|
|
292
292
|
## Score-bar (10-segment, inline-code wrapped)
|
|
293
293
|
|
|
@@ -417,6 +417,7 @@ Pick 2\u20133 items below based on what was actually observed in the response. T
|
|
|
417
417
|
| Top row has phone but no email | "Show [Contact]'s call details + a 60-second opener" | leadbay_prepare_outreach(leadId) |
|
|
418
418
|
| Top row has contacts but no phone/email | "Order contact enrichment to surface email/phone first" | leadbay_enrich_titles(...) or leadbay_prepare_outreach(leadId, enrich:true) |
|
|
419
419
|
| \`computing_scores == true\` or \`computing_wishlist == true\` | "Scores are still being computed \u2014 re-pull in ~30s" | leadbay_pull_leads (retry with same lensId) |
|
|
420
|
+
| Batch is EMPTY and \`computing_wishlist\`/\`computing_scores == true\` (e.g. a just-created lens) | render the \`next_steps\` widget \u2014 it carries "Re-pull in ~30s" (first) + "Refine audience". Do NOT report "no leads": the lens is warming up, not empty | leadbay_pull_leads (retry with same lensId after ~30s) |
|
|
420
421
|
| User wants a narrower / wider audience | "Adjust the lens filters (sector / size)" | leadbay_adjust_audience(...) |
|
|
421
422
|
| Phase 4 research was run (\`research_lead_by_id\` called) AND top contacts lack direct email/phone | "Enrich contacts on [Lead1], [Lead2] to get direct emails and phone numbers" | leadbay_enrich_contacts(leadId, contactId) \u2014 ONE call per contact (the tool takes a single leadId + contactId, never a list) |
|
|
422
423
|
If nothing in the menu applies cleanly, suggest only "pull next page" and "research a specific lead in depth" \u2014 never invent a tool that doesn't exist.
|
|
@@ -931,7 +932,7 @@ When \`bulk_qualify_leads\` returns, surface results in two parts.
|
|
|
931
932
|
|
|
932
933
|
## RENDERING \u2014 markdown table, three columns, score-bar driven
|
|
933
934
|
|
|
934
|
-
Present the response as a markdown table
|
|
935
|
+
Present the response as a markdown table **in the exact order the tool returned the leads** \u2014 this is the Discover-tab order (the backend orders by new-today first, then status, then score). Do **not** re-sort the rows (in particular, do NOT re-order by \`score\`); render them top-to-bottom as received so the list matches what the user sees in the Leadbay UI. Exactly three columns. Do not summarize in prose. Do not show the numeric score anywhere.
|
|
935
936
|
|
|
936
937
|
## Score-bar (10-segment, inline-code wrapped)
|
|
937
938
|
|
|
@@ -1592,6 +1593,8 @@ var REGIONS = {
|
|
|
1592
1593
|
us: "https://api-us.leadbay.app",
|
|
1593
1594
|
fr: "https://api-fr.leadbay.app"
|
|
1594
1595
|
};
|
|
1596
|
+
var API_VERSION = "1.6";
|
|
1597
|
+
var API_PREFIX = `/${API_VERSION}`;
|
|
1595
1598
|
function httpsRequest(method, url, headers, body) {
|
|
1596
1599
|
return new Promise((resolve, reject) => {
|
|
1597
1600
|
const start = Date.now();
|
|
@@ -1647,7 +1650,7 @@ async function resolveRegion(email, password, startWith = "us") {
|
|
|
1647
1650
|
const baseUrl = REGIONS[region];
|
|
1648
1651
|
const body = JSON.stringify({ email, password });
|
|
1649
1652
|
try {
|
|
1650
|
-
const res = await httpsRequest("POST", `${baseUrl}/
|
|
1653
|
+
const res = await httpsRequest("POST", `${baseUrl}${API_PREFIX}/auth/login`, { "Content-Type": "application/json" }, body);
|
|
1651
1654
|
if (res.status === 200) {
|
|
1652
1655
|
const parsed = JSON.parse(res.body);
|
|
1653
1656
|
if (parsed?.token) {
|
|
@@ -1861,7 +1864,7 @@ var LeadbayClient = class {
|
|
|
1861
1864
|
const retryOn401 = opts?.retryOn401 !== false;
|
|
1862
1865
|
await this.acquireSemaphore();
|
|
1863
1866
|
try {
|
|
1864
|
-
const url = `${this._baseUrl}
|
|
1867
|
+
const url = `${this._baseUrl}${API_PREFIX}${path}`;
|
|
1865
1868
|
const headers = {
|
|
1866
1869
|
Authorization: `Bearer ${this.token}`
|
|
1867
1870
|
};
|
|
@@ -1896,7 +1899,7 @@ var LeadbayClient = class {
|
|
|
1896
1899
|
}
|
|
1897
1900
|
await this.acquireSemaphore();
|
|
1898
1901
|
try {
|
|
1899
|
-
const url = `${this._baseUrl}
|
|
1902
|
+
const url = `${this._baseUrl}${API_PREFIX}${path}`;
|
|
1900
1903
|
const headers = {
|
|
1901
1904
|
Authorization: `Bearer ${this.token}`
|
|
1902
1905
|
};
|
|
@@ -1921,7 +1924,7 @@ var LeadbayClient = class {
|
|
|
1921
1924
|
// serialized body (string for text payloads such as CSV; Buffer for binary
|
|
1922
1925
|
// uploads). Auth, semaphore, error mapping, _lastMeta, and mock-mode all
|
|
1923
1926
|
// mirror request() exactly. Used by leadbay_import_leads to upload CSVs to
|
|
1924
|
-
// the wizard at POST /1.
|
|
1927
|
+
// the wizard at POST /1.6/imports.
|
|
1925
1928
|
async requestRawBinary(method, path, contentType, body) {
|
|
1926
1929
|
if (process.env.LEADBAY_MOCK === "1") {
|
|
1927
1930
|
return this.mockRequestBinary(method, path, contentType, body);
|
|
@@ -1931,7 +1934,7 @@ var LeadbayClient = class {
|
|
|
1931
1934
|
}
|
|
1932
1935
|
await this.acquireSemaphore();
|
|
1933
1936
|
try {
|
|
1934
|
-
const url = `${this._baseUrl}
|
|
1937
|
+
const url = `${this._baseUrl}${API_PREFIX}${path}`;
|
|
1935
1938
|
const headers = {
|
|
1936
1939
|
Authorization: `Bearer ${this.token}`,
|
|
1937
1940
|
"Content-Type": contentType
|
|
@@ -1955,7 +1958,7 @@ var LeadbayClient = class {
|
|
|
1955
1958
|
}
|
|
1956
1959
|
}
|
|
1957
1960
|
mockRequest(method, path, body) {
|
|
1958
|
-
const fullPath =
|
|
1961
|
+
const fullPath = `${API_PREFIX}${path}`;
|
|
1959
1962
|
this._lastMeta = {
|
|
1960
1963
|
region: this._region,
|
|
1961
1964
|
endpoint: `${method} ${path}`,
|
|
@@ -1978,7 +1981,7 @@ var LeadbayClient = class {
|
|
|
1978
1981
|
};
|
|
1979
1982
|
}
|
|
1980
1983
|
mockRequestBinary(method, path, contentType, body) {
|
|
1981
|
-
const fullPath =
|
|
1984
|
+
const fullPath = `${API_PREFIX}${path}`;
|
|
1982
1985
|
this._lastMeta = {
|
|
1983
1986
|
region: this._region,
|
|
1984
1987
|
endpoint: `${method} ${path}`,
|
|
@@ -6824,7 +6827,7 @@ WHEN TO USE: at the start of a session to know what the agent can/can't do, afte
|
|
|
6824
6827
|
|
|
6825
6828
|
WHEN NOT TO USE: as a pre-flight gate before bulk ops \u2014 operations themselves return 429; this tool is for context, not gating. And: a recent quota snapshot showing "exhausted" is NOT a reason to refuse a write call when the user has just topped up \u2014 re-call this tool first, then proceed.
|
|
6826
6829
|
`;
|
|
6827
|
-
var leadbay_acknowledge_notification = `Acknowledge a Leadbay notification \u2014 i.e. tell the MCP and the backend "I've seen this and acted on it." Wraps \`POST /1.
|
|
6830
|
+
var leadbay_acknowledge_notification = `Acknowledge a Leadbay notification \u2014 i.e. tell the MCP and the backend "I've seen this and acted on it." Wraps \`POST /1.6/notifications/{id}/seen\` (default) or \`/archive\` (when \`archive:true\`) and drops the entry from the local inbox so subsequent \`_meta.notifications\` payloads stop carrying it.
|
|
6828
6831
|
|
|
6829
6832
|
**When to call.** After you read an entry from \`_meta.notifications\` or \`account_status.notifications\` and have revised whatever prior output the just-finished background work might have made stale (outreach drafts, lead lists, "available leads" claims, followup plans). Mark-seen tells the human team's pipeline you handled this and prevents the notification from re-surfacing on every subsequent tool response.
|
|
6830
6833
|
|
|
@@ -7434,7 +7437,7 @@ WHEN NOT TO USE: from agent flow \u2014 leadbay_adjust_audience handles the draf
|
|
|
7434
7437
|
|
|
7435
7438
|
This tool MUTATES state. The caller (agent or human-in-the-loop) is responsible for confirming intent before invocation; the MCP server does not soft-prompt for confirmation. See \`annotations.destructiveHint\`.
|
|
7436
7439
|
`;
|
|
7437
|
-
var leadbay_create_topup_link = `Generate a one-shot Stripe checkout session for an AI-credits top-up. Wraps \`POST /1.
|
|
7440
|
+
var leadbay_create_topup_link = `Generate a one-shot Stripe checkout session for an AI-credits top-up. Wraps \`POST /1.6/stripe/topup_checkout\` \u2192 \`{url}\`. Returns a fresh Stripe-hosted URL (~1 hour TTL); creating one does NOT charge the user \u2014 payment happens only after the user opens the URL and completes checkout in their browser.
|
|
7438
7441
|
|
|
7439
7442
|
**When a quota window is hit, offer top-up as the FIRST option.** A top-up clears the throttle immediately (no need to wait for the daily/weekly/monthly window reset). The flow:
|
|
7440
7443
|
|
|
@@ -8538,8 +8541,9 @@ On \`preview\` (default \u2014 NOTHING created yet): show the lens that WILL be
|
|
|
8538
8541
|
created (name + resolved sectors/sizes as chips) and ASK the user to confirm
|
|
8539
8542
|
via ask_user_input_v0 ("Create this lens?" / "Change something"). Only on
|
|
8540
8543
|
"yes" re-call with confirm:true. On \`created\`: confirm "Created **<name>**."
|
|
8541
|
-
|
|
8542
|
-
|
|
8544
|
+
(if \`computing_wishlist:true\`, add that leads stream in \u2014 pull in ~30s, don't
|
|
8545
|
+
report "empty"). On \`ambiguous_sectors\` / \`ambiguous_locations\`: surface the
|
|
8546
|
+
candidates to pick from.
|
|
8543
8547
|
|
|
8544
8548
|
---
|
|
8545
8549
|
|
|
@@ -8553,6 +8557,8 @@ Create a brand-new lens (saved audience) and apply its sector/size criteria. Clo
|
|
|
8553
8557
|
|
|
8554
8558
|
**Does not switch the active lens.** The new lens is created but the user stays on their current one. Offer \`leadbay_my_lenses(switchToLensId=<new id>)\` as a next step if they want to start pulling from it.
|
|
8555
8559
|
|
|
8560
|
+
**Leads compute asynchronously.** When the lens has criteria, applying the filter kicks off a backend wishlist rebuild \u2014 the \`created\` result carries \`computing_wishlist:true\`. An immediate \`leadbay_pull_leads\` may read empty for a few seconds while it computes; that lens is *warming up*, not empty. Wait ~30s before the first pull (or offer the user a re-pull). A criteria-less clone inherits the base lens's leads right away (\`computing_wishlist:false\`).
|
|
8561
|
+
|
|
8556
8562
|
WHEN TO USE: when the user wants a NEW lens. Canonical phrasings: "create a lens called X", "make a new audience for Y", "set up a lens for <sector>".
|
|
8557
8563
|
|
|
8558
8564
|
WHEN NOT TO USE: to EDIT an existing lens \u2014 use \`leadbay_adjust_audience\` (pass \`lensName\` to target one by name). Not for listing/switching (\`leadbay_my_lenses\`) or topping up (\`leadbay_extend_lens\`).
|
|
@@ -8606,19 +8612,25 @@ User picks \u2192 call the matching \`Calls\` tool. Constraints: 2\u20134 mutual
|
|
|
8606
8612
|
Pick the rows that fit. On \`created\`, the switch + pull rows are the natural
|
|
8607
8613
|
follow-ups. On \`ambiguous_sectors\`, the only move is to pick a sector and re-call.
|
|
8608
8614
|
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
|
|
8613
|
-
|
|
8614
|
-
|
|
|
8615
|
-
|
|
8616
|
-
| \`
|
|
8617
|
-
|
|
8618
|
-
|
|
8619
|
-
|
|
8615
|
+
**\`created\` with \`computing_wishlist: true\`** \u2014 the new lens's leads are being
|
|
8616
|
+
(re)computed asynchronously. Do NOT fire an immediate \`leadbay_pull_leads\` and
|
|
8617
|
+
report "empty" \u2014 the lens is warming up, not empty. Tell the user the lens was
|
|
8618
|
+
created and its leads are streaming in, and offer to pull in ~30s.
|
|
8619
|
+
|
|
8620
|
+
| Observation | Suggest | Calls |
|
|
8621
|
+
|-----------------------------------------|------------------------------------------|--------------------------------------------------------|
|
|
8622
|
+
| \`preview\` (not yet created) | "Yes, create this lens" | \`leadbay_new_lens(...same args..., confirm=true)\` |
|
|
8623
|
+
| \`preview\` (not yet created) | "Change the sectors/size first" | (re-ask the user, then \`leadbay_new_lens\` with new args) |
|
|
8624
|
+
| Lens created, \`computing_wishlist=true\` | "Give it ~30s, then pull leads (the wishlist is still computing)" | \`leadbay_my_lenses(switchToLensId=<new id>)\` then \`leadbay_pull_leads()\` after ~30s |
|
|
8625
|
+
| Lens created (no criteria) | "Switch to it and pull leads" | \`leadbay_my_lenses(switchToLensId=<new id>)\` then \`leadbay_pull_leads()\` |
|
|
8626
|
+
| Lens created | "Refine the audience further" | \`leadbay_adjust_audience(lensName=<new name>, ...)\` |
|
|
8627
|
+
| Lens created | "Leave it; keep my current lens active" | (no call) |
|
|
8628
|
+
| \`ambiguous_sectors\` | "Pick the right sector and create" | \`leadbay_new_lens(name=..., sectors=[<chosen id>])\` |
|
|
8629
|
+
|
|
8630
|
+
If nothing fits, default to "switch to the new lens and pull leads in ~30s
|
|
8631
|
+
(the wishlist may still be computing)" \u2014 never invent a tool that doesn't exist.
|
|
8620
8632
|
`;
|
|
8621
|
-
var leadbay_open_billing_portal = `Generate a one-shot Stripe customer-portal URL. Wraps \`GET /1.
|
|
8633
|
+
var leadbay_open_billing_portal = `Generate a one-shot Stripe customer-portal URL. Wraps \`GET /1.6/stripe/portal\` \u2192 \`{url}\`. Returns a fresh Stripe-hosted URL the user can open to manage their existing Leadbay subscription: change plan tier, swap payment method, view invoices. The agent does NOT make subscription changes itself \u2014 it surfaces the URL and lets the user act.
|
|
8622
8634
|
|
|
8623
8635
|
Sibling of \`leadbay_create_topup_link\`. Use cases differ:
|
|
8624
8636
|
|
|
@@ -8896,7 +8908,7 @@ table. Detail + status priority below.
|
|
|
8896
8908
|
|
|
8897
8909
|
Pull KNOWN leads from the user's Monitor view \u2014 the re-engagement entry point. Use when the user asks "what should I follow up on", "leads I haven't contacted", "leads in [city]", "before my trip", or any phrasing implying pre-existing pipeline context. For NEW leads from Discover, use \`leadbay_pull_leads\`.
|
|
8898
8910
|
|
|
8899
|
-
Backend: wraps \`GET /1.
|
|
8911
|
+
Backend: wraps \`GET /1.6/monitor?personal=&liked=&filtered=&count=&page=\` plus, when \`set_filter\` is supplied, a preceding \`POST /1.6/monitor/filter\`. The Monitor filter is a single \`FilterItem\` per user \u2014 refreshing restores it.
|
|
8900
8912
|
|
|
8901
8913
|
**Filter mechanism \u2014 store-then-apply.** Pass \`set_filter: { criteria: FilterCriterion[] }\` to overwrite the server-stored filter, then the composite re-fetches with \`filtered:true\`. \`FilterCriterion\` is the backend's \`anyOf\` over 10 typed criteria: \`size\`, \`keywords\`, \`sector_ids\`, \`location_ids\`, \`custom_field\`(\`_comparison\`), \`yc\`, \`liked\`, \`last_action\` (MonitorActionType enum), \`last_action_date\` (with \`last_days\`).
|
|
8902
8914
|
|
|
@@ -9078,7 +9090,8 @@ Examples that should NOT invoke this tool (sound similar, route elsewhere):
|
|
|
9078
9090
|
|
|
9079
9091
|
## RENDER (quick)
|
|
9080
9092
|
|
|
9081
|
-
3-col markdown table
|
|
9093
|
+
3-col markdown table in the order the tool returns them (the Discover-tab
|
|
9094
|
+
order \u2014 do NOT re-sort by score) \u2014 DO NOT print the numeric
|
|
9082
9095
|
score. Col 1 = inline-code 10-segment bar (\`\u25B0\` firmographic, \`\u2756\` AI
|
|
9083
9096
|
booster cap at the right end of the filled run, \`\u25B1\` empty;
|
|
9084
9097
|
filled=round(score/10), ai=round(avg_boost/3.3)) + \`<br>\` + linked
|
|
@@ -9105,7 +9118,7 @@ The active lens can change between calls (5-min cache + backend \`last_requested
|
|
|
9105
9118
|
|
|
9106
9119
|
## RENDERING \u2014 markdown table, three columns, score-bar driven
|
|
9107
9120
|
|
|
9108
|
-
Present the response as a markdown table
|
|
9121
|
+
Present the response as a markdown table **in the exact order the tool returned the leads** \u2014 this is the Discover-tab order (the backend orders by new-today first, then status, then score). Do **not** re-sort the rows (in particular, do NOT re-order by \`score\`); render them top-to-bottom as received so the list matches what the user sees in the Leadbay UI. Exactly three columns. Do not summarize in prose. Do not show the numeric score anywhere.
|
|
9109
9122
|
|
|
9110
9123
|
## Score-bar (10-segment, inline-code wrapped)
|
|
9111
9124
|
|
|
@@ -9211,6 +9224,7 @@ Pick 2\u20133 items below based on what was actually observed in the response. T
|
|
|
9211
9224
|
| Top row has phone but no email | "Show [Contact]'s call details + a 60-second opener" | leadbay_prepare_outreach(leadId) |
|
|
9212
9225
|
| Top row has contacts but no phone/email | "Order contact enrichment to surface email/phone first" | leadbay_enrich_titles(...) or leadbay_prepare_outreach(leadId, enrich:true) |
|
|
9213
9226
|
| \`computing_scores == true\` or \`computing_wishlist == true\` | "Scores are still being computed \u2014 re-pull in ~30s" | leadbay_pull_leads (retry with same lensId) |
|
|
9227
|
+
| Batch is EMPTY and \`computing_wishlist\`/\`computing_scores == true\` (e.g. a just-created lens) | render the \`next_steps\` widget \u2014 it carries "Re-pull in ~30s" (first) + "Refine audience". Do NOT report "no leads": the lens is warming up, not empty | leadbay_pull_leads (retry with same lensId after ~30s) |
|
|
9214
9228
|
| User wants a narrower / wider audience | "Adjust the lens filters (sector / size)" | leadbay_adjust_audience(...) |
|
|
9215
9229
|
| Phase 4 research was run (\`research_lead_by_id\` called) AND top contacts lack direct email/phone | "Enrich contacts on [Lead1], [Lead2] to get direct emails and phone numbers" | leadbay_enrich_contacts(leadId, contactId) \u2014 ONE call per contact (the tool takes a single leadId + contactId, never a list) |
|
|
9216
9230
|
If nothing in the menu applies cleanly, suggest only "pull next page" and "research a specific lead in depth" \u2014 never invent a tool that doesn't exist.
|
|
@@ -12419,7 +12433,7 @@ async function pollRecordsToTerminal(client, importId, budgetMs, expectedRowCoun
|
|
|
12419
12433
|
}
|
|
12420
12434
|
}
|
|
12421
12435
|
if (!exhaustedPagination) {
|
|
12422
|
-
throw client.makeError("IMPORT_PAGINATION_RUNAWAY", `Records pagination exceeded ${maxPagesPerPoll} pages`, `importId=${importId}. Please file a bug at https://github.com/leadbay/
|
|
12436
|
+
throw client.makeError("IMPORT_PAGINATION_RUNAWAY", `Records pagination exceeded ${maxPagesPerPoll} pages`, `importId=${importId}. Please file a bug at https://github.com/leadbay/mcp/issues.`, `GET /imports/${importId}/records`);
|
|
12423
12437
|
}
|
|
12424
12438
|
const snapshot = { total, transient };
|
|
12425
12439
|
const settled = transient === 0;
|
|
@@ -15149,9 +15163,27 @@ function summarise(responses) {
|
|
|
15149
15163
|
return { answered, total, avg_qualification_boost: avg, best_response_excerpt: excerpt };
|
|
15150
15164
|
}
|
|
15151
15165
|
function buildPullLeadsNextSteps(args) {
|
|
15152
|
-
const { leadCount, hasMore, nextPage } = args;
|
|
15153
|
-
if (leadCount <= 0)
|
|
15166
|
+
const { leadCount, hasMore, nextPage, computingWishlist, computingScores } = args;
|
|
15167
|
+
if (leadCount <= 0) {
|
|
15168
|
+
if (computingWishlist || computingScores) {
|
|
15169
|
+
return {
|
|
15170
|
+
question: "This lens is still warming up. What next?",
|
|
15171
|
+
options: [
|
|
15172
|
+
{
|
|
15173
|
+
label: "Re-pull in ~30s",
|
|
15174
|
+
description: "Leads are still being computed for this lens \u2014 wait ~30s, then pull again to see them.",
|
|
15175
|
+
kind: "repull_computing"
|
|
15176
|
+
},
|
|
15177
|
+
{
|
|
15178
|
+
label: "Refine audience",
|
|
15179
|
+
description: "Adjust the lens audience / filters (sector, size, prompt) \u2014 useful if it's coming back sparse.",
|
|
15180
|
+
kind: "refine_audience"
|
|
15181
|
+
}
|
|
15182
|
+
]
|
|
15183
|
+
};
|
|
15184
|
+
}
|
|
15154
15185
|
return null;
|
|
15186
|
+
}
|
|
15155
15187
|
const options = [];
|
|
15156
15188
|
options.push({
|
|
15157
15189
|
label: "Triage board",
|
|
@@ -15243,7 +15275,7 @@ var pullLeads = {
|
|
|
15243
15275
|
},
|
|
15244
15276
|
next_steps: {
|
|
15245
15277
|
type: ["object", "null"],
|
|
15246
|
-
description: "Ready-made NEXT STEPS for the host's choice widget. Each option has a SHORT `label` (\u22645 words, fits AskUserQuestion's label cap on Claude cowork/Claude Code) and a full `description`. For AskUserQuestion (cowork/Claude Code) pass each option as {label, description}. For ask_user_input_v0 (Claude chat/ChatGPT, string-only options) use the `description` as the option string. Use these VERBATIM, in order \u2014 do NOT re-derive, reword, or render as prose when a widget tool exists. options[0] is the artifact offer (build the lead triage board) whenever the batch is non-empty. null only when the batch is empty.",
|
|
15278
|
+
description: "Ready-made NEXT STEPS for the host's choice widget. Each option has a SHORT `label` (\u22645 words, fits AskUserQuestion's label cap on Claude cowork/Claude Code) and a full `description`. For AskUserQuestion (cowork/Claude Code) pass each option as {label, description}. For ask_user_input_v0 (Claude chat/ChatGPT, string-only options) use the `description` as the option string. Use these VERBATIM, in order \u2014 do NOT re-derive, reword, or render as prose when a widget tool exists. options[0] is the artifact offer (build the lead triage board) whenever the batch is non-empty. When the batch is empty but the lens is still computing (computing_wishlist/computing_scores true), this carries a 'Re-pull in ~30s' option (kind:repull_computing) plus 'Refine audience' \u2014 render the widget so the user waits rather than seeing 'no leads.' null only when the batch is empty AND nothing is computing (a genuinely empty / over-narrow lens).",
|
|
15247
15279
|
properties: {
|
|
15248
15280
|
question: { type: "string" },
|
|
15249
15281
|
options: {
|
|
@@ -15334,7 +15366,13 @@ var pullLeads = {
|
|
|
15334
15366
|
const hasMore = currentPage < totalPages - 1;
|
|
15335
15367
|
const nextPage = hasMore ? currentPage + 1 : null;
|
|
15336
15368
|
const leadCount = res.items.length;
|
|
15337
|
-
const nextSteps = buildPullLeadsNextSteps({
|
|
15369
|
+
const nextSteps = buildPullLeadsNextSteps({
|
|
15370
|
+
leadCount,
|
|
15371
|
+
hasMore,
|
|
15372
|
+
nextPage,
|
|
15373
|
+
computingWishlist: res.computing_wishlist,
|
|
15374
|
+
computingScores: res.computing_scores
|
|
15375
|
+
});
|
|
15338
15376
|
return withAgentMemoryMeta(client, {
|
|
15339
15377
|
lens: { id: lensId },
|
|
15340
15378
|
leads: res.items.map((lead) => ({
|
|
@@ -21608,6 +21646,10 @@ var newLens = {
|
|
|
21608
21646
|
items: { type: "object" }
|
|
21609
21647
|
},
|
|
21610
21648
|
filter_applied: { type: "object", description: "On 'created': the FilterPayload POSTed to the new lens." },
|
|
21649
|
+
computing_wishlist: {
|
|
21650
|
+
type: "boolean",
|
|
21651
|
+
description: "On 'created': true when the lens has criteria and its wishlist is (re)computing asynchronously \u2014 an immediate leadbay_pull_leads may read empty; wait ~30s. False for a criteria-less clone (it inherits the base lens's leads immediately)."
|
|
21652
|
+
},
|
|
21611
21653
|
message: { type: "string" },
|
|
21612
21654
|
_meta: { type: "object" }
|
|
21613
21655
|
},
|
|
@@ -21714,7 +21756,13 @@ var newLens = {
|
|
|
21714
21756
|
status: "created",
|
|
21715
21757
|
lens: { id: created.id, name: created.name },
|
|
21716
21758
|
filter_applied: merged,
|
|
21717
|
-
|
|
21759
|
+
// Applying the filter queued a backend wishlist refresh (#3833). The lens
|
|
21760
|
+
// leads are (re)computed asynchronously, so an immediate pull_leads can
|
|
21761
|
+
// read empty for a few seconds. Signal that here (flag-independent — the
|
|
21762
|
+
// backend's own computing_wishlist can lag right after create) so the
|
|
21763
|
+
// agent waits ~30s instead of reporting an empty lens.
|
|
21764
|
+
computing_wishlist: hasCriteria,
|
|
21765
|
+
message: hasCriteria ? `Created "${created.name}". Leads stream in asynchronously \u2014 call leadbay_pull_leads in ~30s to see them (an immediate pull may show an empty lens while the wishlist computes).` : `Created "${created.name}".`,
|
|
21718
21766
|
_meta: { region: client.region }
|
|
21719
21767
|
};
|
|
21720
21768
|
}
|
|
@@ -22769,7 +22817,7 @@ function getCachedUpdateInfo() {
|
|
|
22769
22817
|
function getInFlightCheck() {
|
|
22770
22818
|
return inFlightCheck;
|
|
22771
22819
|
}
|
|
22772
|
-
var RELEASES_LATEST_URL = "https://api.github.com/repos/leadbay/
|
|
22820
|
+
var RELEASES_LATEST_URL = "https://api.github.com/repos/leadbay/mcp/releases/latest";
|
|
22773
22821
|
var CHECK_THROTTLE_MS = 24 * 60 * 60 * 1e3;
|
|
22774
22822
|
var FETCH_TIMEOUT_MS = 5e3;
|
|
22775
22823
|
var USER_AGENT = "leadbay-mcp-update-check";
|
|
@@ -24014,7 +24062,7 @@ function parseWriteEnv(env = process.env) {
|
|
|
24014
24062
|
}
|
|
24015
24063
|
|
|
24016
24064
|
// src/http-server.ts
|
|
24017
|
-
var VERSION = true ? "0.23.
|
|
24065
|
+
var VERSION = true ? "0.23.10" : "0.0.0-dev";
|
|
24018
24066
|
var PORT = Number(process.env.PORT ?? 8080);
|
|
24019
24067
|
var HOST = process.env.HOST ?? "0.0.0.0";
|
|
24020
24068
|
var sseSessions = /* @__PURE__ */ new Map();
|
|
@@ -24056,6 +24104,24 @@ function applyCors(c) {
|
|
|
24056
24104
|
c.header("Access-Control-Allow-Origin", "*");
|
|
24057
24105
|
c.header("Access-Control-Expose-Headers", "WWW-Authenticate");
|
|
24058
24106
|
}
|
|
24107
|
+
var DEFAULT_ALLOWED_ORIGINS = [
|
|
24108
|
+
"https://claude.ai",
|
|
24109
|
+
"https://claude.com",
|
|
24110
|
+
"https://chatgpt.com"
|
|
24111
|
+
];
|
|
24112
|
+
function allowedOrigins() {
|
|
24113
|
+
const extra = (process.env.LEADBAY_MCP_ALLOWED_ORIGINS ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
24114
|
+
return /* @__PURE__ */ new Set([...DEFAULT_ALLOWED_ORIGINS, ...extra]);
|
|
24115
|
+
}
|
|
24116
|
+
function rejectForeignOrigin(c) {
|
|
24117
|
+
const origin = c.req.header("origin");
|
|
24118
|
+
if (!origin) return null;
|
|
24119
|
+
const allowed = allowedOrigins();
|
|
24120
|
+
allowed.add(requestOrigin(c));
|
|
24121
|
+
if (allowed.has(origin)) return null;
|
|
24122
|
+
applyCors(c);
|
|
24123
|
+
return c.json({ error: "forbidden origin" }, 403);
|
|
24124
|
+
}
|
|
24059
24125
|
function servePrm(c, resourcePath) {
|
|
24060
24126
|
applyCors(c);
|
|
24061
24127
|
c.header("Cache-Control", "public, max-age=3600");
|
|
@@ -24094,6 +24160,8 @@ app.use("/mcp", MCP_BODY_LIMIT);
|
|
|
24094
24160
|
app.use("/fr/mcp", MCP_BODY_LIMIT);
|
|
24095
24161
|
app.use("/messages", MCP_BODY_LIMIT);
|
|
24096
24162
|
async function handleStreamable(c, resourcePath) {
|
|
24163
|
+
const foreign = rejectForeignOrigin(c);
|
|
24164
|
+
if (foreign) return foreign;
|
|
24097
24165
|
const token = extractBearer(c.req.header("authorization"));
|
|
24098
24166
|
const resolved = await resolveClientFromToken(token);
|
|
24099
24167
|
if (resolved.authState === "missing" || resolved.authState === "expired") {
|
|
@@ -24139,6 +24207,8 @@ async function handleStreamable(c, resourcePath) {
|
|
|
24139
24207
|
app.all("/mcp", (c) => handleStreamable(c, "/mcp"));
|
|
24140
24208
|
app.all("/fr/mcp", (c) => handleStreamable(c, "/fr/mcp"));
|
|
24141
24209
|
async function handleSse(c, resourcePath) {
|
|
24210
|
+
const foreign = rejectForeignOrigin(c);
|
|
24211
|
+
if (foreign) return foreign;
|
|
24142
24212
|
const token = extractBearer(c.req.header("authorization"));
|
|
24143
24213
|
const resolved = await resolveClientFromToken(token);
|
|
24144
24214
|
if (resolved.authState === "missing" || resolved.authState === "expired") {
|
|
@@ -24160,6 +24230,8 @@ async function handleSse(c, resourcePath) {
|
|
|
24160
24230
|
app.get("/sse", (c) => handleSse(c, "/sse"));
|
|
24161
24231
|
app.get("/fr/sse", (c) => handleSse(c, "/fr/sse"));
|
|
24162
24232
|
app.post("/messages", async (c) => {
|
|
24233
|
+
const foreign = rejectForeignOrigin(c);
|
|
24234
|
+
if (foreign) return foreign;
|
|
24163
24235
|
const sessionId = c.req.query("sessionId");
|
|
24164
24236
|
if (!sessionId) {
|
|
24165
24237
|
return c.json({ error: "missing sessionId" }, 400);
|
|
@@ -1764,7 +1764,7 @@ var init_installer_gui = __esm({
|
|
|
1764
1764
|
init_install_dxt();
|
|
1765
1765
|
init_install_shared();
|
|
1766
1766
|
init_oauth();
|
|
1767
|
-
VERSION = true ? "0.23.
|
|
1767
|
+
VERSION = true ? "0.23.10" : "0.0.0-dev";
|
|
1768
1768
|
MESSAGES = {
|
|
1769
1769
|
en: {
|
|
1770
1770
|
installer: {
|
package/dist/installer-gui.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leadbay/mcp",
|
|
3
|
-
"version": "0.23.
|
|
3
|
+
"version": "0.23.10",
|
|
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",
|
|
@@ -61,13 +61,13 @@
|
|
|
61
61
|
],
|
|
62
62
|
"repository": {
|
|
63
63
|
"type": "git",
|
|
64
|
-
"url": "git+https://github.com/leadbay/
|
|
64
|
+
"url": "git+https://github.com/leadbay/mcp.git",
|
|
65
65
|
"directory": "packages/mcp"
|
|
66
66
|
},
|
|
67
67
|
"bugs": {
|
|
68
|
-
"url": "https://github.com/leadbay/
|
|
68
|
+
"url": "https://github.com/leadbay/mcp/issues"
|
|
69
69
|
},
|
|
70
|
-
"homepage": "https://github.com/leadbay/
|
|
70
|
+
"homepage": "https://github.com/leadbay/mcp/tree/main/packages/mcp#readme",
|
|
71
71
|
"author": "Leadbay",
|
|
72
72
|
"license": "MIT"
|
|
73
73
|
}
|