mcp-fs-shell-windows 0.2.4
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 +23 -0
- package/README.md +147 -0
- package/dist/append_files/handler.js +32 -0
- package/dist/append_files/schema.js +7 -0
- package/dist/checksum_files/handler.js +33 -0
- package/dist/checksum_files/schema.js +5 -0
- package/dist/checksum_files_verif/handler.js +66 -0
- package/dist/checksum_files_verif/helpers.js +6 -0
- package/dist/checksum_files_verif/schema.js +8 -0
- package/dist/content_diff/handler.js +11 -0
- package/dist/content_diff/schema.js +7 -0
- package/dist/copy_files/handler.js +43 -0
- package/dist/copy_files/helpers.js +24 -0
- package/dist/copy_files/schema.js +7 -0
- package/dist/count_lines/handler.js +144 -0
- package/dist/count_lines/schema.js +9 -0
- package/dist/create_directories/handler.js +29 -0
- package/dist/create_directories/schema.js +4 -0
- package/dist/delete_files/handler.js +42 -0
- package/dist/delete_files/schema.js +5 -0
- package/dist/delete_files_by_pattern/handler.js +46 -0
- package/dist/delete_files_by_pattern/schema.js +6 -0
- package/dist/directory_tree/handler.js +7 -0
- package/dist/directory_tree/helpers.js +47 -0
- package/dist/directory_tree/schema.js +5 -0
- package/dist/edit_files/handler.js +62 -0
- package/dist/edit_files/schema.js +11 -0
- package/dist/file_diff/handler.js +28 -0
- package/dist/file_diff/schema.js +5 -0
- package/dist/file_info/handler.js +30 -0
- package/dist/file_info/schema.js +4 -0
- package/dist/fuzzy_find_files/handler.js +74 -0
- package/dist/fuzzy_find_files/schema.js +8 -0
- package/dist/helpers/checksum.js +10 -0
- package/dist/helpers/diff.js +10 -0
- package/dist/helpers/path.js +87 -0
- package/dist/index.js +36 -0
- package/dist/list_directory/handler.js +42 -0
- package/dist/list_directory/schema.js +9 -0
- package/dist/move_files/handler.js +68 -0
- package/dist/move_files/schema.js +8 -0
- package/dist/patch_files/handler.js +34 -0
- package/dist/patch_files/helpers.js +103 -0
- package/dist/patch_files/schema.js +18 -0
- package/dist/read_files/handler.js +36 -0
- package/dist/read_files/schema.js +6 -0
- package/dist/search_files/handler.js +15 -0
- package/dist/search_files/helpers.js +71 -0
- package/dist/search_files/schema.js +8 -0
- package/dist/search_glob/handler.js +77 -0
- package/dist/search_glob/schema.js +8 -0
- package/dist/search_regex/handler.js +159 -0
- package/dist/search_regex/schema.js +10 -0
- package/dist/server.js +698 -0
- package/dist/shell/handler.js +687 -0
- package/dist/shell/schema.js +69 -0
- package/dist/write_new_files/handler.js +55 -0
- package/dist/write_new_files/schema.js +9 -0
- package/package.json +37 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// shell/schema.ts — argument schemas for the 8 shell_* tools.
|
|
2
|
+
// (MCP filesystem fork; standalone shell layer that survives Beledarian being disabled.)
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
// The MCP client kills tool requests that run for "tens of seconds" (error -32001).
|
|
5
|
+
// Measured 2026-08-29: a ~63 s in-harness tool call survived (Beledarian's own
|
|
6
|
+
// 60 s cap fired first), so the client window is >63 s. 28 s keeps a wide margin.
|
|
7
|
+
// Anything longer belongs in the background-job registry (shell_start).
|
|
8
|
+
export const SHELL_MAX_TIMEOUT_SEC = 28;
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Tool descriptions (verbatim — pasted into server.ts ListTools entries):
|
|
11
|
+
//
|
|
12
|
+
// shell_run:
|
|
13
|
+
// "Execute a shell command synchronously and return exit code, stdout, and stderr. Host is Windows; use cmd.exe syntax (e.g. `dir C:\\`, `powershell -NoProfile -Command ...`). Optional input is piped to the command's stdin. Optional cwd overrides the default working directory (see shell_cwd). Bounded: default 5 s timeout, max 28 s — for anything longer use shell_start (background job) and poll with shell_check. Non-zero exit or timeout returns an error that still includes the captured output."
|
|
14
|
+
//
|
|
15
|
+
// shell_test:
|
|
16
|
+
// "Execute a test command (e.g. `npm test`, `pytest`) and return {command, exit_code, stdout, stderr, passed}. Never errors on a failing test. Runs with CI=true. Host is Windows; use cmd.exe syntax. Bounded to 28 s by the MCP client timeout — for longer suites use shell_start + shell_check."
|
|
17
|
+
//
|
|
18
|
+
// shell_start:
|
|
19
|
+
// "Start a long-running shell command as a background job and return immediately with a job ID. Host is Windows; use cmd.exe syntax. The job keeps running inside this MCP server process; output is captured (last 256 KB of stdout/stderr) and appended to a log file. Auto-killed after timeout_hours (default 10, max 10). Poll with shell_check; kill with shell_cancel. Optional cwd overrides the default working directory (see shell_cwd)."
|
|
20
|
+
//
|
|
21
|
+
// shell_check:
|
|
22
|
+
// "Check the status and output of a shell background job started with shell_start (or a shell_terminal window). Returns {id, name, status, exitCode, duration_seconds, stdout_tail, stderr_tail, logFile}. Status values: running, completed, error, cancelled, timeout."
|
|
23
|
+
//
|
|
24
|
+
// shell_cancel:
|
|
25
|
+
// "Kill a running shell job (from shell_start or shell_terminal) by job ID. Kills the whole process tree."
|
|
26
|
+
//
|
|
27
|
+
// shell_terminal:
|
|
28
|
+
// "Open a visible, separate, interactive cmd.exe console window (Windows) that runs the given command (as a batch file) with cmd /k. The window has its own console (the user can type into it) and persists after the command finishes. Use it for interactive sessions (ssh, REPLs, TUI programs, prompted installers) - the one case shell_start cannot cover. Returns a job ID with the window's PID; close the window (kill the whole tree) with shell_cancel. Optional cwd sets the window's starting directory."
|
|
29
|
+
//
|
|
30
|
+
// shell_python:
|
|
31
|
+
// "Execute a Python code snippet (requires system Python on PATH). Writes the code to a temp .py file and runs it. Returns exit code, stdout, stderr. Default 5 s timeout, max 28 s; optional cwd. Non-zero exit returns an error that still includes the captured output."
|
|
32
|
+
//
|
|
33
|
+
// shell_cwd:
|
|
34
|
+
// "Get or set the default working directory used by the other shell_* tools. With no argument returns the current default; with path sets it (must be an existing directory). The default starts as the MCP server process's CWD and resets when the server restarts."
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
export const ShellRunArgsSchema = z.object({
|
|
37
|
+
command: z.string().describe("The shell command to execute (Windows cmd.exe syntax)."),
|
|
38
|
+
input: z.string().optional().describe("Input text to pipe to the command's stdin."),
|
|
39
|
+
timeout_seconds: z.number().min(0.1).max(SHELL_MAX_TIMEOUT_SEC).optional().describe("Timeout in seconds (default: 5, max: 28). For anything longer use shell_start + shell_check."),
|
|
40
|
+
cwd: z.string().optional().describe("Working directory override (default: the shell_cwd default)."),
|
|
41
|
+
});
|
|
42
|
+
export const ShellTestArgsSchema = z.object({
|
|
43
|
+
command: z.string().describe("The test command to run (e.g. 'npm test', 'pytest')."),
|
|
44
|
+
cwd: z.string().optional().describe("Working directory override (default: the shell_cwd default)."),
|
|
45
|
+
});
|
|
46
|
+
export const ShellStartArgsSchema = z.object({
|
|
47
|
+
command: z.string().describe("The command to run as a background job (Windows cmd.exe syntax)."),
|
|
48
|
+
name: z.string().optional().default("shelljob").describe("Short label for the job."),
|
|
49
|
+
timeout_hours: z.number().max(10).optional().default(10).describe("Auto-kill the job after this many hours (default 10, max 10)."),
|
|
50
|
+
cwd: z.string().optional().describe("Working directory override (default: the shell_cwd default)."),
|
|
51
|
+
});
|
|
52
|
+
export const ShellCheckArgsSchema = z.object({
|
|
53
|
+
id: z.string().describe("Job ID returned by shell_start or shell_terminal."),
|
|
54
|
+
});
|
|
55
|
+
export const ShellCancelArgsSchema = z.object({
|
|
56
|
+
id: z.string().describe("Job ID returned by shell_start or shell_terminal."),
|
|
57
|
+
});
|
|
58
|
+
export const ShellTerminalArgsSchema = z.object({
|
|
59
|
+
command: z.string().describe("Command to run in the new window."),
|
|
60
|
+
cwd: z.string().optional().describe("Starting directory for the window (default: the shell_cwd default)."),
|
|
61
|
+
});
|
|
62
|
+
export const ShellPythonArgsSchema = z.object({
|
|
63
|
+
python: z.string().describe("Python code to execute (requires system Python on PATH)."),
|
|
64
|
+
timeout_seconds: z.number().min(0.1).max(SHELL_MAX_TIMEOUT_SEC).optional().describe("Timeout in seconds (default: 5, max: 28)."),
|
|
65
|
+
cwd: z.string().optional().describe("Working directory override (default: the shell_cwd default)."),
|
|
66
|
+
});
|
|
67
|
+
export const ShellCwdArgsSchema = z.object({
|
|
68
|
+
path: z.string().optional().describe("Directory to set as the new default. Omit to just get the current default."),
|
|
69
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { validatePath, ensureDirectoryExists } from "../helpers/path.js";
|
|
4
|
+
export async function handleWriteNewFiles(files, allowedDirectories) {
|
|
5
|
+
const results = [];
|
|
6
|
+
const errors = [];
|
|
7
|
+
await Promise.all(files.map(async (file) => {
|
|
8
|
+
try {
|
|
9
|
+
const validPath = await validatePath(file.path, allowedDirectories);
|
|
10
|
+
// Check if file already exists
|
|
11
|
+
if (!file.overwrite) {
|
|
12
|
+
try {
|
|
13
|
+
await fs.access(validPath);
|
|
14
|
+
// If we get here, the file exists
|
|
15
|
+
throw new Error("File already exists. Pass overwrite: true to replace it, or use patch_files/edit_files to modify it.");
|
|
16
|
+
}
|
|
17
|
+
catch (accessError) {
|
|
18
|
+
// File doesn't exist, which is what we want for this function
|
|
19
|
+
if (accessError.code !== "ENOENT") {
|
|
20
|
+
// Some other error occurred during access check
|
|
21
|
+
throw accessError;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// Ensure parent directory exists
|
|
26
|
+
const directory = path.dirname(validPath);
|
|
27
|
+
await ensureDirectoryExists(directory);
|
|
28
|
+
// Write file content
|
|
29
|
+
if (file.encoding === "base64") {
|
|
30
|
+
await fs.writeFile(validPath, Buffer.from(file.content, "base64"));
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
await fs.writeFile(validPath, file.content, "utf-8");
|
|
34
|
+
}
|
|
35
|
+
results.push(`Successfully wrote to ${file.path}${file.overwrite ? " (overwritten)" : ""}`);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
39
|
+
errors.push(`Failed to write file ${file.path}: ${errorMessage}`);
|
|
40
|
+
}
|
|
41
|
+
}));
|
|
42
|
+
// Format the results
|
|
43
|
+
const successCount = results.length;
|
|
44
|
+
const errorCount = errors.length;
|
|
45
|
+
let output = `Processed ${successCount + errorCount} files:\n`;
|
|
46
|
+
output += `- ${successCount} files written successfully\n`;
|
|
47
|
+
if (successCount > 0) {
|
|
48
|
+
output += "Details:\n" + results.join("\n");
|
|
49
|
+
}
|
|
50
|
+
if (errorCount > 0) {
|
|
51
|
+
output += `- ${errorCount} files failed\n\n`;
|
|
52
|
+
output += "Errors:\n" + errors.join("\n");
|
|
53
|
+
}
|
|
54
|
+
return output;
|
|
55
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const WriteNewFilesArgsSchema = z.object({
|
|
3
|
+
files: z.array(z.object({
|
|
4
|
+
path: z.string().describe("Path to the file to write"),
|
|
5
|
+
content: z.string().describe("Content to write to the file (UTF-8 text, or base64 when encoding is \"base64\")"),
|
|
6
|
+
overwrite: z.boolean().optional().default(false).describe("Replace the file if it already exists. Default: false (fail if it exists)."),
|
|
7
|
+
encoding: z.enum(["utf8", "base64"]).optional().default("utf8").describe("Content encoding. Use \"base64\" for binary files."),
|
|
8
|
+
})).describe("Array of files to write"),
|
|
9
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mcp-fs-shell-windows",
|
|
3
|
+
"version": "0.2.4",
|
|
4
|
+
"description": "MCP filesystem server: batched file tools + standalone Windows shell tools (extended fork)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Gerard",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=20"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"bin": {
|
|
12
|
+
"mcp-fs-shell-windows": "dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc && shx chmod +x dist/*.js",
|
|
19
|
+
"prepare": "npm run build",
|
|
20
|
+
"watch": "tsc --watch"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@modelcontextprotocol/sdk": "0.5.0",
|
|
24
|
+
"diff": "^5.1.0",
|
|
25
|
+
"glob": "^10.3.10",
|
|
26
|
+
"minimatch": "^10.0.1",
|
|
27
|
+
"zod": "^3.23.8",
|
|
28
|
+
"zod-to-json-schema": "^3.23.5"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/diff": "^5.0.9",
|
|
32
|
+
"@types/minimatch": "^5.1.2",
|
|
33
|
+
"@types/node": "^22",
|
|
34
|
+
"shx": "^0.3.4",
|
|
35
|
+
"typescript": "^5.3.3"
|
|
36
|
+
}
|
|
37
|
+
}
|