@leadbay/mcp 0.34.0 → 0.34.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 +38 -0
- package/dist/bin.js +37 -2
- package/dist/http-server.js +42 -2
- 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,43 @@
|
|
|
1
1
|
# Changelog — @leadbay/mcp
|
|
2
2
|
|
|
3
|
+
## 0.34.1 — 2026-09-07
|
|
4
|
+
|
|
5
|
+
`leadbay_set_lead_status` threw `TypeError: (params.lead_ids ?? []).filter is
|
|
6
|
+
not a function` five times in 29 s on the hosted route (product#4079, Sentry
|
|
7
|
+
MCP-3T): a scheduled agent passed `lead_ids` as something other than an array.
|
|
8
|
+
The same class hit `leadbay_new_lens` on 2026-08-04 (`texts.filter is not a
|
|
9
|
+
function`, `locations` as a string, MCP-3B). Both times the agent retried the
|
|
10
|
+
identical call four or five times, because a raw TypeError names no argument.
|
|
11
|
+
|
|
12
|
+
The CallTool handler in `server.ts` never checked `inputSchema` before
|
|
13
|
+
`tool.execute`; its own comment said enforcement was ours, and it only enforced
|
|
14
|
+
`_triggered_by`. 32 tools declare a top-level `array` or `object` parameter and
|
|
15
|
+
none of them defended against a string: four threw, two silently corrupted
|
|
16
|
+
(`adjust_audience` spread `"tech"` into `["t","e","c","h"]`), the rest forwarded
|
|
17
|
+
the string to the backend.
|
|
18
|
+
|
|
19
|
+
One guard now runs before `execute`, after the `LAST_PROMPT_REQUIRED` check
|
|
20
|
+
(`findShapeMismatch`): for each top-level schema property whose `type` is
|
|
21
|
+
`array` or `object`, a present non-null argument of the wrong JSON shape returns
|
|
22
|
+
`BAD_INPUT` naming the field, the expected shape and the received type
|
|
23
|
+
(`lead_ids must be a JSON array (got string)`), through the same envelope branch
|
|
24
|
+
a tool's own `BAD_INPUT` takes. So PostHog sees `ok:false error_code:BAD_INPUT`
|
|
25
|
+
and Sentry groups the event with the tool's existing `BAD_INPUT` issue
|
|
26
|
+
(`source:business`) instead of a `source:unexpected` stack fingerprint.
|
|
27
|
+
|
|
28
|
+
Deliberately not done: no coercion of a bare string into a one-element array (a
|
|
29
|
+
JSON-stringified array would become one bogus id and fail per lead inside
|
|
30
|
+
`failed[]`); no scalar checks (hosts send `"20"` for a number and tools coerce);
|
|
31
|
+
no `required`, `items`, nested or `additionalProperties` validation; no runtime
|
|
32
|
+
dependency. `null` counts as absent. One visible change on an existing tool:
|
|
33
|
+
`leadbay_report_outreach` with `verification` given as a string answered
|
|
34
|
+
`VERIFICATION_REQUIRED`; it now answers `BAD_INPUT … must be a JSON object (got
|
|
35
|
+
string)`. Tools executed directly outside the MCP server (OpenClaw consumes
|
|
36
|
+
`@leadbay/core` without `buildServer`) keep the raw throw.
|
|
37
|
+
|
|
38
|
+
Test: `packages/mcp/test/unit/input-shape-guard.test.ts` drives `tools/call`
|
|
39
|
+
through `buildServer` with the incident shapes.
|
|
40
|
+
|
|
3
41
|
## 0.34.0 — 2026-09-02
|
|
4
42
|
|
|
5
43
|
The OpenAI app directory rejects an app that sells digital goods — "plugins may
|
package/dist/bin.js
CHANGED
|
@@ -26300,6 +26300,40 @@ function extractTriggeredBy(args) {
|
|
|
26300
26300
|
const trimmed = raw.length > 500 ? `${raw.slice(0, 500)}\u2026` : raw;
|
|
26301
26301
|
return { triggered_by: trimmed, cleaned };
|
|
26302
26302
|
}
|
|
26303
|
+
function findShapeMismatch(tool, args) {
|
|
26304
|
+
const schema = tool.inputSchema;
|
|
26305
|
+
if (!schema || schema.type !== "object") return void 0;
|
|
26306
|
+
const props = schema.properties;
|
|
26307
|
+
if (!props || typeof props !== "object") return void 0;
|
|
26308
|
+
for (const [key, spec] of Object.entries(props)) {
|
|
26309
|
+
if (key === TRIGGERED_BY_FIELD || !spec || typeof spec !== "object") continue;
|
|
26310
|
+
const declared = spec.type;
|
|
26311
|
+
if (declared !== "array" && declared !== "object") continue;
|
|
26312
|
+
const value = args[key];
|
|
26313
|
+
if (value === void 0 || value === null) continue;
|
|
26314
|
+
const isArray = Array.isArray(value);
|
|
26315
|
+
const got = isArray ? "array" : typeof value;
|
|
26316
|
+
if (declared === "array" && !isArray) {
|
|
26317
|
+
const items = spec.items;
|
|
26318
|
+
const of = typeof items?.type === "string" ? ` of ${items.type}s` : "";
|
|
26319
|
+
return {
|
|
26320
|
+
error: true,
|
|
26321
|
+
code: "BAD_INPUT",
|
|
26322
|
+
message: `${key} must be a JSON array (got ${got})`,
|
|
26323
|
+
hint: `Re-call with ${key} as a JSON array${of}, e.g. ${key}: ["\u2026"]. Do not JSON-stringify the array.`
|
|
26324
|
+
};
|
|
26325
|
+
}
|
|
26326
|
+
if (declared === "object" && (typeof value !== "object" || isArray)) {
|
|
26327
|
+
return {
|
|
26328
|
+
error: true,
|
|
26329
|
+
code: "BAD_INPUT",
|
|
26330
|
+
message: `${key} must be a JSON object (got ${got})`,
|
|
26331
|
+
hint: `Re-call with ${key} as a JSON object, e.g. ${key}: {\u2026}.`
|
|
26332
|
+
};
|
|
26333
|
+
}
|
|
26334
|
+
}
|
|
26335
|
+
return void 0;
|
|
26336
|
+
}
|
|
26303
26337
|
function toolsListPayload(tools2) {
|
|
26304
26338
|
return tools2.map((t) => {
|
|
26305
26339
|
const out = {
|
|
@@ -26680,7 +26714,8 @@ ${url}
|
|
|
26680
26714
|
isError: true
|
|
26681
26715
|
};
|
|
26682
26716
|
}
|
|
26683
|
-
const
|
|
26717
|
+
const shapeError = findShapeMismatch(tool, args);
|
|
26718
|
+
const result = shapeError ?? await runWithRequestSignal(extra.signal, () => tool.execute(client, args, {
|
|
26684
26719
|
logger: opts.logger,
|
|
26685
26720
|
bulkTracker: opts.bulkTracker,
|
|
26686
26721
|
notificationsInbox: opts.notificationsInbox,
|
|
@@ -28366,7 +28401,7 @@ var OAUTH_BASE_URLS = {
|
|
|
28366
28401
|
fr: "https://staging.api.leadbay.app"
|
|
28367
28402
|
}
|
|
28368
28403
|
};
|
|
28369
|
-
var VERSION = "0.34.
|
|
28404
|
+
var VERSION = "0.34.1";
|
|
28370
28405
|
var HELP = `
|
|
28371
28406
|
leadbay-mcp ${VERSION} \u2014 Leadbay Model Context Protocol server
|
|
28372
28407
|
|
package/dist/http-server.js
CHANGED
|
@@ -24319,6 +24319,40 @@ function extractTriggeredBy(args) {
|
|
|
24319
24319
|
const trimmed = raw.length > 500 ? `${raw.slice(0, 500)}\u2026` : raw;
|
|
24320
24320
|
return { triggered_by: trimmed, cleaned };
|
|
24321
24321
|
}
|
|
24322
|
+
function findShapeMismatch(tool, args) {
|
|
24323
|
+
const schema = tool.inputSchema;
|
|
24324
|
+
if (!schema || schema.type !== "object") return void 0;
|
|
24325
|
+
const props = schema.properties;
|
|
24326
|
+
if (!props || typeof props !== "object") return void 0;
|
|
24327
|
+
for (const [key, spec] of Object.entries(props)) {
|
|
24328
|
+
if (key === TRIGGERED_BY_FIELD || !spec || typeof spec !== "object") continue;
|
|
24329
|
+
const declared = spec.type;
|
|
24330
|
+
if (declared !== "array" && declared !== "object") continue;
|
|
24331
|
+
const value = args[key];
|
|
24332
|
+
if (value === void 0 || value === null) continue;
|
|
24333
|
+
const isArray = Array.isArray(value);
|
|
24334
|
+
const got = isArray ? "array" : typeof value;
|
|
24335
|
+
if (declared === "array" && !isArray) {
|
|
24336
|
+
const items = spec.items;
|
|
24337
|
+
const of = typeof items?.type === "string" ? ` of ${items.type}s` : "";
|
|
24338
|
+
return {
|
|
24339
|
+
error: true,
|
|
24340
|
+
code: "BAD_INPUT",
|
|
24341
|
+
message: `${key} must be a JSON array (got ${got})`,
|
|
24342
|
+
hint: `Re-call with ${key} as a JSON array${of}, e.g. ${key}: ["\u2026"]. Do not JSON-stringify the array.`
|
|
24343
|
+
};
|
|
24344
|
+
}
|
|
24345
|
+
if (declared === "object" && (typeof value !== "object" || isArray)) {
|
|
24346
|
+
return {
|
|
24347
|
+
error: true,
|
|
24348
|
+
code: "BAD_INPUT",
|
|
24349
|
+
message: `${key} must be a JSON object (got ${got})`,
|
|
24350
|
+
hint: `Re-call with ${key} as a JSON object, e.g. ${key}: {\u2026}.`
|
|
24351
|
+
};
|
|
24352
|
+
}
|
|
24353
|
+
}
|
|
24354
|
+
return void 0;
|
|
24355
|
+
}
|
|
24322
24356
|
function toolsListPayload(tools2) {
|
|
24323
24357
|
return tools2.map((t) => {
|
|
24324
24358
|
const out = {
|
|
@@ -24699,7 +24733,8 @@ ${url}
|
|
|
24699
24733
|
isError: true
|
|
24700
24734
|
};
|
|
24701
24735
|
}
|
|
24702
|
-
const
|
|
24736
|
+
const shapeError = findShapeMismatch(tool, args);
|
|
24737
|
+
const result = shapeError ?? await runWithRequestSignal(extra.signal, () => tool.execute(client, args, {
|
|
24703
24738
|
logger: opts.logger,
|
|
24704
24739
|
bulkTracker: opts.bulkTracker,
|
|
24705
24740
|
notificationsInbox: opts.notificationsInbox,
|
|
@@ -25130,7 +25165,7 @@ function parseWriteEnv(env = process.env) {
|
|
|
25130
25165
|
}
|
|
25131
25166
|
|
|
25132
25167
|
// src/http-server.ts
|
|
25133
|
-
var VERSION = true ? "0.34.
|
|
25168
|
+
var VERSION = true ? "0.34.1" : "0.0.0-dev";
|
|
25134
25169
|
var PORT = Number(process.env.PORT ?? 8080);
|
|
25135
25170
|
var HOST = process.env.HOST ?? "0.0.0.0";
|
|
25136
25171
|
var logger = {
|
|
@@ -25263,6 +25298,7 @@ function buildServerFromClient(client, requestTelemetry, resourcePath) {
|
|
|
25263
25298
|
telemetry: requestTelemetry
|
|
25264
25299
|
});
|
|
25265
25300
|
}
|
|
25301
|
+
var OPENAI_APPS_CHALLENGE = process.env.OPENAI_APPS_CHALLENGE ?? "vsJ51IZ_3AqM10YZxXQFmB29IGIMDOZGbpbEgRIT4r4";
|
|
25266
25302
|
var PRM_PREFIX = "/.well-known/oauth-protected-resource";
|
|
25267
25303
|
var RESOURCE_PATHS = ["/mcp", "/sse", "/fr/mcp", "/fr/sse", "/chatgpt/mcp"];
|
|
25268
25304
|
function requestOrigin(c) {
|
|
@@ -25310,6 +25346,10 @@ function sendChallenge(c, resourcePath, authState) {
|
|
|
25310
25346
|
}
|
|
25311
25347
|
var app = new Hono();
|
|
25312
25348
|
app.get("/healthz", (c) => c.json({ ok: true, version: VERSION }));
|
|
25349
|
+
app.get(
|
|
25350
|
+
"/.well-known/openai-apps-challenge",
|
|
25351
|
+
(c) => c.text(OPENAI_APPS_CHALLENGE, 200, { "Cache-Control": "no-store" })
|
|
25352
|
+
);
|
|
25313
25353
|
app.get(PRM_PREFIX, (c) => servePrm(c, "/mcp"));
|
|
25314
25354
|
app.get(`${PRM_PREFIX}/*`, (c) => {
|
|
25315
25355
|
const suffix = c.req.path.slice(PRM_PREFIX.length);
|
package/dist/installer-gui.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leadbay/mcp",
|
|
3
|
-
"version": "0.34.
|
|
3
|
+
"version": "0.34.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",
|