@leadbay/mcp 0.20.0 → 0.21.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 +9 -0
- package/README.md +9 -7
- package/dist/bin.js +7 -4
- package/dist/http-server.js +124 -29
- 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,14 @@
|
|
|
1
1
|
# Changelog — @leadbay/mcp
|
|
2
2
|
|
|
3
|
+
## 0.21.0 — 2026-06-16
|
|
4
|
+
|
|
5
|
+
- **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.
|
|
6
|
+
- **Region-pinned connector URLs**: OAuth discovery runs before sign-in and Leadbay tokens are region-scoped, so the region is encoded in the URL. US accounts use `https://leadbay-mcp-prod.fly.dev/mcp`; FR accounts use `https://leadbay-mcp-prod.fly.dev/fr/mcp`. The path only selects which authorization server the sign-in prompt points at. Permissive CORS + an `OPTIONS` preflight are served on the discovery and MCP endpoints for browser-based remote clients. README's remote-client section updated to document Claude Desktop and the per-region URLs.
|
|
7
|
+
|
|
8
|
+
## 0.20.1 — 2026-06-15
|
|
9
|
+
|
|
10
|
+
- **Triage board stays the first next-step option on a poor-fit batch** (`leadbay_daily_check_in`): when today's batch is an ICP mismatch (every lead AI-scored off-profile), the agent was demoting the interactive triage board below "refine audience" in the NEXT STEPS widget — the plain ordering rule kept losing to the agent's own leverage judgment ("the whole batch is junk, so lead with fixing the lens"). The workflow contract requires the named artifact to be the FIRST option. The ordering rule now holds the triage board at position 1 even on a mismatched batch; the mismatch is surfaced in the prose nudge and offered as a *later* "refine the lens" option, never by displacing the artifact. Verified 5/5/5/5 across 3 consecutive eval runs on an all-off-ICP batch (the exact case that defeated the weaker rule).
|
|
11
|
+
|
|
3
12
|
## 0.20.0 — 2026-06-15
|
|
4
13
|
|
|
5
14
|
- **Proactive update proposal on a fresh session** (product#3742): the auto-update check already ran at boot, but the resulting proposal only reached the user if the agent happened to call `leadbay_account_status` — which a fresh session rarely does, so the "newer version available" prompt was effectively invisible. The cached `update_available` block now also rides along on `_meta.update_available` of the **first ordinary tool result** of a session while an upgrade is pending, gated once-per-version so it surfaces exactly once. `leadbay_account_status` keeps carrying it as a top-level field. The server-instruction paragraph now tells the agent to surface the `ask_user_input_v0` prompt whenever it sees the field on *any* response.
|
package/README.md
CHANGED
|
@@ -290,21 +290,23 @@ Leadbay connection OK.
|
|
|
290
290
|
AI credits: 420 / 1000
|
|
291
291
|
```
|
|
292
292
|
|
|
293
|
-
###
|
|
293
|
+
### Claude Desktop / ChatGPT / remote-MCP clients
|
|
294
294
|
|
|
295
|
-
Leadbay runs a hosted MCP server that any remote-MCP client can connect to without a local install:
|
|
295
|
+
Leadbay runs a hosted MCP server that any remote-MCP client can connect to without a local install. Pick the URL for your account's region:
|
|
296
296
|
|
|
297
297
|
```
|
|
298
|
-
https://leadbay-mcp-prod.fly.dev/mcp
|
|
298
|
+
https://leadbay-mcp-prod.fly.dev/mcp # US accounts
|
|
299
|
+
https://leadbay-mcp-prod.fly.dev/fr/mcp # FR accounts
|
|
299
300
|
```
|
|
300
301
|
|
|
301
|
-
**
|
|
302
|
+
- **Claude Desktop**: Settings → Connectors → Add custom connector → paste the URL.
|
|
303
|
+
- **ChatGPT Desktop**: Settings → Apps → Add app → paste the URL.
|
|
302
304
|
|
|
303
|
-
|
|
305
|
+
On first connect the client runs the Leadbay OAuth sign-in (the server advertises OAuth 2.0 Protected Resource Metadata per RFC 9728 and challenges unauthenticated requests with `401 + WWW-Authenticate`). Sign in once in the browser; the client stores the token and sends it as `Authorization: Bearer <token>` on every request. No token to copy-paste, no local Node install needed.
|
|
304
306
|
|
|
305
|
-
|
|
307
|
+
The region is encoded in the URL because OAuth discovery happens before sign-in and Leadbay tokens are region-scoped — a US account uses `/mcp`, a FR account uses `/fr/mcp`. If the sign-in prompt never appears, you're on an old build of the hosted server (pre-0.21.0); it auto-updates on release.
|
|
306
308
|
|
|
307
|
-
|
|
309
|
+
**Updates are automatic** — the hosted server is always running the latest published release. You never need to update a config file or restart anything on your side.
|
|
308
310
|
|
|
309
311
|
## 4. Example prompts that work
|
|
310
312
|
|
package/dist/bin.js
CHANGED
|
@@ -22038,7 +22038,7 @@ Contact enrichment is offered in the NEXT STEPS widget below \u2014 do NOT emit
|
|
|
22038
22038
|
|
|
22039
22039
|
**REQUIRED OPTIONS \u2014 triggers and position rules:**
|
|
22040
22040
|
- **Recurring language** ("every day", "every morning", "I do this every", "remind me", "automate this", "recurring"): add "Schedule 'Daily prospecting check-in' as a recurring task" and place it **first**.
|
|
22041
|
-
- **\u22655 leads returned**: add "Build an interactive lead triage board for this batch" and place it **first** (or second if the scheduling offer above also applies).
|
|
22041
|
+
- **\u22655 leads returned**: add "Build an interactive lead triage board for this batch" and place it **first** (or second if the scheduling offer above also applies). This holds **even when the batch is a poor fit** (e.g. every lead AI-scored as off-ICP / a vertical mismatch): the triage board is still the first artifact option because the user asked to see and act on *this batch*. When the batch is a mismatch, ALSO offer "Refine the audience / lens so future batches fit better" \u2014 but as a *later* option, never displacing the triage board from first. Leading with audience-refinement instead of the artifact is a contract violation: surface the mismatch in your prose nudge, not by demoting the triage board.
|
|
22042
22042
|
|
|
22043
22043
|
## NEXT STEPS \u2014 after rendering the pull_leads table
|
|
22044
22044
|
|
|
@@ -22079,7 +22079,7 @@ Pick 2\u20133 items below based on what was actually observed in the response. T
|
|
|
22079
22079
|
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.
|
|
22080
22080
|
|
|
22081
22081
|
|
|
22082
|
-
**Final ordering check (do this before rendering):** Recurring offer \u2192 option 1; triage board \u2192 option 1 (or 2 if scheduling is also required). Swap if needed.
|
|
22082
|
+
**Final ordering check (do this before rendering):** Recurring offer \u2192 option 1; triage board \u2192 option 1 (or 2 if scheduling is also required). A poor-fit / mismatched batch does NOT change this \u2014 triage board stays first, refine-audience goes later in the list. Swap if needed.
|
|
22083
22083
|
|
|
22084
22084
|
# GATE \u2014 STOP
|
|
22085
22085
|
|
|
@@ -24623,6 +24623,7 @@ function buildServer(client, opts = {}) {
|
|
|
24623
24623
|
endpoint: err._meta?.endpoint
|
|
24624
24624
|
});
|
|
24625
24625
|
}
|
|
24626
|
+
const httpStatus2 = err._meta?.http_status;
|
|
24626
24627
|
telemetry.captureToolCall({
|
|
24627
24628
|
tool: name,
|
|
24628
24629
|
ok: false,
|
|
@@ -24630,6 +24631,7 @@ function buildServer(client, opts = {}) {
|
|
|
24630
24631
|
format: "error-envelope",
|
|
24631
24632
|
bytes: errText.length,
|
|
24632
24633
|
error_code: code,
|
|
24634
|
+
...typeof httpStatus2 === "number" ? { http_status: httpStatus2 } : {},
|
|
24633
24635
|
triggered_by
|
|
24634
24636
|
});
|
|
24635
24637
|
if (COMPOSITE_FILE_TOOL_NAMES.has(name)) {
|
|
@@ -24638,7 +24640,8 @@ function buildServer(client, opts = {}) {
|
|
|
24638
24640
|
last_prompt: triggered_by ?? "",
|
|
24639
24641
|
ok: false,
|
|
24640
24642
|
duration_ms: errDur,
|
|
24641
|
-
error_code: code
|
|
24643
|
+
error_code: code,
|
|
24644
|
+
...typeof httpStatus2 === "number" ? { http_status: httpStatus2 } : {}
|
|
24642
24645
|
});
|
|
24643
24646
|
}
|
|
24644
24647
|
telemetry.captureException(err, buildBusinessCtx(name, err, triggered_by));
|
|
@@ -25925,7 +25928,7 @@ var OAUTH_BASE_URLS = {
|
|
|
25925
25928
|
fr: "https://staging.api.leadbay.app"
|
|
25926
25929
|
}
|
|
25927
25930
|
};
|
|
25928
|
-
var VERSION = "0.
|
|
25931
|
+
var VERSION = "0.21.0";
|
|
25929
25932
|
var HELP = `
|
|
25930
25933
|
leadbay-mcp ${VERSION} \u2014 Leadbay Model Context Protocol server
|
|
25931
25934
|
|
package/dist/http-server.js
CHANGED
|
@@ -7,6 +7,9 @@ var __export = (target, all) => {
|
|
|
7
7
|
|
|
8
8
|
// src/http-server.ts
|
|
9
9
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
10
|
+
import { realpathSync } from "fs";
|
|
11
|
+
import { basename } from "path";
|
|
12
|
+
import { fileURLToPath } from "url";
|
|
10
13
|
import { Hono } from "hono";
|
|
11
14
|
import { bodyLimit } from "hono/body-limit";
|
|
12
15
|
import { serve } from "@hono/node-server";
|
|
@@ -180,7 +183,7 @@ Contact enrichment is offered in the NEXT STEPS widget below \u2014 do NOT emit
|
|
|
180
183
|
|
|
181
184
|
**REQUIRED OPTIONS \u2014 triggers and position rules:**
|
|
182
185
|
- **Recurring language** ("every day", "every morning", "I do this every", "remind me", "automate this", "recurring"): add "Schedule 'Daily prospecting check-in' as a recurring task" and place it **first**.
|
|
183
|
-
- **\u22655 leads returned**: add "Build an interactive lead triage board for this batch" and place it **first** (or second if the scheduling offer above also applies).
|
|
186
|
+
- **\u22655 leads returned**: add "Build an interactive lead triage board for this batch" and place it **first** (or second if the scheduling offer above also applies). This holds **even when the batch is a poor fit** (e.g. every lead AI-scored as off-ICP / a vertical mismatch): the triage board is still the first artifact option because the user asked to see and act on *this batch*. When the batch is a mismatch, ALSO offer "Refine the audience / lens so future batches fit better" \u2014 but as a *later* option, never displacing the triage board from first. Leading with audience-refinement instead of the artifact is a contract violation: surface the mismatch in your prose nudge, not by demoting the triage board.
|
|
184
187
|
|
|
185
188
|
## NEXT STEPS \u2014 after rendering the pull_leads table
|
|
186
189
|
|
|
@@ -221,7 +224,7 @@ Pick 2\u20133 items below based on what was actually observed in the response. T
|
|
|
221
224
|
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.
|
|
222
225
|
|
|
223
226
|
|
|
224
|
-
**Final ordering check (do this before rendering):** Recurring offer \u2192 option 1; triage board \u2192 option 1 (or 2 if scheduling is also required). Swap if needed.
|
|
227
|
+
**Final ordering check (do this before rendering):** Recurring offer \u2192 option 1; triage board \u2192 option 1 (or 2 if scheduling is also required). A poor-fit / mismatched batch does NOT change this \u2014 triage board stays first, refine-audience goes later in the list. Swap if needed.
|
|
225
228
|
|
|
226
229
|
# GATE \u2014 STOP
|
|
227
230
|
|
|
@@ -22279,6 +22282,7 @@ function buildServer(client, opts = {}) {
|
|
|
22279
22282
|
endpoint: err._meta?.endpoint
|
|
22280
22283
|
});
|
|
22281
22284
|
}
|
|
22285
|
+
const httpStatus2 = err._meta?.http_status;
|
|
22282
22286
|
telemetry.captureToolCall({
|
|
22283
22287
|
tool: name,
|
|
22284
22288
|
ok: false,
|
|
@@ -22286,6 +22290,7 @@ function buildServer(client, opts = {}) {
|
|
|
22286
22290
|
format: "error-envelope",
|
|
22287
22291
|
bytes: errText.length,
|
|
22288
22292
|
error_code: code,
|
|
22293
|
+
...typeof httpStatus2 === "number" ? { http_status: httpStatus2 } : {},
|
|
22289
22294
|
triggered_by
|
|
22290
22295
|
});
|
|
22291
22296
|
if (COMPOSITE_FILE_TOOL_NAMES.has(name)) {
|
|
@@ -22294,7 +22299,8 @@ function buildServer(client, opts = {}) {
|
|
|
22294
22299
|
last_prompt: triggered_by ?? "",
|
|
22295
22300
|
ok: false,
|
|
22296
22301
|
duration_ms: errDur,
|
|
22297
|
-
error_code: code
|
|
22302
|
+
error_code: code,
|
|
22303
|
+
...typeof httpStatus2 === "number" ? { http_status: httpStatus2 } : {}
|
|
22298
22304
|
});
|
|
22299
22305
|
}
|
|
22300
22306
|
telemetry.captureException(err, buildBusinessCtx(name, err, triggered_by));
|
|
@@ -22421,6 +22427,25 @@ async function resolveClientFromToken(token, opts = {}) {
|
|
|
22421
22427
|
};
|
|
22422
22428
|
}
|
|
22423
22429
|
}
|
|
22430
|
+
function regionAuthServer(region) {
|
|
22431
|
+
return region === "fr" ? REGIONS.fr : REGIONS.us;
|
|
22432
|
+
}
|
|
22433
|
+
function protectedResourceMetadata(opts) {
|
|
22434
|
+
return {
|
|
22435
|
+
resource: opts.resourceUrl,
|
|
22436
|
+
authorization_servers: [regionAuthServer(opts.region)],
|
|
22437
|
+
bearer_methods_supported: ["header"]
|
|
22438
|
+
};
|
|
22439
|
+
}
|
|
22440
|
+
function buildWwwAuthenticate(opts) {
|
|
22441
|
+
const parts = ['Bearer realm="mcp"'];
|
|
22442
|
+
if (opts.authState === "expired") {
|
|
22443
|
+
parts.push('error="invalid_token"');
|
|
22444
|
+
parts.push('error_description="The access token is invalid or has expired"');
|
|
22445
|
+
}
|
|
22446
|
+
parts.push(`resource_metadata="${opts.resourceMetadataUrl}"`);
|
|
22447
|
+
return parts.join(", ");
|
|
22448
|
+
}
|
|
22424
22449
|
|
|
22425
22450
|
// src/env.ts
|
|
22426
22451
|
function parseWriteEnv(env = process.env) {
|
|
@@ -22436,7 +22461,7 @@ function parseWriteEnv(env = process.env) {
|
|
|
22436
22461
|
}
|
|
22437
22462
|
|
|
22438
22463
|
// src/http-server.ts
|
|
22439
|
-
var VERSION = true ? "0.
|
|
22464
|
+
var VERSION = true ? "0.21.0" : "0.0.0-dev";
|
|
22440
22465
|
var PORT = Number(process.env.PORT ?? 8080);
|
|
22441
22466
|
var HOST = process.env.HOST ?? "0.0.0.0";
|
|
22442
22467
|
var sseSessions = /* @__PURE__ */ new Map();
|
|
@@ -22458,29 +22483,76 @@ function extractBearer(authHeader) {
|
|
|
22458
22483
|
const m = /^Bearer\s+(.+)$/i.exec(authHeader);
|
|
22459
22484
|
return m ? m[1].trim() : void 0;
|
|
22460
22485
|
}
|
|
22461
|
-
function
|
|
22462
|
-
if (headerValue === "us" || headerValue === "fr") return headerValue;
|
|
22463
|
-
return void 0;
|
|
22464
|
-
}
|
|
22465
|
-
async function buildServerForRequest(token, region) {
|
|
22466
|
-
const resolved = await resolveClientFromToken(token, { region });
|
|
22486
|
+
function buildServerFromClient(client) {
|
|
22467
22487
|
const includeWrite = parseWriteEnv();
|
|
22468
22488
|
const includeAdvanced = process.env.LEADBAY_MCP_ADVANCED === "1";
|
|
22469
|
-
return buildServer(
|
|
22470
|
-
|
|
22471
|
-
|
|
22472
|
-
|
|
22473
|
-
|
|
22489
|
+
return buildServer(client, { version: VERSION, includeWrite, includeAdvanced });
|
|
22490
|
+
}
|
|
22491
|
+
var PRM_PREFIX = "/.well-known/oauth-protected-resource";
|
|
22492
|
+
var RESOURCE_PATHS = ["/mcp", "/fr/mcp", "/sse", "/fr/sse"];
|
|
22493
|
+
function regionForResourcePath(resourcePath) {
|
|
22494
|
+
return /^\/fr(\/|$)/.test(resourcePath) ? "fr" : "us";
|
|
22495
|
+
}
|
|
22496
|
+
function requestOrigin(c) {
|
|
22497
|
+
const url = new URL(c.req.url);
|
|
22498
|
+
const proto = c.req.header("x-forwarded-proto") ?? url.protocol.replace(/:$/, "");
|
|
22499
|
+
const host = c.req.header("host") ?? url.host;
|
|
22500
|
+
return `${proto}://${host}`;
|
|
22501
|
+
}
|
|
22502
|
+
function applyCors(c) {
|
|
22503
|
+
c.header("Access-Control-Allow-Origin", "*");
|
|
22504
|
+
c.header("Access-Control-Expose-Headers", "WWW-Authenticate");
|
|
22505
|
+
}
|
|
22506
|
+
function servePrm(c, resourcePath) {
|
|
22507
|
+
applyCors(c);
|
|
22508
|
+
c.header("Cache-Control", "public, max-age=3600");
|
|
22509
|
+
return c.json(
|
|
22510
|
+
protectedResourceMetadata({
|
|
22511
|
+
resourceUrl: `${requestOrigin(c)}${resourcePath}`,
|
|
22512
|
+
region: regionForResourcePath(resourcePath)
|
|
22513
|
+
})
|
|
22514
|
+
);
|
|
22515
|
+
}
|
|
22516
|
+
function sendChallenge(c, resourcePath, authState) {
|
|
22517
|
+
const resourceMetadataUrl = `${requestOrigin(c)}${PRM_PREFIX}${resourcePath}`;
|
|
22518
|
+
applyCors(c);
|
|
22519
|
+
c.header("WWW-Authenticate", buildWwwAuthenticate({ resourceMetadataUrl, authState }));
|
|
22520
|
+
return c.json(
|
|
22521
|
+
{
|
|
22522
|
+
error: authState === "expired" ? "invalid_token" : "unauthorized",
|
|
22523
|
+
error_description: authState === "expired" ? "Access token is invalid or expired. Sign in with Leadbay again." : "Authentication required. Sign in with Leadbay."
|
|
22524
|
+
},
|
|
22525
|
+
401
|
|
22526
|
+
);
|
|
22474
22527
|
}
|
|
22475
22528
|
var app = new Hono();
|
|
22476
22529
|
app.get("/healthz", (c) => c.json({ ok: true, version: VERSION }));
|
|
22530
|
+
app.get(PRM_PREFIX, (c) => servePrm(c, "/mcp"));
|
|
22531
|
+
app.get(`${PRM_PREFIX}/*`, (c) => {
|
|
22532
|
+
const suffix = c.req.path.slice(PRM_PREFIX.length);
|
|
22533
|
+
const resourcePath = RESOURCE_PATHS.includes(suffix) ? suffix : "/mcp";
|
|
22534
|
+
return servePrm(c, resourcePath);
|
|
22535
|
+
});
|
|
22536
|
+
app.options("*", (c) => {
|
|
22537
|
+
applyCors(c);
|
|
22538
|
+
c.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
22539
|
+
c.header(
|
|
22540
|
+
"Access-Control-Allow-Headers",
|
|
22541
|
+
"Authorization, Content-Type, Mcp-Protocol-Version, Mcp-Session-Id"
|
|
22542
|
+
);
|
|
22543
|
+
return c.body(null, 204);
|
|
22544
|
+
});
|
|
22477
22545
|
var MCP_BODY_LIMIT = bodyLimit({ maxSize: 1 * 1024 * 1024 });
|
|
22478
22546
|
app.use("/mcp", MCP_BODY_LIMIT);
|
|
22547
|
+
app.use("/fr/mcp", MCP_BODY_LIMIT);
|
|
22479
22548
|
app.use("/messages", MCP_BODY_LIMIT);
|
|
22480
|
-
|
|
22549
|
+
async function handleStreamable(c, resourcePath) {
|
|
22481
22550
|
const token = extractBearer(c.req.header("authorization"));
|
|
22482
|
-
const
|
|
22483
|
-
|
|
22551
|
+
const resolved = await resolveClientFromToken(token);
|
|
22552
|
+
if (resolved.authState === "missing" || resolved.authState === "expired") {
|
|
22553
|
+
return sendChallenge(c, resourcePath, resolved.authState);
|
|
22554
|
+
}
|
|
22555
|
+
const server = buildServerFromClient(resolved.client);
|
|
22484
22556
|
const transport = new StreamableHTTPServerTransport({
|
|
22485
22557
|
sessionIdGenerator: void 0,
|
|
22486
22558
|
// Return JSON responses instead of SSE so non-SSE clients (e.g. Codex) work.
|
|
@@ -22516,13 +22588,18 @@ app.all("/mcp", async (c) => {
|
|
|
22516
22588
|
server.close().catch(() => {
|
|
22517
22589
|
});
|
|
22518
22590
|
}
|
|
22519
|
-
}
|
|
22520
|
-
app.
|
|
22591
|
+
}
|
|
22592
|
+
app.all("/mcp", (c) => handleStreamable(c, "/mcp"));
|
|
22593
|
+
app.all("/fr/mcp", (c) => handleStreamable(c, "/fr/mcp"));
|
|
22594
|
+
async function handleSse(c, resourcePath) {
|
|
22521
22595
|
const token = extractBearer(c.req.header("authorization"));
|
|
22522
|
-
const
|
|
22596
|
+
const resolved = await resolveClientFromToken(token);
|
|
22597
|
+
if (resolved.authState === "missing" || resolved.authState === "expired") {
|
|
22598
|
+
return sendChallenge(c, resourcePath, resolved.authState);
|
|
22599
|
+
}
|
|
22523
22600
|
const env = c.env;
|
|
22524
22601
|
const transport = new SSEServerTransport("/messages", env.outgoing);
|
|
22525
|
-
const server =
|
|
22602
|
+
const server = buildServerFromClient(resolved.client);
|
|
22526
22603
|
await server.connect(transport);
|
|
22527
22604
|
const sessionId = transport.sessionId;
|
|
22528
22605
|
sseSessions.set(sessionId, { transport, server, createdAt: Date.now() });
|
|
@@ -22532,7 +22609,9 @@ app.get("/sse", async (c) => {
|
|
|
22532
22609
|
});
|
|
22533
22610
|
};
|
|
22534
22611
|
return new Response(null, { headers: { "x-hono-already-sent": "1" } });
|
|
22535
|
-
}
|
|
22612
|
+
}
|
|
22613
|
+
app.get("/sse", (c) => handleSse(c, "/sse"));
|
|
22614
|
+
app.get("/fr/sse", (c) => handleSse(c, "/fr/sse"));
|
|
22536
22615
|
app.post("/messages", async (c) => {
|
|
22537
22616
|
const sessionId = c.req.query("sessionId");
|
|
22538
22617
|
if (!sessionId) {
|
|
@@ -22547,10 +22626,26 @@ app.post("/messages", async (c) => {
|
|
|
22547
22626
|
await session.transport.handlePostMessage(env.incoming, env.outgoing, body);
|
|
22548
22627
|
return new Response(null, { headers: { "x-hono-already-sent": "1" } });
|
|
22549
22628
|
});
|
|
22550
|
-
var
|
|
22551
|
-
|
|
22552
|
-
|
|
22553
|
-
|
|
22629
|
+
var isEntrypoint = (() => {
|
|
22630
|
+
try {
|
|
22631
|
+
const entry = process.argv[1];
|
|
22632
|
+
if (!entry) return false;
|
|
22633
|
+
const entryName = basename(entry).toLowerCase();
|
|
22634
|
+
if (entryName !== "http-server.js" && entryName !== "leadbay-mcp-http") return false;
|
|
22635
|
+
return realpathSync(fileURLToPath(import.meta.url)) === realpathSync(entry);
|
|
22636
|
+
} catch {
|
|
22637
|
+
return false;
|
|
22638
|
+
}
|
|
22639
|
+
})();
|
|
22640
|
+
if (isEntrypoint) {
|
|
22641
|
+
const _boot = randomUUID4();
|
|
22642
|
+
serve({ fetch: app.fetch, port: PORT, hostname: HOST }, (info) => {
|
|
22643
|
+
process.stderr.write(
|
|
22644
|
+
`leadbay-mcp-http ${VERSION} listening on http://${info.address}:${info.port} (boot=${_boot})
|
|
22554
22645
|
`
|
|
22555
|
-
|
|
22556
|
-
});
|
|
22646
|
+
);
|
|
22647
|
+
});
|
|
22648
|
+
}
|
|
22649
|
+
export {
|
|
22650
|
+
app
|
|
22651
|
+
};
|
|
@@ -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.
|
|
1469
|
+
VERSION = "0.21.0";
|
|
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.
|
|
876
|
+
var VERSION = "0.21.0";
|
|
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.
|
|
3
|
+
"version": "0.21.0",
|
|
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",
|