@leadbay/mcp 0.39.8 → 0.39.9
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/MIGRATION.md +5 -5
- package/dist/bin.js +41 -10
- package/dist/http-server.js +40 -9
- package/dist/installer-electron.js +1 -1
- package/dist/installer-gui.js +1 -1
- package/package.json +1 -1
package/MIGRATION.md
CHANGED
|
@@ -32,9 +32,9 @@ field. On the `notification_id` path the job is done when `in_progress` is false
|
|
|
32
32
|
`still_running[]` is empty on that path from the first poll and must not be read
|
|
33
33
|
as "done". On the `lead_ids` path, done means `still_running[]` is empty.
|
|
34
34
|
|
|
35
|
-
`leadbay_bulk_enrich_status` answers `ENRICH_JOB_NO_COUNTERS
|
|
36
|
-
notification carries
|
|
37
|
-
|
|
35
|
+
`leadbay_bulk_enrich_status` no longer answers `ENRICH_JOB_NO_COUNTERS`. An
|
|
36
|
+
enrichment notification never carries per-contact counters, so the tool reads the
|
|
37
|
+
job's lead set back from the backend and answers through the per-lead path.
|
|
38
38
|
|
|
39
39
|
## Errors removed
|
|
40
40
|
|
|
@@ -43,8 +43,8 @@ notification carries no per-contact counters (the common case) — re-call with
|
|
|
43
43
|
no longer exist, and neither does `~/.leadbay/bulks.json` or the
|
|
44
44
|
`LEADBAY_BULK_STORE_ALLOW_MEMORY` escape hatch. The replacements are
|
|
45
45
|
`ENRICH_STATUS_INPUT_REQUIRED`, `ENRICH_JOB_NOT_FOUND`, `ENRICH_JOB_WRONG_KIND`,
|
|
46
|
-
`
|
|
47
|
-
|
|
46
|
+
`QUALIFY_STATUS_INPUT_REQUIRED`, `QUALIFY_JOB_NOT_FOUND` and
|
|
47
|
+
`QUALIFY_JOB_WRONG_KIND`. The 0.5.0 sections below describe the old store and
|
|
48
48
|
are kept as history.
|
|
49
49
|
|
|
50
50
|
---
|
package/dist/bin.js
CHANGED
|
@@ -1982,7 +1982,7 @@ WHEN TO USE: the user asks for a clickable / interactive artifact, dashboard, or
|
|
|
1982
1982
|
|
|
1983
1983
|
WHEN NOT TO USE: the user wants a plain data answer (route to leadbay_pull_leads / leadbay_pull_followups) or to log a single real outreach you just did (leadbay_report_outreach).
|
|
1984
1984
|
`;
|
|
1985
|
-
leadbay_bulk_enrich_status = `Check status + per-lead contacts for a bulk enrichment you previously launched via leadbay_enrich_titles. Pass the \`notification_id
|
|
1985
|
+
leadbay_bulk_enrich_status = `Check status + per-lead contacts for a bulk enrichment you previously launched via leadbay_enrich_titles. Pass the \`notification_id\`, and/or the \`lead_ids\` + \`titles\` + \`email\` / \`phone\` the launch returned. Either one alone is a valid call: with \`notification_id\` the tool reads the job's lead set back from the backend, so an id kept from an earlier conversation still answers with per-lead progress. Pass \`lead_ids\` as well whenever you still have them \u2014 the job lookup is a scan of your recent notifications, so an archived job may not be found, but the leads always answer. \`titles\` / \`email\` / \`phone\` scope the count to the roles and channel THIS run asked for. When \`include_contacts=true\` (opt-in), includes each contact's email/phone_number/job_title/enrichment.done.
|
|
1986
1986
|
|
|
1987
1987
|
WHEN TO USE: poll this REPEATEDLY after leadbay_enrich_titles returns a \`notification_id\`, staying active until the job is done \u2014 don't stop after one check, and don't hand the turn back to the user while progress is still climbing. "Done" = \`all_done:true\`, OR \`overall_progress.done\` has held steady across several SPACED polls (~15\u201330s apart) over at least ~90s\u20132 min of elapsed time (a reservation the provider never answers stays \`done:false\`, so \`all_done\` can stay false forever \u2014 don't spin indefinitely; a contact with nothing found does flip, to \`done:true\` with \`credits_used:0\`). Do NOT declare a plateau from the first few back-to-back reads: right after launch, \`overall_progress.done\` can sit flat while the backend is still spinning the job up, so space your polls out and give it real elapsed time before treating a flat count as terminal. Also do NOT declare a plateau while the result carries \`partial_failures\` \u2014 a flat \`done\` there means a transient per-lead fetch error (e.g. a 429), NOT an unresolvable contact; keep polling (respecting any \`retry_after\`) or surface it as a temporary status failure, rather than reporting those leads as permanently unresolved. Default \`include_contacts=false\` for the cheap interim polls; set \`include_contacts=true\` on the read you report from to pull each lead's enriched contacts for the completion report.
|
|
1988
1988
|
|
|
@@ -21087,7 +21087,26 @@ async function pMap(items, fn, concurrency) {
|
|
|
21087
21087
|
await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => worker()));
|
|
21088
21088
|
return out;
|
|
21089
21089
|
}
|
|
21090
|
-
|
|
21090
|
+
async function readBulkLeadIds(client, bulkId) {
|
|
21091
|
+
const ids = [];
|
|
21092
|
+
for (let page = 0; page < BULK_LEADS_MAX_PAGES; page += 1) {
|
|
21093
|
+
let res;
|
|
21094
|
+
try {
|
|
21095
|
+
res = await client.request("GET", `/leads/bulk_enrichments/${encodeURIComponent(bulkId)}/leads?contacts=false&count=${BULK_LEADS_PAGE_SIZE}&page=${page}`);
|
|
21096
|
+
} catch {
|
|
21097
|
+
return null;
|
|
21098
|
+
}
|
|
21099
|
+
for (const item of res?.items ?? []) {
|
|
21100
|
+
if (item?.id)
|
|
21101
|
+
ids.push(item.id);
|
|
21102
|
+
}
|
|
21103
|
+
const pages = res?.pagination?.pages ?? 1;
|
|
21104
|
+
if (page + 1 >= pages)
|
|
21105
|
+
return ids;
|
|
21106
|
+
}
|
|
21107
|
+
return null;
|
|
21108
|
+
}
|
|
21109
|
+
var STATUS_FETCH_CONCURRENCY, BULK_LEADS_PAGE_SIZE, BULK_LEADS_MAX_PAGES, bulkEnrichStatus;
|
|
21091
21110
|
var init_bulk_enrich_status = __esm({
|
|
21092
21111
|
"../core/dist/composite/bulk-enrich-status.js"() {
|
|
21093
21112
|
"use strict";
|
|
@@ -21097,6 +21116,8 @@ var init_bulk_enrich_status = __esm({
|
|
|
21097
21116
|
init_credits_helpers();
|
|
21098
21117
|
init_tool_descriptions_generated();
|
|
21099
21118
|
STATUS_FETCH_CONCURRENCY = 5;
|
|
21119
|
+
BULK_LEADS_PAGE_SIZE = 100;
|
|
21120
|
+
BULK_LEADS_MAX_PAGES = 3;
|
|
21100
21121
|
bulkEnrichStatus = {
|
|
21101
21122
|
name: "leadbay_bulk_enrich_status",
|
|
21102
21123
|
annotations: {
|
|
@@ -21112,7 +21133,7 @@ var init_bulk_enrich_status = __esm({
|
|
|
21112
21133
|
properties: {
|
|
21113
21134
|
notification_id: {
|
|
21114
21135
|
type: "string",
|
|
21115
|
-
description: "The `notification_id` returned by leadbay_enrich_titles.
|
|
21136
|
+
description: "The `notification_id` returned by leadbay_enrich_titles. Answers on its own: the tool reads the job's lead set back from the backend, so an id kept from an earlier conversation still gives per-lead progress."
|
|
21116
21137
|
},
|
|
21117
21138
|
lead_ids: {
|
|
21118
21139
|
type: "array",
|
|
@@ -21176,7 +21197,7 @@ var init_bulk_enrich_status = __esm({
|
|
|
21176
21197
|
},
|
|
21177
21198
|
execute: async (client, params, ctx) => {
|
|
21178
21199
|
const includeContacts = params.include_contacts ?? false;
|
|
21179
|
-
|
|
21200
|
+
let leadIds = params.lead_ids ?? [];
|
|
21180
21201
|
const startMs = Date.now();
|
|
21181
21202
|
if (!params.notification_id && leadIds.length === 0) {
|
|
21182
21203
|
return {
|
|
@@ -21189,6 +21210,7 @@ var init_bulk_enrich_status = __esm({
|
|
|
21189
21210
|
let bp = null;
|
|
21190
21211
|
let inProgress = null;
|
|
21191
21212
|
let launchedAt = null;
|
|
21213
|
+
let bulkAnchorId = null;
|
|
21192
21214
|
if (params.notification_id) {
|
|
21193
21215
|
const n = await readNotificationById(client, params.notification_id);
|
|
21194
21216
|
if (n && inferKind(n) !== "bulk_enrich") {
|
|
@@ -21204,6 +21226,7 @@ var init_bulk_enrich_status = __esm({
|
|
|
21204
21226
|
bp = n.bulk_progress;
|
|
21205
21227
|
inProgress = n.in_progress;
|
|
21206
21228
|
launchedAt = n.created_at;
|
|
21229
|
+
bulkAnchorId = anchorIdFor(n, "bulk_enrich");
|
|
21207
21230
|
} else if (leadIds.length === 0) {
|
|
21208
21231
|
return {
|
|
21209
21232
|
error: true,
|
|
@@ -21213,6 +21236,9 @@ var init_bulk_enrich_status = __esm({
|
|
|
21213
21236
|
};
|
|
21214
21237
|
}
|
|
21215
21238
|
}
|
|
21239
|
+
if (!bp && leadIds.length === 0 && bulkAnchorId !== null) {
|
|
21240
|
+
leadIds = await readBulkLeadIds(client, bulkAnchorId) ?? [];
|
|
21241
|
+
}
|
|
21216
21242
|
if (leadIds.length > 0) {
|
|
21217
21243
|
const wantTitles = new Set((params.titles ?? []).map((t) => t.trim().toLowerCase()));
|
|
21218
21244
|
const inThisRun = (c) => {
|
|
@@ -21316,13 +21342,18 @@ var init_bulk_enrich_status = __esm({
|
|
|
21316
21342
|
};
|
|
21317
21343
|
}
|
|
21318
21344
|
if (!bp) {
|
|
21345
|
+
const isReportRead2 = inProgress === false;
|
|
21346
|
+
const creditsRemaining2 = isReportRead2 ? await readCreditsRemaining(client, true) : null;
|
|
21319
21347
|
return {
|
|
21320
|
-
|
|
21321
|
-
|
|
21322
|
-
|
|
21323
|
-
|
|
21348
|
+
notification_id: params.notification_id,
|
|
21349
|
+
...launchedAt ? { launched_at: launchedAt } : {},
|
|
21350
|
+
status: inProgress ? "launched" : "complete",
|
|
21351
|
+
leads: [],
|
|
21352
|
+
overall_progress: { done: 0, total: 0, done_ratio: 0 },
|
|
21324
21353
|
...inProgress !== null ? { in_progress: inProgress } : {},
|
|
21325
|
-
|
|
21354
|
+
all_done: isReportRead2,
|
|
21355
|
+
...isReportRead2 ? { credits_remaining: creditsRemaining2 } : {},
|
|
21356
|
+
counts_hint: "This job's notification carries no per-contact counters and its lead set could not be read back, so done/total are 0. Re-call with the `lead_ids` returned by leadbay_enrich_titles (plus titles/email/phone) to count contacts directly."
|
|
21326
21357
|
};
|
|
21327
21358
|
}
|
|
21328
21359
|
const done = bp.success_count + bp.failure_count + bp.quota_hit_count;
|
|
@@ -32162,7 +32193,7 @@ var OAUTH_BASE_URLS = {
|
|
|
32162
32193
|
fr: "https://staging.api.leadbay.app"
|
|
32163
32194
|
}
|
|
32164
32195
|
};
|
|
32165
|
-
var VERSION = "0.39.
|
|
32196
|
+
var VERSION = "0.39.9";
|
|
32166
32197
|
var HELP = `
|
|
32167
32198
|
leadbay-mcp ${VERSION} \u2014 Leadbay Model Context Protocol server
|
|
32168
32199
|
|
package/dist/http-server.js
CHANGED
|
@@ -4932,7 +4932,7 @@ WHEN TO USE: the user asks for a clickable / interactive artifact, dashboard, or
|
|
|
4932
4932
|
|
|
4933
4933
|
WHEN NOT TO USE: the user wants a plain data answer (route to leadbay_pull_leads / leadbay_pull_followups) or to log a single real outreach you just did (leadbay_report_outreach).
|
|
4934
4934
|
`;
|
|
4935
|
-
var leadbay_bulk_enrich_status = `Check status + per-lead contacts for a bulk enrichment you previously launched via leadbay_enrich_titles. Pass the \`notification_id
|
|
4935
|
+
var leadbay_bulk_enrich_status = `Check status + per-lead contacts for a bulk enrichment you previously launched via leadbay_enrich_titles. Pass the \`notification_id\`, and/or the \`lead_ids\` + \`titles\` + \`email\` / \`phone\` the launch returned. Either one alone is a valid call: with \`notification_id\` the tool reads the job's lead set back from the backend, so an id kept from an earlier conversation still answers with per-lead progress. Pass \`lead_ids\` as well whenever you still have them \u2014 the job lookup is a scan of your recent notifications, so an archived job may not be found, but the leads always answer. \`titles\` / \`email\` / \`phone\` scope the count to the roles and channel THIS run asked for. When \`include_contacts=true\` (opt-in), includes each contact's email/phone_number/job_title/enrichment.done.
|
|
4936
4936
|
|
|
4937
4937
|
WHEN TO USE: poll this REPEATEDLY after leadbay_enrich_titles returns a \`notification_id\`, staying active until the job is done \u2014 don't stop after one check, and don't hand the turn back to the user while progress is still climbing. "Done" = \`all_done:true\`, OR \`overall_progress.done\` has held steady across several SPACED polls (~15\u201330s apart) over at least ~90s\u20132 min of elapsed time (a reservation the provider never answers stays \`done:false\`, so \`all_done\` can stay false forever \u2014 don't spin indefinitely; a contact with nothing found does flip, to \`done:true\` with \`credits_used:0\`). Do NOT declare a plateau from the first few back-to-back reads: right after launch, \`overall_progress.done\` can sit flat while the backend is still spinning the job up, so space your polls out and give it real elapsed time before treating a flat count as terminal. Also do NOT declare a plateau while the result carries \`partial_failures\` \u2014 a flat \`done\` there means a transient per-lead fetch error (e.g. a 429), NOT an unresolvable contact; keep polling (respecting any \`retry_after\`) or surface it as a temporary status failure, rather than reporting those leads as permanently unresolved. Default \`include_contacts=false\` for the cheap interim polls; set \`include_contacts=true\` on the read you report from to pull each lead's enriched contacts for the completion report.
|
|
4938
4938
|
|
|
@@ -23290,6 +23290,27 @@ async function pMap(items, fn, concurrency) {
|
|
|
23290
23290
|
await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => worker()));
|
|
23291
23291
|
return out;
|
|
23292
23292
|
}
|
|
23293
|
+
var BULK_LEADS_PAGE_SIZE = 100;
|
|
23294
|
+
var BULK_LEADS_MAX_PAGES = 3;
|
|
23295
|
+
async function readBulkLeadIds(client, bulkId) {
|
|
23296
|
+
const ids = [];
|
|
23297
|
+
for (let page = 0; page < BULK_LEADS_MAX_PAGES; page += 1) {
|
|
23298
|
+
let res;
|
|
23299
|
+
try {
|
|
23300
|
+
res = await client.request("GET", `/leads/bulk_enrichments/${encodeURIComponent(bulkId)}/leads?contacts=false&count=${BULK_LEADS_PAGE_SIZE}&page=${page}`);
|
|
23301
|
+
} catch {
|
|
23302
|
+
return null;
|
|
23303
|
+
}
|
|
23304
|
+
for (const item of res?.items ?? []) {
|
|
23305
|
+
if (item?.id)
|
|
23306
|
+
ids.push(item.id);
|
|
23307
|
+
}
|
|
23308
|
+
const pages = res?.pagination?.pages ?? 1;
|
|
23309
|
+
if (page + 1 >= pages)
|
|
23310
|
+
return ids;
|
|
23311
|
+
}
|
|
23312
|
+
return null;
|
|
23313
|
+
}
|
|
23293
23314
|
var bulkEnrichStatus = {
|
|
23294
23315
|
name: "leadbay_bulk_enrich_status",
|
|
23295
23316
|
annotations: {
|
|
@@ -23305,7 +23326,7 @@ var bulkEnrichStatus = {
|
|
|
23305
23326
|
properties: {
|
|
23306
23327
|
notification_id: {
|
|
23307
23328
|
type: "string",
|
|
23308
|
-
description: "The `notification_id` returned by leadbay_enrich_titles.
|
|
23329
|
+
description: "The `notification_id` returned by leadbay_enrich_titles. Answers on its own: the tool reads the job's lead set back from the backend, so an id kept from an earlier conversation still gives per-lead progress."
|
|
23309
23330
|
},
|
|
23310
23331
|
lead_ids: {
|
|
23311
23332
|
type: "array",
|
|
@@ -23369,7 +23390,7 @@ var bulkEnrichStatus = {
|
|
|
23369
23390
|
},
|
|
23370
23391
|
execute: async (client, params, ctx) => {
|
|
23371
23392
|
const includeContacts = params.include_contacts ?? false;
|
|
23372
|
-
|
|
23393
|
+
let leadIds = params.lead_ids ?? [];
|
|
23373
23394
|
const startMs = Date.now();
|
|
23374
23395
|
if (!params.notification_id && leadIds.length === 0) {
|
|
23375
23396
|
return {
|
|
@@ -23382,6 +23403,7 @@ var bulkEnrichStatus = {
|
|
|
23382
23403
|
let bp = null;
|
|
23383
23404
|
let inProgress = null;
|
|
23384
23405
|
let launchedAt = null;
|
|
23406
|
+
let bulkAnchorId = null;
|
|
23385
23407
|
if (params.notification_id) {
|
|
23386
23408
|
const n = await readNotificationById(client, params.notification_id);
|
|
23387
23409
|
if (n && inferKind(n) !== "bulk_enrich") {
|
|
@@ -23397,6 +23419,7 @@ var bulkEnrichStatus = {
|
|
|
23397
23419
|
bp = n.bulk_progress;
|
|
23398
23420
|
inProgress = n.in_progress;
|
|
23399
23421
|
launchedAt = n.created_at;
|
|
23422
|
+
bulkAnchorId = anchorIdFor(n, "bulk_enrich");
|
|
23400
23423
|
} else if (leadIds.length === 0) {
|
|
23401
23424
|
return {
|
|
23402
23425
|
error: true,
|
|
@@ -23406,6 +23429,9 @@ var bulkEnrichStatus = {
|
|
|
23406
23429
|
};
|
|
23407
23430
|
}
|
|
23408
23431
|
}
|
|
23432
|
+
if (!bp && leadIds.length === 0 && bulkAnchorId !== null) {
|
|
23433
|
+
leadIds = await readBulkLeadIds(client, bulkAnchorId) ?? [];
|
|
23434
|
+
}
|
|
23409
23435
|
if (leadIds.length > 0) {
|
|
23410
23436
|
const wantTitles = new Set((params.titles ?? []).map((t) => t.trim().toLowerCase()));
|
|
23411
23437
|
const inThisRun = (c) => {
|
|
@@ -23509,13 +23535,18 @@ var bulkEnrichStatus = {
|
|
|
23509
23535
|
};
|
|
23510
23536
|
}
|
|
23511
23537
|
if (!bp) {
|
|
23538
|
+
const isReportRead2 = inProgress === false;
|
|
23539
|
+
const creditsRemaining2 = isReportRead2 ? await readCreditsRemaining(client, true) : null;
|
|
23512
23540
|
return {
|
|
23513
|
-
|
|
23514
|
-
|
|
23515
|
-
|
|
23516
|
-
|
|
23541
|
+
notification_id: params.notification_id,
|
|
23542
|
+
...launchedAt ? { launched_at: launchedAt } : {},
|
|
23543
|
+
status: inProgress ? "launched" : "complete",
|
|
23544
|
+
leads: [],
|
|
23545
|
+
overall_progress: { done: 0, total: 0, done_ratio: 0 },
|
|
23517
23546
|
...inProgress !== null ? { in_progress: inProgress } : {},
|
|
23518
|
-
|
|
23547
|
+
all_done: isReportRead2,
|
|
23548
|
+
...isReportRead2 ? { credits_remaining: creditsRemaining2 } : {},
|
|
23549
|
+
counts_hint: "This job's notification carries no per-contact counters and its lead set could not be read back, so done/total are 0. Re-call with the `lead_ids` returned by leadbay_enrich_titles (plus titles/email/phone) to count contacts directly."
|
|
23519
23550
|
};
|
|
23520
23551
|
}
|
|
23521
23552
|
const done = bp.success_count + bp.failure_count + bp.quota_hit_count;
|
|
@@ -29435,7 +29466,7 @@ function parseWriteEnv(env = process.env) {
|
|
|
29435
29466
|
}
|
|
29436
29467
|
|
|
29437
29468
|
// src/http-server.ts
|
|
29438
|
-
var VERSION = true ? "0.39.
|
|
29469
|
+
var VERSION = true ? "0.39.9" : "0.0.0-dev";
|
|
29439
29470
|
var PORT = Number(process.env.PORT ?? 8080);
|
|
29440
29471
|
var HOST = process.env.HOST ?? "0.0.0.0";
|
|
29441
29472
|
var logger = {
|
package/dist/installer-gui.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leadbay/mcp",
|
|
3
|
-
"version": "0.39.
|
|
3
|
+
"version": "0.39.9",
|
|
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",
|