@leadbay/mcp 0.16.2 → 0.17.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,27 @@
1
1
  # Changelog — @leadbay/mcp
2
2
 
3
+ ## 0.17.0 — 2026-05-29
4
+
5
+ - **Lens extension** (product#3654): two new composites that expose the
6
+ backend's agent-driven on-demand lens fill (backend#1844 / api-specs#205).
7
+ - `leadbay_extend_lens` (write, gated by `LEADBAY_MCP_WRITE=1`) —
8
+ `POST /lenses/{id}/extra_refill`. Translates the backend's 429
9
+ `quota_exceeded` / 409 `refresh_in_progress` / 400 `no_valid_seeds`
10
+ errors into routable `status` envelopes. On 429 the response carries
11
+ `quota.used_today` + `quota.resets_at` and a message instructing the
12
+ agent to surface three options to the user (smaller `extra_count` /
13
+ wait for reset / upgrade plan).
14
+ - `leadbay_seed_candidates` (read) — internal scaffolding for the
15
+ extend flow. Returns ranked candidate leads with rich signal
16
+ (description, sector, tags, qq_answers, engagement). The agent picks
17
+ 3–5 seeds silently and chains to `extend_lens`; the user never
18
+ reviews the seed list.
19
+ - New prompt `leadbay_extend_my_lens` orchestrates the four-phase flow:
20
+ quota pre-check → silent seed pick → fire extend → react to status.
21
+ - `leadbay_account_status` description now mentions the per-org daily
22
+ `LENS_EXTRA_REFILL` quota — pre-check it before calling
23
+ `leadbay_extend_lens`.
24
+
3
25
  ## 0.16.2 — 2026-05-29
4
26
 
5
27
  - **Tighter `_triggered_by` description on composite tools.** Live test of
package/dist/bin.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  granularWriteTools,
13
13
  resolveAgentMemorySummary,
14
14
  resolveRegion
15
- } from "./chunk-3V3EPBLZ.js";
15
+ } from "./chunk-ASAKITU3.js";
16
16
 
17
17
  // src/bin.ts
18
18
  import { realpathSync } from "fs";
@@ -972,6 +972,7 @@ day's batch", "let's prospect". Do NOT trigger on follow-up phrasings
972
972
  ("what should I follow up on", "before my trip") \u2014 those go to
973
973
  \`leadbay_followup_check_in\`.
974
974
  `, "arguments": [], "expected_calls": ["leadbay_account_status", "leadbay_pull_leads", "leadbay_research_lead_by_id", "leadbay_bulk_qualify_leads", "leadbay_enrich_contacts"], "failure_modes": ["Calls leadbay_report_outreach without explicit user authorization", "Surfaces fewer than 10 leads when more are available, or fails to top up via leadbay_qualify_top_n when the batch is short", `Replaces the canonical pull_leads table layout with prose per row (the per-tool RENDERING block is the structural contract; "Today's nudges" goes above it, not in place of it)`, "Skips the nudge paragraph entirely \u2014 the table alone is fine but adding the nudge is the value-add", "Skips deep research on promising leads (Phase 4) \u2014 the agent must call leadbay_research_lead_by_id on each, not just one", "Triggers contact enrichment without asking the user first (it consumes quota)", "Skips the STOP byproduct and proposes next actions on its own", 'Fires 10 parallel leadbay_research_lead_by_id calls and treats "stream closed" errors as terminal \u2014 must serialize and retry singletons', "Re-pulls leadbay_pull_leads without passing the captured lensId, allowing a backend lens shift to discard the Phase 2 batch", 'Treats a "Request timed out" from leadbay_bulk_qualify_leads as terminal instead of retrying with wait_for_completion:false + qualify_status polling', 'Triggers on a follow-up query (e.g., "leads I should follow up with") that should have routed to `leadbay_followup_check_in` \u2014 the two entry points are different data sources (Discover wishlist vs Monitor view) per \xA71.6'] },
975
+ leadbay_extend_my_lens: { "name": "leadbay_extend_my_lens", "short_description": "Add more leads to the current lens on demand \u2014 for users whose appetite\nexceeds the standard daily fill. The agent picks seeds silently from\nwhat's already on the lens, fires the extra refill, and surfaces the\nqueue confirmation. The user never reviews the seed list.\n", "arguments": [{ "name": "extra_count", "description": "How many extra leads to add. Optional. Omit to use the backend default.", "required": false }], "expected_calls": ["leadbay_account_status", "leadbay_seed_candidates", "leadbay_extend_lens", "leadbay_pull_leads"], "failure_modes": ["Surfaces the seed candidate list to the user instead of picking silently \u2014 the user asked for MORE LEADS, not a candidate review meeting", "Skips the seeded path and calls `leadbay_extend_lens` with no `seed_lead_ids`, losing the bias signal the recommender needs", "On 429, silently retries instead of surfacing the three options (smaller / wait / upgrade) via `ask_user_input_v0`", "Forgets to pre-check `LENS_EXTRA_REFILL` quota in `leadbay_account_status` and burns a wasted API call", "Skips the post-queue pull-leads suggestion, so the user doesn't see what just got added"] },
975
976
  leadbay_followup_check_in: { "name": "leadbay_followup_check_in", "short_description": `Run the canonical follow-up check-in: surface KNOWN leads from the
976
977
  Monitor view that need re-engagement today, ranked by AI urgency,
977
978
  with the canonical pull_followups table layout. Trigger when the
@@ -999,6 +1000,7 @@ should I follow up on" to "I'll send via lemlist".
999
1000
  var PROMPT_CATALOG_HEADER = `This server exposes the following workflow prompts via \`prompts/list\` and \`prompts/get\`. Some MCP clients render them as slash commands; if your client does not, you (the agent) should invoke them directly via \`prompts/get\` when the user's request matches one of the triggers described below.`;
1000
1001
  var PROMPT_CATALOG_BULLETS = {
1001
1002
  leadbay_daily_check_in: `- \`leadbay_daily_check_in\`: Run the canonical daily check-in: account state, fresh batch, triage top 10, deep-dive every promising one, offer contact enrichment. The morning DISCOVERY workflow (new leads from the lens wishlist). Trigger on "leadbay leads", "best NEW leads", "what's new today", "show me the day's batch", "let's prospect". Do NOT trigger on follow-up phrasings ("what should I follow up on", "before my trip") \u2014 those go to \`leadbay_followup_check_in\`.`,
1003
+ leadbay_extend_my_lens: `- \`leadbay_extend_my_lens\` (optional args: extra_count): Add more leads to the current lens on demand \u2014 for users whose appetite exceeds the standard daily fill. The agent picks seeds silently from what's already on the lens, fires the extra refill, and surfaces the queue confirmation. The user never reviews the seed list.`,
1002
1004
  leadbay_followup_check_in: `- \`leadbay_followup_check_in\`: Run the canonical follow-up check-in: surface KNOWN leads from the Monitor view that need re-engagement today, ranked by AI urgency, with the canonical pull_followups table layout. Trigger when the user asks "follow up", "already known leads", "leads I haven't contacted", "leads in [city]", "before my trip", "this week", "this month", "what's overdue", "who should I re-engage", or anything that implies pre-existing pipeline context.`,
1003
1005
  leadbay_import_file: `- \`leadbay_import_file\` (optional args: file, instruction): Import a user-supplied CSV/file into Leadbay through five phases with evidence gates \u2014 scan, derive, resolve identities, preserve & commit, then optionally qualify and report. The job is to maximize how many rows the Leadbay system actually ingests and matches.`,
1004
1006
  leadbay_log_outreach: `- \`leadbay_log_outreach\` (required args: lead_id, summary): Log outreach (an email I sent, a call I made, a meeting I had) on a specific lead. Captures verification so the SDR pipeline trusts the entry.`,
@@ -3189,7 +3191,7 @@ var OAUTH_BASE_URLS = {
3189
3191
  fr: "https://staging.api.leadbay.app"
3190
3192
  }
3191
3193
  };
3192
- var VERSION = "0.16.2";
3194
+ var VERSION = "0.17.0";
3193
3195
  var HELP = `
3194
3196
  leadbay-mcp ${VERSION} \u2014 Leadbay Model Context Protocol server
3195
3197
 
@@ -3721,7 +3723,7 @@ async function runLogin(args) {
3721
3723
  }
3722
3724
  try {
3723
3725
  if (pinnedRegion && !allowFallback) {
3724
- const { REGIONS } = await import("./dist-7XHTMWB2.js");
3726
+ const { REGIONS } = await import("./dist-3NYTS7OH.js");
3725
3727
  const baseUrl = REGIONS[pinnedRegion];
3726
3728
  const c = createClient({ region: pinnedRegion });
3727
3729
  const token = await loginAt(baseUrl, email, password);
@@ -4224,7 +4226,7 @@ leadbay-mcp install \u2014 detected MCP clients on this machine:
4224
4226
  let region;
4225
4227
  try {
4226
4228
  if (pinnedRegion && !allowFallback) {
4227
- const { REGIONS } = await import("./dist-7XHTMWB2.js");
4229
+ const { REGIONS } = await import("./dist-3NYTS7OH.js");
4228
4230
  const baseUrl = REGIONS[pinnedRegion];
4229
4231
  token = await loginAt(baseUrl, email, password);
4230
4232
  region = pinnedRegion;
@@ -4960,6 +4960,7 @@ var COMPOSITE_FILE_TOOL_NAMES = /* @__PURE__ */ new Set([
4960
4960
  "leadbay_campaign_progression",
4961
4961
  "leadbay_create_campaign",
4962
4962
  "leadbay_enrich_titles",
4963
+ "leadbay_extend_lens",
4963
4964
  "leadbay_followups_map",
4964
4965
  "leadbay_import_and_qualify",
4965
4966
  "leadbay_import_leads",
@@ -4977,6 +4978,7 @@ var COMPOSITE_FILE_TOOL_NAMES = /* @__PURE__ */ new Set([
4977
4978
  "leadbay_research_lead_by_id",
4978
4979
  "leadbay_research_lead_by_name_fuzzy",
4979
4980
  "leadbay_resolve_import_rows",
4981
+ "leadbay_seed_candidates",
4980
4982
  "leadbay_tour_plan"
4981
4983
  ]);
4982
4984
 
@@ -5008,7 +5010,7 @@ prominently if mid-regen.
5008
5010
 
5009
5011
  ---
5010
5012
 
5011
- Show the user's account state \u2014 admin rights, language, last-active lens, current quota usage across daily/weekly/monthly windows for llm_completion / ai_rescore / web_fetch resources, and whether the org's intelligence is mid-regeneration. Quota windows also hint at the user's consumption pace: heavy recent activity (ai_rescore / web_fetch near their window limits) is a signal that Leadbay will deliver a larger fresh batch next time the user logs back in, since batch size is paced by real consumption.
5013
+ Show the user's account state \u2014 admin rights, language, last-active lens, current quota usage across daily/weekly/monthly windows for llm_completion / ai_rescore / web_fetch / LENS_EXTRA_REFILL resources, and whether the org's intelligence is mid-regeneration. **Pre-check \`LENS_EXTRA_REFILL\` here before calling \`leadbay_extend_lens\`** \u2014 its full requested batch must fit into the remaining daily quota or the call is rejected outright. Quota windows also hint at the user's consumption pace: heavy recent activity (ai_rescore / web_fetch near their window limits) is a signal that Leadbay will deliver a larger fresh batch next time the user logs back in, since batch size is paced by real consumption.
5012
5014
 
5013
5015
  **Top-ups always beat waiting.** When a quota window is hit, the user has two options: wait for the window reset (\`resets_at\` in each quota entry) OR top up AI credits. Top-ups clear the throttle IMMEDIATELY; they are not subject to the same window. When you tell the user about a 429 / quota exhaustion, ALWAYS surface both options \u2014 "wait until <reset>" or "top up now (I can generate the link)" \u2014 and let them pick. Never default-recommend "wait until tomorrow" when a 30-second top-up unblocks the same operation.
5014
5016
 
@@ -5592,6 +5594,102 @@ WHEN NOT TO USE: to enrich a single contact \u2014 that's leadbay_enrich_contact
5592
5594
 
5593
5595
  This tool MUTATES state. The caller (agent or human-in-the-loop) is responsible for confirming intent before invocation; the MCP server does not soft-prompt for confirmation. See \`annotations.destructiveHint\`.
5594
5596
  `;
5597
+ var leadbay_extend_lens = `## WHEN TO USE
5598
+
5599
+ Trigger phrases: "I want more leads on this lens", "extend the lens", "I need a bigger batch today", "fill more leads, I've burned through these", "more leads like the ones in this lens".
5600
+
5601
+ **Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
5602
+
5603
+ Do NOT use for: "show me today's leads" \u2192 \`leadbay_pull_leads\`; "narrow the audience" \u2192 \`leadbay_adjust_audience\`; "stop showing me X" \u2192 \`leadbay_refine_prompt\`.
5604
+
5605
+ Prefer when: user has bigger appetite than the daily lens fill delivers \u2014 additive refill on same criteria
5606
+
5607
+ Examples that SHOULD invoke this tool:
5608
+ - "Give me more leads on this lens \u2014 I want a bigger batch."
5609
+ - "Extend the lens, I've burned through what I had."
5610
+ - "Add 30 more leads like the ones in this batch."
5611
+
5612
+ Examples that should NOT invoke this tool (sound similar, route elsewhere):
5613
+ - "Show me today's leads."
5614
+ - "Narrow the audience to fintech only."
5615
+ - "Which leads should I follow up with this week?"
5616
+
5617
+ ## RENDER (quick)
5618
+
5619
+ \`queued\` \u2192 \u2705 "Queued <N> extra leads on lens <id>. Pull in ~30s." Do NOT
5620
+ list \`accepted_seeds\`; they're internal.
5621
+ \`quota_exceeded\` \u2192 render three options via \`ask_user_input_v0\` (smaller
5622
+ count / wait until reset / upgrade).
5623
+ \`refresh_in_progress\` \u2192 "lens is filling, retry in a minute".
5624
+ \`no_valid_seeds\` \u2192 silently re-call \`leadbay_seed_candidates\`, retry once.
5625
+
5626
+ ---
5627
+
5628
+ Queue an additive extra-refill on a lens \u2014 more leads on the same criteria, without changing the audience. For users whose daily appetite exceeds what the standard fill delivers. Wraps \`POST /lenses/{lensId}/extra_refill\`. The fill happens asynchronously; new leads stream in over ~30s, observable through \`leadbay_pull_leads\`.
5629
+
5630
+ **Mandatory chain \u2014 agent picks seeds silently.** Unless the user has explicitly said "no seeds, just fill it", the agent MUST call \`leadbay_seed_candidates\` FIRST, pick 3\u20135 seed leads using the heuristics in that tool's description, and pass them here as \`seed_lead_ids\`. The seed list is **never shown to the user** \u2014 the user asked for more leads, not a candidate review meeting. The canonical \`leadbay_extend_my_lens\` prompt drives this chain.
5631
+
5632
+ **Seeds are optional at the wire level** \u2014 omit or empty array \u2192 backend falls back to default centroid strategies (same behaviour as a normal fill). The response's \`accepted_seeds\` echoes the subset that passed validation. Prefer the seeded path because it gives the recommender a signal beyond the lens centroid (which it already biases on).
5633
+
5634
+ **Quota gate.** Each call is charged against the per-org daily \`LENS_EXTRA_REFILL\` quota at pre-flight time (FREEMIUM=0 / TIER1=150 / TIER2=1000). The **full requested batch** must fit \u2014 there is no partial fulfillment. **Pre-check via \`leadbay_account_status\`**: look at \`quota.org.resources[]\` for the \`LENS_EXTRA_REFILL\` entry to see how much was used today and when it resets.
5635
+
5636
+ **Status envelope (translated from raw API errors so the agent routes on \`status\`).**
5637
+
5638
+ - \`status: "queued"\` \u2014 fill is queued. \`accepted_seeds\` lists IDs that passed validation. NEXT STEP: call \`leadbay_pull_leads\` in ~30s.
5639
+ - \`status: "quota_exceeded"\` \u2014 daily LENS_EXTRA_REFILL hit. Response carries \`quota: {used_today, resets_at}\` + a \`message\` to surface. **Render three options via \`ask_user_input_v0\`**: (1) smaller \`extra_count\`, (2) wait until \`resets_at\`, (3) upgrade plan (TIER1=150, TIER2=1000). Do NOT silently retry.
5640
+ - \`status: "refresh_in_progress"\` \u2014 a refresh or extra-refill is already running. Tell the user to wait and call \`leadbay_pull_leads\` in ~30s.
5641
+ - \`status: "no_valid_seeds"\` \u2014 seeds went stale. Silently re-call \`leadbay_seed_candidates\` and retry once; only surface to the user if the second attempt also fails.
5642
+
5643
+ WHEN TO USE: when the user has a bigger appetite than the daily lens fill delivers \u2014 they want MORE of the same kind of leads, on demand. Canonical phrasings: "I want more leads on this lens", "extend the lens", "give me a bigger batch today". The \`leadbay_extend_my_lens\` prompt is the user-facing entry point that orchestrates the whole flow.
5644
+
5645
+ WHEN NOT TO USE: for daily inbox pulls (\`leadbay_pull_leads\`). Not for audience criteria changes (\`leadbay_adjust_audience\` / \`leadbay_refine_prompt\`). Never call this without seeds unless the user explicitly opted out \u2014 the seeded path produces materially better fill.
5646
+
5647
+ This tool MUTATES state. The caller (agent or human-in-the-loop) is responsible for confirming intent before invocation; the MCP server does not soft-prompt for confirmation. See \`annotations.destructiveHint\`.
5648
+
5649
+
5650
+ ---
5651
+
5652
+ ## NEXT STEPS \u2014 after \`leadbay_extend_lens\`
5653
+
5654
+ **RENDER NEXT STEPS via \`ask_user_input_v0\` when the host exposes it.**
5655
+
5656
+ The (Observation, Suggest, Calls) table below is the source of truth for which moves are valid. Pick the 2\u20134 most relevant rows based on what the response actually contains, then surface them as a \`single_select\` quick-select widget:
5657
+
5658
+ \`\`\`
5659
+ ask_user_input_v0({
5660
+ questions: [{
5661
+ question: "What next?",
5662
+ type: "single_select",
5663
+ options: [
5664
+ "<Suggest column from row 1>",
5665
+ "<Suggest column from row 2>",
5666
+ "<Suggest column from row 3>"
5667
+ ]
5668
+ }]
5669
+ })
5670
+ \`\`\`
5671
+
5672
+ When the user picks an option, you call the matching tool from the \`Calls\` column. Constraints carried over from the widget contract: 2\u20134 mutually-exclusive options per question, button-sized labels (\u22646 words), max 3 questions per call.
5673
+
5674
+ **Fallback prose mode** \u2014 when the host doesn't expose \`ask_user_input_v0\` (or it returned an error): surface the same 2\u20133 picks as a short bulleted list of "Suggest" phrasings. The table itself stays internal; never recite the whole table to the user.
5675
+
5676
+ ---
5677
+
5678
+
5679
+
5680
+ Pick the row matching the response \`status\`. Seed-picking is internal; do NOT add chips that imply the user reviewed candidates.
5681
+
5682
+ | \`status\` | Suggest | Calls |
5683
+ |-------------------------|---------------------------------------------------------------|--------------------------------------------------------|
5684
+ | \`queued\` | "Pull leads in ~30s to see the new ones" | \`leadbay_pull_leads()\` (after a short wait) |
5685
+ | \`quota_exceeded\` | "Try with a smaller \`extra_count\`" | \`leadbay_extend_lens(extra_count=<smaller>)\` |
5686
+ | \`quota_exceeded\` | "Wait until the daily quota resets at \`<resets_at>\`" | (no call \u2014 surface the reset time to the user) |
5687
+ | \`quota_exceeded\` | "Upgrade plan for a higher daily limit" | (no call \u2014 direct user to contact account manager / sales) |
5688
+ | \`refresh_in_progress\` | "Lens is already filling \u2014 pull leads in a minute" | \`leadbay_pull_leads()\` (after a short wait) |
5689
+ | \`no_valid_seeds\` | (silent retry \u2014 re-call \`leadbay_seed_candidates\` then \`leadbay_extend_lens\`) | internal \u2014 only surface if the second attempt also fails |
5690
+
5691
+ If nothing matches cleanly, default to "pull leads now to see what's queued" \u2014 never invent a tool that doesn't exist.
5692
+ `;
5595
5693
  var leadbay_followups_map = `## WHEN TO USE
5596
5694
 
5597
5695
  Trigger phrases: "I'm going to <city>", "visit in person", "map of leads", "plan my itinerary".
@@ -7389,6 +7487,56 @@ Below the table, a one-liner: \`"Ready: K rows \xB7 Ambiguous: A rows \xB7 Unmat
7389
7487
  | Unmatched rows but websites present | "Import anyway \u2014 Leadbay will crawl and match later" | leadbay_import_leads (status check after) |
7390
7488
  | User wants to skip rows they can't ID | "Drop unmatched rows and import the rest" | leadbay_import_leads (with filtered records) |
7391
7489
  `;
7490
+ var leadbay_seed_candidates = `## WHEN TO USE
7491
+
7492
+ Trigger phrases: "(internal) agent decided to extend the lens \u2014 fetch seed candidates".
7493
+
7494
+ **Memory:** recall + capture via \`leadbay_agent_memory_*\` tools.
7495
+
7496
+ Do NOT use for: "show me today's leads" \u2192 \`leadbay_pull_leads\`; "leads I should follow up with" \u2192 \`leadbay_pull_followups\`; "narrow the audience" \u2192 \`leadbay_adjust_audience\`; "stop showing me X" \u2192 \`leadbay_refine_prompt\`.
7497
+
7498
+ Prefer when: agent is mid-\`leadbay_extend_my_lens\` flow and needs to pick seeds before calling \`leadbay_extend_lens\`
7499
+
7500
+ Examples that SHOULD invoke this tool:
7501
+ - "(agent-internal) user asked for more leads \u2014 fetch seeds before calling extend_lens"
7502
+
7503
+ Examples that should NOT invoke this tool (sound similar, route elsewhere):
7504
+ - "Show me today's leads."
7505
+ - "Restrict the audience to fintech only."
7506
+ - "Which leads should I follow up with this week?"
7507
+
7508
+ ## RENDER (quick)
7509
+
7510
+ DO NOT RENDER TO THE USER. This is internal data the agent reasons over
7511
+ before calling \`leadbay_extend_lens\`. No table, no list of company names,
7512
+ no "here are your candidates". The user asked for more leads; surface the
7513
+ *outcome* of extend_lens, not the picking step.
7514
+
7515
+ ---
7516
+
7517
+ **INTERNAL TOOL \u2014 do not surface candidates to the user.** The user asked for more leads on the lens (a higher daily appetite than the standard fill delivers), not to manually review candidates. This tool exists so the agent can pick seeds *silently*, then chain to \`leadbay_extend_lens\`. Picking is an agent decision; the user only sees the extend confirmation.
7518
+
7519
+ Backed by \`GET /lenses/{lensId}/seed_candidates\`. By construction every lead returned is a valid input to \`extra_refill\` (same eligibility query). Defaults to the user's last-active lens.
7520
+
7521
+ **Pick 3\u20135 seeds that represent the *kind* of leads the user wants more of**, using these signals in priority order:
7522
+
7523
+ 1. **\`engagement\`** (load-bearing) \u2014 \`liked: true\`, \`org_contacts_count > 0\`, and \`prospecting_actions_count > 0\` mean the user (or their team) already validated this lead. These are the strongest signal.
7524
+ 2. **\`qq_answers\`** \u2014 what the AI agent already answered when qualifying this lead. Match candidates whose answers align with the target profile.
7525
+ 3. **\`tags\`** \u2014 purchase-intent alignment, ordered by score (most-relevant first).
7526
+ 4. **\`sector\`, \`size_min\`, \`size_max\`** \u2014 shape similarity to known-good prospects.
7527
+ 5. **\`ai_agent_score\`** \u2014 overall AI fit (0\u201399); null when the lead has not been AI-rescored.
7528
+ 6. **\`description\`** \u2014 short company blurb for the final tie-breaker.
7529
+
7530
+ **Default heuristic** (no explicit user steering): top 3 by engagement (prefer \`liked: true\`; break ties by \`org_contacts_count + prospecting_actions_count\`), then fill to 5 with the top \`ai_agent_score\` rows whose \`tags\` overlap the engagement leaders' tags.
7531
+
7532
+ **Once seeds are picked, call \`leadbay_extend_lens\` immediately with \`seed_lead_ids=[...picked lead_ids]\`.** Do not pause for user approval; the user wants more leads, not a seed-review meeting.
7533
+
7534
+ WHEN TO USE: only as the scaffolding step inside an extend-the-lens flow. The \`leadbay_extend_my_lens\` prompt orchestrates this; agents called this tool by themselves should be rare.
7535
+
7536
+ WHEN NOT TO USE: when the user wants to CHANGE the audience (sector / size / criteria) \u2014 route to \`leadbay_adjust_audience\` or \`leadbay_refine_prompt\`. Not for the daily inbox pull \u2014 route to \`leadbay_pull_leads\`. Never as a "here are some candidates, which do you want?" user-facing surface.
7537
+
7538
+ Response shape (relayed verbatim from the backend): \`{ candidates: [{lead_id, name, description?, sector?, size_min?, size_max?, website?, ai_agent_score?, tags[], qq_answers[], org_lead_status?, engagement: {liked, org_contacts_count, prospecting_actions_count}}] }\`.
7539
+ `;
7392
7540
  var leadbay_select_leads = `Add leads to the user's transient selection (used by selection-scoped bulk operations). Accepts 1-1000 \`leadIds\` per call.
7393
7541
 
7394
7542
  WHEN TO USE: low-level. The user's selection is a per-token global state \u2014 be careful when invoking directly.
@@ -13657,7 +13805,7 @@ var accountStatus = {
13657
13805
  },
13658
13806
  quota: {
13659
13807
  type: ["object", "null"],
13660
- description: "Per-resource quota state (llm_completion, ai_rescore, web_fetch) across daily/weekly/monthly windows. Null if /quota_status failed (logged in stderr)."
13808
+ description: "Per-resource quota state (llm_completion, ai_rescore, web_fetch, LENS_EXTRA_REFILL) across daily/weekly/monthly windows. Null if /quota_status failed (logged in stderr). Pre-check the LENS_EXTRA_REFILL entry before calling leadbay_extend_lens."
13661
13809
  },
13662
13810
  _meta: {
13663
13811
  type: "object",
@@ -17066,6 +17214,182 @@ var refinePrompt = {
17066
17214
  }
17067
17215
  };
17068
17216
 
17217
+ // ../core/dist/composite/seed-candidates.js
17218
+ var seedCandidates = {
17219
+ name: "leadbay_seed_candidates",
17220
+ annotations: {
17221
+ title: "List candidate seeds for a lens extra-refill",
17222
+ readOnlyHint: true,
17223
+ destructiveHint: false,
17224
+ idempotentHint: true,
17225
+ openWorldHint: true
17226
+ },
17227
+ description: leadbay_seed_candidates,
17228
+ inputSchema: {
17229
+ type: "object",
17230
+ properties: {
17231
+ lensId: {
17232
+ type: "number",
17233
+ description: "Lens to fetch candidates for. Defaults to the user's last-active lens."
17234
+ },
17235
+ limit: {
17236
+ type: "number",
17237
+ description: "Max candidates to return, 1\u201350 (backend default 20)."
17238
+ }
17239
+ },
17240
+ additionalProperties: false
17241
+ },
17242
+ outputSchema: {
17243
+ type: "object",
17244
+ properties: {
17245
+ lens: {
17246
+ type: "object",
17247
+ properties: { id: { type: "number" } }
17248
+ },
17249
+ candidates: {
17250
+ type: "array",
17251
+ description: "Ranked candidate leads \u2014 each is a valid seed for leadbay_extend_lens. Pick 3\u20135 that represent the kind of leads the user wants more of.",
17252
+ items: { type: "object" }
17253
+ }
17254
+ },
17255
+ required: ["lens", "candidates"]
17256
+ },
17257
+ execute: async (client, params) => {
17258
+ const lensId = params.lensId ?? await client.resolveDefaultLens();
17259
+ const limit = params.limit != null ? Math.max(1, Math.min(params.limit, 50)) : 20;
17260
+ const res = await client.request("GET", `/lenses/${lensId}/seed_candidates?limit=${limit}`);
17261
+ return {
17262
+ lens: { id: lensId },
17263
+ candidates: res.candidates
17264
+ };
17265
+ }
17266
+ };
17267
+
17268
+ // ../core/dist/composite/extend-lens.js
17269
+ function httpStatus(err) {
17270
+ return err?._meta?.http_status;
17271
+ }
17272
+ async function readExtraRefillQuota(client) {
17273
+ try {
17274
+ const me = await client.resolveMe();
17275
+ const quota = await client.request("GET", `/organizations/${me.organization.id}/quota_status`);
17276
+ const entry = quota.org?.resources?.find((r) => r.resource_type === "LENS_EXTRA_REFILL");
17277
+ return {
17278
+ count: entry?.count ?? null,
17279
+ resets_at: entry?.resets_at ?? null
17280
+ };
17281
+ } catch {
17282
+ return { count: null, resets_at: null };
17283
+ }
17284
+ }
17285
+ var extendLens = {
17286
+ name: "leadbay_extend_lens",
17287
+ annotations: {
17288
+ title: "Extend a lens with additional leads (extra refill)",
17289
+ readOnlyHint: false,
17290
+ destructiveHint: false,
17291
+ idempotentHint: false,
17292
+ openWorldHint: true
17293
+ },
17294
+ description: leadbay_extend_lens,
17295
+ optional: true,
17296
+ // gated behind LEADBAY_MCP_WRITE=1 in MCP
17297
+ inputSchema: {
17298
+ type: "object",
17299
+ properties: {
17300
+ lensId: {
17301
+ type: "number",
17302
+ description: "Lens to extend. Defaults to the user's last-active lens."
17303
+ },
17304
+ seed_lead_ids: {
17305
+ type: "array",
17306
+ description: "Optional list of lead UUIDs from leadbay_seed_candidates to bias the recommender. Omit or empty array \u2192 default-strategy fallback (same behaviour as a normal fill).",
17307
+ items: { type: "string" }
17308
+ },
17309
+ extra_count: {
17310
+ type: "number",
17311
+ description: "How many extra leads to request. Omit to use the backend default. The full requested count must fit into the remaining daily LENS_EXTRA_REFILL quota \u2014 otherwise the call is rejected outright (status: quota_exceeded)."
17312
+ }
17313
+ },
17314
+ additionalProperties: false
17315
+ },
17316
+ outputSchema: {
17317
+ type: "object",
17318
+ properties: {
17319
+ status: {
17320
+ type: "string",
17321
+ description: "queued | quota_exceeded | refresh_in_progress | no_valid_seeds"
17322
+ },
17323
+ lens: {
17324
+ type: "object",
17325
+ properties: { id: { type: "number" } }
17326
+ },
17327
+ accepted_seeds: {
17328
+ type: "array",
17329
+ description: "Subset of seed_lead_ids that passed validation and will bias the fill. Empty when no seeds were submitted (default-strategies fallback). Present only on status=queued.",
17330
+ items: { type: "string" }
17331
+ },
17332
+ message: {
17333
+ type: "string",
17334
+ description: "Human-readable summary. On error statuses, this is the line to surface to the user."
17335
+ },
17336
+ quota: {
17337
+ type: "object",
17338
+ description: "Only present on status=quota_exceeded. Shows the org's daily LENS_EXTRA_REFILL state.",
17339
+ properties: {
17340
+ used_today: { type: ["number", "null"] },
17341
+ resets_at: { type: ["string", "null"] }
17342
+ }
17343
+ }
17344
+ },
17345
+ required: ["status", "lens"]
17346
+ },
17347
+ execute: async (client, params) => {
17348
+ const lensId = params.lensId ?? await client.resolveDefaultLens();
17349
+ const body = {
17350
+ seed_lead_ids: params.seed_lead_ids ?? []
17351
+ };
17352
+ if (params.extra_count != null) {
17353
+ body.extra_count = params.extra_count;
17354
+ }
17355
+ try {
17356
+ const res = await client.request("POST", `/lenses/${lensId}/extra_refill`, body);
17357
+ return {
17358
+ status: "queued",
17359
+ lens: { id: lensId },
17360
+ accepted_seeds: res.accepted_seeds,
17361
+ message: "Extra refill queued. Leads stream in asynchronously \u2014 call leadbay_pull_leads in ~30s to see them."
17362
+ };
17363
+ } catch (err) {
17364
+ const status = httpStatus(err);
17365
+ if (status === 429) {
17366
+ const q = await readExtraRefillQuota(client);
17367
+ return {
17368
+ status: "quota_exceeded",
17369
+ lens: { id: lensId },
17370
+ quota: { used_today: q.count, resets_at: q.resets_at },
17371
+ message: "Daily LENS_EXTRA_REFILL quota exhausted. Surface to user: (1) try a smaller extra_count, (2) wait for the daily reset" + (q.resets_at ? ` (resets at ${q.resets_at})` : "") + ", or (3) upgrade plan for a higher daily limit (TIER1=150, TIER2=1000)."
17372
+ };
17373
+ }
17374
+ if (status === 409) {
17375
+ return {
17376
+ status: "refresh_in_progress",
17377
+ lens: { id: lensId },
17378
+ message: "A refresh or extra-refill is already running on this lens. Wait, then call leadbay_pull_leads in ~30s."
17379
+ };
17380
+ }
17381
+ if (status === 400) {
17382
+ return {
17383
+ status: "no_valid_seeds",
17384
+ lens: { id: lensId },
17385
+ message: "Every submitted seed failed validation (likely stale \u2014 the lens shape may have changed). Refetch via leadbay_seed_candidates and retry."
17386
+ };
17387
+ }
17388
+ throw err;
17389
+ }
17390
+ }
17391
+ };
17392
+
17069
17393
  // ../core/dist/composite/answer-clarification.js
17070
17394
  var answerClarification = {
17071
17395
  name: "leadbay_answer_clarification",
@@ -17649,6 +17973,9 @@ var compositeReadTools = [
17649
17973
  qualifyStatus,
17650
17974
  importStatus,
17651
17975
  resolveImportRows,
17976
+ // seed-candidates is a read-only discovery surface for the extend flow.
17977
+ // Always exposed so the agent can show candidates even in read-only deployments.
17978
+ seedCandidates,
17652
17979
  // listMappableFields is granular-shaped but the import composites depend on
17653
17980
  // it for discoverability; expose it always-on so agents can find custom fields
17654
17981
  // without needing LEADBAY_MCP_ADVANCED=1.
@@ -17692,7 +18019,10 @@ var compositeWriteTools = [
17692
18019
  // Backend POST endpoints; gated behind LEADBAY_MCP_WRITE=1 in MCP.
17693
18020
  createCampaign,
17694
18021
  addLeadsToCampaign,
17695
- removeLeadsFromCampaign
18022
+ removeLeadsFromCampaign,
18023
+ // Lens extend — agent-driven on-demand fill (additive). Gated behind
18024
+ // LEADBAY_MCP_WRITE=1. Subject to per-org daily LENS_EXTRA_REFILL quota.
18025
+ extendLens
17696
18026
  ];
17697
18027
  var compositeTools = [
17698
18028
  ...compositeReadTools,
@@ -17815,6 +18145,8 @@ export {
17815
18145
  bulkEnrichStatus,
17816
18146
  adjustAudience,
17817
18147
  refinePrompt,
18148
+ seedCandidates,
18149
+ extendLens,
17818
18150
  answerClarification,
17819
18151
  reportOutreach,
17820
18152
  reportFriction,
@@ -50,6 +50,7 @@ import {
50
50
  enrichContacts,
51
51
  enrichTitles,
52
52
  ensureAgentMemorySummary,
53
+ extendLens,
53
54
  followupsMap,
54
55
  formatLoginError,
55
56
  getClarification,
@@ -115,6 +116,7 @@ import {
115
116
  resolveAgentMemorySummary,
116
117
  resolveImportRows,
117
118
  resolveRegion,
119
+ seedCandidates,
118
120
  selectLeads,
119
121
  setActiveLens,
120
122
  setEpilogueStatus,
@@ -125,7 +127,7 @@ import {
125
127
  updateLens,
126
128
  updateLensFilter,
127
129
  withAgentMemoryMeta
128
- } from "./chunk-3V3EPBLZ.js";
130
+ } from "./chunk-ASAKITU3.js";
129
131
  export {
130
132
  AgentMemoryCaptureInputSchema,
131
133
  AgentMemoryEntrySchema,
@@ -177,6 +179,7 @@ export {
177
179
  enrichContacts,
178
180
  enrichTitles,
179
181
  ensureAgentMemorySummary,
182
+ extendLens,
180
183
  followupsMap,
181
184
  formatLoginError,
182
185
  getClarification,
@@ -242,6 +245,7 @@ export {
242
245
  resolveAgentMemorySummary,
243
246
  resolveImportRows,
244
247
  resolveRegion,
248
+ seedCandidates,
245
249
  selectLeads,
246
250
  setActiveLens,
247
251
  setEpilogueStatus,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leadbay/mcp",
3
- "version": "0.16.2",
3
+ "version": "0.17.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",