@yawlabs/mcph 0.30.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 +4 -0
- package/dist/index.js +72 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@yawlabs/mcph` are documented here. This project uses [semantic versioning](https://semver.org) and a CI-gated release flow: pushing a `vX.Y.Z` tag triggers `.github/workflows/release.yml`, which publishes to npm.
|
|
4
4
|
|
|
5
|
+
## 0.31.0 — 2026-04-18
|
|
6
|
+
|
|
7
|
+
- **"Did you mean?" suggestions on `mcp_connect_activate`** — When a caller tries to activate a namespace that doesn't exist, the error message now splits the two underlying cases: (a) not installed at all (with up to 3 fuzzy-matched installed namespaces via substring containment or ≤2 edit distance, or a pointer to `mcp_connect_discover` when nothing is close), and (b) installed but disabled in the dashboard (with a pointer to `mcp.hosting` to enable). Replaces the previous conflated "`X` not found or disabled" message.
|
|
8
|
+
|
|
5
9
|
## 0.30.0 — 2026-04-18
|
|
6
10
|
|
|
7
11
|
- **Inline bundle completions in `discover()`** — When a curated bundle has some installed servers but is missing one or two, `mcp_connect_discover` surfaces a "Bundle completions" block with the partial bundle id, what's already installed, and what to add. Top 3 entries, ranked by fewest-missing first (cheapest to complete), tie-broken by most-momentum then id. Same data source as `mcp_connect_bundles action="match"`, but inline so the model can act on the nudge without the extra round-trip. Suppressed when no curated bundle has any overlap with the installed set.
|
package/dist/index.js
CHANGED
|
@@ -946,7 +946,7 @@ function errorMessage(err) {
|
|
|
946
946
|
}
|
|
947
947
|
|
|
948
948
|
// src/doctor-cmd.ts
|
|
949
|
-
var VERSION = true ? "0.
|
|
949
|
+
var VERSION = true ? "0.31.0" : "dev";
|
|
950
950
|
async function runDoctor(opts = {}) {
|
|
951
951
|
const lines = [];
|
|
952
952
|
const write = opts.out ?? ((s) => process.stdout.write(s));
|
|
@@ -2135,6 +2135,60 @@ function stepBindingKey(step, index) {
|
|
|
2135
2135
|
return typeof step.id === "string" && step.id.length > 0 ? step.id : String(index);
|
|
2136
2136
|
}
|
|
2137
2137
|
|
|
2138
|
+
// src/fuzzy.ts
|
|
2139
|
+
function levenshtein(a, b) {
|
|
2140
|
+
if (a === b) return 0;
|
|
2141
|
+
const aLen = a.length;
|
|
2142
|
+
const bLen = b.length;
|
|
2143
|
+
if (aLen === 0) return bLen;
|
|
2144
|
+
if (bLen === 0) return aLen;
|
|
2145
|
+
let prev = new Array(bLen + 1);
|
|
2146
|
+
let curr = new Array(bLen + 1);
|
|
2147
|
+
for (let j = 0; j <= bLen; j++) prev[j] = j;
|
|
2148
|
+
for (let i = 1; i <= aLen; i++) {
|
|
2149
|
+
curr[0] = i;
|
|
2150
|
+
for (let j = 1; j <= bLen; j++) {
|
|
2151
|
+
const cost = a.charCodeAt(i - 1) === b.charCodeAt(j - 1) ? 0 : 1;
|
|
2152
|
+
curr[j] = Math.min(
|
|
2153
|
+
curr[j - 1] + 1,
|
|
2154
|
+
// insertion
|
|
2155
|
+
prev[j] + 1,
|
|
2156
|
+
// deletion
|
|
2157
|
+
prev[j - 1] + cost
|
|
2158
|
+
// substitution
|
|
2159
|
+
);
|
|
2160
|
+
}
|
|
2161
|
+
[prev, curr] = [curr, prev];
|
|
2162
|
+
}
|
|
2163
|
+
return prev[bLen];
|
|
2164
|
+
}
|
|
2165
|
+
function closestNames(query, candidates, limit) {
|
|
2166
|
+
if (limit <= 0) return [];
|
|
2167
|
+
const q = query.toLowerCase();
|
|
2168
|
+
const scored = [];
|
|
2169
|
+
for (const c of candidates) {
|
|
2170
|
+
if (c === query) continue;
|
|
2171
|
+
const lc = c.toLowerCase();
|
|
2172
|
+
let score = null;
|
|
2173
|
+
if (lc === q) {
|
|
2174
|
+
score = 0;
|
|
2175
|
+
} else if (lc.startsWith(q) || q.startsWith(lc)) {
|
|
2176
|
+
score = 1;
|
|
2177
|
+
} else if (lc.includes(q) || q.includes(lc)) {
|
|
2178
|
+
score = 2;
|
|
2179
|
+
} else {
|
|
2180
|
+
const d = levenshtein(q, lc);
|
|
2181
|
+
if (d <= 2) score = 2 + d;
|
|
2182
|
+
}
|
|
2183
|
+
if (score !== null) scored.push({ name: c, score });
|
|
2184
|
+
}
|
|
2185
|
+
scored.sort((a, b) => {
|
|
2186
|
+
if (a.score !== b.score) return a.score - b.score;
|
|
2187
|
+
return a.name.localeCompare(b.name);
|
|
2188
|
+
});
|
|
2189
|
+
return scored.slice(0, limit).map((s) => s.name);
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2138
2192
|
// src/guide.ts
|
|
2139
2193
|
import { readFile as readFile5 } from "fs/promises";
|
|
2140
2194
|
var GUIDE_READ_TIMEOUT_MS = 1e3;
|
|
@@ -3836,7 +3890,7 @@ function categorizeSpawnError(err) {
|
|
|
3836
3890
|
}
|
|
3837
3891
|
async function connectToUpstream(config, onDisconnect, onListChanged) {
|
|
3838
3892
|
const client = new Client(
|
|
3839
|
-
{ name: "mcph", version: true ? "0.
|
|
3893
|
+
{ name: "mcph", version: true ? "0.31.0" : "dev" },
|
|
3840
3894
|
{ capabilities: {} }
|
|
3841
3895
|
);
|
|
3842
3896
|
let transport;
|
|
@@ -4353,7 +4407,7 @@ var ConnectServer = class _ConnectServer {
|
|
|
4353
4407
|
this.apiUrl = apiUrl6;
|
|
4354
4408
|
this.token = token6;
|
|
4355
4409
|
this.server = new Server(
|
|
4356
|
-
{ name: "mcph", version: true ? "0.
|
|
4410
|
+
{ name: "mcph", version: true ? "0.31.0" : "dev" },
|
|
4357
4411
|
{
|
|
4358
4412
|
capabilities: {
|
|
4359
4413
|
tools: { listChanged: true },
|
|
@@ -5320,10 +5374,21 @@ ${activeCount} loaded in this session, ${totalTools} tools in context${tokenSumm
|
|
|
5320
5374
|
serverId: existing.config.id
|
|
5321
5375
|
};
|
|
5322
5376
|
}
|
|
5323
|
-
const
|
|
5324
|
-
if (!
|
|
5325
|
-
|
|
5377
|
+
const anyMatch = this.config?.servers.find((s) => s.namespace === namespace);
|
|
5378
|
+
if (!anyMatch) {
|
|
5379
|
+
const allNamespaces = this.config?.servers.map((s) => s.namespace) ?? [];
|
|
5380
|
+
const suggestions = closestNames(namespace, allNamespaces, 3);
|
|
5381
|
+
const hint = suggestions.length > 0 ? ` Did you mean: ${suggestions.join(", ")}?` : " Use mcp_connect_discover to see installed servers.";
|
|
5382
|
+
return { ok: false, isChanged: false, message: `"${namespace}" is not installed.${hint}` };
|
|
5383
|
+
}
|
|
5384
|
+
if (!anyMatch.isActive) {
|
|
5385
|
+
return {
|
|
5386
|
+
ok: false,
|
|
5387
|
+
isChanged: false,
|
|
5388
|
+
message: `"${namespace}" is installed but disabled. Enable it at https://mcp.hosting to activate.`
|
|
5389
|
+
};
|
|
5326
5390
|
}
|
|
5391
|
+
const serverConfig = anyMatch;
|
|
5327
5392
|
if (!profileAllows(this.profile, namespace)) {
|
|
5328
5393
|
return {
|
|
5329
5394
|
ok: false,
|
|
@@ -6422,7 +6487,7 @@ ${installBlock}
|
|
|
6422
6487
|
);
|
|
6423
6488
|
process.exit(0);
|
|
6424
6489
|
} else if (subcommand === "--version" || subcommand === "-V") {
|
|
6425
|
-
process.stdout.write(`mcph ${true ? "0.
|
|
6490
|
+
process.stdout.write(`mcph ${true ? "0.31.0" : "dev"}
|
|
6426
6491
|
`);
|
|
6427
6492
|
process.exit(0);
|
|
6428
6493
|
} else {
|
package/package.json
CHANGED