@shell-shock/plugin-mcp 0.1.1
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/LICENSE +201 -0
- package/README.md +273 -0
- package/dist/components/mcp-command.cjs +223 -0
- package/dist/components/mcp-command.d.cts +14 -0
- package/dist/components/mcp-command.d.cts.map +1 -0
- package/dist/components/mcp-command.d.mts +14 -0
- package/dist/components/mcp-command.d.mts.map +1 -0
- package/dist/components/mcp-command.mjs +223 -0
- package/dist/components/mcp-command.mjs.map +1 -0
- package/dist/generator.cjs +46 -0
- package/dist/generator.d.cts +10 -0
- package/dist/generator.d.cts.map +1 -0
- package/dist/generator.d.mts +10 -0
- package/dist/generator.d.mts.map +1 -0
- package/dist/generator.mjs +45 -0
- package/dist/generator.mjs.map +1 -0
- package/dist/index.cjs +79 -0
- package/dist/index.d.cts +12 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +12 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +77 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types/index.cjs +1 -0
- package/dist/types/index.d.cts +2 -0
- package/dist/types/index.d.mts +2 -0
- package/dist/types/index.mjs +3 -0
- package/dist/types/plugin.cjs +0 -0
- package/dist/types/plugin.d.cts +21 -0
- package/dist/types/plugin.d.cts.map +1 -0
- package/dist/types/plugin.d.mts +21 -0
- package/dist/types/plugin.d.mts.map +1 -0
- package/dist/types/plugin.mjs +1 -0
- package/package.json +144 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
let _alloy_js_core_jsx_runtime = require("@alloy-js/core/jsx-runtime");
|
|
3
|
+
let _stryke_path_join = require("@stryke/path/join");
|
|
4
|
+
let _alloy_js_core = require("@alloy-js/core");
|
|
5
|
+
let _power_plant_alloy_js_typescript = require("@power-plant/alloy-js/typescript");
|
|
6
|
+
let _shell_shock_core_contexts_power_plant = require("@shell-shock/core/contexts/power-plant");
|
|
7
|
+
|
|
8
|
+
//#region src/components/mcp-command.tsx
|
|
9
|
+
function toFlagName(input) {
|
|
10
|
+
return input.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[^a-z0-9-]/gi, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
|
|
11
|
+
}
|
|
12
|
+
function toToolName(path) {
|
|
13
|
+
return path.replace(/[/:\s]+/g, "_").replace(/[^\w-]/g, "_").replace(/_{2,}/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
14
|
+
}
|
|
15
|
+
function serializeCommand(command) {
|
|
16
|
+
const optionList = Object.values(command.options ?? {}).map((option) => `--${toFlagName(option.name)} (${option.type}${option.required ? ", required" : ""})`).join(", ");
|
|
17
|
+
const argList = command.args.map((arg) => `${arg.name}:${arg.type}${arg.required ? " (required)" : ""}${arg.variadic ? "[]" : ""}`).join(", ");
|
|
18
|
+
const commandPath = command.path ?? command.name;
|
|
19
|
+
return `{
|
|
20
|
+
id: ${JSON.stringify(command.id)},
|
|
21
|
+
name: ${JSON.stringify(command.name)},
|
|
22
|
+
path: ${JSON.stringify(commandPath)},
|
|
23
|
+
segments: ${JSON.stringify(command.segments)},
|
|
24
|
+
title: ${JSON.stringify(command.title)},
|
|
25
|
+
description: ${JSON.stringify(command.description + (optionList ? `\nOptions: ${optionList}` : "") + (argList ? `\nArgs: ${argList}` : ""))},
|
|
26
|
+
toolName: ${JSON.stringify(toToolName(commandPath) || command.name)},
|
|
27
|
+
options: ${JSON.stringify(Object.values(command.options ?? {}).map((option) => ({
|
|
28
|
+
name: option.name,
|
|
29
|
+
title: option.title,
|
|
30
|
+
description: option.description,
|
|
31
|
+
type: option.type,
|
|
32
|
+
required: option.required,
|
|
33
|
+
variadic: option.variadic
|
|
34
|
+
})), null, 2)},
|
|
35
|
+
args: ${JSON.stringify(command.args.map((arg) => ({
|
|
36
|
+
name: arg.name,
|
|
37
|
+
title: arg.title,
|
|
38
|
+
description: arg.description,
|
|
39
|
+
type: arg.type,
|
|
40
|
+
required: arg.required,
|
|
41
|
+
variadic: arg.variadic
|
|
42
|
+
})), null, 2)}
|
|
43
|
+
}`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Generates the MCP command module using Alloy source generation.
|
|
47
|
+
*/
|
|
48
|
+
function McpCommandModule(props) {
|
|
49
|
+
const context = (0, _shell_shock_core_contexts_power_plant.usePowerlines)();
|
|
50
|
+
const resolvedPath = (0, _stryke_path_join.joinPaths)(context.entryPath, "mcp", "command.ts");
|
|
51
|
+
const commands = props.commands.filter((command) => !command.virtual && command.path !== props.commandName).map((command) => serializeCommand(command)).join(",\n");
|
|
52
|
+
return (0, _alloy_js_core_jsx_runtime.createComponent)(_power_plant_alloy_js_typescript.TypescriptFile, {
|
|
53
|
+
path: resolvedPath,
|
|
54
|
+
imports: {
|
|
55
|
+
"@shell-shock/core": ["defineMetadata", "defineOptions"],
|
|
56
|
+
"@modelcontextprotocol/server": ["McpServer"],
|
|
57
|
+
"@modelcontextprotocol/server/stdio": ["StdioServerTransport"],
|
|
58
|
+
"shell-shock:exec": ["spawn"],
|
|
59
|
+
"zod/v4": ["* as z"]
|
|
60
|
+
},
|
|
61
|
+
get children() {
|
|
62
|
+
return _alloy_js_core.code`
|
|
63
|
+
const COMMAND_NAME = ${JSON.stringify(props.commandName)};
|
|
64
|
+
const APP_NAME = ${JSON.stringify(props.appName)};
|
|
65
|
+
|
|
66
|
+
const COMMANDS = [
|
|
67
|
+
${commands}
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
export const metadata = defineMetadata({
|
|
71
|
+
title: "MCP Server",
|
|
72
|
+
description:
|
|
73
|
+
"Starts an MCP stdio server that exposes this Shell Shock application's commands as tools.",
|
|
74
|
+
icon: "🔌",
|
|
75
|
+
tags: ["Utility", "MCP"]
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
export const options = defineOptions({
|
|
79
|
+
includeSelf: {
|
|
80
|
+
type: "boolean",
|
|
81
|
+
title: "Include MCP Command",
|
|
82
|
+
description:
|
|
83
|
+
"Whether to expose the MCP command itself as a tool in the generated server.",
|
|
84
|
+
default: false,
|
|
85
|
+
required: false,
|
|
86
|
+
variadic: false
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
function toCliArgs(optionsMap: Record<string, unknown>): string[] {
|
|
91
|
+
const args: string[] = [];
|
|
92
|
+
|
|
93
|
+
for (const [rawName, rawValue] of Object.entries(optionsMap ?? {})) {
|
|
94
|
+
if (!/^[a-zA-Z0-9_\-]+$/.test(rawName)) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const flag = toFlagName(rawName);
|
|
99
|
+
if (!flag) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (rawValue === undefined || rawValue === null) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (typeof rawValue === "boolean") {
|
|
108
|
+
args.push(rawValue ? "--" + flag : "--no-" + flag);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (Array.isArray(rawValue)) {
|
|
113
|
+
for (const item of rawValue) {
|
|
114
|
+
if (item === undefined || item === null) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
args.push("--" + flag, String(item));
|
|
119
|
+
}
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
args.push("--" + flag, String(rawValue));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return args;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export default async function handler(options: { includeSelf?: boolean }) {
|
|
130
|
+
const commandMap = new Map<string, typeof COMMANDS[number]>();
|
|
131
|
+
const usedToolNames = new Set<string>();
|
|
132
|
+
const includeSelf = options.includeSelf === true;
|
|
133
|
+
|
|
134
|
+
for (const command of COMMANDS) {
|
|
135
|
+
if (!includeSelf && command.path === COMMAND_NAME) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
let toolName = command.toolName;
|
|
140
|
+
if (usedToolNames.has(toolName)) {
|
|
141
|
+
let index = 2;
|
|
142
|
+
while (usedToolNames.has(toolName + "_" + String(index))) {
|
|
143
|
+
index += 1;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
toolName = toolName + "_" + String(index);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
usedToolNames.add(toolName);
|
|
150
|
+
commandMap.set(toolName, command);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const server = new McpServer({
|
|
154
|
+
name: APP_NAME + "-shell-shock",
|
|
155
|
+
version: "1.0.0"
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
for (const [toolName, command] of commandMap.entries()) {
|
|
159
|
+
server.registerTool(
|
|
160
|
+
toolName,
|
|
161
|
+
{
|
|
162
|
+
title: command.title,
|
|
163
|
+
description: command.description,
|
|
164
|
+
inputSchema: z.object({
|
|
165
|
+
options: z.record(z.unknown()).optional(),
|
|
166
|
+
args: z.array(z.string()).optional(),
|
|
167
|
+
cwd: z.string().optional(),
|
|
168
|
+
timeoutMs: z.number().int().positive().optional()
|
|
169
|
+
})
|
|
170
|
+
},
|
|
171
|
+
async input => {
|
|
172
|
+
const commandArgv = [
|
|
173
|
+
...command.segments,
|
|
174
|
+
...toCliArgs((input.options ?? {}) as Record<string, unknown>),
|
|
175
|
+
...((input.args ?? []) as string[])
|
|
176
|
+
];
|
|
177
|
+
|
|
178
|
+
const launchArgv =
|
|
179
|
+
process.argv.length >= 2
|
|
180
|
+
? [process.argv[0]!, process.argv[1]!, ...commandArgv]
|
|
181
|
+
: [COMMAND_NAME, ...commandArgv];
|
|
182
|
+
|
|
183
|
+
const result = await spawn(launchArgv, {
|
|
184
|
+
cwd: input.cwd,
|
|
185
|
+
timeoutMs: input.timeoutMs ?? 300_000
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const output = [result.stdout, result.stderr]
|
|
189
|
+
.filter(Boolean)
|
|
190
|
+
.join("\n")
|
|
191
|
+
.trim();
|
|
192
|
+
|
|
193
|
+
const isError = (result.code ?? 0) !== 0;
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
isError,
|
|
197
|
+
content: [
|
|
198
|
+
{
|
|
199
|
+
type: "text" as const,
|
|
200
|
+
text:
|
|
201
|
+
output.length > 0
|
|
202
|
+
? output
|
|
203
|
+
: isError
|
|
204
|
+
? "Command failed with exit code " +
|
|
205
|
+
String(result.code ?? 1) +
|
|
206
|
+
"."
|
|
207
|
+
: "Command completed successfully."
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
await server.connect(new StdioServerTransport());
|
|
216
|
+
}
|
|
217
|
+
`;
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
//#endregion
|
|
223
|
+
exports.McpCommandModule = McpCommandModule;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CommandTree } from "@shell-shock/core";
|
|
2
|
+
//#region src/components/mcp-command.d.ts
|
|
3
|
+
interface McpCommandModuleProps {
|
|
4
|
+
appName: string;
|
|
5
|
+
commandName: string;
|
|
6
|
+
commands: CommandTree[];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Generates the MCP command module using Alloy source generation.
|
|
10
|
+
*/
|
|
11
|
+
declare function McpCommandModule(props: McpCommandModuleProps): import("@alloy-js/core").Children;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { McpCommandModule, McpCommandModuleProps };
|
|
14
|
+
//# sourceMappingURL=mcp-command.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-command.d.cts","names":[],"sources":["../../src/components/mcp-command.tsx"],"mappings":";;UAyBiB;EACf;EACA;EACA,UAAU;;;;;iBAoFI,iBAAiB,OAAO,iDAAqB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CommandTree } from "@shell-shock/core";
|
|
2
|
+
//#region src/components/mcp-command.d.ts
|
|
3
|
+
interface McpCommandModuleProps {
|
|
4
|
+
appName: string;
|
|
5
|
+
commandName: string;
|
|
6
|
+
commands: CommandTree[];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Generates the MCP command module using Alloy source generation.
|
|
10
|
+
*/
|
|
11
|
+
declare function McpCommandModule(props: McpCommandModuleProps): import("@alloy-js/core").Children;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { McpCommandModule, McpCommandModuleProps };
|
|
14
|
+
//# sourceMappingURL=mcp-command.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-command.d.mts","names":[],"sources":["../../src/components/mcp-command.tsx"],"mappings":""}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { createComponent } from "@alloy-js/core/jsx-runtime";
|
|
2
|
+
import { joinPaths } from "@stryke/path/join";
|
|
3
|
+
import { code } from "@alloy-js/core";
|
|
4
|
+
import { TypescriptFile } from "@power-plant/alloy-js/typescript";
|
|
5
|
+
import { usePowerlines } from "@shell-shock/core/contexts/power-plant";
|
|
6
|
+
|
|
7
|
+
//#region src/components/mcp-command.tsx
|
|
8
|
+
function toFlagName(input) {
|
|
9
|
+
return input.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[^a-z0-9-]/gi, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
|
|
10
|
+
}
|
|
11
|
+
function toToolName(path) {
|
|
12
|
+
return path.replace(/[/:\s]+/g, "_").replace(/[^\w-]/g, "_").replace(/_{2,}/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
13
|
+
}
|
|
14
|
+
function serializeCommand(command) {
|
|
15
|
+
const optionList = Object.values(command.options ?? {}).map((option) => `--${toFlagName(option.name)} (${option.type}${option.required ? ", required" : ""})`).join(", ");
|
|
16
|
+
const argList = command.args.map((arg) => `${arg.name}:${arg.type}${arg.required ? " (required)" : ""}${arg.variadic ? "[]" : ""}`).join(", ");
|
|
17
|
+
const commandPath = command.path ?? command.name;
|
|
18
|
+
return `{
|
|
19
|
+
id: ${JSON.stringify(command.id)},
|
|
20
|
+
name: ${JSON.stringify(command.name)},
|
|
21
|
+
path: ${JSON.stringify(commandPath)},
|
|
22
|
+
segments: ${JSON.stringify(command.segments)},
|
|
23
|
+
title: ${JSON.stringify(command.title)},
|
|
24
|
+
description: ${JSON.stringify(command.description + (optionList ? `\nOptions: ${optionList}` : "") + (argList ? `\nArgs: ${argList}` : ""))},
|
|
25
|
+
toolName: ${JSON.stringify(toToolName(commandPath) || command.name)},
|
|
26
|
+
options: ${JSON.stringify(Object.values(command.options ?? {}).map((option) => ({
|
|
27
|
+
name: option.name,
|
|
28
|
+
title: option.title,
|
|
29
|
+
description: option.description,
|
|
30
|
+
type: option.type,
|
|
31
|
+
required: option.required,
|
|
32
|
+
variadic: option.variadic
|
|
33
|
+
})), null, 2)},
|
|
34
|
+
args: ${JSON.stringify(command.args.map((arg) => ({
|
|
35
|
+
name: arg.name,
|
|
36
|
+
title: arg.title,
|
|
37
|
+
description: arg.description,
|
|
38
|
+
type: arg.type,
|
|
39
|
+
required: arg.required,
|
|
40
|
+
variadic: arg.variadic
|
|
41
|
+
})), null, 2)}
|
|
42
|
+
}`;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Generates the MCP command module using Alloy source generation.
|
|
46
|
+
*/
|
|
47
|
+
function McpCommandModule(props) {
|
|
48
|
+
const context = usePowerlines();
|
|
49
|
+
const resolvedPath = joinPaths(context.entryPath, "mcp", "command.ts");
|
|
50
|
+
const commands = props.commands.filter((command) => !command.virtual && command.path !== props.commandName).map((command) => serializeCommand(command)).join(",\n");
|
|
51
|
+
return createComponent(TypescriptFile, {
|
|
52
|
+
path: resolvedPath,
|
|
53
|
+
imports: {
|
|
54
|
+
"@shell-shock/core": ["defineMetadata", "defineOptions"],
|
|
55
|
+
"@modelcontextprotocol/server": ["McpServer"],
|
|
56
|
+
"@modelcontextprotocol/server/stdio": ["StdioServerTransport"],
|
|
57
|
+
"shell-shock:exec": ["spawn"],
|
|
58
|
+
"zod/v4": ["* as z"]
|
|
59
|
+
},
|
|
60
|
+
get children() {
|
|
61
|
+
return code`
|
|
62
|
+
const COMMAND_NAME = ${JSON.stringify(props.commandName)};
|
|
63
|
+
const APP_NAME = ${JSON.stringify(props.appName)};
|
|
64
|
+
|
|
65
|
+
const COMMANDS = [
|
|
66
|
+
${commands}
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
export const metadata = defineMetadata({
|
|
70
|
+
title: "MCP Server",
|
|
71
|
+
description:
|
|
72
|
+
"Starts an MCP stdio server that exposes this Shell Shock application's commands as tools.",
|
|
73
|
+
icon: "🔌",
|
|
74
|
+
tags: ["Utility", "MCP"]
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
export const options = defineOptions({
|
|
78
|
+
includeSelf: {
|
|
79
|
+
type: "boolean",
|
|
80
|
+
title: "Include MCP Command",
|
|
81
|
+
description:
|
|
82
|
+
"Whether to expose the MCP command itself as a tool in the generated server.",
|
|
83
|
+
default: false,
|
|
84
|
+
required: false,
|
|
85
|
+
variadic: false
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
function toCliArgs(optionsMap: Record<string, unknown>): string[] {
|
|
90
|
+
const args: string[] = [];
|
|
91
|
+
|
|
92
|
+
for (const [rawName, rawValue] of Object.entries(optionsMap ?? {})) {
|
|
93
|
+
if (!/^[a-zA-Z0-9_\-]+$/.test(rawName)) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const flag = toFlagName(rawName);
|
|
98
|
+
if (!flag) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (rawValue === undefined || rawValue === null) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (typeof rawValue === "boolean") {
|
|
107
|
+
args.push(rawValue ? "--" + flag : "--no-" + flag);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (Array.isArray(rawValue)) {
|
|
112
|
+
for (const item of rawValue) {
|
|
113
|
+
if (item === undefined || item === null) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
args.push("--" + flag, String(item));
|
|
118
|
+
}
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
args.push("--" + flag, String(rawValue));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return args;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export default async function handler(options: { includeSelf?: boolean }) {
|
|
129
|
+
const commandMap = new Map<string, typeof COMMANDS[number]>();
|
|
130
|
+
const usedToolNames = new Set<string>();
|
|
131
|
+
const includeSelf = options.includeSelf === true;
|
|
132
|
+
|
|
133
|
+
for (const command of COMMANDS) {
|
|
134
|
+
if (!includeSelf && command.path === COMMAND_NAME) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
let toolName = command.toolName;
|
|
139
|
+
if (usedToolNames.has(toolName)) {
|
|
140
|
+
let index = 2;
|
|
141
|
+
while (usedToolNames.has(toolName + "_" + String(index))) {
|
|
142
|
+
index += 1;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
toolName = toolName + "_" + String(index);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
usedToolNames.add(toolName);
|
|
149
|
+
commandMap.set(toolName, command);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const server = new McpServer({
|
|
153
|
+
name: APP_NAME + "-shell-shock",
|
|
154
|
+
version: "1.0.0"
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
for (const [toolName, command] of commandMap.entries()) {
|
|
158
|
+
server.registerTool(
|
|
159
|
+
toolName,
|
|
160
|
+
{
|
|
161
|
+
title: command.title,
|
|
162
|
+
description: command.description,
|
|
163
|
+
inputSchema: z.object({
|
|
164
|
+
options: z.record(z.unknown()).optional(),
|
|
165
|
+
args: z.array(z.string()).optional(),
|
|
166
|
+
cwd: z.string().optional(),
|
|
167
|
+
timeoutMs: z.number().int().positive().optional()
|
|
168
|
+
})
|
|
169
|
+
},
|
|
170
|
+
async input => {
|
|
171
|
+
const commandArgv = [
|
|
172
|
+
...command.segments,
|
|
173
|
+
...toCliArgs((input.options ?? {}) as Record<string, unknown>),
|
|
174
|
+
...((input.args ?? []) as string[])
|
|
175
|
+
];
|
|
176
|
+
|
|
177
|
+
const launchArgv =
|
|
178
|
+
process.argv.length >= 2
|
|
179
|
+
? [process.argv[0]!, process.argv[1]!, ...commandArgv]
|
|
180
|
+
: [COMMAND_NAME, ...commandArgv];
|
|
181
|
+
|
|
182
|
+
const result = await spawn(launchArgv, {
|
|
183
|
+
cwd: input.cwd,
|
|
184
|
+
timeoutMs: input.timeoutMs ?? 300_000
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const output = [result.stdout, result.stderr]
|
|
188
|
+
.filter(Boolean)
|
|
189
|
+
.join("\n")
|
|
190
|
+
.trim();
|
|
191
|
+
|
|
192
|
+
const isError = (result.code ?? 0) !== 0;
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
isError,
|
|
196
|
+
content: [
|
|
197
|
+
{
|
|
198
|
+
type: "text" as const,
|
|
199
|
+
text:
|
|
200
|
+
output.length > 0
|
|
201
|
+
? output
|
|
202
|
+
: isError
|
|
203
|
+
? "Command failed with exit code " +
|
|
204
|
+
String(result.code ?? 1) +
|
|
205
|
+
"."
|
|
206
|
+
: "Command completed successfully."
|
|
207
|
+
}
|
|
208
|
+
]
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
await server.connect(new StdioServerTransport());
|
|
215
|
+
}
|
|
216
|
+
`;
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
//#endregion
|
|
222
|
+
export { McpCommandModule };
|
|
223
|
+
//# sourceMappingURL=mcp-command.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-command.mjs","names":[],"sources":[],"mappings":""}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
|
|
2
|
+
const require_components_mcp_command = require('./components/mcp-command.cjs');
|
|
3
|
+
let _alloy_js_core_jsx_runtime = require("@alloy-js/core/jsx-runtime");
|
|
4
|
+
let _shell_shock_core_helpers_power_plant = require("@shell-shock/core/helpers/power-plant");
|
|
5
|
+
let _shell_shock_core_plugin_utils = require("@shell-shock/core/plugin-utils");
|
|
6
|
+
|
|
7
|
+
//#region src/generator.tsx
|
|
8
|
+
/**
|
|
9
|
+
* Power Plant generator for the Shell Shock MCP server command module.
|
|
10
|
+
*
|
|
11
|
+
* @see https://github.com/storm-software/power-plant/tree/main/packages/generators/alloy-js
|
|
12
|
+
*/
|
|
13
|
+
const mcpGenerator = (0, _shell_shock_core_helpers_power_plant.defineCommandGenerator)({
|
|
14
|
+
meta: {
|
|
15
|
+
name: "shell-shock-mcp",
|
|
16
|
+
title: "Shell Shock MCP Generator",
|
|
17
|
+
description: "Generates an MCP stdio server command module from the Shell Shock command tree specification.",
|
|
18
|
+
version: "1.0",
|
|
19
|
+
tags: [
|
|
20
|
+
"shell-shock",
|
|
21
|
+
"mcp",
|
|
22
|
+
"alloy-js"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
generator: async (_commands, options) => {
|
|
26
|
+
if (options.template) {
|
|
27
|
+
await (0, _shell_shock_core_helpers_power_plant.renderCommandTemplate)(options, options.template);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const context = options.context;
|
|
31
|
+
const commands = (await (0, _shell_shock_core_plugin_utils.getCommandList)(context)).sort((a, b) => (a.path ?? a.name).localeCompare(b.path ?? b.name));
|
|
32
|
+
await (0, _shell_shock_core_helpers_power_plant.renderCommandTemplate)(options, (0, _alloy_js_core_jsx_runtime.createComponent)(require_components_mcp_command.McpCommandModule, {
|
|
33
|
+
get appName() {
|
|
34
|
+
return context.config.name;
|
|
35
|
+
},
|
|
36
|
+
get commandName() {
|
|
37
|
+
return context.config.mcp.command.name;
|
|
38
|
+
},
|
|
39
|
+
commands
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
//#endregion
|
|
45
|
+
exports.default = mcpGenerator;
|
|
46
|
+
exports.mcpGenerator = mcpGenerator;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/generator.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Power Plant generator for the Shell Shock MCP server command module.
|
|
4
|
+
*
|
|
5
|
+
* @see https://github.com/storm-software/power-plant/tree/main/packages/generators/alloy-js
|
|
6
|
+
*/
|
|
7
|
+
declare const mcpGenerator: import("@power-plant/core").GeneratorConfigObject<Record<string, import("@shell-shock/schema").SerializedCommandTree>, import("@shell-shock/core/helpers/power-plant").CommandGeneratorOptions, void>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { mcpGenerator as default, mcpGenerator };
|
|
10
|
+
//# sourceMappingURL=generator.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.d.cts","names":[],"sources":["../src/generator.tsx"],"mappings":";;;;;;cA+Ba,0CAAY,sBAAA,6CAAA,wEAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/generator.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Power Plant generator for the Shell Shock MCP server command module.
|
|
4
|
+
*
|
|
5
|
+
* @see https://github.com/storm-software/power-plant/tree/main/packages/generators/alloy-js
|
|
6
|
+
*/
|
|
7
|
+
declare const mcpGenerator: import("@power-plant/core").GeneratorConfigObject<Record<string, import("@shell-shock/schema").SerializedCommandTree>, import("@shell-shock/core/helpers/power-plant").CommandGeneratorOptions, void>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { mcpGenerator as default, mcpGenerator };
|
|
10
|
+
//# sourceMappingURL=generator.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.d.mts","names":[],"sources":["../src/generator.tsx"],"mappings":""}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { McpCommandModule } from "./components/mcp-command.mjs";
|
|
2
|
+
import { createComponent } from "@alloy-js/core/jsx-runtime";
|
|
3
|
+
import { defineCommandGenerator, renderCommandTemplate } from "@shell-shock/core/helpers/power-plant";
|
|
4
|
+
import { getCommandList } from "@shell-shock/core/plugin-utils";
|
|
5
|
+
|
|
6
|
+
//#region src/generator.tsx
|
|
7
|
+
/**
|
|
8
|
+
* Power Plant generator for the Shell Shock MCP server command module.
|
|
9
|
+
*
|
|
10
|
+
* @see https://github.com/storm-software/power-plant/tree/main/packages/generators/alloy-js
|
|
11
|
+
*/
|
|
12
|
+
const mcpGenerator = defineCommandGenerator({
|
|
13
|
+
meta: {
|
|
14
|
+
name: "shell-shock-mcp",
|
|
15
|
+
title: "Shell Shock MCP Generator",
|
|
16
|
+
description: "Generates an MCP stdio server command module from the Shell Shock command tree specification.",
|
|
17
|
+
version: "1.0",
|
|
18
|
+
tags: [
|
|
19
|
+
"shell-shock",
|
|
20
|
+
"mcp",
|
|
21
|
+
"alloy-js"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
generator: async (_commands, options) => {
|
|
25
|
+
if (options.template) {
|
|
26
|
+
await renderCommandTemplate(options, options.template);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const context = options.context;
|
|
30
|
+
const commands = (await getCommandList(context)).sort((a, b) => (a.path ?? a.name).localeCompare(b.path ?? b.name));
|
|
31
|
+
await renderCommandTemplate(options, createComponent(McpCommandModule, {
|
|
32
|
+
get appName() {
|
|
33
|
+
return context.config.name;
|
|
34
|
+
},
|
|
35
|
+
get commandName() {
|
|
36
|
+
return context.config.mcp.command.name;
|
|
37
|
+
},
|
|
38
|
+
commands
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
export { mcpGenerator as default, mcpGenerator };
|
|
45
|
+
//# sourceMappingURL=generator.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.mjs","names":[],"sources":[],"mappings":""}
|