u-foo 2.4.10 → 2.4.11
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/bin/ufoo.js +19 -0
- package/package.json +1 -1
- package/src/app/chat/commandExecutor.js +97 -0
- package/src/app/chat/commands.js +15 -0
package/bin/ufoo.js
CHANGED
|
@@ -13,6 +13,21 @@ function hasGlobalModeFlag(args = []) {
|
|
|
13
13
|
return args.includes("-g") || args.includes("--global");
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
function printMcpHelp() {
|
|
17
|
+
console.log("Usage: ufoo mcp [options]");
|
|
18
|
+
console.log("");
|
|
19
|
+
console.log("Run the local global ufoo MCP bridge over stdio.");
|
|
20
|
+
console.log("");
|
|
21
|
+
console.log("Options:");
|
|
22
|
+
console.log(" --no-auto-start Do not auto-start the home-scoped global controller daemon");
|
|
23
|
+
console.log(" -h, --help Display help for the MCP bridge command");
|
|
24
|
+
console.log("");
|
|
25
|
+
console.log("Notes:");
|
|
26
|
+
console.log(" Configure MCP-capable clients with command: ufoo mcp");
|
|
27
|
+
console.log(" Example without daemon auto-start: ufoo mcp --no-auto-start");
|
|
28
|
+
console.log(" Human diagnostics are available in chat: /mcp status, /mcp tools, /mcp help");
|
|
29
|
+
}
|
|
30
|
+
|
|
16
31
|
async function main() {
|
|
17
32
|
const globalMode = hasGlobalModeFlag(rawArgv);
|
|
18
33
|
const argv = rawArgv.filter((arg) => arg !== "-g" && arg !== "--global");
|
|
@@ -28,6 +43,10 @@ async function main() {
|
|
|
28
43
|
return;
|
|
29
44
|
}
|
|
30
45
|
if (cmd === "mcp") {
|
|
46
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
47
|
+
printMcpHelp();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
31
50
|
await runMcpServer({
|
|
32
51
|
autoStart: !argv.includes("--no-auto-start"),
|
|
33
52
|
});
|
package/package.json
CHANGED
|
@@ -24,6 +24,10 @@ const {
|
|
|
24
24
|
inspectDirectAuthStatus,
|
|
25
25
|
formatDirectAuthStatus,
|
|
26
26
|
} = require("../../agents/providers/directAuthStatus");
|
|
27
|
+
const {
|
|
28
|
+
buildToolList: defaultBuildMcpToolList,
|
|
29
|
+
createUfooMcpServer: defaultCreateMcpServer,
|
|
30
|
+
} = require("../../runtime/daemon/mcpServer");
|
|
27
31
|
|
|
28
32
|
function defaultCreateDoctor(projectRoot) {
|
|
29
33
|
const UfooDoctor = require("../cli/features/doctor");
|
|
@@ -147,6 +151,8 @@ function createCommandExecutor(options = {}) {
|
|
|
147
151
|
runGroupCore = runGroupCoreCommand,
|
|
148
152
|
inspectDirectAuth = inspectDirectAuthStatus,
|
|
149
153
|
formatDirectAuth = formatDirectAuthStatus,
|
|
154
|
+
buildMcpToolList = defaultBuildMcpToolList,
|
|
155
|
+
createMcpServer = defaultCreateMcpServer,
|
|
150
156
|
requestCron = null,
|
|
151
157
|
globalMode = false,
|
|
152
158
|
listProjects = () => [],
|
|
@@ -335,6 +341,93 @@ function createCommandExecutor(options = {}) {
|
|
|
335
341
|
);
|
|
336
342
|
}
|
|
337
343
|
|
|
344
|
+
function logMcpHelp() {
|
|
345
|
+
logMessage("system", "{cyan-fg}MCP bridge:{/cyan-fg} local stdio bridge for external MCP-capable agents");
|
|
346
|
+
logMessage("system", " • Configure client command: ufoo mcp");
|
|
347
|
+
logMessage("system", " • Disable daemon auto-start: ufoo mcp --no-auto-start");
|
|
348
|
+
logMessage("system", " • Topology: one global bridge, project tools route through registered project daemons");
|
|
349
|
+
logMessage("system", " • Chat diagnostics: /mcp status, /mcp tools, /mcp help");
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
async function readMcpStatus() {
|
|
353
|
+
const server = createMcpServer({
|
|
354
|
+
autoStart: false,
|
|
355
|
+
validateProjectRoot: true,
|
|
356
|
+
});
|
|
357
|
+
const response = await server.handleRequest({
|
|
358
|
+
jsonrpc: "2.0",
|
|
359
|
+
id: "chat-mcp-status",
|
|
360
|
+
method: "tools/call",
|
|
361
|
+
params: {
|
|
362
|
+
name: "ufoo_mcp_status",
|
|
363
|
+
arguments: {},
|
|
364
|
+
},
|
|
365
|
+
});
|
|
366
|
+
if (response && response.error) {
|
|
367
|
+
const message = response.error.message || "MCP status request failed";
|
|
368
|
+
throw new Error(message);
|
|
369
|
+
}
|
|
370
|
+
return response && response.result ? response.result.structuredContent : null;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
async function handleMcpCommand(args = []) {
|
|
374
|
+
const subcommand = String(args[0] || "status").trim().toLowerCase();
|
|
375
|
+
|
|
376
|
+
if (subcommand === "help") {
|
|
377
|
+
logMcpHelp();
|
|
378
|
+
renderScreen();
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (subcommand === "tools") {
|
|
383
|
+
try {
|
|
384
|
+
const tools = buildMcpToolList();
|
|
385
|
+
logMessage("system", `{cyan-fg}MCP tools:{/cyan-fg} ${tools.length} exposed tool(s)`);
|
|
386
|
+
for (const tool of tools) {
|
|
387
|
+
const name = escapeBlessed(tool.name || "");
|
|
388
|
+
const desc = escapeBlessed(tool.description || "");
|
|
389
|
+
logMessage("system", ` • {cyan-fg}${name}{/cyan-fg}${desc ? ` - ${desc}` : ""}`);
|
|
390
|
+
}
|
|
391
|
+
} catch (err) {
|
|
392
|
+
logMessage("error", `{white-fg}✗{/white-fg} MCP tools failed: ${escapeBlessed(err.message)}`);
|
|
393
|
+
}
|
|
394
|
+
renderScreen();
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (subcommand === "status") {
|
|
399
|
+
try {
|
|
400
|
+
const status = await readMcpStatus();
|
|
401
|
+
if (!status) {
|
|
402
|
+
throw new Error("empty MCP status response");
|
|
403
|
+
}
|
|
404
|
+
const projects = Array.isArray(status.projects) ? status.projects : [];
|
|
405
|
+
logMessage("system", "{cyan-fg}MCP bridge:{/cyan-fg} local stdio server");
|
|
406
|
+
logMessage("system", " • command: {cyan-fg}ufoo mcp{/cyan-fg}");
|
|
407
|
+
logMessage("system", ` • global controller: ${escapeBlessed(status.global_controller_root || "")}`);
|
|
408
|
+
logMessage("system", ` • daemon: ${status.global_controller_running ? "{green-fg}running{/green-fg}" : "{yellow-fg}not running{/yellow-fg}"}`);
|
|
409
|
+
logMessage("system", " • client auto-start: enabled by default");
|
|
410
|
+
logMessage("system", ` • status probe auto-start: ${status.auto_start ? "enabled" : "disabled"}`);
|
|
411
|
+
logMessage("system", ` • registered projects: ${projects.length}`);
|
|
412
|
+
for (const project of projects.slice(0, 5)) {
|
|
413
|
+
const label = project.project_name || project.name || project.project_root || "";
|
|
414
|
+
const root = project.project_root || "";
|
|
415
|
+
logMessage("system", ` - ${escapeBlessed(label)}${root && root !== label ? ` (${escapeBlessed(root)})` : ""}`);
|
|
416
|
+
}
|
|
417
|
+
if (projects.length > 5) {
|
|
418
|
+
logMessage("system", ` - ... ${projects.length - 5} more`);
|
|
419
|
+
}
|
|
420
|
+
} catch (err) {
|
|
421
|
+
logMessage("error", `{white-fg}✗{/white-fg} MCP status failed: ${escapeBlessed(err.message)}`);
|
|
422
|
+
}
|
|
423
|
+
renderScreen();
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
logMessage("error", "{white-fg}✗{/white-fg} Unknown MCP command. Use: status, tools, help");
|
|
428
|
+
renderScreen();
|
|
429
|
+
}
|
|
430
|
+
|
|
338
431
|
async function handleBusCommand(args = []) {
|
|
339
432
|
const subcommand = args[0];
|
|
340
433
|
|
|
@@ -1608,6 +1701,9 @@ function createCommandExecutor(options = {}) {
|
|
|
1608
1701
|
logMessage("error", "{white-fg}✗{/white-fg} Multi-window mode is not available");
|
|
1609
1702
|
}
|
|
1610
1703
|
return true;
|
|
1704
|
+
case "mcp":
|
|
1705
|
+
await handleMcpCommand(args);
|
|
1706
|
+
return true;
|
|
1611
1707
|
case "doctor":
|
|
1612
1708
|
await handleDoctorCommand();
|
|
1613
1709
|
return true;
|
|
@@ -1670,6 +1766,7 @@ function createCommandExecutor(options = {}) {
|
|
|
1670
1766
|
handleDoctorCommand,
|
|
1671
1767
|
handleStatusCommand,
|
|
1672
1768
|
handleDaemonCommand,
|
|
1769
|
+
handleMcpCommand,
|
|
1673
1770
|
handleInitCommand,
|
|
1674
1771
|
handleBusCommand,
|
|
1675
1772
|
handleCtxCommand,
|
package/src/app/chat/commands.js
CHANGED
|
@@ -49,6 +49,14 @@ const COMMAND_TREE = {
|
|
|
49
49
|
},
|
|
50
50
|
"/init": { desc: "Initialize workspace" },
|
|
51
51
|
"/multi": { desc: "Toggle multi-window agent view" },
|
|
52
|
+
"/mcp": {
|
|
53
|
+
desc: "MCP bridge diagnostics",
|
|
54
|
+
children: {
|
|
55
|
+
status: { desc: "Show global MCP bridge status", order: 1 },
|
|
56
|
+
tools: { desc: "List exposed MCP tools", order: 2 },
|
|
57
|
+
help: { desc: "Show MCP setup hints", order: 3 },
|
|
58
|
+
},
|
|
59
|
+
},
|
|
52
60
|
"/open": { desc: "Open project path in global mode" },
|
|
53
61
|
"/launch": {
|
|
54
62
|
desc: "Launch new agent",
|
|
@@ -298,6 +306,13 @@ function describeCommandForChat(text) {
|
|
|
298
306
|
return "Managing cron tasks";
|
|
299
307
|
}
|
|
300
308
|
|
|
309
|
+
if (command === "mcp") {
|
|
310
|
+
if (!sub || sub === "status") return "Checking MCP bridge status";
|
|
311
|
+
if (sub === "tools") return "Listing MCP tools";
|
|
312
|
+
if (sub === "help") return "Showing MCP setup help";
|
|
313
|
+
return `Running /mcp ${sub}`;
|
|
314
|
+
}
|
|
315
|
+
|
|
301
316
|
if (command === "settings") return !sub || sub === "show" ? "Showing settings" : "Updating settings";
|
|
302
317
|
if (command === "ctx") return `Checking context${sub ? ` ${sub}` : ""}`;
|
|
303
318
|
if (command === "doctor") return "Running ufoo diagnostics";
|