Skip to content

Commit 195d257

Browse files
committed
Create wrapper shim scripts
1 parent 8a9e422 commit 195d257

2 files changed

Lines changed: 126 additions & 2 deletions

File tree

mcp/mcp-cli-api/src/main/java/software/amazon/smithy/java/mcp/cli/ConfigUtils.java

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,12 @@ private ConfigUtils() {}
5353
.serializeTypeInDocuments(false)
5454
.build();
5555

56+
private static final String OS = System.getProperty("os.name").toLowerCase();
57+
private static final boolean WINDOWS = OS.contains("windows");
58+
5659
private static final Path CONFIG_DIR = resolveFromHomeDir(".config", "smithy-mcp");
5760
private static final Path BUNDLE_DIR = CONFIG_DIR.resolve("bundles");
61+
private static final Path SHIMS_DIR = CONFIG_DIR.resolve("mcp-servers");
5862
private static final Path CONFIG_PATH = CONFIG_DIR.resolve("config.json");
5963

6064
private static final DefaultConfigProvider DEFAULT_CONFIG_PROVIDER;
@@ -63,6 +67,7 @@ private ConfigUtils() {}
6367
try {
6468
ensureDirectoryExists(CONFIG_DIR);
6569
ensureDirectoryExists(BUNDLE_DIR);
70+
ensureDirectoryExists(SHIMS_DIR);
6671
} catch (IOException e) {
6772
throw new RuntimeException(e);
6873
}
@@ -169,6 +174,8 @@ public static void removeMcpBundle(Config currentConfig, String bundleName) thro
169174
updateConfig(newConfig);
170175
var bundleFile = getBundleFileLocation(bundleName);
171176
Files.deleteIfExists(bundleFile);
177+
// Remove wrapper script if it exists
178+
removeWrapperScript(bundleName);
172179
}
173180

174181
public static void addToClientConfigs(Config config, String name, Set<String> clients, McpServerConfig serverConfig)
@@ -333,4 +340,110 @@ private static String captureProcessOutput(Process process) throws IOException {
333340
return in.lines().collect(Collectors.joining(System.lineSeparator()));
334341
}
335342
}
343+
344+
public static void createWrapperScript(String bundleName) throws IOException {
345+
Path scriptPath = SHIMS_DIR.resolve(bundleName);
346+
String scriptContent = createScriptContent(bundleName);
347+
348+
Files.writeString(scriptPath, scriptContent, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
349+
scriptPath.toFile().setExecutable(true);
350+
}
351+
352+
private static String createScriptContent(String bundleName) {
353+
if (WINDOWS) {
354+
return "@echo off\nmcp-registry start-server " + bundleName + " %*\n";
355+
} else {
356+
return "#!/bin/bash\nexec mcp-registry start-server " + bundleName + " \"$@\"\n";
357+
}
358+
}
359+
360+
public static void removeWrapperScript(String bundleName) throws IOException {
361+
Path scriptPath = SHIMS_DIR.resolve(bundleName);
362+
Files.deleteIfExists(scriptPath);
363+
}
364+
365+
public static boolean isMcpServersDirInPath() {
366+
String pathEnv = System.getenv("PATH");
367+
if (pathEnv == null) {
368+
return false;
369+
}
370+
371+
String shimsDirStr = SHIMS_DIR.toAbsolutePath().toString();
372+
return pathEnv.contains(shimsDirStr);
373+
}
374+
375+
public static void ensureMcpServersDirInPath() {
376+
if (isMcpServersDirInPath()) {
377+
return;
378+
}
379+
380+
String shimsDirStr = SHIMS_DIR.toAbsolutePath().toString();
381+
382+
if (WINDOWS) {
383+
printWindowsPathInstructions(shimsDirStr);
384+
} else {
385+
if (!tryAddToShellConfigs(shimsDirStr)) {
386+
printUnixPathInstructions(shimsDirStr);
387+
}
388+
}
389+
}
390+
391+
private static boolean tryAddToShellConfigs(String shimsDirStr) {
392+
var pathExport = "export PATH=\"" + shimsDirStr + ":$PATH\"";
393+
var comment = "# Added by smithy-mcp";
394+
var configFiles = List.of(".zshrc", ".bashrc", ".profile", ".bash_profile");
395+
396+
String addedTo = null;
397+
398+
for (var configFile : configFiles) {
399+
var configPath = resolveFromHomeDir(configFile);
400+
401+
if (Files.exists(configPath)) {
402+
try {
403+
// Check if already present
404+
var lines = Files.readAllLines(configPath, StandardCharsets.UTF_8);
405+
boolean alreadyPresent = lines.stream()
406+
.anyMatch(line -> line.contains(shimsDirStr) && line.contains("PATH"));
407+
408+
if (!alreadyPresent) {
409+
// Add the export statement
410+
lines.add("");
411+
lines.add(comment);
412+
lines.add(pathExport);
413+
414+
Files.write(configPath,
415+
lines,
416+
StandardCharsets.UTF_8,
417+
StandardOpenOption.WRITE,
418+
StandardOpenOption.TRUNCATE_EXISTING);
419+
420+
System.out.println("Added mcp-servers directory to PATH in " + configFile);
421+
addedTo = configFile;
422+
}
423+
} catch (IOException e) {
424+
// Continue to next config file if this one fails
425+
}
426+
}
427+
}
428+
429+
if (addedTo != null) {
430+
System.out.println("Please restart your shell or run 'source ~/" + configFiles + "' to reload your PATH");
431+
return true;
432+
}
433+
return false;
434+
}
435+
436+
private static void printWindowsPathInstructions(String shimsDirStr) {
437+
System.out.println("\nTo use the installed bundle as a command, add the mcp-servers directory to your PATH:");
438+
System.out.println(" set PATH=" + shimsDirStr + ";%PATH%");
439+
System.out.println("Or permanently add it through System Properties > Environment Variables");
440+
System.out.println();
441+
}
442+
443+
private static void printUnixPathInstructions(String shimsDirStr) {
444+
System.out.println("\nTo use the installed bundle as a command, add the mcp-servers directory to your PATH:");
445+
System.out.println(" export PATH=\"" + shimsDirStr + ":$PATH\"");
446+
System.out.println("Add this line to your shell profile (~/.bashrc, ~/.zshrc, etc.) to make it permanent");
447+
System.out.println();
448+
}
336449
}

mcp/mcp-cli/src/main/java/software/amazon/smithy/java/mcp/cli/commands/InstallBundle.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,22 @@ protected void execute(ExecutionContext context) throws IOException {
4343
var config = context.config();
4444
var bundle = registry.getMcpBundle(name);
4545
ConfigUtils.addMcpBundle(config, name, bundle);
46-
var command = "mcp-registry";
47-
var args = List.of("start-server", name);
46+
47+
var command = name;
48+
List<String> args = null;
49+
boolean shouldCreateWrapper = true;
50+
4851
if (bundle.getValue() instanceof GenericBundle genericBundle && genericBundle.isExecuteDirectly()) {
4952
command = genericBundle.getRun().getExecutable();
5053
args = genericBundle.getRun().getArgs();
54+
shouldCreateWrapper = false;
55+
}
56+
57+
if (shouldCreateWrapper) {
58+
ConfigUtils.createWrapperScript(name);
59+
ConfigUtils.ensureMcpServersDirInPath();
5160
}
61+
5262
var newClientConfig = McpServerConfig.builder()
5363
.command(command)
5464
.args(args)
@@ -60,6 +70,7 @@ protected void execute(ExecutionContext context) throws IOException {
6070
ConfigUtils.addToClientConfigs(config, name, clients, newClientConfig);
6171

6272
System.out.println("Successfully installed " + name);
73+
6374
if (print) {
6475
System.out.println("You can add the following to your MCP Servers config to use " + name);
6576
System.out.println(newClientConfig);

0 commit comments

Comments
 (0)