@leadbay/mcp 0.29.0 → 0.31.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 +98 -0
- package/README.md +3 -4
- package/dist/bin.js +1930 -218
- package/dist/http-server.js +2010 -262
- 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,103 @@
|
|
|
1
1
|
# Changelog — @leadbay/mcp
|
|
2
2
|
|
|
3
|
+
## 0.30.0 — 2026-08-19
|
|
4
|
+
|
|
5
|
+
Encode the **single-country rule** across every location-accepting surface
|
|
6
|
+
(product#3951). Each backend serves exactly ONE country, so a country name is
|
|
7
|
+
never a location criterion — whole-country intent means omitting the filter.
|
|
8
|
+
It never failed loudly: the admin-area index excludes country nodes
|
|
9
|
+
(product#3885), so the value trigram-matched a same-named town ("France" → the
|
|
10
|
+
commune of Francs, "United States" → Statesboro) and silently fenced the search
|
|
11
|
+
to one village. 3/3 sessions in the 2026-08-02 acceptance eval passed one; an FR
|
|
12
|
+
session burned six variants inside that fence before answering wrongly.
|
|
13
|
+
|
|
14
|
+
- **The descriptions were telling the agent to do it.** This was a
|
|
15
|
+
contradiction sweep, not a missing rule. `followups-map.md.tmpl:47` said to
|
|
16
|
+
pass `countries ("France", "United States")` and advertised
|
|
17
|
+
`level 2 (country)` as searchable; `pull-followups`, `adjust-audience`,
|
|
18
|
+
`new-lens`, `tour-plan` and the `leadbay_followup_check_in` prompt each
|
|
19
|
+
legitimized country-level values. All rewritten to enumerate the levels the
|
|
20
|
+
argument accepts. (Their `"Bavaria"` examples went too — a German region on a
|
|
21
|
+
US/FR-only product.)
|
|
22
|
+
- **New shared snippet** `heuristics/single-country-universe.md`, included by 8
|
|
23
|
+
tool descriptions and 5 prompts, carrying the rule, the measured failure and
|
|
24
|
+
a recovery that branches — because one recovery is wrong for most cases.
|
|
25
|
+
`country_locations[].axis` and `[].kind` decide it: only the HOME country on
|
|
26
|
+
the INCLUDE axis means "omit the argument". A foreign country is unsupported,
|
|
27
|
+
not unfiltered (re-running unfiltered answers a France question with US
|
|
28
|
+
leads). On the EXCLUDE axis omitting is the inverse of the request. And when
|
|
29
|
+
the argument carries a real place beside the country, only the country comes
|
|
30
|
+
off — "keep the city, drop the country".
|
|
31
|
+
- **Mechanical rejection** in `_country-guard.ts` + `_country-names.ts` (full
|
|
32
|
+
ISO 3166-1, English + French, no new dependency). Delivered in each tool's own
|
|
33
|
+
idiom: composites return `status: "country_level_location"` and write nothing,
|
|
34
|
+
`update_lens_filter` throws (including on `dry_run`), `list_locations` returns
|
|
35
|
+
its empty envelope. Always the first statement of `execute`, so a bad value
|
|
36
|
+
costs zero HTTP.
|
|
37
|
+
- **Exemptions that keep real prospecting working:** a `sovereign` field
|
|
38
|
+
(Guadeloupe/Martinique/Réunion/Guyane valid on FR, Puerto Rico/Guam on US),
|
|
39
|
+
region homonyms (Georgia the state, Jersey), and no foreign alpha-2 rejection
|
|
40
|
+
on US, where 26 ISO codes double as state postal codes. Test sweeps over all
|
|
41
|
+
50 states + postal codes and all 13 régions + 101 départements hold the line.
|
|
42
|
+
- **New audit** `test/audit/single-country-rule.test.ts` — asserts the rule is
|
|
43
|
+
present in all 11 surfaces AND that none of them still says a country is a
|
|
44
|
+
valid geo value, so the pre-fix state is unmergeable. It imports
|
|
45
|
+
`COUNTRY_LEVEL_LOCATION` from core so a rename cannot leave the prose
|
|
46
|
+
teaching a recovery for an error that no longer exists.
|
|
47
|
+
- **`WORKFLOWS.md`**: row 39 gains the country-is-not-a-territory rule and a
|
|
48
|
+
success criterion; new row 52 "Country-wide scope — omit the location filter"
|
|
49
|
+
with its contract.
|
|
50
|
+
- **Writes stop rather than retry.** On `new_lens` / `adjust_audience` /
|
|
51
|
+
`update_lens_filter`, "drop the country and re-call" persists a lens change
|
|
52
|
+
expressing a scope the workspace already has — the mutation WORKFLOWS.md
|
|
53
|
+
forbids for this ask. The guard stops instead, but only when the country was
|
|
54
|
+
the request's ONLY scope: a sector, a size or a real place elsewhere in the
|
|
55
|
+
request is written as asked. An exclusion that is not a foreign country
|
|
56
|
+
blocks the write outright whatever else survives, since dropping it persists
|
|
57
|
+
the opposite of what was asked.
|
|
58
|
+
- **The country is read, never inferred.** `_meta.region` is the only evidence
|
|
59
|
+
of which country a workspace serves; the user's wording is not, and
|
|
60
|
+
`agent_memory_capture` must never store it — a wrong country there is
|
|
61
|
+
replayed as remembered fact.
|
|
62
|
+
- **Two eval scenarios** under `test/eval/scenarios/country-scope/` (over- and
|
|
63
|
+
under-deliver). Gated behind `EVAL=1`; CI protection is the audit. Run live
|
|
64
|
+
on FR and US staging tenants: no country value reached a geo argument on any
|
|
65
|
+
call, no lens was written, no country was captured to memory, and the country
|
|
66
|
+
named in each answer traced to `_meta.region`.
|
|
67
|
+
- Freed the budget for the snippet by de-padding the `pull-followups` NEXT
|
|
68
|
+
STEPS table (1109 chars of markdown column alignment, no content change) —
|
|
69
|
+
that tool was 52 chars from the 17000 cap.
|
|
70
|
+
- **Closed four holes found reviewing the above.** (1) The wrapper list caught
|
|
71
|
+
"across the United States" and "dans toute la France" but not the bare
|
|
72
|
+
prepositions that carry most real traffic — `in the United States`,
|
|
73
|
+
`en France`, `aux États-Unis`, `dans la France` — so the plainest spelling of
|
|
74
|
+
the bug was the one that still reached `/geo/search`. (2) `EU` and
|
|
75
|
+
`European Union` were covered while **`UE` / `Union européenne`** were not, on
|
|
76
|
+
the one backend whose users write French; the French supra-national spellings
|
|
77
|
+
are in now. (3) A `set_filter` carrying a country BESIDE a real criterion
|
|
78
|
+
emitted one hint that said both "say the result covers everything" and "never
|
|
79
|
+
as covering everything" — the `otherScope` flag was consulted only for writes,
|
|
80
|
+
and both read call sites hardcoded `false` while computing the true value one
|
|
81
|
+
line above. The hint and its sibling caveat now derive from one fact.
|
|
82
|
+
(4) `leadbay_top_accounts_to_activate` rendered with `territory: "France"`
|
|
83
|
+
opened with "pass it as `locations` on the lens" — an instruction to make the
|
|
84
|
+
exact call the rest of the prompt forbids, ~35 lines above the branch that
|
|
85
|
+
would have corrected it. The substituted sentence now carries the country
|
|
86
|
+
caveat itself. The existing audit could not see any of this: it reads the
|
|
87
|
+
UNRENDERED body, where that sentence is still `{{arg:territory_block}}`, so
|
|
88
|
+
`test/audit/prompt-rendered-country-args.test.ts` renders each prompt with
|
|
89
|
+
hostile arguments instead.
|
|
90
|
+
- The shared snippet documented a weaker rule than the code enforces: it named
|
|
91
|
+
the write-stop for a country-only scope and for non-foreign exclusions, but
|
|
92
|
+
not for a **foreign / supra-national INCLUDE carrying other criteria**, which
|
|
93
|
+
the guard does stop. An agent following the snippet could pre-strip the
|
|
94
|
+
country and save a home-country lens for a territory nobody asked about,
|
|
95
|
+
never reaching the guard at all.
|
|
96
|
+
|
|
97
|
+
Known gap: a country passed as an already-resolved numeric admin-area id stays
|
|
98
|
+
invisible client-side (deciding whether id "1234" is a country needs a lookup
|
|
99
|
+
this client does not have). Tracked in product#3939; a test records it.
|
|
100
|
+
|
|
3
101
|
## 0.28.0 — 2026-07-31
|
|
4
102
|
|
|
5
103
|
Add **`leadbay_top_accounts_to_activate`** — a prompt that builds a ranked
|
package/README.md
CHANGED
|
@@ -280,11 +280,10 @@ Leadbay connection OK.
|
|
|
280
280
|
|
|
281
281
|
### Claude Desktop / ChatGPT / remote-MCP clients
|
|
282
282
|
|
|
283
|
-
Leadbay runs a hosted MCP server that any remote-MCP client can connect to without a local install.
|
|
283
|
+
Leadbay runs a hosted MCP server that any remote-MCP client can connect to without a local install. One URL works for every region:
|
|
284
284
|
|
|
285
285
|
```
|
|
286
|
-
https://mcp.leadbay.app/mcp # US
|
|
287
|
-
https://mcp.leadbay.app/fr/mcp # FR accounts
|
|
286
|
+
https://mcp.leadbay.app/mcp # all accounts (US and FR)
|
|
288
287
|
```
|
|
289
288
|
|
|
290
289
|
- **Claude Desktop**: Settings → Connectors → Add custom connector → paste the URL.
|
|
@@ -292,7 +291,7 @@ https://mcp.leadbay.app/fr/mcp # FR accounts
|
|
|
292
291
|
|
|
293
292
|
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.
|
|
294
293
|
|
|
295
|
-
|
|
294
|
+
You don't pick a region. Sign-in goes through Stargate, Leadbay's single region-agnostic OAuth authority, and your region rides in the token itself rather than in the connector path — so `/mcp` resolves US and FR accounts alike. `/fr/mcp` still works as a compatibility alias for connectors configured before this change; there is no need to migrate and no benefit to using it. 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.
|
|
296
295
|
|
|
297
296
|
**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.
|
|
298
297
|
|