@leadbay/mcp 0.35.2 → 0.36.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 CHANGED
@@ -1,5 +1,59 @@
1
1
  # Changelog — @leadbay/mcp
2
2
 
3
+ ## 0.36.0 — 2026-09-08
4
+
5
+ The OpenAI submission form flags every tool without an `outputSchema`
6
+ ("Recommended: Add an outputSchema so models can better understand this tool's
7
+ results"). 43 of the 58 tools on `/chatgpt/mcp` already had one. This adds four
8
+ of the remaining 15:
9
+
10
+ - `leadbay_account_history`, `leadbay_team_activity` — rich nested payloads the
11
+ model previously had to infer from prose.
12
+ - `leadbay_getting_started`, `leadbay_artifact_kit` — static manifests; cheap to
13
+ declare, and both are consumed programmatically.
14
+
15
+ Each gets a real entry in `output-schema-conformance.test.ts` CASES, not an
16
+ OPT_OUT: a mocked happy-path round-trip whose structuredContent is asserted
17
+ against the schema. Mutation-checked — renaming `trend` in the team_activity
18
+ schema fails with `$.trend: return contains key not declared in
19
+ outputSchema.properties (drift)`.
20
+
21
+ A local Codex review of this branch found three real defects in the first pass,
22
+ all fixed here:
23
+
24
+ - `account_history` declared `signals` as an object. `research_lead_by_id`,
25
+ whose payload it passes straight through, declares it an **array**. The
26
+ conformance walk checks required keys and undeclared keys, not types, so it
27
+ did not catch this.
28
+ - The `account_history` conformance case under-mocked the fan-out. It never
29
+ mocked `/leads/{id}/contacts?IncludeEnriched=true`, and gave one generic
30
+ `/activities` script for the two reads that happen (research's `count=20`,
31
+ then the tool's own `count=<n>`). The harness consumes a script once, so the
32
+ second read rejected, `.catch()`ed to empty, and the case asserted a degraded
33
+ timeline while staying schema-conformant. Proven: with the old mocks the new
34
+ `account-history-full-fanout.test.ts` fails `expected [] to have a length of
35
+ 1`.
36
+ - `artifact_kit`'s schema omitted `_meta`. `buildServer` injects
37
+ `_meta.update_available` / `_meta.notifications` into successful object
38
+ results before setting `structuredContent`, so it is a real top-level key at
39
+ runtime. The other three declared it.
40
+
41
+ Two deliberate limits:
42
+
43
+ - **`leadbay_list_sectors` is excluded.** It returns a bare array, and
44
+ `server.ts` only emits `structuredContent` for plain objects, so a schema
45
+ there would promise a payload the server never sends. Making it honest means
46
+ changing the return to an object, which breaks existing callers.
47
+ - On `account_history`, the blobs passed through verbatim from
48
+ `research_lead_by_id` (`signals`, `firmographics`, `contacts`, `engagement`)
49
+ are declared as bare objects with no `properties`. The conformance walk only
50
+ recurses into declared object-properties that carry their own `properties`,
51
+ so research can grow a field without breaking this tool.
52
+
53
+ The remaining 10 tools without a schema are write acknowledgements
54
+ (`pin_contact`, `like_lead`, `set_telemetry`, …). A schema for `{ok:true}`
55
+ teaches the model nothing; left alone on purpose.
56
+
3
57
  ## 0.35.2 — 2026-09-08
4
58
 
5
59
  A backend `bad_request` 400 is now `BAD_INPUT` (product#4085).
package/dist/bin.js CHANGED
@@ -15740,6 +15740,32 @@ var init_getting_started = __esm({
15740
15740
  openWorldHint: false
15741
15741
  },
15742
15742
  description: leadbay_getting_started,
15743
+ outputSchema: {
15744
+ type: "object",
15745
+ properties: {
15746
+ version: { type: "number", description: "Manifest version; bump means the script changed." },
15747
+ intro: { type: "string", description: "What to say before gate 1." },
15748
+ one_option_rule: {
15749
+ type: "string",
15750
+ description: "The invariant every gate obeys: one way forward plus one way out, never three."
15751
+ },
15752
+ docs_url: { type: "string", description: "The canonical setup guide." },
15753
+ docs_note: { type: "string", description: "The only two moments that link may appear." },
15754
+ calendly_url: { type: "string", description: "1:1 setup session, offered on exit only." },
15755
+ exit_offer: { type: "string", description: "How and when to make that offer." },
15756
+ steps: {
15757
+ type: "array",
15758
+ description: "The gates, in order. Each carries n, gate_label, gate_description, explain, next_steps (the widget payload), calls, args, and optional forbidden_args / spend / quota_note / pin / branches. Render next_steps VERBATIM."
15759
+ },
15760
+ keep_going: {
15761
+ type: "array",
15762
+ description: "The hand-off cards: what the user should TYPE to get each thing back once the buttons are gone. Every phrase is lifted from a tool's own routing triggers."
15763
+ },
15764
+ stop: { type: "string", description: "How to close the tour." },
15765
+ _meta: { type: "object", description: "Server-injected notices, when present." }
15766
+ },
15767
+ required: ["version", "intro", "steps", "keep_going", "stop"]
15768
+ },
15743
15769
  write: false,
15744
15770
  inputSchema: {
15745
15771
  type: "object",
@@ -16018,6 +16044,63 @@ var init_account_history = __esm({
16018
16044
  openWorldHint: true
16019
16045
  },
16020
16046
  description: leadbay_account_history,
16047
+ outputSchema: {
16048
+ type: "object",
16049
+ properties: {
16050
+ lead: {
16051
+ type: "object",
16052
+ description: "Which account this history is about.",
16053
+ properties: {
16054
+ id: { type: "string" },
16055
+ name: { type: ["string", "null"] }
16056
+ },
16057
+ required: ["id"]
16058
+ },
16059
+ signals: {
16060
+ // An ARRAY of priority-ordered sections, matching what
16061
+ // research_lead_by_id's own outputSchema declares — this is its payload
16062
+ // passed straight through. Null when the research call has no web-fetch
16063
+ // content to reshape.
16064
+ type: ["array", "null"],
16065
+ description: "Live signals, verbatim from leadbay_research_lead_by_id \u2014 why this account is hot NOW."
16066
+ },
16067
+ firmographics: { type: ["object", "null"], description: "Company facts, verbatim from research." },
16068
+ qualification: { type: "array", description: "Per-question qualification answers, verbatim from research." },
16069
+ contacts: { type: ["object", "null"], description: "Reachable contacts + candidates, verbatim from research." },
16070
+ engagement: { type: ["object", "null"], description: "Engagement counters, verbatim from research." },
16071
+ notes: {
16072
+ type: "array",
16073
+ description: "FULL note bodies \u2014 the part research only counts. Oldest first."
16074
+ },
16075
+ activities: {
16076
+ type: "object",
16077
+ description: "The interaction timeline research only summarizes.",
16078
+ properties: {
16079
+ activities: {
16080
+ type: "array",
16081
+ description: "One entry per logged interaction.",
16082
+ items: {
16083
+ type: "object",
16084
+ properties: {
16085
+ type: { type: "string" },
16086
+ date: { type: "string" }
16087
+ }
16088
+ }
16089
+ },
16090
+ total: {
16091
+ type: "number",
16092
+ description: "Total on the server, which can exceed the number returned."
16093
+ }
16094
+ },
16095
+ required: ["activities", "total"]
16096
+ },
16097
+ _meta: {
16098
+ type: "object",
16099
+ description: "Research's pass-through metadata (lens_id, web_fetch_in_progress, has_reachable_contact, \u2026) plus region and this call's counts."
16100
+ }
16101
+ },
16102
+ required: ["lead", "notes", "activities"]
16103
+ },
16021
16104
  inputSchema: {
16022
16105
  type: "object",
16023
16106
  properties: {
@@ -21362,6 +21445,62 @@ var init_team_activity = __esm({
21362
21445
  openWorldHint: true
21363
21446
  },
21364
21447
  description: leadbay_team_activity,
21448
+ outputSchema: {
21449
+ type: "object",
21450
+ properties: {
21451
+ range: {
21452
+ type: "object",
21453
+ description: "The window actually queried, after `weeks` was resolved to dates.",
21454
+ properties: {
21455
+ from: { type: "string", description: "ISO date (YYYY-MM-DD), inclusive." },
21456
+ to: { type: "string", description: "ISO date (YYYY-MM-DD), inclusive." },
21457
+ periodicity: { type: "string", description: "DAILY or WEEKLY \u2014 the trend bucket size." }
21458
+ },
21459
+ required: ["from", "to", "periodicity"]
21460
+ },
21461
+ reps: {
21462
+ type: "array",
21463
+ description: "One row per rep, already renamed from the backend's KPI vocabulary. Non-admins get only themselves; the backend does that scoping.",
21464
+ items: {
21465
+ type: "object",
21466
+ properties: {
21467
+ user_id: { type: "string" },
21468
+ name: { type: ["string", "null"] },
21469
+ email: { type: ["string", "null"] },
21470
+ total_activities: { type: "number" },
21471
+ likes: { type: "number" },
21472
+ saves: { type: "number" },
21473
+ website_clicks: { type: "number" },
21474
+ exported: { type: "number" },
21475
+ profile_views: { type: "number" },
21476
+ contacts_added: { type: "number" },
21477
+ contacts_purchased: { type: "number" },
21478
+ notes: { type: "number" },
21479
+ meetings_or_interest: {
21480
+ type: "number",
21481
+ description: "Epilogue outcomes logged in the window \u2014 the 'deals' signal."
21482
+ },
21483
+ could_not_reach: { type: "number" },
21484
+ lost: { type: "number" },
21485
+ still_chasing: { type: "number" }
21486
+ }
21487
+ }
21488
+ },
21489
+ trend: {
21490
+ type: "array",
21491
+ description: "Activity over time, one point per period.",
21492
+ items: {
21493
+ type: "object",
21494
+ properties: {
21495
+ date: { type: "string" },
21496
+ count: { type: "number" }
21497
+ }
21498
+ }
21499
+ },
21500
+ _meta: { type: "object", description: "Region + any server-injected notices." }
21501
+ },
21502
+ required: ["range", "reps", "trend"]
21503
+ },
21365
21504
  write: false,
21366
21505
  inputSchema: {
21367
21506
  type: "object",
@@ -21512,6 +21651,19 @@ var init_artifact_kit = __esm({
21512
21651
  openWorldHint: false
21513
21652
  },
21514
21653
  description: leadbay_artifact_kit,
21654
+ outputSchema: {
21655
+ type: "object",
21656
+ properties: {
21657
+ version: { type: "string", description: "Kit version; bump means the runtime changed." },
21658
+ runtime: { type: "string", description: "The self-contained JS the artifact inlines." },
21659
+ usage_guide: { type: "string", description: "Markdown guide for building the artifact." },
21660
+ // buildServer injects _meta.update_available / _meta.notifications into
21661
+ // successful object results before emitting structuredContent, so it is a
21662
+ // real top-level key at runtime even though execute() never writes it.
21663
+ _meta: { type: "object", description: "Server-injected notices, when present." }
21664
+ },
21665
+ required: ["version", "runtime", "usage_guide"]
21666
+ },
21515
21667
  write: false,
21516
21668
  inputSchema: {
21517
21669
  type: "object",
@@ -28051,7 +28203,7 @@ var OAUTH_BASE_URLS = {
28051
28203
  fr: "https://staging.api.leadbay.app"
28052
28204
  }
28053
28205
  };
28054
- var VERSION = "0.35.2";
28206
+ var VERSION = "0.36.0";
28055
28207
  var HELP = `
28056
28208
  leadbay-mcp ${VERSION} \u2014 Leadbay Model Context Protocol server
28057
28209
 
@@ -17862,6 +17862,32 @@ var gettingStarted = {
17862
17862
  openWorldHint: false
17863
17863
  },
17864
17864
  description: leadbay_getting_started2,
17865
+ outputSchema: {
17866
+ type: "object",
17867
+ properties: {
17868
+ version: { type: "number", description: "Manifest version; bump means the script changed." },
17869
+ intro: { type: "string", description: "What to say before gate 1." },
17870
+ one_option_rule: {
17871
+ type: "string",
17872
+ description: "The invariant every gate obeys: one way forward plus one way out, never three."
17873
+ },
17874
+ docs_url: { type: "string", description: "The canonical setup guide." },
17875
+ docs_note: { type: "string", description: "The only two moments that link may appear." },
17876
+ calendly_url: { type: "string", description: "1:1 setup session, offered on exit only." },
17877
+ exit_offer: { type: "string", description: "How and when to make that offer." },
17878
+ steps: {
17879
+ type: "array",
17880
+ description: "The gates, in order. Each carries n, gate_label, gate_description, explain, next_steps (the widget payload), calls, args, and optional forbidden_args / spend / quota_note / pin / branches. Render next_steps VERBATIM."
17881
+ },
17882
+ keep_going: {
17883
+ type: "array",
17884
+ description: "The hand-off cards: what the user should TYPE to get each thing back once the buttons are gone. Every phrase is lifted from a tool's own routing triggers."
17885
+ },
17886
+ stop: { type: "string", description: "How to close the tour." },
17887
+ _meta: { type: "object", description: "Server-injected notices, when present." }
17888
+ },
17889
+ required: ["version", "intro", "steps", "keep_going", "stop"]
17890
+ },
17865
17891
  write: false,
17866
17892
  inputSchema: {
17867
17893
  type: "object",
@@ -18118,6 +18144,63 @@ var accountHistory = {
18118
18144
  openWorldHint: true
18119
18145
  },
18120
18146
  description: leadbay_account_history,
18147
+ outputSchema: {
18148
+ type: "object",
18149
+ properties: {
18150
+ lead: {
18151
+ type: "object",
18152
+ description: "Which account this history is about.",
18153
+ properties: {
18154
+ id: { type: "string" },
18155
+ name: { type: ["string", "null"] }
18156
+ },
18157
+ required: ["id"]
18158
+ },
18159
+ signals: {
18160
+ // An ARRAY of priority-ordered sections, matching what
18161
+ // research_lead_by_id's own outputSchema declares — this is its payload
18162
+ // passed straight through. Null when the research call has no web-fetch
18163
+ // content to reshape.
18164
+ type: ["array", "null"],
18165
+ description: "Live signals, verbatim from leadbay_research_lead_by_id \u2014 why this account is hot NOW."
18166
+ },
18167
+ firmographics: { type: ["object", "null"], description: "Company facts, verbatim from research." },
18168
+ qualification: { type: "array", description: "Per-question qualification answers, verbatim from research." },
18169
+ contacts: { type: ["object", "null"], description: "Reachable contacts + candidates, verbatim from research." },
18170
+ engagement: { type: ["object", "null"], description: "Engagement counters, verbatim from research." },
18171
+ notes: {
18172
+ type: "array",
18173
+ description: "FULL note bodies \u2014 the part research only counts. Oldest first."
18174
+ },
18175
+ activities: {
18176
+ type: "object",
18177
+ description: "The interaction timeline research only summarizes.",
18178
+ properties: {
18179
+ activities: {
18180
+ type: "array",
18181
+ description: "One entry per logged interaction.",
18182
+ items: {
18183
+ type: "object",
18184
+ properties: {
18185
+ type: { type: "string" },
18186
+ date: { type: "string" }
18187
+ }
18188
+ }
18189
+ },
18190
+ total: {
18191
+ type: "number",
18192
+ description: "Total on the server, which can exceed the number returned."
18193
+ }
18194
+ },
18195
+ required: ["activities", "total"]
18196
+ },
18197
+ _meta: {
18198
+ type: "object",
18199
+ description: "Research's pass-through metadata (lens_id, web_fetch_in_progress, has_reachable_contact, \u2026) plus region and this call's counts."
18200
+ }
18201
+ },
18202
+ required: ["lead", "notes", "activities"]
18203
+ },
18121
18204
  inputSchema: {
18122
18205
  type: "object",
18123
18206
  properties: {
@@ -23288,6 +23371,62 @@ var teamActivity = {
23288
23371
  openWorldHint: true
23289
23372
  },
23290
23373
  description: leadbay_team_activity,
23374
+ outputSchema: {
23375
+ type: "object",
23376
+ properties: {
23377
+ range: {
23378
+ type: "object",
23379
+ description: "The window actually queried, after `weeks` was resolved to dates.",
23380
+ properties: {
23381
+ from: { type: "string", description: "ISO date (YYYY-MM-DD), inclusive." },
23382
+ to: { type: "string", description: "ISO date (YYYY-MM-DD), inclusive." },
23383
+ periodicity: { type: "string", description: "DAILY or WEEKLY \u2014 the trend bucket size." }
23384
+ },
23385
+ required: ["from", "to", "periodicity"]
23386
+ },
23387
+ reps: {
23388
+ type: "array",
23389
+ description: "One row per rep, already renamed from the backend's KPI vocabulary. Non-admins get only themselves; the backend does that scoping.",
23390
+ items: {
23391
+ type: "object",
23392
+ properties: {
23393
+ user_id: { type: "string" },
23394
+ name: { type: ["string", "null"] },
23395
+ email: { type: ["string", "null"] },
23396
+ total_activities: { type: "number" },
23397
+ likes: { type: "number" },
23398
+ saves: { type: "number" },
23399
+ website_clicks: { type: "number" },
23400
+ exported: { type: "number" },
23401
+ profile_views: { type: "number" },
23402
+ contacts_added: { type: "number" },
23403
+ contacts_purchased: { type: "number" },
23404
+ notes: { type: "number" },
23405
+ meetings_or_interest: {
23406
+ type: "number",
23407
+ description: "Epilogue outcomes logged in the window \u2014 the 'deals' signal."
23408
+ },
23409
+ could_not_reach: { type: "number" },
23410
+ lost: { type: "number" },
23411
+ still_chasing: { type: "number" }
23412
+ }
23413
+ }
23414
+ },
23415
+ trend: {
23416
+ type: "array",
23417
+ description: "Activity over time, one point per period.",
23418
+ items: {
23419
+ type: "object",
23420
+ properties: {
23421
+ date: { type: "string" },
23422
+ count: { type: "number" }
23423
+ }
23424
+ }
23425
+ },
23426
+ _meta: { type: "object", description: "Region + any server-injected notices." }
23427
+ },
23428
+ required: ["range", "reps", "trend"]
23429
+ },
23291
23430
  write: false,
23292
23431
  inputSchema: {
23293
23432
  type: "object",
@@ -23417,6 +23556,19 @@ var artifactKit = {
23417
23556
  openWorldHint: false
23418
23557
  },
23419
23558
  description: leadbay_artifact_kit,
23559
+ outputSchema: {
23560
+ type: "object",
23561
+ properties: {
23562
+ version: { type: "string", description: "Kit version; bump means the runtime changed." },
23563
+ runtime: { type: "string", description: "The self-contained JS the artifact inlines." },
23564
+ usage_guide: { type: "string", description: "Markdown guide for building the artifact." },
23565
+ // buildServer injects _meta.update_available / _meta.notifications into
23566
+ // successful object results before emitting structuredContent, so it is a
23567
+ // real top-level key at runtime even though execute() never writes it.
23568
+ _meta: { type: "object", description: "Server-injected notices, when present." }
23569
+ },
23570
+ required: ["version", "runtime", "usage_guide"]
23571
+ },
23420
23572
  write: false,
23421
23573
  inputSchema: {
23422
23574
  type: "object",
@@ -25416,7 +25568,7 @@ function parseWriteEnv(env = process.env) {
25416
25568
  }
25417
25569
 
25418
25570
  // src/http-server.ts
25419
- var VERSION = true ? "0.35.2" : "0.0.0-dev";
25571
+ var VERSION = true ? "0.36.0" : "0.0.0-dev";
25420
25572
  var PORT = Number(process.env.PORT ?? 8080);
25421
25573
  var HOST = process.env.HOST ?? "0.0.0.0";
25422
25574
  var logger = {
@@ -1805,7 +1805,7 @@ var init_installer_gui = __esm({
1805
1805
  init_install_dxt();
1806
1806
  init_install_shared();
1807
1807
  init_oauth();
1808
- VERSION = true ? "0.35.2" : "0.0.0-dev";
1808
+ VERSION = true ? "0.36.0" : "0.0.0-dev";
1809
1809
  MESSAGES = {
1810
1810
  en: {
1811
1811
  installer: {
@@ -1068,7 +1068,7 @@ async function oauthLogin(opts) {
1068
1068
  }
1069
1069
 
1070
1070
  // installer/installer-gui.ts
1071
- var VERSION = true ? "0.35.2" : "0.0.0-dev";
1071
+ var VERSION = true ? "0.36.0" : "0.0.0-dev";
1072
1072
  var MESSAGES = {
1073
1073
  en: {
1074
1074
  installer: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leadbay/mcp",
3
- "version": "0.35.2",
3
+ "version": "0.36.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",