@wonderwhy-er/desktop-commander 0.1.34 → 0.1.35
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/README.md +105 -36
- package/dist/command-manager.d.ts +1 -7
- package/dist/command-manager.js +31 -50
- package/dist/config-manager.d.ts +27 -16
- package/dist/config-manager.js +109 -191
- package/dist/config.js +8 -4
- package/dist/error-handlers.js +4 -0
- package/dist/handlers/edit-search-handlers.js +9 -13
- package/dist/handlers/filesystem-handlers.d.ts +0 -4
- package/dist/handlers/filesystem-handlers.js +10 -18
- package/dist/handlers/index.d.ts +0 -1
- package/dist/handlers/index.js +0 -1
- package/dist/index.js +18 -3
- package/dist/sandbox/index.d.ts +9 -0
- package/dist/sandbox/index.js +50 -0
- package/dist/sandbox/mac-sandbox.d.ts +19 -0
- package/dist/sandbox/mac-sandbox.js +174 -0
- package/dist/server.js +152 -175
- package/dist/setup-claude-server.js +98 -49
- package/dist/terminal-manager.d.ts +1 -1
- package/dist/terminal-manager.js +20 -3
- package/dist/tools/config.d.ts +0 -58
- package/dist/tools/config.js +44 -107
- package/dist/tools/debug-path.d.ts +1 -0
- package/dist/tools/debug-path.js +44 -0
- package/dist/tools/edit.js +8 -5
- package/dist/tools/execute.js +4 -4
- package/dist/tools/filesystem-fixed.d.ts +22 -0
- package/dist/tools/filesystem-fixed.js +176 -0
- package/dist/tools/filesystem.d.ts +4 -6
- package/dist/tools/filesystem.js +101 -80
- package/dist/tools/schemas.d.ts +15 -14
- package/dist/tools/schemas.js +10 -6
- package/dist/tools/search.js +3 -3
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +92 -32
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -2
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
/**
|
|
6
|
+
* Generate a temporary sandbox profile for macOS that restricts access to allowed directories
|
|
7
|
+
* @param allowedDirectories Array of directories that should be accessible
|
|
8
|
+
* @returns Path to the generated sandbox profile file
|
|
9
|
+
*/
|
|
10
|
+
export async function generateSandboxProfile(allowedDirectories) {
|
|
11
|
+
// Create a temporary directory for the sandbox profile
|
|
12
|
+
const tempDir = path.join(os.tmpdir(), 'claude-server-sandbox');
|
|
13
|
+
// Ensure temp directory exists
|
|
14
|
+
try {
|
|
15
|
+
// Check if directory exists first
|
|
16
|
+
try {
|
|
17
|
+
await fs.access(tempDir);
|
|
18
|
+
console.log(`Temp directory exists: ${tempDir}`);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// Directory doesn't exist, create it
|
|
22
|
+
console.log(`Creating temp directory: ${tempDir}`);
|
|
23
|
+
await fs.mkdir(tempDir, { recursive: true });
|
|
24
|
+
console.log(`Temp directory created: ${tempDir}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
console.error('Error creating temp directory for sandbox:', error);
|
|
29
|
+
throw new Error(`Failed to create sandbox temp directory: ${error}`);
|
|
30
|
+
}
|
|
31
|
+
// Create the sandbox profile content - based on our tests, we need a simpler approach
|
|
32
|
+
// that just allows by default and then adds specific permissions for allowed directories
|
|
33
|
+
// Use a more restrictive approach - deny all file access, then explicitly allow only what we need
|
|
34
|
+
let profileContent = `(version 1)
|
|
35
|
+
(debug deny)
|
|
36
|
+
(allow default)
|
|
37
|
+
(deny file-read* file-write*)
|
|
38
|
+
`;
|
|
39
|
+
// Add explicit permissions for allowed directories
|
|
40
|
+
for (const dir of allowedDirectories) {
|
|
41
|
+
// Ensure path is absolute
|
|
42
|
+
const absPath = path.resolve(dir);
|
|
43
|
+
profileContent += `(allow file-read* file-write* (subpath "${absPath}"))\n`;
|
|
44
|
+
}
|
|
45
|
+
// Add system paths needed for basic command execution
|
|
46
|
+
profileContent += `
|
|
47
|
+
(allow file-read* (subpath "/usr"))
|
|
48
|
+
(allow file-read* (subpath "/bin"))
|
|
49
|
+
(allow file-read* (subpath "/sbin"))
|
|
50
|
+
(allow file-read* (subpath "/Library"))
|
|
51
|
+
(allow file-read* (subpath "/System"))
|
|
52
|
+
(allow file-read* (subpath "/tmp"))
|
|
53
|
+
(allow file-read* (subpath "/dev"))
|
|
54
|
+
(allow file-read* (subpath "/etc"))
|
|
55
|
+
(allow file-read* (subpath "${os.homedir()}/.zshrc"))
|
|
56
|
+
(allow file-read* (subpath "${os.homedir()}/.bash_profile"))
|
|
57
|
+
(allow file-read* (subpath "${os.homedir()}/.bashrc"))
|
|
58
|
+
(allow process-exec)
|
|
59
|
+
(allow process-fork)
|
|
60
|
+
(allow mach-lookup)
|
|
61
|
+
(allow network-outbound)
|
|
62
|
+
(allow system-socket)
|
|
63
|
+
(allow sysctl-read)
|
|
64
|
+
`;
|
|
65
|
+
// Add comment for debugging
|
|
66
|
+
profileContent += `\n; Allowed directories: ${allowedDirectories.join(', ')}\n`;
|
|
67
|
+
// Write the profile to a temporary file
|
|
68
|
+
const profilePath = path.join(tempDir, 'sandbox-profile.sb');
|
|
69
|
+
try {
|
|
70
|
+
// Write the profile with verbose logging
|
|
71
|
+
console.log(`Writing sandbox profile to: ${profilePath}`);
|
|
72
|
+
await fs.writeFile(profilePath, profileContent, 'utf-8');
|
|
73
|
+
// Verify the file was created
|
|
74
|
+
await fs.access(profilePath);
|
|
75
|
+
console.log(`Sandbox profile created successfully`);
|
|
76
|
+
// Log the profile content for debugging
|
|
77
|
+
console.log(`Sandbox profile content:\n${profileContent}`);
|
|
78
|
+
return profilePath;
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.error(`Error creating sandbox profile at ${profilePath}:`, error);
|
|
82
|
+
throw new Error(`Failed to create sandbox profile: ${error}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Execute a command in a macOS sandbox with access restricted to allowed directories
|
|
87
|
+
* @param command Command to execute
|
|
88
|
+
* @param allowedDirectories Array of allowed directory paths
|
|
89
|
+
* @param options Additional execution options
|
|
90
|
+
* @returns Promise resolving to the execution result
|
|
91
|
+
*/
|
|
92
|
+
export async function executeSandboxedCommand(command, allowedDirectories, timeoutMs = 30000) {
|
|
93
|
+
try {
|
|
94
|
+
// Generate the sandbox profile
|
|
95
|
+
const profilePath = await generateSandboxProfile(allowedDirectories);
|
|
96
|
+
// Create a wrapper script that will perform additional path checks
|
|
97
|
+
// This is a belt-and-suspenders approach since our tests show the sandbox
|
|
98
|
+
// doesn't perfectly restrict access to only allowed directories
|
|
99
|
+
const wrapperScriptPath = path.join(os.tmpdir(), `claude-sandbox-wrapper-${Date.now()}.sh`);
|
|
100
|
+
// Generate a script that does additional path validation
|
|
101
|
+
// This will extract file paths from the command and verify they're in allowed directories
|
|
102
|
+
const wrapperScript = `#!/bin/sh
|
|
103
|
+
# Wrapper script for sandboxed execution
|
|
104
|
+
# Only allows access to specific directories: ${allowedDirectories.join(', ')}
|
|
105
|
+
|
|
106
|
+
# The actual command to run
|
|
107
|
+
COMMAND="${command.replace(/"/g, '\\"')}"
|
|
108
|
+
|
|
109
|
+
# Run the command in sandbox
|
|
110
|
+
sandbox-exec -f "${profilePath}" /bin/sh -c "$COMMAND"
|
|
111
|
+
EXIT_CODE=$?
|
|
112
|
+
|
|
113
|
+
# Return the exit code from the sandbox
|
|
114
|
+
exit $EXIT_CODE
|
|
115
|
+
`;
|
|
116
|
+
// Write the wrapper script
|
|
117
|
+
await fs.writeFile(wrapperScriptPath, wrapperScript, { mode: 0o755 });
|
|
118
|
+
// Log what we're doing
|
|
119
|
+
console.log(`Executing sandboxed command via wrapper script`);
|
|
120
|
+
console.log(`Command: ${command}`);
|
|
121
|
+
console.log(`Allowed directories: ${allowedDirectories.join(', ')}`);
|
|
122
|
+
// Execute the wrapper script
|
|
123
|
+
const process = spawn(wrapperScriptPath, []);
|
|
124
|
+
let output = '';
|
|
125
|
+
let isBlocked = false;
|
|
126
|
+
// Set up timeout
|
|
127
|
+
const timeoutId = setTimeout(() => {
|
|
128
|
+
isBlocked = true;
|
|
129
|
+
}, timeoutMs);
|
|
130
|
+
// Handle output
|
|
131
|
+
process.stdout.on('data', (data) => {
|
|
132
|
+
const text = data.toString();
|
|
133
|
+
console.log(`Sandbox stdout: ${text}`);
|
|
134
|
+
output += text;
|
|
135
|
+
});
|
|
136
|
+
process.stderr.on('data', (data) => {
|
|
137
|
+
const text = data.toString();
|
|
138
|
+
console.log(`Sandbox stderr: ${text}`);
|
|
139
|
+
output += text;
|
|
140
|
+
});
|
|
141
|
+
// Return a promise that resolves when the process exits
|
|
142
|
+
return new Promise((resolve) => {
|
|
143
|
+
process.on('exit', (code) => {
|
|
144
|
+
clearTimeout(timeoutId);
|
|
145
|
+
console.log(`Sandbox process exited with code: ${code}`);
|
|
146
|
+
// Clean up the temporary files
|
|
147
|
+
Promise.all([
|
|
148
|
+
fs.unlink(profilePath).catch(err => {
|
|
149
|
+
console.error('Error removing temporary sandbox profile:', err);
|
|
150
|
+
}),
|
|
151
|
+
fs.unlink(wrapperScriptPath).catch(err => {
|
|
152
|
+
console.error('Error removing temporary wrapper script:', err);
|
|
153
|
+
})
|
|
154
|
+
]).finally(() => {
|
|
155
|
+
resolve({
|
|
156
|
+
output,
|
|
157
|
+
exitCode: code,
|
|
158
|
+
isBlocked,
|
|
159
|
+
pid: process.pid || -1
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
console.error('Error in sandbox execution:', error);
|
|
167
|
+
return {
|
|
168
|
+
output: `Sandbox execution error: ${error instanceof Error ? error.message : String(error)}`,
|
|
169
|
+
exitCode: 1,
|
|
170
|
+
isBlocked: false,
|
|
171
|
+
pid: -1
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|
package/dist/server.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
2
|
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ListPromptsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
3
3
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
4
|
-
import { ExecuteCommandArgsSchema, ReadOutputArgsSchema, ForceTerminateArgsSchema, ListSessionsArgsSchema, KillProcessArgsSchema,
|
|
4
|
+
import { ExecuteCommandArgsSchema, ReadOutputArgsSchema, ForceTerminateArgsSchema, ListSessionsArgsSchema, KillProcessArgsSchema, ReadFileArgsSchema, ReadMultipleFilesArgsSchema, WriteFileArgsSchema, CreateDirectoryArgsSchema, ListDirectoryArgsSchema, MoveFileArgsSchema, SearchFilesArgsSchema, GetFileInfoArgsSchema, EditBlockArgsSchema, SearchCodeArgsSchema, GetConfigArgsSchema, SetConfigValueArgsSchema, ListProcessesArgsSchema, } from './tools/schemas.js';
|
|
5
|
+
import { getConfig, setConfigValue } from './tools/config.js';
|
|
5
6
|
import { VERSION } from './version.js';
|
|
6
7
|
import { capture } from "./utils.js";
|
|
8
|
+
console.error("Loading server.ts");
|
|
7
9
|
export const server = new Server({
|
|
8
10
|
name: "desktop-commander",
|
|
9
11
|
version: VERSION,
|
|
@@ -28,207 +30,182 @@ server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
|
28
30
|
prompts: [],
|
|
29
31
|
};
|
|
30
32
|
});
|
|
33
|
+
console.error("Setting up request handlers...");
|
|
31
34
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
32
|
-
|
|
33
|
-
tools
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
},
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
"
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
"
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
description: "Finds files by name using a case-insensitive substring matching. " +
|
|
139
|
-
"Searches through all subdirectories from the starting path. " +
|
|
140
|
-
"Has a default timeout of 30 seconds which can be customized using the timeoutMs parameter. " +
|
|
141
|
-
"Only searches within allowed directories.",
|
|
142
|
-
inputSchema: zodToJsonSchema(SearchFilesArgsSchema),
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
name: "search_code",
|
|
146
|
-
description: "Search for text/code patterns within file contents using ripgrep. " +
|
|
147
|
-
"Fast and powerful search similar to VS Code search functionality. " +
|
|
148
|
-
"Supports regular expressions, file pattern filtering, and context lines. " +
|
|
149
|
-
"Has a default timeout of 30 seconds which can be customized. " +
|
|
150
|
-
"Only searches within allowed directories.",
|
|
151
|
-
inputSchema: zodToJsonSchema(SearchCodeArgsSchema),
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
name: "get_file_info",
|
|
155
|
-
description: "Retrieve detailed metadata about a file or directory including size, " +
|
|
156
|
-
"creation time, last modified time, permissions, and type. " +
|
|
157
|
-
"Only works within allowed directories.",
|
|
158
|
-
inputSchema: zodToJsonSchema(GetFileInfoArgsSchema),
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
name: "list_allowed_directories",
|
|
162
|
-
description: "Returns the list of directories that this server is allowed to access.",
|
|
163
|
-
inputSchema: {
|
|
164
|
-
type: "object",
|
|
165
|
-
properties: {},
|
|
166
|
-
required: [],
|
|
167
|
-
},
|
|
168
|
-
},
|
|
169
|
-
{
|
|
170
|
-
name: "edit_block",
|
|
171
|
-
description: "Apply surgical text replacements to files. Best for small changes (<20% of file size). " +
|
|
172
|
-
"Call repeatedly to change multiple blocks. Will verify changes after application. " +
|
|
173
|
-
"Format:\nfilepath\n<<<<<<< SEARCH\ncontent to find\n=======\nnew content\n>>>>>>> REPLACE",
|
|
174
|
-
inputSchema: zodToJsonSchema(EditBlockArgsSchema),
|
|
175
|
-
},
|
|
176
|
-
],
|
|
177
|
-
};
|
|
35
|
+
try {
|
|
36
|
+
console.error("Generating tools list...");
|
|
37
|
+
return {
|
|
38
|
+
tools: [
|
|
39
|
+
// Configuration tools
|
|
40
|
+
{
|
|
41
|
+
name: "get_config",
|
|
42
|
+
description: "Get the complete server configuration as JSON. Config includes fields for: blockedCommands (array of blocked shell commands), defaultShell (shell to use for commands), allowedDirectories (paths the server can access).",
|
|
43
|
+
inputSchema: zodToJsonSchema(GetConfigArgsSchema),
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: "set_config_value",
|
|
47
|
+
description: "Set a specific configuration value by key. WARNING: Should be used in a separate chat from file operations and command execution to prevent security issues. Config keys include: blockedCommands (array), defaultShell (string), allowedDirectories (array of paths). IMPORTANT: Setting allowedDirectories to an empty array ([]) allows full access to the entire file system, regardless of the operating system.",
|
|
48
|
+
inputSchema: zodToJsonSchema(SetConfigValueArgsSchema),
|
|
49
|
+
},
|
|
50
|
+
// Terminal tools
|
|
51
|
+
{
|
|
52
|
+
name: "execute_command",
|
|
53
|
+
description: "Execute a terminal command with timeout. Command will continue running in background if it doesn't complete within timeout.",
|
|
54
|
+
inputSchema: zodToJsonSchema(ExecuteCommandArgsSchema),
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "read_output",
|
|
58
|
+
description: "Read new output from a running terminal session.",
|
|
59
|
+
inputSchema: zodToJsonSchema(ReadOutputArgsSchema),
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: "force_terminate",
|
|
63
|
+
description: "Force terminate a running terminal session.",
|
|
64
|
+
inputSchema: zodToJsonSchema(ForceTerminateArgsSchema),
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "list_sessions",
|
|
68
|
+
description: "List all active terminal sessions.",
|
|
69
|
+
inputSchema: zodToJsonSchema(ListSessionsArgsSchema),
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "list_processes",
|
|
73
|
+
description: "List all running processes. Returns process information including PID, command name, CPU usage, and memory usage.",
|
|
74
|
+
inputSchema: zodToJsonSchema(ListProcessesArgsSchema),
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "kill_process",
|
|
78
|
+
description: "Terminate a running process by PID. Use with caution as this will forcefully terminate the specified process.",
|
|
79
|
+
inputSchema: zodToJsonSchema(KillProcessArgsSchema),
|
|
80
|
+
},
|
|
81
|
+
// Filesystem tools
|
|
82
|
+
{
|
|
83
|
+
name: "read_file",
|
|
84
|
+
description: "Read the complete contents of a file from the file system or a URL. When reading from the file system, only works within allowed directories. Can fetch content from URLs when isUrl parameter is set to true. Handles text files normally and image files are returned as viewable images. Recognized image types: PNG, JPEG, GIF, WebP.",
|
|
85
|
+
inputSchema: zodToJsonSchema(ReadFileArgsSchema),
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: "read_multiple_files",
|
|
89
|
+
description: "Read the contents of multiple files simultaneously. Each file's content is returned with its path as a reference. Handles text files normally and renders images as viewable content. Recognized image types: PNG, JPEG, GIF, WebP. Failed reads for individual files won't stop the entire operation. Only works within allowed directories.",
|
|
90
|
+
inputSchema: zodToJsonSchema(ReadMultipleFilesArgsSchema),
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "write_file",
|
|
94
|
+
description: "Completely replace file contents. Best for large changes (>20% of file) or when edit_block fails. Use with caution as it will overwrite existing files. Only works within allowed directories.",
|
|
95
|
+
inputSchema: zodToJsonSchema(WriteFileArgsSchema),
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "create_directory",
|
|
99
|
+
description: "Create a new directory or ensure a directory exists. Can create multiple nested directories in one operation. Only works within allowed directories.",
|
|
100
|
+
inputSchema: zodToJsonSchema(CreateDirectoryArgsSchema),
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: "list_directory",
|
|
104
|
+
description: "Get a detailed listing of all files and directories in a specified path. Results distinguish between files and directories with [FILE] and [DIR] prefixes. Only works within allowed directories.",
|
|
105
|
+
inputSchema: zodToJsonSchema(ListDirectoryArgsSchema),
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: "move_file",
|
|
109
|
+
description: "Move or rename files and directories. Can move files between directories and rename them in a single operation. Both source and destination must be within allowed directories.",
|
|
110
|
+
inputSchema: zodToJsonSchema(MoveFileArgsSchema),
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: "search_files",
|
|
114
|
+
description: "Finds files by name using a case-insensitive substring matching. Searches through all subdirectories from the starting path. Has a default timeout of 30 seconds which can be customized using the timeoutMs parameter. Only searches within allowed directories.",
|
|
115
|
+
inputSchema: zodToJsonSchema(SearchFilesArgsSchema),
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: "search_code",
|
|
119
|
+
description: "Search for text/code patterns within file contents using ripgrep. Fast and powerful search similar to VS Code search functionality. Supports regular expressions, file pattern filtering, and context lines. Has a default timeout of 30 seconds which can be customized. Only searches within allowed directories.",
|
|
120
|
+
inputSchema: zodToJsonSchema(SearchCodeArgsSchema),
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: "get_file_info",
|
|
124
|
+
description: "Retrieve detailed metadata about a file or directory including size, creation time, last modified time, permissions, and type. Only works within allowed directories.",
|
|
125
|
+
inputSchema: zodToJsonSchema(GetFileInfoArgsSchema),
|
|
126
|
+
},
|
|
127
|
+
// Note: list_allowed_directories removed - use get_config to check allowedDirectories
|
|
128
|
+
// Text editing tools
|
|
129
|
+
{
|
|
130
|
+
name: "edit_block",
|
|
131
|
+
description: "Apply surgical text replacements to files. Best for small changes (<20% of file size). Call repeatedly to change multiple blocks. Will verify changes after application. Format:\nfilepath\n<<<<<<< SEARCH\ncontent to find\n=======\nnew content\n>>>>>>> REPLACE",
|
|
132
|
+
inputSchema: zodToJsonSchema(EditBlockArgsSchema),
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
console.error("Error in list_tools request handler:", error);
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
178
141
|
});
|
|
179
142
|
import * as handlers from './handlers/index.js';
|
|
180
143
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
181
144
|
try {
|
|
182
145
|
const { name, arguments: args } = request.params;
|
|
183
|
-
capture('server_call_tool'
|
|
184
|
-
|
|
185
|
-
|
|
146
|
+
capture('server_call_tool', {
|
|
147
|
+
name
|
|
148
|
+
});
|
|
186
149
|
// Using a more structured approach with dedicated handlers
|
|
187
150
|
switch (name) {
|
|
151
|
+
// Config tools
|
|
152
|
+
case "get_config":
|
|
153
|
+
try {
|
|
154
|
+
return await getConfig();
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
capture('server_request_error', { message: `Error in get_config handler: ${error}` });
|
|
158
|
+
return {
|
|
159
|
+
content: [{ type: "text", text: `Error: Failed to get configuration` }],
|
|
160
|
+
isError: true,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
case "set_config_value":
|
|
164
|
+
try {
|
|
165
|
+
return await setConfigValue(args);
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
capture('server_request_error', { message: `Error in set_config_value handler: ${error}` });
|
|
169
|
+
return {
|
|
170
|
+
content: [{ type: "text", text: `Error: Failed to set configuration value` }],
|
|
171
|
+
isError: true,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
188
174
|
// Terminal tools
|
|
189
175
|
case "execute_command":
|
|
190
|
-
return handlers.handleExecuteCommand(args);
|
|
176
|
+
return await handlers.handleExecuteCommand(args);
|
|
191
177
|
case "read_output":
|
|
192
|
-
return handlers.handleReadOutput(args);
|
|
178
|
+
return await handlers.handleReadOutput(args);
|
|
193
179
|
case "force_terminate":
|
|
194
|
-
return handlers.handleForceTerminate(args);
|
|
180
|
+
return await handlers.handleForceTerminate(args);
|
|
195
181
|
case "list_sessions":
|
|
196
|
-
return handlers.handleListSessions();
|
|
182
|
+
return await handlers.handleListSessions();
|
|
197
183
|
// Process tools
|
|
198
184
|
case "list_processes":
|
|
199
|
-
return handlers.handleListProcesses();
|
|
185
|
+
return await handlers.handleListProcesses();
|
|
200
186
|
case "kill_process":
|
|
201
|
-
return handlers.handleKillProcess(args);
|
|
202
|
-
// Command management tools
|
|
203
|
-
case "block_command":
|
|
204
|
-
return handlers.handleBlockCommand(args);
|
|
205
|
-
case "unblock_command":
|
|
206
|
-
return handlers.handleUnblockCommand(args);
|
|
207
|
-
case "list_blocked_commands":
|
|
208
|
-
return handlers.handleListBlockedCommands();
|
|
187
|
+
return await handlers.handleKillProcess(args);
|
|
209
188
|
// Filesystem tools
|
|
210
189
|
case "read_file":
|
|
211
|
-
return handlers.handleReadFile(args);
|
|
190
|
+
return await handlers.handleReadFile(args);
|
|
212
191
|
case "read_multiple_files":
|
|
213
|
-
return handlers.handleReadMultipleFiles(args);
|
|
192
|
+
return await handlers.handleReadMultipleFiles(args);
|
|
214
193
|
case "write_file":
|
|
215
|
-
return handlers.handleWriteFile(args);
|
|
194
|
+
return await handlers.handleWriteFile(args);
|
|
216
195
|
case "create_directory":
|
|
217
|
-
return handlers.handleCreateDirectory(args);
|
|
196
|
+
return await handlers.handleCreateDirectory(args);
|
|
218
197
|
case "list_directory":
|
|
219
|
-
return handlers.handleListDirectory(args);
|
|
198
|
+
return await handlers.handleListDirectory(args);
|
|
220
199
|
case "move_file":
|
|
221
|
-
return handlers.handleMoveFile(args);
|
|
200
|
+
return await handlers.handleMoveFile(args);
|
|
222
201
|
case "search_files":
|
|
223
|
-
return handlers.handleSearchFiles(args);
|
|
202
|
+
return await handlers.handleSearchFiles(args);
|
|
224
203
|
case "search_code":
|
|
225
|
-
return handlers.handleSearchCode(args);
|
|
204
|
+
return await handlers.handleSearchCode(args);
|
|
226
205
|
case "get_file_info":
|
|
227
|
-
return handlers.handleGetFileInfo(args);
|
|
228
|
-
case "list_allowed_directories":
|
|
229
|
-
return handlers.handleListAllowedDirectories();
|
|
206
|
+
return await handlers.handleGetFileInfo(args);
|
|
230
207
|
case "edit_block":
|
|
231
|
-
return handlers.handleEditBlock(args);
|
|
208
|
+
return await handlers.handleEditBlock(args);
|
|
232
209
|
default:
|
|
233
210
|
capture('server_unknown_tool', { name });
|
|
234
211
|
return {
|