Skip to content

Commit 9d35053

Browse files
committed
refactor: mcp command register
1 parent 26a66ac commit 9d35053

3 files changed

Lines changed: 134 additions & 133 deletions

File tree

src/commands/index.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

src/commands/mcp.ts

Lines changed: 102 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -12,118 +12,114 @@ import { getMCPClientManager } from "../mcp/manager.js";
1212
import type { MCPServerConfig, TransportType } from "../mcp/types.js";
1313
import { createLogger } from "../logger/index.js";
1414

15-
export function createMCPCommand(): Command {
16-
const mcp = new Command("mcp");
17-
mcp.description("Manage MCP (Model Context Protocol) servers");
15+
export const mcp = new Command("mcp");
16+
mcp.description("Manage MCP (Model Context Protocol) servers");
1817

19-
mcp
20-
.command("add")
21-
.description("Add a new MCP server")
22-
.argument("<name>", "Server name")
23-
.option(
24-
"-t, --transport <type>",
25-
"Transport type: stdio | sse | ws | streamable-http (alias: http)",
26-
"stdio",
27-
)
28-
.option(
29-
"-C, --command <command>",
30-
"Command to run the server (for stdio transport)",
31-
)
32-
.option(
33-
"-a, --args [args...]",
34-
"Arguments for the server command (for stdio transport)",
35-
[],
36-
)
37-
.option("-u, --url <url>", "URL for SSE/HTTP/WS transport")
38-
.option("-e, --env [envs...]", "Environment variables (KEY=VALUE)")
39-
.option("-H, --header [headers...]", "HTTP headers (KEY=VALUE)")
40-
.option("--timeout <ms>", "Operation timeout in ms", (v) => parseInt(v, 10))
41-
.option("--enabled", "Add server as enabled", true)
42-
.action(async function (this: Command, name: string, opts: any) {
43-
let config: MCPServerConfig;
44-
switch (opts.transport as TransportType) {
45-
case TRANSPORT_TYPES.STDIO:
46-
config = {
47-
type: TRANSPORT_TYPES.STDIO,
48-
command: opts.command,
49-
args: opts.args,
50-
env: parseKeyValue(opts.env),
51-
timeout: opts.timeout,
52-
enabled: opts.enabled,
53-
};
54-
break;
55-
case TRANSPORT_TYPES.SSE:
56-
config = {
57-
type: TRANSPORT_TYPES.SSE,
58-
url: opts.url,
59-
headers: parseKeyValue(opts.header),
60-
timeout: opts.timeout,
61-
enabled: opts.enabled,
62-
};
63-
break;
64-
case TRANSPORT_TYPES.WS:
65-
config = {
66-
type: TRANSPORT_TYPES.WS,
67-
url: opts.url,
68-
timeout: opts.timeout,
69-
enabled: opts.enabled,
70-
};
71-
break;
72-
case TRANSPORT_TYPES.HTTP:
73-
case TRANSPORT_TYPES.STREAMABLE_HTTP:
74-
config = {
75-
type: TRANSPORT_TYPES.STREAMABLE_HTTP,
76-
url: opts.url,
77-
headers: parseKeyValue(opts.header),
78-
timeout: opts.timeout,
79-
enabled: opts.enabled,
80-
};
81-
break;
82-
default:
83-
throw new Error(`Unknown transport type: ${opts.transport}`);
84-
}
85-
await addMCPServer(name, config);
86-
const path = getDefaultConfigPath();
87-
console.log(chalk.green(`✓ Added MCP server: ${name} to ${path}`));
88-
});
18+
mcp
19+
.command("add")
20+
.description("Add a new MCP server")
21+
.argument("<name>", "Server name")
22+
.option(
23+
"-t, --transport <type>",
24+
"Transport type: stdio | sse | ws | streamable-http (alias: http)",
25+
"stdio",
26+
)
27+
.option(
28+
"-C, --command <command>",
29+
"Command to run the server (for stdio transport)",
30+
)
31+
.option(
32+
"-a, --args [args...]",
33+
"Arguments for the server command (for stdio transport)",
34+
[],
35+
)
36+
.option("-u, --url <url>", "URL for SSE/HTTP/WS transport")
37+
.option("-e, --env [envs...]", "Environment variables (KEY=VALUE)")
38+
.option("-H, --header [headers...]", "HTTP headers (KEY=VALUE)")
39+
.option("--timeout <ms>", "Operation timeout in ms", (v) => parseInt(v, 10))
40+
.option("--enabled", "Add server as enabled", true)
41+
.action(async function (this: Command, name: string, opts: any) {
42+
let config: MCPServerConfig;
43+
switch (opts.transport as TransportType) {
44+
case TRANSPORT_TYPES.STDIO:
45+
config = {
46+
type: TRANSPORT_TYPES.STDIO,
47+
command: opts.command,
48+
args: opts.args,
49+
env: parseKeyValue(opts.env),
50+
timeout: opts.timeout,
51+
enabled: opts.enabled,
52+
};
53+
break;
54+
case TRANSPORT_TYPES.SSE:
55+
config = {
56+
type: TRANSPORT_TYPES.SSE,
57+
url: opts.url,
58+
headers: parseKeyValue(opts.header),
59+
timeout: opts.timeout,
60+
enabled: opts.enabled,
61+
};
62+
break;
63+
case TRANSPORT_TYPES.WS:
64+
config = {
65+
type: TRANSPORT_TYPES.WS,
66+
url: opts.url,
67+
timeout: opts.timeout,
68+
enabled: opts.enabled,
69+
};
70+
break;
71+
case TRANSPORT_TYPES.HTTP:
72+
case TRANSPORT_TYPES.STREAMABLE_HTTP:
73+
config = {
74+
type: TRANSPORT_TYPES.STREAMABLE_HTTP,
75+
url: opts.url,
76+
headers: parseKeyValue(opts.header),
77+
timeout: opts.timeout,
78+
enabled: opts.enabled,
79+
};
80+
break;
81+
default:
82+
throw new Error(`Unknown transport type: ${opts.transport}`);
83+
}
84+
await addMCPServer(name, config);
85+
const path = getDefaultConfigPath();
86+
console.log(chalk.green(`✓ Added MCP server: ${name} to ${path}`));
87+
});
8988

90-
mcp
91-
.command("list")
92-
.description("List configured MCP servers (checks health)")
93-
.action(async function (this: Command) {
94-
const program = this.parent?.parent;
95-
const verbose = program?.opts<{ verbose?: boolean }>().verbose ?? false;
89+
mcp
90+
.command("list")
91+
.description("List configured MCP servers (checks health)")
92+
.action(async function (this: Command) {
93+
const program = this.parent?.parent;
94+
const verbose = program?.opts<{ verbose?: boolean }>().verbose ?? false;
9695

97-
const { waitUntilExit } = render(
98-
React.createElement(MCPList, { verbose }),
99-
);
100-
await waitUntilExit();
101-
});
96+
console.log("Starting MCP server health check...");
97+
const { waitUntilExit } = render(React.createElement(MCPList, { verbose }));
10298

103-
mcp
104-
.command("remove <name>")
105-
.description("Remove an MCP server")
106-
.action(async function (this: Command, name: string) {
107-
const program = this.parent?.parent;
108-
const verbose = program?.opts<{ verbose?: boolean }>().verbose ?? false;
109-
const logger = createLogger({ silent: !verbose, level: "info" });
99+
await waitUntilExit();
100+
});
110101

111-
const mcpClientManager = getMCPClientManager();
112-
mcpClientManager.setLogger(logger);
102+
mcp
103+
.command("remove <name>")
104+
.description("Remove an MCP server")
105+
.action(async function (this: Command, name: string) {
106+
const program = this.parent?.parent;
107+
const verbose = program?.opts<{ verbose?: boolean }>().verbose ?? false;
108+
const logger = createLogger({ silent: !verbose, level: "info" });
113109

114-
await mcpClientManager.removeClient(name);
110+
const mcpClientManager = getMCPClientManager();
111+
mcpClientManager.setLogger(logger);
115112

116-
await removeMCPServer(name);
117-
console.log(chalk.green(`✓ Removed MCP server: ${name}`));
118-
});
113+
await mcpClientManager.removeClient(name);
119114

120-
mcp
121-
.command("test <name>")
122-
.description("Test connection to an MCP server")
123-
.action(async (name: string) => {
124-
const { waitUntilExit } = render(React.createElement(MCPTest, { name }));
125-
await waitUntilExit();
126-
});
115+
await removeMCPServer(name);
116+
console.log(chalk.green(`✓ Removed MCP server: ${name}`));
117+
});
127118

128-
return mcp;
129-
}
119+
mcp
120+
.command("test <name>")
121+
.description("Test connection to an MCP server")
122+
.action(async (name: string) => {
123+
const { waitUntilExit } = render(React.createElement(MCPTest, { name }));
124+
await waitUntilExit();
125+
});

src/index.ts

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,42 @@ import { Command } from "commander";
66

77
import App from "./ui/app.js";
88
import pkg from "../package.json" with { type: "json" };
9-
import { registerBuiltInCommands } from "./commands/index.js";
9+
import { mcp } from "./commands/mcp.js";
1010

11-
const program = new Command();
11+
async function main() {
12+
const program = new Command();
1213

13-
program
14-
.name("mstudio")
15-
.description((pkg as any).description)
16-
.version((pkg as any).version, "-V, --version", "Output the version number");
14+
program
15+
.name("mstudio")
16+
.description((pkg as any).description)
17+
.version(
18+
(pkg as any).version,
19+
"-V, --version",
20+
"Output the version number",
21+
);
1722

18-
// Common options
19-
program
20-
.allowExcessArguments(true)
21-
.allowUnknownOption()
22-
.option("-c, --config <path>", "Path to config file")
23-
.option("-v, --verbose", "Enable verbose logging", false);
23+
// Common options
24+
program
25+
.allowExcessArguments(true)
26+
.allowUnknownOption()
27+
.option("-c, --config <path>", "Path to config file")
28+
.option("-v, --verbose", "Enable verbose logging", false);
2429

25-
// Register built-in commands
26-
registerBuiltInCommands(program);
30+
// Register built-in commands
31+
program.addCommand(mcp);
2732

28-
// If user supplies only options but no subcommand, show interactive UI
29-
program.action(() => {
30-
render(React.createElement(App));
31-
});
33+
// If user supplies only options but no subcommand, show interactive UI
34+
program.action(() => {
35+
render(React.createElement(App));
36+
});
3237

33-
program.showHelpAfterError("(add --help for usage)");
34-
program.configureHelp({ sortSubcommands: true, sortOptions: true });
38+
program.showHelpAfterError("(add --help for usage)");
39+
program.configureHelp({ sortSubcommands: true, sortOptions: true });
3540

36-
program.parse(process.argv);
41+
program.parse(process.argv);
42+
}
43+
44+
process.on("SIGINT", () => process.exit(0));
45+
process.on("SIGTERM", () => process.exit(0));
46+
47+
main();

0 commit comments

Comments
 (0)