@leadbay/mcp 0.21.0 → 0.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/bin.js +38 -8
- package/dist/http-server.js +37 -7
- package/dist/installer-electron.js +1 -1
- package/dist/installer-gui.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog — @leadbay/mcp
|
|
2
2
|
|
|
3
|
+
## 0.21.1 — 2026-06-16
|
|
4
|
+
|
|
5
|
+
- **CSV import no longer 400s on a lead status the agent didn't uppercase** (product#3745): `leadbay_import_leads` / `leadbay_import_and_qualify` forwarded `default_status` / `statuses` values verbatim to `POST /imports/{id}/update_mappings`, whose backend `MappingsPayload` decodes them as the strict, case-sensitive `LeadStatus` enum (`DEFAULT, INBOUND, UNWANTED, WANTED, LOST, WON`). A value like "Won" failed deserialization and the whole call 400'd with an opaque "JSON deserialization error" before any record committed — JM hit this trying to tag 179 companies as Won. The MCP now owns the canonical set and enforces it before sending: status values are matched case-insensitively to their enum member ("Won" → "WON"), an empty default means no default, and a genuinely unknown status returns a clear `IMPORT_INVALID_STATUS` error naming the valid values instead of an opaque backend 400. The two tools' input schemas now declare the enum.
|
|
6
|
+
|
|
3
7
|
## 0.21.0 — 2026-06-16
|
|
4
8
|
|
|
5
9
|
- **Hosted MCP now triggers OAuth sign-in in Claude Desktop / ChatGPT** (remote custom connectors): the Fly endpoint was not an OAuth-compliant resource server, so a remote client had nothing to discover, never prompted the user to sign in, and then surfaced a host-side "needs auth / token expired" state even though the user never had a token. The server now implements the MCP authorization spec (RFC 9728): it serves OAuth 2.0 Protected Resource Metadata at `/.well-known/oauth-protected-resource[/<resource>]` and answers an unauthenticated (or invalid/expired) `POST /mcp` with `401` + `WWW-Authenticate: Bearer ... resource_metadata="…"`. The client discovers the Leadbay authorization server (the existing regional backend used by `login --oauth`) and runs the browser sign-in. Tool requests auto-probe both regions, so a valid token routes correctly and a stale one re-prompts instead of erroring.
|
package/dist/bin.js
CHANGED
|
@@ -10828,6 +10828,13 @@ function coerceCell(client, v, path) {
|
|
|
10828
10828
|
return String(v);
|
|
10829
10829
|
throw client.makeError("IMPORT_INVALID_CELL_TYPE", `Cell at ${path} is ${Array.isArray(v) ? "an array" : typeof v}, expected string|number|boolean|null`, `Convert the value to a string before passing.`, "POST /imports");
|
|
10830
10830
|
}
|
|
10831
|
+
function enforceLeadStatus(client, raw, path) {
|
|
10832
|
+
const canonical = String(raw).trim().toUpperCase();
|
|
10833
|
+
if (!LEAD_STATUS_SET.has(canonical)) {
|
|
10834
|
+
throw client.makeError("IMPORT_INVALID_STATUS", `${path} ${JSON.stringify(raw)} is not a valid lead status`, `Use one of ${LEAD_STATUSES.join(", ")} (case-insensitive), or omit it.`, "POST /imports");
|
|
10835
|
+
}
|
|
10836
|
+
return canonical;
|
|
10837
|
+
}
|
|
10831
10838
|
function prepareDomainsMode(client, inputs) {
|
|
10832
10839
|
const validInputs = [];
|
|
10833
10840
|
const malformedDomains = [];
|
|
@@ -10949,6 +10956,12 @@ function prepareRecordsMode(client, records, mappings, customFieldCatalog) {
|
|
|
10949
10956
|
if (normDomain && !byDomain.has(normDomain))
|
|
10950
10957
|
byDomain.set(normDomain, idx);
|
|
10951
10958
|
});
|
|
10959
|
+
const statuses = {};
|
|
10960
|
+
for (const [cell, status] of Object.entries(mappings.statuses ?? {})) {
|
|
10961
|
+
statuses[cell] = enforceLeadStatus(client, status, `mappings.statuses[${JSON.stringify(cell)}]`);
|
|
10962
|
+
}
|
|
10963
|
+
const rawDefault = mappings.default_status;
|
|
10964
|
+
const default_status = rawDefault == null || String(rawDefault).trim() === "" ? null : enforceLeadStatus(client, rawDefault, "mappings.default_status");
|
|
10952
10965
|
return {
|
|
10953
10966
|
mode: "records",
|
|
10954
10967
|
validInputs,
|
|
@@ -10958,8 +10971,8 @@ function prepareRecordsMode(client, records, mappings, customFieldCatalog) {
|
|
|
10958
10971
|
header,
|
|
10959
10972
|
mappings: {
|
|
10960
10973
|
fields: { ...normalizedFields },
|
|
10961
|
-
statuses
|
|
10962
|
-
default_status
|
|
10974
|
+
statuses,
|
|
10975
|
+
default_status
|
|
10963
10976
|
}
|
|
10964
10977
|
};
|
|
10965
10978
|
}
|
|
@@ -11334,7 +11347,7 @@ async function runImportInBackground(client, prep, uploadedChunks, opts, ctx, ha
|
|
|
11334
11347
|
})();
|
|
11335
11348
|
}, 0);
|
|
11336
11349
|
}
|
|
11337
|
-
var CHUNK_SIZE, POLL_INTERVAL_MS2, DEFAULT_PER_PHASE_BUDGET_MS, DEFAULT_TOTAL_BUDGET_MS, STABILIZATION_POLLS, MAX_COLUMN_NAME_LEN, RESERVED_COLUMN_RE, CUSTOM_FIELD_RE, IMPORT_RESOLVER_FIELDS, PUBLIC_MAILBOX_DOMAINS, importLeads;
|
|
11350
|
+
var CHUNK_SIZE, POLL_INTERVAL_MS2, DEFAULT_PER_PHASE_BUDGET_MS, DEFAULT_TOTAL_BUDGET_MS, STABILIZATION_POLLS, MAX_COLUMN_NAME_LEN, RESERVED_COLUMN_RE, CUSTOM_FIELD_RE, IMPORT_RESOLVER_FIELDS, PUBLIC_MAILBOX_DOMAINS, LEAD_STATUSES, LEAD_STATUS_SET, importLeads;
|
|
11338
11351
|
var init_import_leads = __esm({
|
|
11339
11352
|
"../core/dist/composite/import-leads.js"() {
|
|
11340
11353
|
"use strict";
|
|
@@ -11379,6 +11392,15 @@ var init_import_leads = __esm({
|
|
|
11379
11392
|
"163.com",
|
|
11380
11393
|
"126.com"
|
|
11381
11394
|
]);
|
|
11395
|
+
LEAD_STATUSES = [
|
|
11396
|
+
"DEFAULT",
|
|
11397
|
+
"INBOUND",
|
|
11398
|
+
"UNWANTED",
|
|
11399
|
+
"WANTED",
|
|
11400
|
+
"LOST",
|
|
11401
|
+
"WON"
|
|
11402
|
+
];
|
|
11403
|
+
LEAD_STATUS_SET = new Set(LEAD_STATUSES);
|
|
11382
11404
|
importLeads = {
|
|
11383
11405
|
name: "leadbay_import_leads",
|
|
11384
11406
|
annotations: {
|
|
@@ -11437,11 +11459,12 @@ var init_import_leads = __esm({
|
|
|
11437
11459
|
},
|
|
11438
11460
|
statuses: {
|
|
11439
11461
|
type: "object",
|
|
11440
|
-
description:
|
|
11462
|
+
description: `Optional map of raw CSV status-cell text \u2192 lead status (rarely needed). Keys are the verbatim cell strings; values must be one of ${LEAD_STATUSES.join(", ")} (case-insensitive). Defaults to {}.`
|
|
11441
11463
|
},
|
|
11442
11464
|
default_status: {
|
|
11443
11465
|
type: ["string", "null"],
|
|
11444
|
-
|
|
11466
|
+
enum: [...LEAD_STATUSES, null],
|
|
11467
|
+
description: `Optional default lead status applied to rows without an explicit status. One of ${LEAD_STATUSES.join(", ")} (case-insensitive). Defaults to null.`
|
|
11445
11468
|
}
|
|
11446
11469
|
},
|
|
11447
11470
|
required: ["fields"]
|
|
@@ -17499,8 +17522,15 @@ var init_import_and_qualify = __esm({
|
|
|
17499
17522
|
type: "object",
|
|
17500
17523
|
description: "Ergonomic shorthand: `{CsvColumn: <number-id>}` or `{CsvColumn: '<field-name>'}` for custom-field mappings. Resolved against /crm/custom_fields catalog."
|
|
17501
17524
|
},
|
|
17502
|
-
statuses: {
|
|
17503
|
-
|
|
17525
|
+
statuses: {
|
|
17526
|
+
type: "object",
|
|
17527
|
+
description: `Optional map of raw CSV status-cell text \u2192 lead status. Values must be one of ${LEAD_STATUSES.join(", ")} (case-insensitive); keys are the verbatim cell strings.`
|
|
17528
|
+
},
|
|
17529
|
+
default_status: {
|
|
17530
|
+
type: ["string", "null"],
|
|
17531
|
+
enum: [...LEAD_STATUSES, null],
|
|
17532
|
+
description: `Optional default lead status. One of ${LEAD_STATUSES.join(", ")} (case-insensitive).`
|
|
17533
|
+
}
|
|
17504
17534
|
},
|
|
17505
17535
|
// mappings has a closed shape (fields/custom_fields/statuses/default_status).
|
|
17506
17536
|
// Inner objects (fields, custom_fields, statuses) keep open shapes
|
|
@@ -25928,7 +25958,7 @@ var OAUTH_BASE_URLS = {
|
|
|
25928
25958
|
fr: "https://staging.api.leadbay.app"
|
|
25929
25959
|
}
|
|
25930
25960
|
};
|
|
25931
|
-
var VERSION = "0.21.
|
|
25961
|
+
var VERSION = "0.21.1";
|
|
25932
25962
|
var HELP = `
|
|
25933
25963
|
leadbay-mcp ${VERSION} \u2014 Leadbay Model Context Protocol server
|
|
25934
25964
|
|
package/dist/http-server.js
CHANGED
|
@@ -11524,6 +11524,22 @@ function coerceCell(client, v, path) {
|
|
|
11524
11524
|
return String(v);
|
|
11525
11525
|
throw client.makeError("IMPORT_INVALID_CELL_TYPE", `Cell at ${path} is ${Array.isArray(v) ? "an array" : typeof v}, expected string|number|boolean|null`, `Convert the value to a string before passing.`, "POST /imports");
|
|
11526
11526
|
}
|
|
11527
|
+
var LEAD_STATUSES = [
|
|
11528
|
+
"DEFAULT",
|
|
11529
|
+
"INBOUND",
|
|
11530
|
+
"UNWANTED",
|
|
11531
|
+
"WANTED",
|
|
11532
|
+
"LOST",
|
|
11533
|
+
"WON"
|
|
11534
|
+
];
|
|
11535
|
+
var LEAD_STATUS_SET = new Set(LEAD_STATUSES);
|
|
11536
|
+
function enforceLeadStatus(client, raw, path) {
|
|
11537
|
+
const canonical = String(raw).trim().toUpperCase();
|
|
11538
|
+
if (!LEAD_STATUS_SET.has(canonical)) {
|
|
11539
|
+
throw client.makeError("IMPORT_INVALID_STATUS", `${path} ${JSON.stringify(raw)} is not a valid lead status`, `Use one of ${LEAD_STATUSES.join(", ")} (case-insensitive), or omit it.`, "POST /imports");
|
|
11540
|
+
}
|
|
11541
|
+
return canonical;
|
|
11542
|
+
}
|
|
11527
11543
|
function prepareDomainsMode(client, inputs) {
|
|
11528
11544
|
const validInputs = [];
|
|
11529
11545
|
const malformedDomains = [];
|
|
@@ -11645,6 +11661,12 @@ function prepareRecordsMode(client, records, mappings, customFieldCatalog) {
|
|
|
11645
11661
|
if (normDomain && !byDomain.has(normDomain))
|
|
11646
11662
|
byDomain.set(normDomain, idx);
|
|
11647
11663
|
});
|
|
11664
|
+
const statuses = {};
|
|
11665
|
+
for (const [cell, status] of Object.entries(mappings.statuses ?? {})) {
|
|
11666
|
+
statuses[cell] = enforceLeadStatus(client, status, `mappings.statuses[${JSON.stringify(cell)}]`);
|
|
11667
|
+
}
|
|
11668
|
+
const rawDefault = mappings.default_status;
|
|
11669
|
+
const default_status = rawDefault == null || String(rawDefault).trim() === "" ? null : enforceLeadStatus(client, rawDefault, "mappings.default_status");
|
|
11648
11670
|
return {
|
|
11649
11671
|
mode: "records",
|
|
11650
11672
|
validInputs,
|
|
@@ -11654,8 +11676,8 @@ function prepareRecordsMode(client, records, mappings, customFieldCatalog) {
|
|
|
11654
11676
|
header,
|
|
11655
11677
|
mappings: {
|
|
11656
11678
|
fields: { ...normalizedFields },
|
|
11657
|
-
statuses
|
|
11658
|
-
default_status
|
|
11679
|
+
statuses,
|
|
11680
|
+
default_status
|
|
11659
11681
|
}
|
|
11660
11682
|
};
|
|
11661
11683
|
}
|
|
@@ -12048,11 +12070,12 @@ var importLeads = {
|
|
|
12048
12070
|
},
|
|
12049
12071
|
statuses: {
|
|
12050
12072
|
type: "object",
|
|
12051
|
-
description:
|
|
12073
|
+
description: `Optional map of raw CSV status-cell text \u2192 lead status (rarely needed). Keys are the verbatim cell strings; values must be one of ${LEAD_STATUSES.join(", ")} (case-insensitive). Defaults to {}.`
|
|
12052
12074
|
},
|
|
12053
12075
|
default_status: {
|
|
12054
12076
|
type: ["string", "null"],
|
|
12055
|
-
|
|
12077
|
+
enum: [...LEAD_STATUSES, null],
|
|
12078
|
+
description: `Optional default lead status applied to rows without an explicit status. One of ${LEAD_STATUSES.join(", ")} (case-insensitive). Defaults to null.`
|
|
12056
12079
|
}
|
|
12057
12080
|
},
|
|
12058
12081
|
required: ["fields"]
|
|
@@ -17627,8 +17650,15 @@ var importAndQualify = {
|
|
|
17627
17650
|
type: "object",
|
|
17628
17651
|
description: "Ergonomic shorthand: `{CsvColumn: <number-id>}` or `{CsvColumn: '<field-name>'}` for custom-field mappings. Resolved against /crm/custom_fields catalog."
|
|
17629
17652
|
},
|
|
17630
|
-
statuses: {
|
|
17631
|
-
|
|
17653
|
+
statuses: {
|
|
17654
|
+
type: "object",
|
|
17655
|
+
description: `Optional map of raw CSV status-cell text \u2192 lead status. Values must be one of ${LEAD_STATUSES.join(", ")} (case-insensitive); keys are the verbatim cell strings.`
|
|
17656
|
+
},
|
|
17657
|
+
default_status: {
|
|
17658
|
+
type: ["string", "null"],
|
|
17659
|
+
enum: [...LEAD_STATUSES, null],
|
|
17660
|
+
description: `Optional default lead status. One of ${LEAD_STATUSES.join(", ")} (case-insensitive).`
|
|
17661
|
+
}
|
|
17632
17662
|
},
|
|
17633
17663
|
// mappings has a closed shape (fields/custom_fields/statuses/default_status).
|
|
17634
17664
|
// Inner objects (fields, custom_fields, statuses) keep open shapes
|
|
@@ -22461,7 +22491,7 @@ function parseWriteEnv(env = process.env) {
|
|
|
22461
22491
|
}
|
|
22462
22492
|
|
|
22463
22493
|
// src/http-server.ts
|
|
22464
|
-
var VERSION = true ? "0.21.
|
|
22494
|
+
var VERSION = true ? "0.21.1" : "0.0.0-dev";
|
|
22465
22495
|
var PORT = Number(process.env.PORT ?? 8080);
|
|
22466
22496
|
var HOST = process.env.HOST ?? "0.0.0.0";
|
|
22467
22497
|
var sseSessions = /* @__PURE__ */ new Map();
|
|
@@ -1466,7 +1466,7 @@ var init_installer_gui = __esm({
|
|
|
1466
1466
|
init_install_dxt();
|
|
1467
1467
|
init_install_shared();
|
|
1468
1468
|
init_oauth();
|
|
1469
|
-
VERSION = "0.21.
|
|
1469
|
+
VERSION = "0.21.1";
|
|
1470
1470
|
PORT = Number(process.env.LEADBAY_INSTALLER_PORT ?? 0);
|
|
1471
1471
|
sessions = /* @__PURE__ */ new Map();
|
|
1472
1472
|
OAUTH_BASE_URLS = {
|
package/dist/installer-gui.js
CHANGED
|
@@ -873,7 +873,7 @@ async function oauthLogin(opts) {
|
|
|
873
873
|
}
|
|
874
874
|
|
|
875
875
|
// installer/installer-gui.ts
|
|
876
|
-
var VERSION = "0.21.
|
|
876
|
+
var VERSION = "0.21.1";
|
|
877
877
|
var PORT = Number(process.env.LEADBAY_INSTALLER_PORT ?? 0);
|
|
878
878
|
var sessions = /* @__PURE__ */ new Map();
|
|
879
879
|
var OAUTH_BASE_URLS = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leadbay/mcp",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.1",
|
|
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",
|