@leadbay/mcp 0.12.1 → 0.14.0
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 +15 -0
- package/README.md +32 -11
- package/dist/bin.js +217 -26
- package/dist/{chunk-J2Y4LCFM.js → chunk-SX4SKXMM.js} +5267 -204
- package/dist/{dist-YYVFSDMH.js → dist-CRE74TH2.js} +77 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog — @leadbay/mcp
|
|
2
2
|
|
|
3
|
+
## 0.13.0 — 2026-05-21
|
|
4
|
+
|
|
5
|
+
- **Agent memory v1**: added always-on recall/capture/review tools backed by
|
|
6
|
+
local append-only JSONL at `~/.leadbay/memory/{account_id}/`.
|
|
7
|
+
- Leads-touching tool responses now attach `_meta.agent_memory.summary` with
|
|
8
|
+
the consolidated top signals unless `LEADBAY_AGENT_MEMORY=off` is set.
|
|
9
|
+
- Server instructions, prompt descriptions, and workflow prompts now teach the
|
|
10
|
+
memory protocol, including capture of new taste signals and review-gated
|
|
11
|
+
retractions.
|
|
12
|
+
- Added `agent-memory://summary` resource and PostHog events for memory
|
|
13
|
+
capture/recall/prune.
|
|
14
|
+
- **Pin bumps**: every active `@leadbay/mcp@0.12` install/runtime reference in
|
|
15
|
+
docs, generated client config, DXT, MCP Registry metadata, and Claude plugin
|
|
16
|
+
metadata is now `@0.13`.
|
|
17
|
+
|
|
3
18
|
## 0.12.1 — 2026-05-21
|
|
4
19
|
|
|
5
20
|
MCPB hotfix for Claude Desktop.
|
package/README.md
CHANGED
|
@@ -21,10 +21,31 @@ A Model Context Protocol server that lets Claude Desktop, Cursor, Claude Code, a
|
|
|
21
21
|
|
|
22
22
|
> **0.3.0 behavior change** — composite write tools (`refine_prompt`, `report_outreach`, `adjust_audience`, `bulk_qualify_leads`, `enrich_titles`, `answer_clarification`, `import_leads`) are **ON by default**. Set `LEADBAY_MCP_WRITE=0` (or `--no-write` on `install`) to restore the previous read-only behavior. `leadbay-mcp install` now also registers Claude Code at `--scope user` so Leadbay is visible from any project. See [MIGRATION.md](./MIGRATION.md).
|
|
23
23
|
|
|
24
|
+
## Agent memory
|
|
25
|
+
|
|
26
|
+
Leadbay MCP keeps a local, per-account agent memory at
|
|
27
|
+
`~/.leadbay/memory/{account_id}/`. It stores append-only JSONL learnings
|
|
28
|
+
about user taste signals such as preferred sectors, regions, deal size,
|
|
29
|
+
communication style, and qualification rules.
|
|
30
|
+
|
|
31
|
+
The memory tools are always exposed:
|
|
32
|
+
|
|
33
|
+
- `leadbay_agent_memory_recall` reads the consolidated top signals.
|
|
34
|
+
- `leadbay_agent_memory_capture` appends a new learning after the user reveals
|
|
35
|
+
a material preference.
|
|
36
|
+
- `leadbay_agent_memory_review` lists entries and gates retractions or org
|
|
37
|
+
promotion through user confirmation.
|
|
38
|
+
|
|
39
|
+
The main leads-touching tools (`leadbay_account_status`,
|
|
40
|
+
`leadbay_pull_leads`, `leadbay_pull_followups`,
|
|
41
|
+
`leadbay_prepare_outreach`, `leadbay_research_lead_by_id`) also attach
|
|
42
|
+
`_meta.agent_memory.summary` automatically. Set `LEADBAY_AGENT_MEMORY=off`
|
|
43
|
+
to suppress this ambient metadata.
|
|
44
|
+
|
|
24
45
|
## 1. Install (one command)
|
|
25
46
|
|
|
26
47
|
```bash
|
|
27
|
-
npx -y @leadbay/mcp@0.
|
|
48
|
+
npx -y @leadbay/mcp@0.13 install --email you@yourcompany.com --region us
|
|
28
49
|
# (you'll be prompted for your password — it's not echoed)
|
|
29
50
|
```
|
|
30
51
|
|
|
@@ -67,14 +88,14 @@ Claude Desktop 2026 ships the DXT (Desktop Extension) system — the legacy `cla
|
|
|
67
88
|
|
|
68
89
|
If you installed Node from the official [nodejs.org](https://nodejs.org) `.pkg`, `/usr/local/lib/node_modules` is root-owned. Any of these works:
|
|
69
90
|
|
|
70
|
-
- **Use `npx` (recommended, no global install):** all examples above use `npx -y @leadbay/mcp@0.
|
|
91
|
+
- **Use `npx` (recommended, no global install):** all examples above use `npx -y @leadbay/mcp@0.13 ...` — no global install needed.
|
|
71
92
|
- **`sudo npm install -g @leadbay/mcp`** (enter your macOS password).
|
|
72
93
|
- **Use a Node version manager** — [nvm](https://github.com/nvm-sh/nvm), [volta](https://volta.sh), [fnm](https://github.com/Schniz/fnm). They install Node under your home directory, so `npm install -g` works without sudo.
|
|
73
94
|
|
|
74
95
|
### If you'd rather mint a token without auto-install
|
|
75
96
|
|
|
76
97
|
```bash
|
|
77
|
-
npx -y @leadbay/mcp@0.
|
|
98
|
+
npx -y @leadbay/mcp@0.13 login \
|
|
78
99
|
--email you@yourcompany.com \
|
|
79
100
|
--region us
|
|
80
101
|
```
|
|
@@ -92,7 +113,7 @@ Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) o
|
|
|
92
113
|
"mcpServers": {
|
|
93
114
|
"leadbay": {
|
|
94
115
|
"command": "npx",
|
|
95
|
-
"args": ["-y", "@leadbay/mcp@0.
|
|
116
|
+
"args": ["-y", "@leadbay/mcp@0.13"],
|
|
96
117
|
"env": {
|
|
97
118
|
"LEADBAY_TOKEN": "<paste-token-from-step-1>",
|
|
98
119
|
"LEADBAY_REGION": "us"
|
|
@@ -113,7 +134,7 @@ In Cursor settings, add the MCP server:
|
|
|
113
134
|
"mcp.servers": {
|
|
114
135
|
"leadbay": {
|
|
115
136
|
"command": "npx",
|
|
116
|
-
"args": ["-y", "@leadbay/mcp@0.
|
|
137
|
+
"args": ["-y", "@leadbay/mcp@0.13"],
|
|
117
138
|
"env": { "LEADBAY_TOKEN": "<paste-token>", "LEADBAY_REGION": "us" }
|
|
118
139
|
}
|
|
119
140
|
}
|
|
@@ -126,7 +147,7 @@ In Cursor settings, add the MCP server:
|
|
|
126
147
|
claude mcp add leadbay --scope user \
|
|
127
148
|
--env LEADBAY_TOKEN=<paste-token> \
|
|
128
149
|
--env LEADBAY_REGION=us \
|
|
129
|
-
-- npx -y @leadbay/mcp@0.
|
|
150
|
+
-- npx -y @leadbay/mcp@0.13
|
|
130
151
|
```
|
|
131
152
|
|
|
132
153
|
> **`--scope user`** registers Leadbay globally for your account (visible from any project). Without it, `claude mcp add` defaults to project-local scope and the server only appears in conversations opened from the directory where you ran the command.
|
|
@@ -138,7 +159,7 @@ claude mcp add leadbay --scope user \
|
|
|
138
159
|
Before starting Claude, run:
|
|
139
160
|
|
|
140
161
|
```bash
|
|
141
|
-
LEADBAY_TOKEN=<paste-token> npx -y @leadbay/mcp@0.
|
|
162
|
+
LEADBAY_TOKEN=<paste-token> npx -y @leadbay/mcp@0.13 doctor
|
|
142
163
|
```
|
|
143
164
|
|
|
144
165
|
Expected output:
|
|
@@ -366,14 +387,14 @@ The user's literal text replaces `verification.ref` in the outreach record, and
|
|
|
366
387
|
| `No enrichment credits remaining` | Out of quota | Contact Leadbay support to extend quota |
|
|
367
388
|
| Claude Desktop "loading forever" on first use | `npx` cold-start fetching the package | First run takes ~10s. Prefer `npm install -g @leadbay/mcp` for faster startup. |
|
|
368
389
|
| Claude Desktop doesn't show Leadbay tools | Server crashed at startup | Check `~/Library/Logs/Claude/mcp*.log` (macOS) or `%APPDATA%\Claude\logs\mcp*.log` (Windows). |
|
|
369
|
-
| Claude Code can't find Leadbay in a new conversation | MCP server installed at project scope (default before 0.3.0) | Re-run with `--scope user`: `claude mcp remove leadbay && claude mcp add leadbay --scope user --env LEADBAY_TOKEN=… --env LEADBAY_REGION=us -- npx -y @leadbay/mcp@0.
|
|
390
|
+
| Claude Code can't find Leadbay in a new conversation | MCP server installed at project scope (default before 0.3.0) | Re-run with `--scope user`: `claude mcp remove leadbay && claude mcp add leadbay --scope user --env LEADBAY_TOKEN=… --env LEADBAY_REGION=us -- npx -y @leadbay/mcp@0.13` |
|
|
370
391
|
| Agent reports "tool not found" for `refine_prompt` / `adjust_audience` etc. | Pre-0.3.0 install with `LEADBAY_MCP_WRITE` unset (writes were off) | Either re-run `npx @leadbay/mcp install` or remove `LEADBAY_MCP_WRITE=0` from your client config (writes are on by default in 0.3.0+) |
|
|
371
392
|
|
|
372
393
|
## 5. Upgrade & rotation
|
|
373
394
|
|
|
374
|
-
**Upgrade**: change the pinned minor in your config, e.g. `"@leadbay/mcp@0.2"` → `"@leadbay/mcp@0.
|
|
395
|
+
**Upgrade**: change the pinned minor in your config, e.g. `"@leadbay/mcp@0.2"` → `"@leadbay/mcp@0.13"`, then restart the client. **0.3.0 enables composite write tools by default** — see [MIGRATION.md](./MIGRATION.md). See also the [changelog](https://github.com/leadbay/leadclaw/releases).
|
|
375
396
|
|
|
376
|
-
**Rotate token**: re-run `npx -y @leadbay/mcp@0.
|
|
397
|
+
**Rotate token**: re-run `npx -y @leadbay/mcp@0.13 install --email you@yourcompany.com --region us` (or `login`) — the new session token replaces the old one in your MCP client config, and logging in again invalidates the prior session on most session backends.
|
|
377
398
|
|
|
378
399
|
## 6. Advanced
|
|
379
400
|
|
|
@@ -486,7 +507,7 @@ After your first authenticated call, your PostHog `distinctId` is set to your Le
|
|
|
486
507
|
"mcpServers": {
|
|
487
508
|
"leadbay": {
|
|
488
509
|
"command": "npx",
|
|
489
|
-
"args": ["-y", "@leadbay/mcp@0.
|
|
510
|
+
"args": ["-y", "@leadbay/mcp@0.13"],
|
|
490
511
|
"env": {
|
|
491
512
|
"LEADBAY_TOKEN": "u.…",
|
|
492
513
|
"LEADBAY_REGION": "us",
|
package/dist/bin.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
LeadbayClient,
|
|
4
|
+
agentMemoryTools,
|
|
4
5
|
compositeReadTools,
|
|
5
6
|
compositeWriteTools,
|
|
6
7
|
createClient,
|
|
@@ -8,8 +9,9 @@ import {
|
|
|
8
9
|
formatLoginError,
|
|
9
10
|
granularReadTools,
|
|
10
11
|
granularWriteTools,
|
|
12
|
+
resolveAgentMemorySummary,
|
|
11
13
|
resolveRegion
|
|
12
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-SX4SKXMM.js";
|
|
13
15
|
|
|
14
16
|
// src/bin.ts
|
|
15
17
|
import { realpathSync } from "fs";
|
|
@@ -34,6 +36,11 @@ import {
|
|
|
34
36
|
|
|
35
37
|
// src/prompts.generated.ts
|
|
36
38
|
var leadbay_daily_check_in = `
|
|
39
|
+
## MEMORY
|
|
40
|
+
|
|
41
|
+
Before responding, glance at any \`_meta.agent_memory.summary\` returned by tool calls earlier in this session and reflect its top signals in your reasoning ("Filtering by your stated preference for healthcare"). After any material new taste signal from the user this conversation (sector, region, deal size, communication style, qualification rule, explicit retraction), call \`leadbay_agent_memory_capture\` to persist it: \`source:"user_stated"\` if literal, \`source:"inferred"\` with confidence <=6 if inferred.
|
|
42
|
+
|
|
43
|
+
|
|
37
44
|
Run the Leadbay daily check-in for me. Treat this prompt the same way for any equivalent ask focused on NEW leads from the Discover wishlist: "get me leadbay leads", "best NEW leads to prospect today", "what's new today", "show me my batch", "let's prospect". For follow-up phrasings ("what should I follow up on", "leads I've already worked", "before my trip"), this is the wrong prompt \u2014 route to \`leadbay_followup_check_in\` instead. If the user's intent is ambiguous ("what should I work on?"), ASK once before picking an entry point.
|
|
38
45
|
|
|
39
46
|
# Resilience rules for Leadbay long-running tools
|
|
@@ -411,6 +418,11 @@ If I declined the campaign step, end the turn \u2014 the map + drafts are enough
|
|
|
411
418
|
Done. The map is the surface; the drafts are the action; the campaign is the persistence layer for managerial follow-up after the trip.
|
|
412
419
|
`;
|
|
413
420
|
var leadbay_prospecting_overview = `
|
|
421
|
+
## MEMORY
|
|
422
|
+
|
|
423
|
+
Before responding, glance at any \`_meta.agent_memory.summary\` returned by tool calls earlier in this session and reflect its top signals in your reasoning ("Filtering by your stated preference for healthcare"). After any material new taste signal from the user this conversation (sector, region, deal size, communication style, qualification rule, explicit retraction), call \`leadbay_agent_memory_capture\` to persist it: \`source:"user_stated"\` if literal, \`source:"inferred"\` with confidence <=6 if inferred.
|
|
424
|
+
|
|
425
|
+
|
|
414
426
|
# Leadbay Prospecting \u2014 Orientation
|
|
415
427
|
|
|
416
428
|
You are working with Leadbay through the \`leadbay_*\` MCP tools. This prompt orients you to the user's mental model so you don't re-discover the workflow each session.
|
|
@@ -674,6 +686,11 @@ IRON LAW \u2014 DO NOT ANSWER CLARIFICATIONS ON THE USER'S BEHALF. If the respon
|
|
|
674
686
|
If the response status is \`applied\`, tell me Leadbay is regenerating intelligence and recommend I check back in a few minutes via \`leadbay_account_status\` (\`computing_intelligence\` flips to false when ready). If the status is anything else, name it explicitly.
|
|
675
687
|
`;
|
|
676
688
|
var leadbay_research_a_domain = `
|
|
689
|
+
## MEMORY
|
|
690
|
+
|
|
691
|
+
Before responding, glance at any \`_meta.agent_memory.summary\` returned by tool calls earlier in this session and reflect its top signals in your reasoning ("Filtering by your stated preference for healthcare"). After any material new taste signal from the user this conversation (sector, region, deal size, communication style, qualification rule, explicit retraction), call \`leadbay_agent_memory_capture\` to persist it: \`source:"user_stated"\` if literal, \`source:"inferred"\` with confidence <=6 if inferred.
|
|
692
|
+
|
|
693
|
+
|
|
677
694
|
IRON LAW \u2014 NO FABRICATION. Every lead id, contact email, custom field id, mapping decision, and tool argument must trace to a value you read from the file the user attached or to an output from a leadbay_* tool call in this session. Do not invent values. Do not "fill in" a missing leadId with a name match. Do not synthesize a CRM id from a guess. If a value is missing, leave the field blank and say so.
|
|
678
695
|
|
|
679
696
|
|
|
@@ -1219,6 +1236,7 @@ function getPrompt(name, args = {}) {
|
|
|
1219
1236
|
var LEAD_URI_RE = /^lead:\/\/([0-9a-f-]{36})\/profile$/i;
|
|
1220
1237
|
var LENS_URI_RE = /^lens:\/\/(\d+)\/definition$/;
|
|
1221
1238
|
var ORG_TASTE_URI = "org://taste-profile";
|
|
1239
|
+
var AGENT_MEMORY_SUMMARY_URI = "agent-memory://summary";
|
|
1222
1240
|
function listResources() {
|
|
1223
1241
|
return [
|
|
1224
1242
|
{
|
|
@@ -1226,6 +1244,12 @@ function listResources() {
|
|
|
1226
1244
|
name: "Org taste profile",
|
|
1227
1245
|
description: "The org's qualification questions, intent tags, and ICP signals \u2014 the agent's knowledge base for what makes a lead a fit.",
|
|
1228
1246
|
mimeType: "application/json"
|
|
1247
|
+
},
|
|
1248
|
+
{
|
|
1249
|
+
uri: AGENT_MEMORY_SUMMARY_URI,
|
|
1250
|
+
name: "Agent memory summary",
|
|
1251
|
+
description: "Consolidated top Leadbay agent-memory signals for this account. Local-file, read-only resource.",
|
|
1252
|
+
mimeType: "text/markdown"
|
|
1229
1253
|
}
|
|
1230
1254
|
];
|
|
1231
1255
|
}
|
|
@@ -1256,11 +1280,29 @@ function jsonContent(uri, value) {
|
|
|
1256
1280
|
]
|
|
1257
1281
|
};
|
|
1258
1282
|
}
|
|
1283
|
+
function textContent(uri, mimeType, text) {
|
|
1284
|
+
return {
|
|
1285
|
+
contents: [
|
|
1286
|
+
{
|
|
1287
|
+
uri,
|
|
1288
|
+
mimeType,
|
|
1289
|
+
text
|
|
1290
|
+
}
|
|
1291
|
+
]
|
|
1292
|
+
};
|
|
1293
|
+
}
|
|
1259
1294
|
async function readResource(uri, client) {
|
|
1260
1295
|
if (uri === ORG_TASTE_URI) {
|
|
1261
1296
|
const taste = await client.resolveTasteProfile();
|
|
1262
1297
|
return jsonContent(uri, taste);
|
|
1263
1298
|
}
|
|
1299
|
+
if (uri === AGENT_MEMORY_SUMMARY_URI) {
|
|
1300
|
+
const me = await client.resolveMe();
|
|
1301
|
+
const memory = await resolveAgentMemorySummary({
|
|
1302
|
+
accountId: me.organization.id
|
|
1303
|
+
});
|
|
1304
|
+
return textContent(uri, "text/markdown", memory.summary);
|
|
1305
|
+
}
|
|
1264
1306
|
const leadMatch = LEAD_URI_RE.exec(uri);
|
|
1265
1307
|
if (leadMatch) {
|
|
1266
1308
|
const leadId = leadMatch[1];
|
|
@@ -1281,7 +1323,7 @@ async function readResource(uri, client) {
|
|
|
1281
1323
|
return jsonContent(uri, { lensId, filter, scoring });
|
|
1282
1324
|
}
|
|
1283
1325
|
throw new Error(
|
|
1284
|
-
`Unsupported resource URI: ${uri}. Supported schemes: lead://{uuid}/profile, lens://{id}/definition, org://taste-profile.`
|
|
1326
|
+
`Unsupported resource URI: ${uri}. Supported schemes: lead://{uuid}/profile, lens://{id}/definition, org://taste-profile, agent-memory://summary.`
|
|
1285
1327
|
);
|
|
1286
1328
|
}
|
|
1287
1329
|
|
|
@@ -1307,6 +1349,10 @@ var EV_MCP_UPDATE_PROMPTED = "mcp update prompted";
|
|
|
1307
1349
|
var EV_MCP_UPDATE_INSTALL_CLICKED = "mcp update install_clicked";
|
|
1308
1350
|
var EV_MCP_UPDATE_DISMISSED = "mcp update dismissed";
|
|
1309
1351
|
var EV_MCP_VERSION_UPDATED = "mcp version updated";
|
|
1352
|
+
var EV_AGENT_MEMORY_CAPTURED = "agent_memory_captured";
|
|
1353
|
+
var EV_AGENT_MEMORY_RECALLED = "agent_memory_recalled";
|
|
1354
|
+
var EV_AGENT_MEMORY_PRUNED = "agent_memory_pruned";
|
|
1355
|
+
var EV_FRICTION_REPORTED = "mcp friction reported";
|
|
1310
1356
|
|
|
1311
1357
|
// src/telemetry.ts
|
|
1312
1358
|
var NOOP_TELEMETRY = {
|
|
@@ -1320,6 +1366,14 @@ var NOOP_TELEMETRY = {
|
|
|
1320
1366
|
},
|
|
1321
1367
|
captureStartup: () => {
|
|
1322
1368
|
},
|
|
1369
|
+
captureAgentMemoryCaptured: () => {
|
|
1370
|
+
},
|
|
1371
|
+
captureAgentMemoryRecalled: () => {
|
|
1372
|
+
},
|
|
1373
|
+
captureAgentMemoryPruned: () => {
|
|
1374
|
+
},
|
|
1375
|
+
captureFrictionReported: () => {
|
|
1376
|
+
},
|
|
1323
1377
|
captureException: () => {
|
|
1324
1378
|
},
|
|
1325
1379
|
captureUpdateCheck: () => {
|
|
@@ -1378,8 +1432,17 @@ function initTelemetry(opts) {
|
|
|
1378
1432
|
sendDefaultPii: false,
|
|
1379
1433
|
// Tag every captured event with the surface so Sentry views can
|
|
1380
1434
|
// split MCP issues from web-app issues without per-call work.
|
|
1435
|
+
// Version is also encoded in `release` above, but a dedicated
|
|
1436
|
+
// `mcp_version` tag is filterable from Sentry's issue list without
|
|
1437
|
+
// expanding the release dropdown — load-bearing when triaging
|
|
1438
|
+
// "errors at reinstall on @0.13" vs older clients still on @0.11.
|
|
1381
1439
|
initialScope: {
|
|
1382
|
-
tags: {
|
|
1440
|
+
tags: {
|
|
1441
|
+
source: "mcp",
|
|
1442
|
+
mcp_version: version,
|
|
1443
|
+
node_version: process.versions.node,
|
|
1444
|
+
platform: process.platform
|
|
1445
|
+
}
|
|
1383
1446
|
}
|
|
1384
1447
|
});
|
|
1385
1448
|
sentryReady = true;
|
|
@@ -1504,6 +1567,18 @@ function initTelemetry(opts) {
|
|
|
1504
1567
|
captureStartup(props) {
|
|
1505
1568
|
emit(EV_STARTUP, { ...props });
|
|
1506
1569
|
},
|
|
1570
|
+
captureAgentMemoryCaptured(props) {
|
|
1571
|
+
emit(EV_AGENT_MEMORY_CAPTURED, { ...props });
|
|
1572
|
+
},
|
|
1573
|
+
captureAgentMemoryRecalled(props) {
|
|
1574
|
+
emit(EV_AGENT_MEMORY_RECALLED, { ...props });
|
|
1575
|
+
},
|
|
1576
|
+
captureAgentMemoryPruned(props) {
|
|
1577
|
+
emit(EV_AGENT_MEMORY_PRUNED, { ...props });
|
|
1578
|
+
},
|
|
1579
|
+
captureFrictionReported(props) {
|
|
1580
|
+
emit(EV_FRICTION_REPORTED, { ...props });
|
|
1581
|
+
},
|
|
1507
1582
|
captureUpdateCheck(props) {
|
|
1508
1583
|
emit(EV_MCP_UPDATE_CHECK, { ...props });
|
|
1509
1584
|
},
|
|
@@ -1867,6 +1942,7 @@ function buildAcknowledgeUpdateTool(opts) {
|
|
|
1867
1942
|
var VERIFICATION_MANDATE = "After every email, call, message, or meeting with a lead's contact, you MUST call leadbay_report_outreach with verification={source, ref} (gmail_message_id from the Gmail send, calendar_event_id from a booking, or user_confirmed='<the user's literal confirmation>'). Skipping or fabricating verification poisons the human team's pipeline.";
|
|
1868
1943
|
var MENTAL_MODEL_PARAGRAPH = "How Leadbay works (mental model): Leadbay is a sales inbox, not a queryable database. Each day the user logs back in, a fresh batch of leads is delivered. Batch size is paced by how many leads the user has actually acted on recently \u2014 some workflows produce a big stream of smaller prospects, others a narrow stream of bigger ones. Pulling more won't produce more; the user acting on leads (outreach, skips, saves) does.";
|
|
1869
1944
|
var QUOTA_AND_TOPUP_PARAGRAPH = "Quota & top-ups: when a tool returns QUOTA_EXCEEDED / 429, the user has TWO options \u2014 wait for the window reset (daily / weekly / monthly resets shown in leadbay_account_status), OR top up AI credits (top-ups clear the throttle IMMEDIATELY \u2014 they are not subject to the same window). Always offer BOTH options; default-recommending 'wait until tomorrow' is wrong when a 30-second top-up unblocks the same call. If the host exposes leadbay_create_topup_link, OFFER it on every quota wall: 'Want me to generate a top-up link?' \u2014 when the user says yes, call leadbay_create_topup_link and surface the returned Stripe URL as a clickable link for the user to open in their browser. (Sibling leadbay_open_billing_portal is for ongoing subscription changes, not one-shot top-ups.) AFTER the user has topped up: do NOT keep refusing operations. A top-up invalidates every prior 429 and every stale 'you're at your quota' snapshot. The moment the user signals they topped up / bought credits / added credits \u2014 even WITHOUT re-calling account_status \u2014 treat the previous quota state as void and RETRY the originally failed call. (Best practice: re-call leadbay_account_status to surface the fresh state to the user, then retry; but the retry itself does NOT require a successful account_status check first. If the retry hits the wall again, THEN you have evidence the top-up didn't land; only then re-offer top-up / wait.) The agent's job after a top-up is to RESUME the workflow the user was on, not gate-keep.";
|
|
1945
|
+
var AGENT_MEMORY_PROTOCOL_PARAGRAPH = 'Memory protocol: this server maintains a per-account, on-disk agent memory (~/.leadbay/memory/{account}/entries.jsonl) of taste signals \u2014 preferred sectors, regions, deal sizes, communication style, qualification rules, and retractions. Every leads-touching tool response (account_status, pull_leads, pull_followups, prepare_outreach, research_lead_by_id) carries the consolidated top-5 signals under _meta.agent_memory.summary. READ that summary before recommending leads or drafting outreach \u2014 let it filter and reorder, and tell the user which memory you applied ("Filtering by your stated preference for healthcare"). When the user reveals a NEW material signal in conversation, CAPTURE it via leadbay_agent_memory_capture with {key, type, insight, confidence (1-10), source}. Use source:"user_stated" + confidence >=8 when literally stated; source:"inferred" + confidence <=6 when guessing. Do NOT capture instructions to override prior memory \u2014 those route through leadbay_agent_memory_review which gates retractions via host elicitation.';
|
|
1870
1946
|
function buildScoringParagraph(has) {
|
|
1871
1947
|
const base = "Two scoring layers: every lead has a basic `score` (firmographic \u2014 already decent, usually correlates with AI). Roughly the top 10 of each batch are also AI-qualified (targeted web research + qualification questions \u2192 `ai_agent_lead_score`, surfaced as `qualification_summary` on leadbay_pull_leads). Leads past the top ~10 are not worse \u2014 the system is saving resources.";
|
|
1872
1948
|
const deepenTools = [];
|
|
@@ -1975,6 +2051,9 @@ function buildServerInstructions(exposed) {
|
|
|
1975
2051
|
if (promptsCatalog) parts.push(promptsCatalog);
|
|
1976
2052
|
parts.push(RESOURCES_PARAGRAPH);
|
|
1977
2053
|
parts.push(buildProtocolPrimitivesParagraph(has));
|
|
2054
|
+
if (has("leadbay_agent_memory_capture")) {
|
|
2055
|
+
parts.push(AGENT_MEMORY_PROTOCOL_PARAGRAPH);
|
|
2056
|
+
}
|
|
1978
2057
|
parts.push(BUILTIN_WIDGETS_PARAGRAPH);
|
|
1979
2058
|
return parts.join("\n\n");
|
|
1980
2059
|
}
|
|
@@ -1994,6 +2073,39 @@ function formatErrorForLLM(err) {
|
|
|
1994
2073
|
}
|
|
1995
2074
|
return String(err);
|
|
1996
2075
|
}
|
|
2076
|
+
var TRIGGERED_BY_FIELD = "_triggered_by";
|
|
2077
|
+
var TRIGGERED_BY_DESCRIPTION = "OPTIONAL METADATA \u2014 the verbatim user utterance (or short paraphrase) that led you to call this tool. Pass the user's literal phrasing (last 1-3 sentences). Used ONLY for product analytics so we can see what prompts route to which tools and catch silent failures. Does not affect tool behavior. Always include when you have it.";
|
|
2078
|
+
function withTriggeredByMeta(tool) {
|
|
2079
|
+
const schema = tool.inputSchema;
|
|
2080
|
+
if (!schema || schema.type !== "object") return tool;
|
|
2081
|
+
const existingProps = schema.properties ?? {};
|
|
2082
|
+
if (Object.prototype.hasOwnProperty.call(existingProps, TRIGGERED_BY_FIELD)) {
|
|
2083
|
+
return tool;
|
|
2084
|
+
}
|
|
2085
|
+
return {
|
|
2086
|
+
...tool,
|
|
2087
|
+
inputSchema: {
|
|
2088
|
+
...schema,
|
|
2089
|
+
properties: {
|
|
2090
|
+
...existingProps,
|
|
2091
|
+
[TRIGGERED_BY_FIELD]: {
|
|
2092
|
+
type: "string",
|
|
2093
|
+
description: TRIGGERED_BY_DESCRIPTION
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
};
|
|
2098
|
+
}
|
|
2099
|
+
function extractTriggeredBy(args) {
|
|
2100
|
+
const raw = args[TRIGGERED_BY_FIELD];
|
|
2101
|
+
if (typeof raw !== "string" || raw.length === 0) {
|
|
2102
|
+
return { triggered_by: void 0, cleaned: args };
|
|
2103
|
+
}
|
|
2104
|
+
const { [TRIGGERED_BY_FIELD]: _omit, ...cleaned } = args;
|
|
2105
|
+
void _omit;
|
|
2106
|
+
const trimmed = raw.length > 500 ? `${raw.slice(0, 500)}\u2026` : raw;
|
|
2107
|
+
return { triggered_by: trimmed, cleaned };
|
|
2108
|
+
}
|
|
1997
2109
|
function toolsListPayload(tools) {
|
|
1998
2110
|
return tools.map((t) => {
|
|
1999
2111
|
const out = {
|
|
@@ -2008,6 +2120,7 @@ function toolsListPayload(tools) {
|
|
|
2008
2120
|
}
|
|
2009
2121
|
function buildServer(client, opts = {}) {
|
|
2010
2122
|
const exposedTools = [];
|
|
2123
|
+
exposedTools.push(...agentMemoryTools);
|
|
2011
2124
|
exposedTools.push(...compositeReadTools);
|
|
2012
2125
|
if (opts.includeWrite) {
|
|
2013
2126
|
exposedTools.push(...compositeWriteTools);
|
|
@@ -2034,7 +2147,7 @@ function buildServer(client, opts = {}) {
|
|
|
2034
2147
|
const toolByName = /* @__PURE__ */ new Map();
|
|
2035
2148
|
for (const t of exposedTools) {
|
|
2036
2149
|
if (!toolByName.has(t.name) && t.name !== "leadbay_login") {
|
|
2037
|
-
toolByName.set(t.name, t);
|
|
2150
|
+
toolByName.set(t.name, withTriggeredByMeta(t));
|
|
2038
2151
|
}
|
|
2039
2152
|
}
|
|
2040
2153
|
const exposedNames = new Set(toolByName.keys());
|
|
@@ -2152,6 +2265,46 @@ function buildServer(client, opts = {}) {
|
|
|
2152
2265
|
}
|
|
2153
2266
|
};
|
|
2154
2267
|
const isLeadbayBusinessError = (err) => err != null && typeof err === "object" && err.error === true && typeof err.code === "string";
|
|
2268
|
+
const captureFrictionTelemetry = (toolName, result) => {
|
|
2269
|
+
if (toolName !== "leadbay_report_friction") return;
|
|
2270
|
+
if (!result || typeof result !== "object") return;
|
|
2271
|
+
const fr = result._friction;
|
|
2272
|
+
if (!fr || typeof fr !== "object") return;
|
|
2273
|
+
if (typeof fr.category !== "string" || typeof fr.user_quote !== "string") {
|
|
2274
|
+
return;
|
|
2275
|
+
}
|
|
2276
|
+
telemetry.captureFrictionReported({
|
|
2277
|
+
category: fr.category,
|
|
2278
|
+
user_quote: fr.user_quote,
|
|
2279
|
+
...typeof fr.tool_called === "string" ? { tool_called: fr.tool_called } : {},
|
|
2280
|
+
...typeof fr.severity === "string" ? { severity: fr.severity } : {},
|
|
2281
|
+
...typeof fr.details === "string" ? { details: fr.details } : {}
|
|
2282
|
+
});
|
|
2283
|
+
};
|
|
2284
|
+
const captureAgentMemoryTelemetry = (toolName, result) => {
|
|
2285
|
+
if (!result || typeof result !== "object") return;
|
|
2286
|
+
const meta = result._meta ?? {};
|
|
2287
|
+
if (toolName === "leadbay_agent_memory_capture") {
|
|
2288
|
+
telemetry.captureAgentMemoryCaptured({
|
|
2289
|
+
source: result.captured?.source ?? meta.source,
|
|
2290
|
+
scope: result.captured?.scope ?? meta.scope,
|
|
2291
|
+
key: result.captured?.key,
|
|
2292
|
+
type: result.captured?.type,
|
|
2293
|
+
account_id_hash: meta.account_id_hash
|
|
2294
|
+
});
|
|
2295
|
+
} else if (toolName === "leadbay_agent_memory_recall") {
|
|
2296
|
+
telemetry.captureAgentMemoryRecalled({
|
|
2297
|
+
entries_returned: result.entries_returned,
|
|
2298
|
+
total_active: result.total_active,
|
|
2299
|
+
account_id_hash: meta.account_id_hash
|
|
2300
|
+
});
|
|
2301
|
+
} else if (toolName === "leadbay_agent_memory_review" && result.changed === true && (result.action === "retract" || result.action === "prune")) {
|
|
2302
|
+
telemetry.captureAgentMemoryPruned({
|
|
2303
|
+
action: result.action,
|
|
2304
|
+
account_id_hash: meta.account_id_hash
|
|
2305
|
+
});
|
|
2306
|
+
}
|
|
2307
|
+
};
|
|
2155
2308
|
server.setRequestHandler(CallToolRequestSchema, async (req, extra) => {
|
|
2156
2309
|
const callStart = Date.now();
|
|
2157
2310
|
const name = req.params.name;
|
|
@@ -2168,7 +2321,8 @@ function buildServer(client, opts = {}) {
|
|
|
2168
2321
|
isError: true
|
|
2169
2322
|
};
|
|
2170
2323
|
}
|
|
2171
|
-
const
|
|
2324
|
+
const rawArgs = req.params.arguments ?? {};
|
|
2325
|
+
const { triggered_by, cleaned: args } = extractTriggeredBy(rawArgs);
|
|
2172
2326
|
const progressToken = req.params?._meta?.progressToken;
|
|
2173
2327
|
const progress = progressToken !== void 0 ? (params) => {
|
|
2174
2328
|
extra.sendNotification({
|
|
@@ -2227,7 +2381,8 @@ function buildServer(client, opts = {}) {
|
|
|
2227
2381
|
duration_ms: envDur,
|
|
2228
2382
|
format: "error-envelope",
|
|
2229
2383
|
bytes: envText.length,
|
|
2230
|
-
error_code: envCode
|
|
2384
|
+
error_code: envCode,
|
|
2385
|
+
triggered_by
|
|
2231
2386
|
});
|
|
2232
2387
|
if (DEBUG_ON) {
|
|
2233
2388
|
process.stderr.write(
|
|
@@ -2258,8 +2413,11 @@ function buildServer(client, opts = {}) {
|
|
|
2258
2413
|
ok: true,
|
|
2259
2414
|
duration_ms: mdDur,
|
|
2260
2415
|
format: "markdown",
|
|
2261
|
-
bytes: mdBytes
|
|
2416
|
+
bytes: mdBytes,
|
|
2417
|
+
triggered_by
|
|
2262
2418
|
});
|
|
2419
|
+
captureAgentMemoryTelemetry(name, env.structured);
|
|
2420
|
+
captureFrictionTelemetry(name, env.structured);
|
|
2263
2421
|
if (name === "leadbay_create_topup_link" && typeof env.structured?.url === "string") {
|
|
2264
2422
|
telemetry.captureTopupLink({ tool: name });
|
|
2265
2423
|
}
|
|
@@ -2287,8 +2445,11 @@ function buildServer(client, opts = {}) {
|
|
|
2287
2445
|
ok: true,
|
|
2288
2446
|
duration_ms: okDur,
|
|
2289
2447
|
format: "json",
|
|
2290
|
-
bytes: okBytes
|
|
2448
|
+
bytes: okBytes,
|
|
2449
|
+
triggered_by
|
|
2291
2450
|
});
|
|
2451
|
+
captureAgentMemoryTelemetry(name, result);
|
|
2452
|
+
captureFrictionTelemetry(name, result);
|
|
2292
2453
|
if (name === "leadbay_create_topup_link" && typeof result?.url === "string") {
|
|
2293
2454
|
telemetry.captureTopupLink({ tool: name });
|
|
2294
2455
|
}
|
|
@@ -2317,7 +2478,8 @@ function buildServer(client, opts = {}) {
|
|
|
2317
2478
|
duration_ms: errDur,
|
|
2318
2479
|
format: "error-envelope",
|
|
2319
2480
|
bytes: errText.length,
|
|
2320
|
-
error_code: code
|
|
2481
|
+
error_code: code,
|
|
2482
|
+
triggered_by
|
|
2321
2483
|
});
|
|
2322
2484
|
} else {
|
|
2323
2485
|
telemetry.captureException(err, { tool: name });
|
|
@@ -2327,7 +2489,8 @@ function buildServer(client, opts = {}) {
|
|
|
2327
2489
|
duration_ms: errDur,
|
|
2328
2490
|
format: "error-envelope",
|
|
2329
2491
|
bytes: errText.length,
|
|
2330
|
-
error_code: code
|
|
2492
|
+
error_code: code,
|
|
2493
|
+
triggered_by
|
|
2331
2494
|
});
|
|
2332
2495
|
}
|
|
2333
2496
|
if (DEBUG_ON) {
|
|
@@ -2542,7 +2705,7 @@ async function createDefaultUpdateStateStore(opts = {}) {
|
|
|
2542
2705
|
|
|
2543
2706
|
// src/bin.ts
|
|
2544
2707
|
import { createRequire } from "module";
|
|
2545
|
-
var VERSION = "0.
|
|
2708
|
+
var VERSION = "0.14.0";
|
|
2546
2709
|
var HELP = `
|
|
2547
2710
|
leadbay-mcp ${VERSION} \u2014 Leadbay Model Context Protocol server
|
|
2548
2711
|
|
|
@@ -2591,7 +2754,7 @@ EXAMPLE Claude Desktop config (~/Library/Application Support/Claude/claude_deskt
|
|
|
2591
2754
|
"mcpServers": {
|
|
2592
2755
|
"leadbay": {
|
|
2593
2756
|
"command": "npx",
|
|
2594
|
-
"args": ["-y", "@leadbay/mcp@0.
|
|
2757
|
+
"args": ["-y", "@leadbay/mcp@0.13"],
|
|
2595
2758
|
"env": {
|
|
2596
2759
|
"LEADBAY_TOKEN": "lb_...",
|
|
2597
2760
|
"LEADBAY_REGION": "us",
|
|
@@ -2892,7 +3055,7 @@ async function runLogin(args) {
|
|
|
2892
3055
|
let result;
|
|
2893
3056
|
try {
|
|
2894
3057
|
if (pinnedRegion && !allowFallback) {
|
|
2895
|
-
const { REGIONS } = await import("./dist-
|
|
3058
|
+
const { REGIONS } = await import("./dist-CRE74TH2.js");
|
|
2896
3059
|
const baseUrl = REGIONS[pinnedRegion];
|
|
2897
3060
|
const c = createClient({ region: pinnedRegion });
|
|
2898
3061
|
const token = await loginAt(baseUrl, email, password);
|
|
@@ -2902,8 +3065,9 @@ async function runLogin(args) {
|
|
|
2902
3065
|
result = await resolveRegion(email, password, pinnedRegion ?? void 0);
|
|
2903
3066
|
}
|
|
2904
3067
|
} catch (err) {
|
|
2905
|
-
process.stderr.write(`leadbay-mcp login: ${err?.message ?? String(err)}
|
|
3068
|
+
process.stderr.write(`leadbay-mcp@${VERSION} login: ${err?.message ?? String(err)}
|
|
2906
3069
|
`);
|
|
3070
|
+
await reportCliFailure("__login__", err);
|
|
2907
3071
|
return 1;
|
|
2908
3072
|
}
|
|
2909
3073
|
const config = {
|
|
@@ -2911,7 +3075,7 @@ async function runLogin(args) {
|
|
|
2911
3075
|
mcpServers: {
|
|
2912
3076
|
leadbay: {
|
|
2913
3077
|
command: "npx",
|
|
2914
|
-
args: ["-y", "@leadbay/mcp@0.
|
|
3078
|
+
args: ["-y", "@leadbay/mcp@0.13"],
|
|
2915
3079
|
env: {
|
|
2916
3080
|
LEADBAY_TOKEN: result.token,
|
|
2917
3081
|
LEADBAY_REGION: result.region
|
|
@@ -2951,7 +3115,7 @@ Or for Claude Code (token included \u2014 same warning applies):
|
|
|
2951
3115
|
claude mcp add leadbay --scope user \\
|
|
2952
3116
|
--env LEADBAY_TOKEN=${result.token} \\
|
|
2953
3117
|
--env LEADBAY_REGION=${result.region} \\
|
|
2954
|
-
-- npx -y @leadbay/mcp@0.
|
|
3118
|
+
-- npx -y @leadbay/mcp@0.13
|
|
2955
3119
|
|
|
2956
3120
|
Restart your MCP client to pick up the new server.
|
|
2957
3121
|
`
|
|
@@ -3057,7 +3221,7 @@ For Claude Code, run:
|
|
|
3057
3221
|
claude mcp add leadbay --scope user \\
|
|
3058
3222
|
--env LEADBAY_TOKEN=$(jq -r .mcpServers.leadbay.env.LEADBAY_TOKEN ${quotedPath}) \\
|
|
3059
3223
|
--env LEADBAY_REGION=${result.region} \\
|
|
3060
|
-
-- npx -y @leadbay/mcp@0.
|
|
3224
|
+
-- npx -y @leadbay/mcp@0.13
|
|
3061
3225
|
`
|
|
3062
3226
|
);
|
|
3063
3227
|
}
|
|
@@ -3237,7 +3401,7 @@ function buildClaudeCodeAddArgs(token, region, includeWrite, telemetryEnabled) {
|
|
|
3237
3401
|
`LEADBAY_TELEMETRY_ENABLED=${telemetryEnabled ? "true" : "false"}`
|
|
3238
3402
|
];
|
|
3239
3403
|
if (!includeWrite) args.push("--env", `LEADBAY_MCP_WRITE=0`);
|
|
3240
|
-
args.push("--", "npx", "-y", "@leadbay/mcp@0.
|
|
3404
|
+
args.push("--", "npx", "-y", "@leadbay/mcp@0.13");
|
|
3241
3405
|
return args;
|
|
3242
3406
|
}
|
|
3243
3407
|
async function installInClaudeCode(token, region, includeWrite, telemetryEnabled) {
|
|
@@ -3287,7 +3451,7 @@ async function installInJsonConfig(configPath, token, region, includeWrite, tele
|
|
|
3287
3451
|
if (!includeWrite) env.LEADBAY_MCP_WRITE = "0";
|
|
3288
3452
|
parsed.mcpServers.leadbay = {
|
|
3289
3453
|
command: "npx",
|
|
3290
|
-
args: ["-y", "@leadbay/mcp@0.
|
|
3454
|
+
args: ["-y", "@leadbay/mcp@0.13"],
|
|
3291
3455
|
env
|
|
3292
3456
|
};
|
|
3293
3457
|
const tmp = configPath + ".tmp";
|
|
@@ -3391,7 +3555,7 @@ leadbay-mcp install \u2014 detected MCP clients on this machine:
|
|
|
3391
3555
|
let region;
|
|
3392
3556
|
try {
|
|
3393
3557
|
if (pinnedRegion && !allowFallback) {
|
|
3394
|
-
const { REGIONS } = await import("./dist-
|
|
3558
|
+
const { REGIONS } = await import("./dist-CRE74TH2.js");
|
|
3395
3559
|
const baseUrl = REGIONS[pinnedRegion];
|
|
3396
3560
|
token = await loginAt(baseUrl, email, password);
|
|
3397
3561
|
region = pinnedRegion;
|
|
@@ -3401,8 +3565,9 @@ leadbay-mcp install \u2014 detected MCP clients on this machine:
|
|
|
3401
3565
|
region = result.region;
|
|
3402
3566
|
}
|
|
3403
3567
|
} catch (err) {
|
|
3404
|
-
process.stderr.write(`leadbay-mcp install: ${err?.message ?? String(err)}
|
|
3568
|
+
process.stderr.write(`leadbay-mcp@${VERSION} install: ${err?.message ?? String(err)}
|
|
3405
3569
|
`);
|
|
3570
|
+
await reportCliFailure("__install_login__", err);
|
|
3406
3571
|
return 1;
|
|
3407
3572
|
}
|
|
3408
3573
|
process.stderr.write(`Logged in to ${region.toUpperCase()} backend.
|
|
@@ -3454,17 +3619,26 @@ leadbay-mcp install \u2014 detected MCP clients on this machine:
|
|
|
3454
3619
|
}
|
|
3455
3620
|
results.push({ id: c.id, label: c.label, ...res });
|
|
3456
3621
|
}
|
|
3457
|
-
process.stderr.write(
|
|
3622
|
+
process.stderr.write(`
|
|
3623
|
+
=== install summary (leadbay-mcp@${VERSION}) ===
|
|
3624
|
+
`);
|
|
3458
3625
|
let anyOk = false;
|
|
3459
3626
|
for (const r of results) {
|
|
3460
3627
|
process.stderr.write(` ${r.ok ? "\u2713" : "\u2717"} ${r.label.padEnd(16)} ${r.message}
|
|
3461
3628
|
`);
|
|
3462
|
-
if (r.ok)
|
|
3629
|
+
if (r.ok) {
|
|
3630
|
+
anyOk = true;
|
|
3631
|
+
} else if (!r.message.startsWith("skipped")) {
|
|
3632
|
+
await reportCliFailure(
|
|
3633
|
+
`install:${r.id}`,
|
|
3634
|
+
new Error(`${r.label}: ${r.message}`)
|
|
3635
|
+
);
|
|
3636
|
+
}
|
|
3463
3637
|
}
|
|
3464
3638
|
process.stderr.write(
|
|
3465
3639
|
`
|
|
3466
3640
|
The token was written into client config files but never printed to your terminal.
|
|
3467
|
-
Verify with: LEADBAY_TOKEN=$(...) npx -y @leadbay/mcp@0.
|
|
3641
|
+
Verify with: LEADBAY_TOKEN=$(...) npx -y @leadbay/mcp@0.13 doctor
|
|
3468
3642
|
Restart your MCP client(s) to pick up the new server.
|
|
3469
3643
|
If you ever leak the token, run \`leadbay-mcp login --email <you> --region <us|fr>\` to mint a fresh one (which invalidates the prior session).
|
|
3470
3644
|
`
|
|
@@ -3490,6 +3664,7 @@ async function runDoctor() {
|
|
|
3490
3664
|
const me = await client.request("GET", "/users/me");
|
|
3491
3665
|
process.stdout.write(
|
|
3492
3666
|
`Leadbay connection OK.
|
|
3667
|
+
Version: leadbay-mcp@${VERSION} (node ${process.versions.node}, ${process.platform})
|
|
3493
3668
|
Region: ${baseUrl ? "(custom baseUrl)" : region}
|
|
3494
3669
|
Base URL: ${client.baseUrl}
|
|
3495
3670
|
Organization: ${me.organization.name} (${me.organization.id})
|
|
@@ -3503,25 +3678,41 @@ async function runDoctor() {
|
|
|
3503
3678
|
if (err?.code === "AUTH_EXPIRED" || err?.code === "NOT_AUTHENTICATED") {
|
|
3504
3679
|
process.stderr.write(
|
|
3505
3680
|
`Leadbay: your LEADBAY_TOKEN is not valid for ${region}. ${err.hint}
|
|
3681
|
+
(leadbay-mcp@${VERSION})
|
|
3506
3682
|
`
|
|
3507
3683
|
);
|
|
3684
|
+
await reportCliFailure("__doctor_auth__", err);
|
|
3508
3685
|
return 1;
|
|
3509
3686
|
}
|
|
3510
3687
|
}
|
|
3511
3688
|
if (baseUrl) break;
|
|
3512
3689
|
}
|
|
3513
3690
|
process.stderr.write(
|
|
3514
|
-
|
|
3691
|
+
`Leadbay doctor: could not reach any Leadbay region with this token. Check the token and your network.
|
|
3692
|
+
(leadbay-mcp@${VERSION})
|
|
3693
|
+
`
|
|
3694
|
+
);
|
|
3695
|
+
await reportCliFailure(
|
|
3696
|
+
"__doctor_unreachable__",
|
|
3697
|
+
new Error("doctor: no region reachable with current token")
|
|
3515
3698
|
);
|
|
3516
3699
|
return 1;
|
|
3517
3700
|
}
|
|
3701
|
+
async function reportCliFailure(label, err) {
|
|
3702
|
+
try {
|
|
3703
|
+
const bootTelemetry = initTelemetry({ version: VERSION });
|
|
3704
|
+
bootTelemetry.captureException(err, { tool: label });
|
|
3705
|
+
await bootTelemetry.shutdown();
|
|
3706
|
+
} catch {
|
|
3707
|
+
}
|
|
3708
|
+
}
|
|
3518
3709
|
var startupSafetyNetsInstalled = false;
|
|
3519
3710
|
function installStartupSafetyNets(logger) {
|
|
3520
3711
|
if (startupSafetyNetsInstalled) return;
|
|
3521
3712
|
startupSafetyNetsInstalled = true;
|
|
3522
3713
|
const reportAndExit = (label, err) => {
|
|
3523
3714
|
const msg = err instanceof Error ? err.stack ?? err.message : String(err);
|
|
3524
|
-
process.stderr.write(`leadbay-mcp: ${label}: ${msg}
|
|
3715
|
+
process.stderr.write(`leadbay-mcp@${VERSION}: ${label}: ${msg}
|
|
3525
3716
|
`);
|
|
3526
3717
|
logger.error?.(`${label}: ${msg}`);
|
|
3527
3718
|
try {
|