mcp-squared 0.4.0 → 0.6.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/README.md +53 -21
- package/dist/index.js +1298 -467
- package/dist/tui/config.js +374 -22
- package/package.json +7 -3
package/dist/tui/config.js
CHANGED
|
@@ -123,6 +123,274 @@ function ensureConfigDir(configPath) {
|
|
|
123
123
|
var SOCKET_FILENAME = "mcp-squared.sock", INSTANCE_DIR_NAME = "instances", SOCKET_DIR_NAME = "sockets", DAEMON_DIR_NAME = "daemon", DAEMON_REGISTRY_FILENAME = "daemon.json", DAEMON_SOCKET_FILENAME = "daemon.sock", CONFIG_FILENAME = "mcp-squared.toml", CONFIG_DIR_NAME = ".mcp-squared", APP_NAME = "mcp-squared";
|
|
124
124
|
var init_paths = () => {};
|
|
125
125
|
|
|
126
|
+
// src/capabilities/inference.ts
|
|
127
|
+
function createEmptyScores() {
|
|
128
|
+
return CAPABILITY_IDS.reduce((acc, capability) => {
|
|
129
|
+
acc[capability] = 0;
|
|
130
|
+
return acc;
|
|
131
|
+
}, {});
|
|
132
|
+
}
|
|
133
|
+
function extractSchemaSignal(schema) {
|
|
134
|
+
if (!schema || schema.type !== "object") {
|
|
135
|
+
return "";
|
|
136
|
+
}
|
|
137
|
+
const keys = Object.keys(schema.properties ?? {});
|
|
138
|
+
const required = schema.required ?? [];
|
|
139
|
+
return `${keys.join(" ")} ${required.join(" ")}`;
|
|
140
|
+
}
|
|
141
|
+
function scoreTextSignals(scores, text) {
|
|
142
|
+
for (const capability of CAPABILITY_IDS) {
|
|
143
|
+
for (const pattern of CAPABILITY_PATTERNS[capability]) {
|
|
144
|
+
if (pattern.test(text)) {
|
|
145
|
+
scores[capability] += 4;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function getHighestScoringCapability(scores) {
|
|
151
|
+
const bestScore = Math.max(...Object.values(scores));
|
|
152
|
+
if (bestScore <= 0) {
|
|
153
|
+
return "general";
|
|
154
|
+
}
|
|
155
|
+
for (const capability of CAPABILITY_PRIORITY) {
|
|
156
|
+
if (scores[capability] === bestScore) {
|
|
157
|
+
return capability;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return "general";
|
|
161
|
+
}
|
|
162
|
+
function inferNamespaceCapability(namespace, tools, capabilityOverrides = {}) {
|
|
163
|
+
const override = capabilityOverrides[namespace];
|
|
164
|
+
if (override) {
|
|
165
|
+
return override;
|
|
166
|
+
}
|
|
167
|
+
const scores = createEmptyScores();
|
|
168
|
+
const namespaceText = namespace.toLowerCase();
|
|
169
|
+
for (const hint of NAMESPACE_HINTS) {
|
|
170
|
+
if (hint.pattern.test(namespaceText)) {
|
|
171
|
+
scores[hint.capability] += hint.score;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
for (const tool of tools) {
|
|
175
|
+
const signal = [
|
|
176
|
+
tool.name,
|
|
177
|
+
tool.description ?? "",
|
|
178
|
+
extractSchemaSignal(tool.inputSchema)
|
|
179
|
+
].join(" ").toLowerCase();
|
|
180
|
+
scoreTextSignals(scores, signal);
|
|
181
|
+
}
|
|
182
|
+
return getHighestScoringCapability(scores);
|
|
183
|
+
}
|
|
184
|
+
function groupNamespacesByCapability(inventories, capabilityOverrides = {}) {
|
|
185
|
+
const grouped = CAPABILITY_IDS.reduce((acc, capability) => {
|
|
186
|
+
acc[capability] = [];
|
|
187
|
+
return acc;
|
|
188
|
+
}, {});
|
|
189
|
+
const byNamespace = {};
|
|
190
|
+
const sorted = [...inventories].sort((a, b) => a.namespace.localeCompare(b.namespace));
|
|
191
|
+
for (const inventory of sorted) {
|
|
192
|
+
const capability = inferNamespaceCapability(inventory.namespace, inventory.tools, capabilityOverrides);
|
|
193
|
+
byNamespace[inventory.namespace] = capability;
|
|
194
|
+
grouped[capability].push(inventory.namespace);
|
|
195
|
+
}
|
|
196
|
+
return { byNamespace, grouped };
|
|
197
|
+
}
|
|
198
|
+
var CAPABILITY_IDS, CAPABILITY_PRIORITY, NAMESPACE_HINTS, CAPABILITY_PATTERNS;
|
|
199
|
+
var init_inference = __esm(() => {
|
|
200
|
+
CAPABILITY_IDS = [
|
|
201
|
+
"code_search",
|
|
202
|
+
"docs",
|
|
203
|
+
"browser_automation",
|
|
204
|
+
"issue_tracking",
|
|
205
|
+
"cms_content",
|
|
206
|
+
"design",
|
|
207
|
+
"ai_media_generation",
|
|
208
|
+
"hosting_deploy",
|
|
209
|
+
"time_util",
|
|
210
|
+
"research",
|
|
211
|
+
"general"
|
|
212
|
+
];
|
|
213
|
+
CAPABILITY_PRIORITY = [
|
|
214
|
+
"code_search",
|
|
215
|
+
"docs",
|
|
216
|
+
"browser_automation",
|
|
217
|
+
"issue_tracking",
|
|
218
|
+
"cms_content",
|
|
219
|
+
"design",
|
|
220
|
+
"ai_media_generation",
|
|
221
|
+
"hosting_deploy",
|
|
222
|
+
"time_util",
|
|
223
|
+
"research",
|
|
224
|
+
"general"
|
|
225
|
+
];
|
|
226
|
+
NAMESPACE_HINTS = [
|
|
227
|
+
{
|
|
228
|
+
capability: "code_search",
|
|
229
|
+
pattern: /(auggie|augment|ctxdb|code|source|repo|symbol|search)/i,
|
|
230
|
+
score: 24
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
capability: "docs",
|
|
234
|
+
pattern: /(context7|ref|docs?|documentation|shadcn)/i,
|
|
235
|
+
score: 18
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
capability: "browser_automation",
|
|
239
|
+
pattern: /(chrome|devtools|browser|playwright|puppeteer|webdriver)/i,
|
|
240
|
+
score: 24
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
capability: "issue_tracking",
|
|
244
|
+
pattern: /(linear|jira|issue|ticket|project|milestone)/i,
|
|
245
|
+
score: 20
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
capability: "cms_content",
|
|
249
|
+
pattern: /(sanity|content|cms|dataset|schema|studio)/i,
|
|
250
|
+
score: 20
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
capability: "design",
|
|
254
|
+
pattern: /(pencil|figma|ui|design|artifact|visual)/i,
|
|
255
|
+
score: 20
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
capability: "hosting_deploy",
|
|
259
|
+
pattern: /(vercel|host|hosting|domain|dns|vps|deploy|infra)/i,
|
|
260
|
+
score: 22
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
capability: "time_util",
|
|
264
|
+
pattern: /(time|timezone|clock|date|utc)/i,
|
|
265
|
+
score: 22
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
capability: "ai_media_generation",
|
|
269
|
+
pattern: /(wavespeed|stability|replicate|midjourney|dall.?e|runway|imagen|flux|fal\.ai|dreamstudio)/i,
|
|
270
|
+
score: 24
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
capability: "research",
|
|
274
|
+
pattern: /(exa|perplexity|firecrawl|crawl|scrape|research|search)/i,
|
|
275
|
+
score: 16
|
|
276
|
+
}
|
|
277
|
+
];
|
|
278
|
+
CAPABILITY_PATTERNS = {
|
|
279
|
+
code_search: [
|
|
280
|
+
/\bcodebase\b/i,
|
|
281
|
+
/\bsource\b/i,
|
|
282
|
+
/\brepo(?:sitory)?\b/i,
|
|
283
|
+
/\bsymbol(?:s)?\b/i,
|
|
284
|
+
/\bdefinition(?:s)?\b/i,
|
|
285
|
+
/\breference(?:s)?\b/i,
|
|
286
|
+
/\busage(?:s)?\b/i,
|
|
287
|
+
/\bsearch_context\b/i,
|
|
288
|
+
/\bcodebase-retrieval\b/i,
|
|
289
|
+
/\bdirectory_path\b/i
|
|
290
|
+
],
|
|
291
|
+
docs: [
|
|
292
|
+
/\bdoc(?:s|umentation)?\b/i,
|
|
293
|
+
/\bread_docs\b/i,
|
|
294
|
+
/\bquery-docs\b/i,
|
|
295
|
+
/\breference\b/i,
|
|
296
|
+
/\bmanual\b/i,
|
|
297
|
+
/\bknowledge\b/i,
|
|
298
|
+
/\bregist(?:ry|ries)\b/i,
|
|
299
|
+
/\bcomponent(?:s)?\b/i,
|
|
300
|
+
/\bexample(?:s)?\b/i
|
|
301
|
+
],
|
|
302
|
+
browser_automation: [
|
|
303
|
+
/\bbrowser\b/i,
|
|
304
|
+
/\bdevtools\b/i,
|
|
305
|
+
/\bnavigate\b/i,
|
|
306
|
+
/\bclick\b/i,
|
|
307
|
+
/\bhover\b/i,
|
|
308
|
+
/\bnetwork\b/i,
|
|
309
|
+
/\bconsole\b/i,
|
|
310
|
+
/\bscreenshot\b/i,
|
|
311
|
+
/\bpage\b/i
|
|
312
|
+
],
|
|
313
|
+
issue_tracking: [
|
|
314
|
+
/\bissue(?:s)?\b/i,
|
|
315
|
+
/\bticket(?:s)?\b/i,
|
|
316
|
+
/\bmilestone(?:s)?\b/i,
|
|
317
|
+
/\bcycle(?:s)?\b/i,
|
|
318
|
+
/\bproject(?:s)?\b/i,
|
|
319
|
+
/\bcomment(?:s)?\b/i,
|
|
320
|
+
/\blinear\b/i
|
|
321
|
+
],
|
|
322
|
+
cms_content: [
|
|
323
|
+
/\bcms\b/i,
|
|
324
|
+
/\bcontent\b/i,
|
|
325
|
+
/\bdocument(?:s)?\b/i,
|
|
326
|
+
/\bdataset(?:s)?\b/i,
|
|
327
|
+
/\bschema\b/i,
|
|
328
|
+
/\bpublish\b/i,
|
|
329
|
+
/\bdraft(?:s)?\b/i,
|
|
330
|
+
/\bsanity\b/i,
|
|
331
|
+
/\bmigration\b/i
|
|
332
|
+
],
|
|
333
|
+
design: [
|
|
334
|
+
/\bdesign\b/i,
|
|
335
|
+
/\bui\b/i,
|
|
336
|
+
/\bartifact\b/i,
|
|
337
|
+
/\bstyle_guide\b/i,
|
|
338
|
+
/\bscreenshot\b/i,
|
|
339
|
+
/\bdiagram\b/i,
|
|
340
|
+
/\bimage\b/i,
|
|
341
|
+
/\blayout\b/i,
|
|
342
|
+
/\bframe\b/i
|
|
343
|
+
],
|
|
344
|
+
ai_media_generation: [
|
|
345
|
+
/\btext.to.image\b/i,
|
|
346
|
+
/\bimage.to.image\b/i,
|
|
347
|
+
/\btext.to.video\b/i,
|
|
348
|
+
/\binpaint(?:ing)?\b/i,
|
|
349
|
+
/\bupscal(?:e|ing)\b/i,
|
|
350
|
+
/\bgenerat(?:e|ion)\b.*\bimage/i,
|
|
351
|
+
/\bimage\b.*\bgenerat(?:e|ion)\b/i,
|
|
352
|
+
/\bai\b.*\b(?:image|photo|video)\b/i,
|
|
353
|
+
/\bstable.diffusion\b/i,
|
|
354
|
+
/\bdiffusion\b/i,
|
|
355
|
+
/\bprompt\b.*\b(?:image|visual)\b/i
|
|
356
|
+
],
|
|
357
|
+
hosting_deploy: [
|
|
358
|
+
/\bdeploy(?:ment)?\b/i,
|
|
359
|
+
/\bhosting\b/i,
|
|
360
|
+
/\bdomain(?:s)?\b/i,
|
|
361
|
+
/\bdns\b/i,
|
|
362
|
+
/\bvps\b/i,
|
|
363
|
+
/\bvirtual_machine(?:s)?\b/i,
|
|
364
|
+
/\bfirewall\b/i,
|
|
365
|
+
/\bwebsite\b/i,
|
|
366
|
+
/\bbilling\b/i,
|
|
367
|
+
/\bnameserver(?:s)?\b/i
|
|
368
|
+
],
|
|
369
|
+
time_util: [
|
|
370
|
+
/\btime\b/i,
|
|
371
|
+
/\btimezone\b/i,
|
|
372
|
+
/\butc\b/i,
|
|
373
|
+
/\bclock\b/i,
|
|
374
|
+
/\bdate\b/i,
|
|
375
|
+
/\bconvert_time\b/i,
|
|
376
|
+
/\bget_current_time\b/i
|
|
377
|
+
],
|
|
378
|
+
research: [
|
|
379
|
+
/\bresearch\b/i,
|
|
380
|
+
/\bcrawl\b/i,
|
|
381
|
+
/\bscrape\b/i,
|
|
382
|
+
/\bextract\b/i,
|
|
383
|
+
/\bsemantic_search\b/i,
|
|
384
|
+
/\bweb_search\b/i,
|
|
385
|
+
/\bask\b/i,
|
|
386
|
+
/\bperplexity\b/i,
|
|
387
|
+
/\bfirecrawl\b/i,
|
|
388
|
+
/\bexa\b/i
|
|
389
|
+
],
|
|
390
|
+
general: []
|
|
391
|
+
};
|
|
392
|
+
});
|
|
393
|
+
|
|
126
394
|
// src/tui/config.ts
|
|
127
395
|
import {
|
|
128
396
|
ASCIIFontRenderable,
|
|
@@ -378,6 +646,7 @@ import { parse as parseToml } from "smol-toml";
|
|
|
378
646
|
import { ZodError } from "zod";
|
|
379
647
|
|
|
380
648
|
// src/config/schema.ts
|
|
649
|
+
init_inference();
|
|
381
650
|
import { z } from "zod";
|
|
382
651
|
var LATEST_SCHEMA_VERSION = 1;
|
|
383
652
|
var LogLevelSchema = z.enum([
|
|
@@ -434,6 +703,18 @@ var SecuritySchema = z.object({
|
|
|
434
703
|
});
|
|
435
704
|
var SearchModeSchema = z.enum(["fast", "semantic", "hybrid"]);
|
|
436
705
|
var DetailLevelSchema = z.enum(["L0", "L1", "L2"]);
|
|
706
|
+
var CapabilityIdSchema = z.enum(CAPABILITY_IDS);
|
|
707
|
+
var DynamicToolSurfaceInferenceSchema = z.enum([
|
|
708
|
+
"heuristic_with_overrides",
|
|
709
|
+
"hybrid"
|
|
710
|
+
]);
|
|
711
|
+
var DynamicToolSurfaceRefreshSchema = z.enum(["on_connect"]);
|
|
712
|
+
var DynamicToolSurfaceSchema = z.object({
|
|
713
|
+
inference: DynamicToolSurfaceInferenceSchema.default("heuristic_with_overrides"),
|
|
714
|
+
refresh: DynamicToolSurfaceRefreshSchema.default("on_connect"),
|
|
715
|
+
capabilityOverrides: z.record(z.string().min(1), CapabilityIdSchema).default({}),
|
|
716
|
+
semanticConfidenceThreshold: z.number().min(0).max(1).default(0.45)
|
|
717
|
+
});
|
|
437
718
|
var PreferredNamespacesByIntentSchema = z.object({
|
|
438
719
|
codeSearch: z.array(z.string().min(1)).default([])
|
|
439
720
|
});
|
|
@@ -475,6 +756,12 @@ var OperationsSchema = z.object({
|
|
|
475
756
|
enabled: true,
|
|
476
757
|
minCooccurrenceThreshold: 2,
|
|
477
758
|
maxBundleSuggestions: 3
|
|
759
|
+
}),
|
|
760
|
+
dynamicToolSurface: DynamicToolSurfaceSchema.default({
|
|
761
|
+
inference: "heuristic_with_overrides",
|
|
762
|
+
refresh: "on_connect",
|
|
763
|
+
capabilityOverrides: {},
|
|
764
|
+
semanticConfidenceThreshold: 0.45
|
|
478
765
|
})
|
|
479
766
|
}).default({
|
|
480
767
|
findTools: {
|
|
@@ -491,6 +778,12 @@ var OperationsSchema = z.object({
|
|
|
491
778
|
enabled: true,
|
|
492
779
|
minCooccurrenceThreshold: 2,
|
|
493
780
|
maxBundleSuggestions: 3
|
|
781
|
+
},
|
|
782
|
+
dynamicToolSurface: {
|
|
783
|
+
inference: "heuristic_with_overrides",
|
|
784
|
+
refresh: "on_connect",
|
|
785
|
+
capabilityOverrides: {},
|
|
786
|
+
semanticConfidenceThreshold: 0.45
|
|
494
787
|
}
|
|
495
788
|
});
|
|
496
789
|
var ConfigSchema = z.object({
|
|
@@ -544,6 +837,34 @@ function migrateV0ToV1(config) {
|
|
|
544
837
|
|
|
545
838
|
// src/config/load.ts
|
|
546
839
|
init_paths();
|
|
840
|
+
function isRecord(value) {
|
|
841
|
+
return typeof value === "object" && value !== null;
|
|
842
|
+
}
|
|
843
|
+
function getDeprecatedDynamicToolSurfaceKeys(raw) {
|
|
844
|
+
const operations = raw["operations"];
|
|
845
|
+
if (!isRecord(operations)) {
|
|
846
|
+
return [];
|
|
847
|
+
}
|
|
848
|
+
const dynamicToolSurface = operations["dynamicToolSurface"];
|
|
849
|
+
if (!isRecord(dynamicToolSurface)) {
|
|
850
|
+
return [];
|
|
851
|
+
}
|
|
852
|
+
const deprecated = [];
|
|
853
|
+
if ("mode" in dynamicToolSurface) {
|
|
854
|
+
deprecated.push("operations.dynamicToolSurface.mode");
|
|
855
|
+
}
|
|
856
|
+
if ("naming" in dynamicToolSurface) {
|
|
857
|
+
deprecated.push("operations.dynamicToolSurface.naming");
|
|
858
|
+
}
|
|
859
|
+
return deprecated;
|
|
860
|
+
}
|
|
861
|
+
function warnDeprecatedDynamicToolSurfaceKeys(filePath, keys) {
|
|
862
|
+
if (keys.length === 0) {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
console.warn(`[mcp\xB2] Deprecated config keys in ${filePath}: ${keys.join(", ")}. Run 'mcp-squared migrate' to clean up legacy settings.`);
|
|
866
|
+
}
|
|
867
|
+
|
|
547
868
|
class ConfigError extends Error {
|
|
548
869
|
cause;
|
|
549
870
|
constructor(message, cause) {
|
|
@@ -611,6 +932,7 @@ async function loadConfigFromPath(filePath, source) {
|
|
|
611
932
|
} catch (err) {
|
|
612
933
|
throw new ConfigParseError(filePath, err);
|
|
613
934
|
}
|
|
935
|
+
warnDeprecatedDynamicToolSurfaceKeys(filePath, getDeprecatedDynamicToolSurfaceKeys(rawConfig));
|
|
614
936
|
const migrated = migrateConfig(rawConfig);
|
|
615
937
|
let config;
|
|
616
938
|
try {
|
|
@@ -1473,60 +1795,68 @@ function cleanupExpiredTokens() {
|
|
|
1473
1795
|
}
|
|
1474
1796
|
}
|
|
1475
1797
|
}
|
|
1476
|
-
function validateConfirmationToken(token,
|
|
1798
|
+
function validateConfirmationToken(token, capability, action) {
|
|
1477
1799
|
cleanupExpiredTokens();
|
|
1478
1800
|
const confirmation = pendingConfirmations.get(token);
|
|
1479
1801
|
if (!confirmation) {
|
|
1480
1802
|
return false;
|
|
1481
1803
|
}
|
|
1482
|
-
if (confirmation.
|
|
1804
|
+
if (confirmation.capability !== capability || confirmation.action !== action) {
|
|
1483
1805
|
return false;
|
|
1484
1806
|
}
|
|
1485
1807
|
pendingConfirmations.delete(token);
|
|
1486
1808
|
return true;
|
|
1487
1809
|
}
|
|
1488
|
-
function createConfirmationToken(
|
|
1810
|
+
function createConfirmationToken(capability, action) {
|
|
1489
1811
|
cleanupExpiredTokens();
|
|
1490
1812
|
const token = generateToken();
|
|
1491
1813
|
pendingConfirmations.set(token, {
|
|
1492
|
-
|
|
1493
|
-
|
|
1814
|
+
capability,
|
|
1815
|
+
action,
|
|
1494
1816
|
createdAt: Date.now()
|
|
1495
1817
|
});
|
|
1496
1818
|
return token;
|
|
1497
1819
|
}
|
|
1498
1820
|
function evaluatePolicy(context, config) {
|
|
1499
|
-
const
|
|
1821
|
+
const capability = context.capability ?? context.serverKey;
|
|
1822
|
+
const action = context.action ?? context.toolName;
|
|
1823
|
+
const confirmationToken = context.confirmationToken;
|
|
1500
1824
|
const { block, confirm, allow } = config.security.tools;
|
|
1501
|
-
if (
|
|
1825
|
+
if (!capability || !action) {
|
|
1502
1826
|
return {
|
|
1503
1827
|
decision: "block",
|
|
1504
|
-
reason:
|
|
1828
|
+
reason: "Missing capability/action in security policy context"
|
|
1505
1829
|
};
|
|
1506
1830
|
}
|
|
1507
|
-
if (matchesAnyPattern(
|
|
1831
|
+
if (matchesAnyPattern(block, capability, action)) {
|
|
1832
|
+
return {
|
|
1833
|
+
decision: "block",
|
|
1834
|
+
reason: `Action "${action}" in capability "${capability}" is blocked by security policy`
|
|
1835
|
+
};
|
|
1836
|
+
}
|
|
1837
|
+
if (matchesAnyPattern(allow, capability, action)) {
|
|
1508
1838
|
return {
|
|
1509
1839
|
decision: "allow",
|
|
1510
|
-
reason: `
|
|
1840
|
+
reason: `Action "${action}" is allowed by security policy`
|
|
1511
1841
|
};
|
|
1512
1842
|
}
|
|
1513
|
-
if (matchesAnyPattern(confirm,
|
|
1514
|
-
if (confirmationToken && validateConfirmationToken(confirmationToken,
|
|
1843
|
+
if (matchesAnyPattern(confirm, capability, action)) {
|
|
1844
|
+
if (confirmationToken && validateConfirmationToken(confirmationToken, capability, action)) {
|
|
1515
1845
|
return {
|
|
1516
1846
|
decision: "allow",
|
|
1517
|
-
reason: `
|
|
1847
|
+
reason: `Action "${action}" confirmed with valid token`
|
|
1518
1848
|
};
|
|
1519
1849
|
}
|
|
1520
|
-
const token = createConfirmationToken(
|
|
1850
|
+
const token = createConfirmationToken(capability, action);
|
|
1521
1851
|
return {
|
|
1522
1852
|
decision: "confirm",
|
|
1523
|
-
reason: `
|
|
1853
|
+
reason: `Action "${action}" in capability "${capability}" requires confirmation`,
|
|
1524
1854
|
confirmationToken: token
|
|
1525
1855
|
};
|
|
1526
1856
|
}
|
|
1527
1857
|
return {
|
|
1528
1858
|
decision: "block",
|
|
1529
|
-
reason: `
|
|
1859
|
+
reason: `Action "${action}" in capability "${capability}" is not in the allow or confirm list`
|
|
1530
1860
|
};
|
|
1531
1861
|
}
|
|
1532
1862
|
function compilePolicy(config) {
|
|
@@ -1685,6 +2015,26 @@ async function waitForProcessExit(proc, timeoutMs) {
|
|
|
1685
2015
|
}
|
|
1686
2016
|
|
|
1687
2017
|
// src/upstream/cataloger.ts
|
|
2018
|
+
var AUTH_ERROR_PATTERNS = [
|
|
2019
|
+
"invalid_token",
|
|
2020
|
+
"invalid token",
|
|
2021
|
+
"unauthorized",
|
|
2022
|
+
"no token provided",
|
|
2023
|
+
"no authorization",
|
|
2024
|
+
"api key",
|
|
2025
|
+
"api_key",
|
|
2026
|
+
"authentication required",
|
|
2027
|
+
"authentication failed",
|
|
2028
|
+
"invalid credentials",
|
|
2029
|
+
"invalid api",
|
|
2030
|
+
"forbidden",
|
|
2031
|
+
"access denied",
|
|
2032
|
+
"not authenticated"
|
|
2033
|
+
];
|
|
2034
|
+
function isAuthError(message) {
|
|
2035
|
+
const lower = message.toLowerCase();
|
|
2036
|
+
return AUTH_ERROR_PATTERNS.some((pattern) => lower.includes(pattern));
|
|
2037
|
+
}
|
|
1688
2038
|
function resolveEnvVars(env) {
|
|
1689
2039
|
const resolved = {};
|
|
1690
2040
|
for (const [key, value] of Object.entries(env)) {
|
|
@@ -1765,7 +2115,7 @@ class Cataloger {
|
|
|
1765
2115
|
if (err instanceof UnauthorizedError2 && connection.authProvider) {
|
|
1766
2116
|
if (connection.authProvider.isNonInteractive()) {
|
|
1767
2117
|
connection.authPending = true;
|
|
1768
|
-
connection.status = "
|
|
2118
|
+
connection.status = "needs_auth";
|
|
1769
2119
|
connection.error = `OAuth authorization required. Run: mcp-squared auth ${key}`;
|
|
1770
2120
|
return;
|
|
1771
2121
|
}
|
|
@@ -1789,8 +2139,9 @@ class Cataloger {
|
|
|
1789
2139
|
}));
|
|
1790
2140
|
connection.status = "connected";
|
|
1791
2141
|
} catch (err) {
|
|
1792
|
-
|
|
1793
|
-
connection.
|
|
2142
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
2143
|
+
connection.status = isAuthError(errorMsg) ? "needs_auth" : "error";
|
|
2144
|
+
connection.error = errorMsg;
|
|
1794
2145
|
try {
|
|
1795
2146
|
await this.cleanupConnection(connection);
|
|
1796
2147
|
} catch (_cleanupErr) {}
|
|
@@ -1952,13 +2303,14 @@ class Cataloger {
|
|
|
1952
2303
|
if (err instanceof UnauthorizedError2 && connection.authProvider) {
|
|
1953
2304
|
if (connection.authProvider.isNonInteractive()) {
|
|
1954
2305
|
connection.authPending = true;
|
|
1955
|
-
connection.status = "
|
|
2306
|
+
connection.status = "needs_auth";
|
|
1956
2307
|
connection.error = `OAuth authorization required. Run: mcp-squared auth ${key}`;
|
|
1957
2308
|
return;
|
|
1958
2309
|
}
|
|
1959
2310
|
}
|
|
1960
|
-
|
|
1961
|
-
connection.
|
|
2311
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
2312
|
+
connection.status = isAuthError(errorMsg) ? "needs_auth" : "error";
|
|
2313
|
+
connection.error = errorMsg;
|
|
1962
2314
|
}
|
|
1963
2315
|
}
|
|
1964
2316
|
async refreshAllTools() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-squared",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "MCP² (Mercury Control Plane) - A local-first meta-server and proxy for the Model Context Protocol",
|
|
5
5
|
"author": "aditzel",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -60,10 +60,13 @@
|
|
|
60
60
|
"url": "https://github.com/aditzel/mcp-squared"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
+
"@hono/node-server": "^1.19.11",
|
|
63
64
|
"@huggingface/transformers": "^3.8.1",
|
|
64
65
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
65
66
|
"@opentui/core": "^0.1.82",
|
|
67
|
+
"hono": "^4.12.5",
|
|
66
68
|
"smol-toml": "^1.6.0",
|
|
69
|
+
"tar": "^7.5.10",
|
|
67
70
|
"yaml": "^2.8.2",
|
|
68
71
|
"zod": "^4.3.6"
|
|
69
72
|
},
|
|
@@ -72,10 +75,11 @@
|
|
|
72
75
|
"@opentelemetry/sdk-trace-base": "^1.30.1"
|
|
73
76
|
},
|
|
74
77
|
"overrides": {
|
|
78
|
+
"@hono/node-server": "^1.19.11",
|
|
75
79
|
"ajv": "^8.18.0",
|
|
76
80
|
"diff": "8.0.3",
|
|
77
|
-
"hono": "^4.
|
|
81
|
+
"hono": "^4.12.5",
|
|
78
82
|
"qs": "6.15.0",
|
|
79
|
-
"tar": "7.5.
|
|
83
|
+
"tar": "^7.5.10"
|
|
80
84
|
}
|
|
81
85
|
}
|