@wonderwhy-er/desktop-commander 0.2.14 → 0.2.16
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 +44 -1
- package/dist/custom-stdio.js +4 -2
- package/dist/handlers/search-handlers.js +4 -0
- package/dist/index.js +28 -10
- package/dist/search-manager.d.ts +2 -1
- package/dist/search-manager.js +14 -16
- package/dist/server.d.ts +1 -0
- package/dist/server.js +110 -5
- package/dist/tools/config.js +1 -11
- package/dist/types.d.ts +1 -0
- package/dist/utils/system-info.d.ts +12 -0
- package/dist/utils/system-info.js +58 -7
- package/dist/utils/usageTracker.js +15 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -86,6 +86,11 @@ For debugging mode (allows Node.js inspector connection):
|
|
|
86
86
|
```
|
|
87
87
|
npx @wonderwhy-er/desktop-commander@latest setup --debug
|
|
88
88
|
```
|
|
89
|
+
|
|
90
|
+
**Command line options during setup:**
|
|
91
|
+
- `--debug`: Enable debugging mode for Node.js inspector
|
|
92
|
+
- `--no-onboarding`: Disable onboarding prompts for new users
|
|
93
|
+
|
|
89
94
|
Restart Claude if running.
|
|
90
95
|
|
|
91
96
|
**✅ Auto-Updates:** Yes - automatically updates when you restart Claude
|
|
@@ -652,6 +657,44 @@ set_config_value({ "key": "fileWriteLineLimit", "value": 25 })
|
|
|
652
657
|
|
|
653
658
|
4. **Always verify configuration after changes**: Use `get_config({})` to confirm your changes were applied correctly.
|
|
654
659
|
|
|
660
|
+
## Command Line Options
|
|
661
|
+
|
|
662
|
+
Desktop Commander supports several command line options for customizing behavior:
|
|
663
|
+
|
|
664
|
+
### Disable Onboarding
|
|
665
|
+
|
|
666
|
+
By default, Desktop Commander shows helpful onboarding prompts to new users (those with fewer than 10 tool calls). You can disable this behavior:
|
|
667
|
+
|
|
668
|
+
```bash
|
|
669
|
+
# Disable onboarding for this session
|
|
670
|
+
node dist/index.js --no-onboarding
|
|
671
|
+
|
|
672
|
+
# Or if using npm scripts
|
|
673
|
+
npm run start:no-onboarding
|
|
674
|
+
|
|
675
|
+
# For npx installations, modify your claude_desktop_config.json:
|
|
676
|
+
{
|
|
677
|
+
"mcpServers": {
|
|
678
|
+
"desktop-commander": {
|
|
679
|
+
"command": "npx",
|
|
680
|
+
"args": [
|
|
681
|
+
"-y",
|
|
682
|
+
"@wonderwhy-er/desktop-commander@latest",
|
|
683
|
+
"--no-onboarding"
|
|
684
|
+
]
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
**When onboarding is automatically disabled:**
|
|
691
|
+
- When the MCP client name is set to "desktop-commander"
|
|
692
|
+
- When using the `--no-onboarding` flag
|
|
693
|
+
- After users have used onboarding prompts or made 10+ tool calls
|
|
694
|
+
|
|
695
|
+
**Debug information:**
|
|
696
|
+
The server will log when onboarding is disabled: `"Onboarding disabled via --no-onboarding flag"`
|
|
697
|
+
|
|
655
698
|
## Using Different Shells
|
|
656
699
|
|
|
657
700
|
You can specify which shell to use for command execution:
|
|
@@ -911,7 +954,7 @@ External telemetry (sent to analytics services) is enabled by default but can be
|
|
|
911
954
|
|
|
912
955
|
**Note:** This only disables external telemetry. Local usage analytics remain active for tool functionality but is not share externally
|
|
913
956
|
|
|
914
|
-
For complete details about data collection, please see our [Privacy Policy](
|
|
957
|
+
For complete details about data collection, please see our [Privacy Policy](https://legal.desktopcommander.app/privacy_desktop_commander_mcp).
|
|
915
958
|
|
|
916
959
|
## Verifications
|
|
917
960
|
[](https://mseep.ai/app/25ff7a06-58bc-40b8-bd79-ebb715140f1a)
|
package/dist/custom-stdio.js
CHANGED
|
@@ -22,14 +22,16 @@ export class FilteredStdioServerTransport extends StdioServerTransport {
|
|
|
22
22
|
this.setupConsoleRedirection();
|
|
23
23
|
// Setup stdout filtering for any other output
|
|
24
24
|
this.setupStdoutFiltering();
|
|
25
|
-
//
|
|
26
|
-
|
|
25
|
+
// Note: We defer the initialization notification until enableNotifications() is called
|
|
26
|
+
// to ensure MCP protocol compliance - notifications must not be sent before initialization
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
29
|
* Call this method after MCP initialization is complete to enable JSON-RPC notifications
|
|
30
30
|
*/
|
|
31
31
|
enableNotifications() {
|
|
32
32
|
this.isInitialized = true;
|
|
33
|
+
// Send the deferred initialization notification first
|
|
34
|
+
this.sendLogNotification('info', ['Enhanced FilteredStdioServerTransport initialized']);
|
|
33
35
|
// Replay all buffered messages in chronological order
|
|
34
36
|
if (this.messageBuffer.length > 0) {
|
|
35
37
|
this.sendLogNotification('info', [`Replaying ${this.messageBuffer.length} buffered initialization messages`]);
|
|
@@ -132,6 +132,10 @@ export async function handleGetMoreSearchResults(args) {
|
|
|
132
132
|
}
|
|
133
133
|
if (results.isComplete) {
|
|
134
134
|
output += `\n✅ Search completed.`;
|
|
135
|
+
// Warn users if search was incomplete due to permission issues
|
|
136
|
+
if (results.wasIncomplete) {
|
|
137
|
+
output += `\n⚠️ Warning: Some files were inaccessible due to permissions. Results may be incomplete.`;
|
|
138
|
+
}
|
|
135
139
|
}
|
|
136
140
|
return {
|
|
137
141
|
content: [{ type: "text", text: output }],
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { FilteredStdioServerTransport } from './custom-stdio.js';
|
|
3
|
-
import { server } from './server.js';
|
|
3
|
+
import { server, flushDeferredMessages } from './server.js';
|
|
4
4
|
import { configManager } from './config-manager.js';
|
|
5
5
|
import { runSetup } from './npm-scripts/setup.js';
|
|
6
6
|
import { runUninstall } from './npm-scripts/uninstall.js';
|
|
7
7
|
import { capture } from './utils/capture.js';
|
|
8
8
|
import { logToStderr, logger } from './utils/logger.js';
|
|
9
|
+
// Store messages to defer until after initialization
|
|
10
|
+
const deferredMessages = [];
|
|
11
|
+
function deferLog(level, message) {
|
|
12
|
+
deferredMessages.push({ level, message });
|
|
13
|
+
}
|
|
9
14
|
async function runServer() {
|
|
10
15
|
try {
|
|
11
16
|
// Check if first argument is "setup"
|
|
@@ -18,17 +23,24 @@ async function runServer() {
|
|
|
18
23
|
await runUninstall();
|
|
19
24
|
return;
|
|
20
25
|
}
|
|
26
|
+
// Parse command line arguments for onboarding control
|
|
27
|
+
const DISABLE_ONBOARDING = process.argv.includes('--no-onboarding');
|
|
28
|
+
if (DISABLE_ONBOARDING) {
|
|
29
|
+
logToStderr('info', 'Onboarding disabled via --no-onboarding flag');
|
|
30
|
+
}
|
|
31
|
+
// Set global flag for onboarding control
|
|
32
|
+
global.disableOnboarding = DISABLE_ONBOARDING;
|
|
21
33
|
try {
|
|
22
|
-
|
|
34
|
+
deferLog('info', 'Loading configuration...');
|
|
23
35
|
await configManager.loadConfig();
|
|
24
|
-
|
|
36
|
+
deferLog('info', 'Configuration loaded successfully');
|
|
25
37
|
}
|
|
26
38
|
catch (configError) {
|
|
27
|
-
|
|
39
|
+
deferLog('error', `Failed to load configuration: ${configError instanceof Error ? configError.message : String(configError)}`);
|
|
28
40
|
if (configError instanceof Error && configError.stack) {
|
|
29
|
-
|
|
41
|
+
deferLog('debug', `Stack trace: ${configError.stack}`);
|
|
30
42
|
}
|
|
31
|
-
|
|
43
|
+
deferLog('warning', 'Continuing with in-memory configuration only');
|
|
32
44
|
// Continue anyway - we'll use an in-memory config
|
|
33
45
|
}
|
|
34
46
|
const transport = new FilteredStdioServerTransport();
|
|
@@ -63,17 +75,23 @@ async function runServer() {
|
|
|
63
75
|
process.exit(1);
|
|
64
76
|
});
|
|
65
77
|
capture('run_server_start');
|
|
66
|
-
|
|
78
|
+
deferLog('info', 'Connecting server...');
|
|
67
79
|
// Set up event-driven initialization completion handler
|
|
68
80
|
server.oninitialized = () => {
|
|
69
81
|
// This callback is triggered after the client sends the "initialized" notification
|
|
70
82
|
// At this point, the MCP protocol handshake is fully complete
|
|
71
83
|
transport.enableNotifications();
|
|
72
|
-
//
|
|
73
|
-
|
|
84
|
+
// Flush all deferred messages from both index.ts and server.ts
|
|
85
|
+
while (deferredMessages.length > 0) {
|
|
86
|
+
const msg = deferredMessages.shift();
|
|
87
|
+
transport.sendLog('info', msg.message);
|
|
88
|
+
}
|
|
89
|
+
flushDeferredMessages();
|
|
90
|
+
// Now we can send regular logging messages
|
|
91
|
+
transport.sendLog('info', 'Server connected successfully');
|
|
92
|
+
transport.sendLog('info', 'MCP fully initialized, all startup messages sent');
|
|
74
93
|
};
|
|
75
94
|
await server.connect(transport);
|
|
76
|
-
logToStderr('info', 'Server connected successfully');
|
|
77
95
|
}
|
|
78
96
|
catch (error) {
|
|
79
97
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
package/dist/search-manager.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export interface SearchSession {
|
|
|
18
18
|
buffer: string;
|
|
19
19
|
totalMatches: number;
|
|
20
20
|
totalContextLines: number;
|
|
21
|
+
wasIncomplete?: boolean;
|
|
21
22
|
}
|
|
22
23
|
export interface SearchSessionOptions {
|
|
23
24
|
rootPath: string;
|
|
@@ -64,6 +65,7 @@ export interface SearchSessionOptions {
|
|
|
64
65
|
error?: string;
|
|
65
66
|
hasMoreResults: boolean;
|
|
66
67
|
runtime: number;
|
|
68
|
+
wasIncomplete?: boolean;
|
|
67
69
|
};
|
|
68
70
|
/**
|
|
69
71
|
* Terminate a search session (like force_terminate)
|
|
@@ -105,4 +107,3 @@ export interface SearchSessionOptions {
|
|
|
105
107
|
private parseLine;
|
|
106
108
|
}
|
|
107
109
|
export declare const searchManager: SearchManager;
|
|
108
|
-
export declare function stopSearchManagerCleanup(): void;
|
package/dist/search-manager.js
CHANGED
|
@@ -120,7 +120,8 @@ import { capture } from './utils/capture.js';
|
|
|
120
120
|
isError: session.isError && !!session.error?.trim(), // Only error if we have actual errors
|
|
121
121
|
error: session.error?.trim() || undefined,
|
|
122
122
|
hasMoreResults: false, // Tail always returns what's available
|
|
123
|
-
runtime: Date.now() - session.startTime
|
|
123
|
+
runtime: Date.now() - session.startTime,
|
|
124
|
+
wasIncomplete: session.wasIncomplete
|
|
124
125
|
};
|
|
125
126
|
}
|
|
126
127
|
// Handle positive offsets (range behavior) - like file reading
|
|
@@ -136,7 +137,8 @@ import { capture } from './utils/capture.js';
|
|
|
136
137
|
isError: session.isError && !!session.error?.trim(), // Only error if we have actual errors
|
|
137
138
|
error: session.error?.trim() || undefined,
|
|
138
139
|
hasMoreResults,
|
|
139
|
-
runtime: Date.now() - session.startTime
|
|
140
|
+
runtime: Date.now() - session.startTime,
|
|
141
|
+
wasIncomplete: session.wasIncomplete
|
|
140
142
|
};
|
|
141
143
|
}
|
|
142
144
|
/**
|
|
@@ -149,7 +151,6 @@ import { capture } from './utils/capture.js';
|
|
|
149
151
|
}
|
|
150
152
|
if (!session.process.killed) {
|
|
151
153
|
session.process.kill('SIGTERM');
|
|
152
|
-
capture('search_session_terminated', { sessionId });
|
|
153
154
|
}
|
|
154
155
|
// Don't delete session immediately - let user read final results
|
|
155
156
|
// It will be cleaned up by cleanup process
|
|
@@ -178,7 +179,6 @@ import { capture } from './utils/capture.js';
|
|
|
178
179
|
for (const [sessionId, session] of this.sessions) {
|
|
179
180
|
if (session.isComplete && session.lastReadTime < cutoffTime) {
|
|
180
181
|
this.sessions.delete(sessionId);
|
|
181
|
-
capture('search_session_cleaned_up', { sessionId });
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
}
|
|
@@ -289,6 +289,9 @@ import { capture } from './utils/capture.js';
|
|
|
289
289
|
});
|
|
290
290
|
process.stderr?.on('data', (data) => {
|
|
291
291
|
const errorText = data.toString();
|
|
292
|
+
// Store error text for potential user display, but don't capture individual errors
|
|
293
|
+
// We'll capture incomplete search status in the completion event instead
|
|
294
|
+
session.error = (session.error || '') + errorText;
|
|
292
295
|
// Filter meaningful errors
|
|
293
296
|
const filteredErrors = errorText
|
|
294
297
|
.split('\n')
|
|
@@ -320,6 +323,11 @@ import { capture } from './utils/capture.js';
|
|
|
320
323
|
this.processBufferedOutput(session, true);
|
|
321
324
|
}
|
|
322
325
|
session.isComplete = true;
|
|
326
|
+
// Track if search was incomplete due to access issues
|
|
327
|
+
// Ripgrep exit code 2 means "some files couldn't be searched"
|
|
328
|
+
if (code === 2) {
|
|
329
|
+
session.wasIncomplete = true;
|
|
330
|
+
}
|
|
323
331
|
// Only treat as error if:
|
|
324
332
|
// 1. Unexpected exit code (not 0, 1, or 2) AND
|
|
325
333
|
// 2. We have meaningful errors after filtering AND
|
|
@@ -340,7 +348,8 @@ import { capture } from './utils/capture.js';
|
|
|
340
348
|
exitCode: code,
|
|
341
349
|
totalResults: session.totalMatches + session.totalContextLines,
|
|
342
350
|
totalMatches: session.totalMatches,
|
|
343
|
-
runtime: Date.now() - session.startTime
|
|
351
|
+
runtime: Date.now() - session.startTime,
|
|
352
|
+
wasIncomplete: session.wasIncomplete || false // NEW: Track incomplete searches
|
|
344
353
|
});
|
|
345
354
|
// Rely on cleanupSessions(maxAge) only; no per-session timer
|
|
346
355
|
});
|
|
@@ -348,10 +357,6 @@ import { capture } from './utils/capture.js';
|
|
|
348
357
|
session.isComplete = true;
|
|
349
358
|
session.isError = true;
|
|
350
359
|
session.error = `Process error: ${error.message}`;
|
|
351
|
-
capture('search_session_process_error', {
|
|
352
|
-
sessionId: session.id,
|
|
353
|
-
error: error.message
|
|
354
|
-
});
|
|
355
360
|
// Rely on cleanupSessions(maxAge) only; no per-session timer
|
|
356
361
|
});
|
|
357
362
|
}
|
|
@@ -462,10 +467,3 @@ function startCleanupIfNeeded() {
|
|
|
462
467
|
}, 1000);
|
|
463
468
|
}
|
|
464
469
|
}
|
|
465
|
-
// Export cleanup function for graceful shutdown
|
|
466
|
-
export function stopSearchManagerCleanup() {
|
|
467
|
-
if (cleanupInterval) {
|
|
468
|
-
clearInterval(cleanupInterval);
|
|
469
|
-
cleanupInterval = null;
|
|
470
|
-
}
|
|
471
|
-
}
|
package/dist/server.d.ts
CHANGED
package/dist/server.js
CHANGED
|
@@ -18,8 +18,20 @@ import { usageTracker } from './utils/usageTracker.js';
|
|
|
18
18
|
import { processDockerPrompt } from './utils/dockerPrompt.js';
|
|
19
19
|
import { VERSION } from './version.js';
|
|
20
20
|
import { capture, capture_call_tool } from "./utils/capture.js";
|
|
21
|
-
import { logToStderr } from './utils/logger.js';
|
|
22
|
-
|
|
21
|
+
import { logToStderr, logger } from './utils/logger.js';
|
|
22
|
+
// Store startup messages to send after initialization
|
|
23
|
+
const deferredMessages = [];
|
|
24
|
+
function deferLog(level, message) {
|
|
25
|
+
deferredMessages.push({ level, message });
|
|
26
|
+
}
|
|
27
|
+
// Function to flush deferred messages after initialization
|
|
28
|
+
export function flushDeferredMessages() {
|
|
29
|
+
while (deferredMessages.length > 0) {
|
|
30
|
+
const msg = deferredMessages.shift();
|
|
31
|
+
logger.info(msg.message);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
deferLog('info', 'Loading server.ts');
|
|
23
35
|
export const server = new Server({
|
|
24
36
|
name: "desktop-commander",
|
|
25
37
|
version: VERSION,
|
|
@@ -57,8 +69,8 @@ server.setRequestHandler(InitializeRequestSchema, async (request) => {
|
|
|
57
69
|
name: clientInfo.name || 'unknown',
|
|
58
70
|
version: clientInfo.version || 'unknown'
|
|
59
71
|
};
|
|
60
|
-
//
|
|
61
|
-
|
|
72
|
+
// Defer client connection message until after initialization
|
|
73
|
+
deferLog('info', `Client connected: ${currentClient.name} v${currentClient.version}`);
|
|
62
74
|
}
|
|
63
75
|
// Return standard initialization response
|
|
64
76
|
return {
|
|
@@ -82,7 +94,7 @@ server.setRequestHandler(InitializeRequestSchema, async (request) => {
|
|
|
82
94
|
});
|
|
83
95
|
// Export current client info for access by other modules
|
|
84
96
|
export { currentClient };
|
|
85
|
-
|
|
97
|
+
deferLog('info', 'Setting up request handlers...');
|
|
86
98
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
87
99
|
try {
|
|
88
100
|
logToStderr('debug', 'Generating tools list...');
|
|
@@ -105,6 +117,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
105
117
|
- systemInfo (operating system and environment details)
|
|
106
118
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
107
119
|
inputSchema: zodToJsonSchema(GetConfigArgsSchema),
|
|
120
|
+
annotations: {
|
|
121
|
+
title: "Get Configuration",
|
|
122
|
+
readOnlyHint: true,
|
|
123
|
+
},
|
|
108
124
|
},
|
|
109
125
|
{
|
|
110
126
|
name: "set_config_value",
|
|
@@ -127,6 +143,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
127
143
|
|
|
128
144
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
129
145
|
inputSchema: zodToJsonSchema(SetConfigValueArgsSchema),
|
|
146
|
+
annotations: {
|
|
147
|
+
title: "Set Configuration Value",
|
|
148
|
+
readOnlyHint: false,
|
|
149
|
+
destructiveHint: true,
|
|
150
|
+
openWorldHint: false,
|
|
151
|
+
},
|
|
130
152
|
},
|
|
131
153
|
// Filesystem tools
|
|
132
154
|
{
|
|
@@ -165,6 +187,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
165
187
|
${PATH_GUIDANCE}
|
|
166
188
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
167
189
|
inputSchema: zodToJsonSchema(ReadFileArgsSchema),
|
|
190
|
+
annotations: {
|
|
191
|
+
title: "Read File or URL",
|
|
192
|
+
readOnlyHint: true,
|
|
193
|
+
openWorldHint: true,
|
|
194
|
+
},
|
|
168
195
|
},
|
|
169
196
|
{
|
|
170
197
|
name: "read_multiple_files",
|
|
@@ -181,6 +208,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
181
208
|
${PATH_GUIDANCE}
|
|
182
209
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
183
210
|
inputSchema: zodToJsonSchema(ReadMultipleFilesArgsSchema),
|
|
211
|
+
annotations: {
|
|
212
|
+
title: "Read Multiple Files",
|
|
213
|
+
readOnlyHint: true,
|
|
214
|
+
},
|
|
184
215
|
},
|
|
185
216
|
{
|
|
186
217
|
name: "write_file",
|
|
@@ -214,6 +245,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
214
245
|
${PATH_GUIDANCE}
|
|
215
246
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
216
247
|
inputSchema: zodToJsonSchema(WriteFileArgsSchema),
|
|
248
|
+
annotations: {
|
|
249
|
+
title: "Write File",
|
|
250
|
+
readOnlyHint: false,
|
|
251
|
+
destructiveHint: true,
|
|
252
|
+
openWorldHint: false,
|
|
253
|
+
},
|
|
217
254
|
},
|
|
218
255
|
{
|
|
219
256
|
name: "create_directory",
|
|
@@ -239,6 +276,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
239
276
|
${PATH_GUIDANCE}
|
|
240
277
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
241
278
|
inputSchema: zodToJsonSchema(ListDirectoryArgsSchema),
|
|
279
|
+
annotations: {
|
|
280
|
+
title: "List Directory Contents",
|
|
281
|
+
readOnlyHint: true,
|
|
282
|
+
},
|
|
242
283
|
},
|
|
243
284
|
{
|
|
244
285
|
name: "move_file",
|
|
@@ -251,6 +292,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
251
292
|
${PATH_GUIDANCE}
|
|
252
293
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
253
294
|
inputSchema: zodToJsonSchema(MoveFileArgsSchema),
|
|
295
|
+
annotations: {
|
|
296
|
+
title: "Move/Rename File",
|
|
297
|
+
readOnlyHint: false,
|
|
298
|
+
destructiveHint: true,
|
|
299
|
+
openWorldHint: false,
|
|
300
|
+
},
|
|
254
301
|
},
|
|
255
302
|
{
|
|
256
303
|
name: "start_search",
|
|
@@ -360,6 +407,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
360
407
|
|
|
361
408
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
362
409
|
inputSchema: zodToJsonSchema(GetMoreSearchResultsArgsSchema),
|
|
410
|
+
annotations: {
|
|
411
|
+
title: "Get Search Results",
|
|
412
|
+
readOnlyHint: true,
|
|
413
|
+
},
|
|
363
414
|
},
|
|
364
415
|
{
|
|
365
416
|
name: "stop_search",
|
|
@@ -387,6 +438,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
387
438
|
|
|
388
439
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
389
440
|
inputSchema: zodToJsonSchema(ListSearchesArgsSchema),
|
|
441
|
+
annotations: {
|
|
442
|
+
title: "List Active Searches",
|
|
443
|
+
readOnlyHint: true,
|
|
444
|
+
},
|
|
390
445
|
},
|
|
391
446
|
{
|
|
392
447
|
name: "get_file_info",
|
|
@@ -406,6 +461,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
406
461
|
${PATH_GUIDANCE}
|
|
407
462
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
408
463
|
inputSchema: zodToJsonSchema(GetFileInfoArgsSchema),
|
|
464
|
+
annotations: {
|
|
465
|
+
title: "Get File Information",
|
|
466
|
+
readOnlyHint: true,
|
|
467
|
+
},
|
|
409
468
|
},
|
|
410
469
|
// Note: list_allowed_directories removed - use get_config to check allowedDirectories
|
|
411
470
|
// Text editing tools
|
|
@@ -445,6 +504,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
445
504
|
${PATH_GUIDANCE}
|
|
446
505
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
447
506
|
inputSchema: zodToJsonSchema(EditBlockArgsSchema),
|
|
507
|
+
annotations: {
|
|
508
|
+
title: "Edit Text Block",
|
|
509
|
+
readOnlyHint: false,
|
|
510
|
+
destructiveHint: true,
|
|
511
|
+
openWorldHint: false,
|
|
512
|
+
},
|
|
448
513
|
},
|
|
449
514
|
// Terminal tools
|
|
450
515
|
{
|
|
@@ -501,6 +566,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
501
566
|
${PATH_GUIDANCE}
|
|
502
567
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
503
568
|
inputSchema: zodToJsonSchema(StartProcessArgsSchema),
|
|
569
|
+
annotations: {
|
|
570
|
+
title: "Start Terminal Process",
|
|
571
|
+
readOnlyHint: false,
|
|
572
|
+
destructiveHint: true,
|
|
573
|
+
openWorldHint: true,
|
|
574
|
+
},
|
|
504
575
|
},
|
|
505
576
|
{
|
|
506
577
|
name: "read_process_output",
|
|
@@ -528,6 +599,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
528
599
|
|
|
529
600
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
530
601
|
inputSchema: zodToJsonSchema(ReadProcessOutputArgsSchema),
|
|
602
|
+
annotations: {
|
|
603
|
+
title: "Read Process Output",
|
|
604
|
+
readOnlyHint: true,
|
|
605
|
+
},
|
|
531
606
|
},
|
|
532
607
|
{
|
|
533
608
|
name: "interact_with_process",
|
|
@@ -580,6 +655,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
580
655
|
|
|
581
656
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
582
657
|
inputSchema: zodToJsonSchema(InteractWithProcessArgsSchema),
|
|
658
|
+
annotations: {
|
|
659
|
+
title: "Send Input to Process",
|
|
660
|
+
readOnlyHint: false,
|
|
661
|
+
destructiveHint: true,
|
|
662
|
+
openWorldHint: true,
|
|
663
|
+
},
|
|
583
664
|
},
|
|
584
665
|
{
|
|
585
666
|
name: "force_terminate",
|
|
@@ -588,6 +669,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
588
669
|
|
|
589
670
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
590
671
|
inputSchema: zodToJsonSchema(ForceTerminateArgsSchema),
|
|
672
|
+
annotations: {
|
|
673
|
+
title: "Force Terminate Process",
|
|
674
|
+
readOnlyHint: false,
|
|
675
|
+
destructiveHint: true,
|
|
676
|
+
openWorldHint: false,
|
|
677
|
+
},
|
|
591
678
|
},
|
|
592
679
|
{
|
|
593
680
|
name: "list_sessions",
|
|
@@ -606,6 +693,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
606
693
|
|
|
607
694
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
608
695
|
inputSchema: zodToJsonSchema(ListSessionsArgsSchema),
|
|
696
|
+
annotations: {
|
|
697
|
+
title: "List Terminal Sessions",
|
|
698
|
+
readOnlyHint: true,
|
|
699
|
+
},
|
|
609
700
|
},
|
|
610
701
|
{
|
|
611
702
|
name: "list_processes",
|
|
@@ -616,6 +707,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
616
707
|
|
|
617
708
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
618
709
|
inputSchema: zodToJsonSchema(ListProcessesArgsSchema),
|
|
710
|
+
annotations: {
|
|
711
|
+
title: "List Running Processes",
|
|
712
|
+
readOnlyHint: true,
|
|
713
|
+
},
|
|
619
714
|
},
|
|
620
715
|
{
|
|
621
716
|
name: "kill_process",
|
|
@@ -626,6 +721,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
626
721
|
|
|
627
722
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
628
723
|
inputSchema: zodToJsonSchema(KillProcessArgsSchema),
|
|
724
|
+
annotations: {
|
|
725
|
+
title: "Kill Process",
|
|
726
|
+
readOnlyHint: false,
|
|
727
|
+
destructiveHint: true,
|
|
728
|
+
openWorldHint: false,
|
|
729
|
+
},
|
|
629
730
|
},
|
|
630
731
|
{
|
|
631
732
|
name: "get_usage_stats",
|
|
@@ -636,6 +737,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
636
737
|
|
|
637
738
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
638
739
|
inputSchema: zodToJsonSchema(GetUsageStatsArgsSchema),
|
|
740
|
+
annotations: {
|
|
741
|
+
title: "Get Usage Statistics",
|
|
742
|
+
readOnlyHint: true,
|
|
743
|
+
},
|
|
639
744
|
},
|
|
640
745
|
{
|
|
641
746
|
name: "give_feedback_to_desktop_commander",
|
package/dist/tools/config.js
CHANGED
|
@@ -14,17 +14,7 @@ export async function getConfig() {
|
|
|
14
14
|
const configWithSystemInfo = {
|
|
15
15
|
...config,
|
|
16
16
|
currentClient,
|
|
17
|
-
systemInfo
|
|
18
|
-
platform: systemInfo.platform,
|
|
19
|
-
platformName: systemInfo.platformName,
|
|
20
|
-
defaultShell: systemInfo.defaultShell,
|
|
21
|
-
pathSeparator: systemInfo.pathSeparator,
|
|
22
|
-
isWindows: systemInfo.isWindows,
|
|
23
|
-
isMacOS: systemInfo.isMacOS,
|
|
24
|
-
isLinux: systemInfo.isLinux,
|
|
25
|
-
docker: systemInfo.docker,
|
|
26
|
-
examplePaths: systemInfo.examplePaths
|
|
27
|
-
}
|
|
17
|
+
systemInfo
|
|
28
18
|
};
|
|
29
19
|
console.error(`getConfig result: ${JSON.stringify(configWithSystemInfo, null, 2)}`);
|
|
30
20
|
return {
|
package/dist/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { ChildProcess } from 'child_process';
|
|
|
2
2
|
import { FilteredStdioServerTransport } from './custom-stdio.js';
|
|
3
3
|
declare global {
|
|
4
4
|
var mcpTransport: FilteredStdioServerTransport | undefined;
|
|
5
|
+
var disableOnboarding: boolean | undefined;
|
|
5
6
|
}
|
|
6
7
|
export interface ProcessInfo {
|
|
7
8
|
pid: number;
|
|
@@ -29,6 +29,18 @@ export interface SystemInfo {
|
|
|
29
29
|
isMacOS: boolean;
|
|
30
30
|
isLinux: boolean;
|
|
31
31
|
docker: ContainerInfo;
|
|
32
|
+
isDXT: boolean;
|
|
33
|
+
nodeInfo?: {
|
|
34
|
+
version: string;
|
|
35
|
+
path: string;
|
|
36
|
+
npmVersion?: string;
|
|
37
|
+
};
|
|
38
|
+
processInfo: {
|
|
39
|
+
pid: number;
|
|
40
|
+
arch: string;
|
|
41
|
+
platform: string;
|
|
42
|
+
versions: NodeJS.ProcessVersions;
|
|
43
|
+
};
|
|
32
44
|
examplePaths: {
|
|
33
45
|
home: string;
|
|
34
46
|
temp: string;
|
|
@@ -305,6 +305,27 @@ function getContainerEnvironment(containerType) {
|
|
|
305
305
|
}
|
|
306
306
|
return Object.keys(env).length > 0 ? env : undefined;
|
|
307
307
|
}
|
|
308
|
+
/**
|
|
309
|
+
* Detect Node.js installation and version from current process
|
|
310
|
+
*/
|
|
311
|
+
function detectNodeInfo() {
|
|
312
|
+
try {
|
|
313
|
+
// Get Node.js version from current process
|
|
314
|
+
const version = process.version.replace('v', ''); // Remove 'v' prefix
|
|
315
|
+
// Get Node.js executable path from current process
|
|
316
|
+
const path = process.execPath;
|
|
317
|
+
// Get npm version from environment if available
|
|
318
|
+
const npmVersion = process.env.npm_version;
|
|
319
|
+
return {
|
|
320
|
+
version,
|
|
321
|
+
path,
|
|
322
|
+
...(npmVersion && { npmVersion })
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
return undefined;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
308
329
|
/**
|
|
309
330
|
* Get comprehensive system information for tool prompts
|
|
310
331
|
*/
|
|
@@ -397,6 +418,15 @@ export function getSystemInfo() {
|
|
|
397
418
|
examplePaths.accessible = mountPoints.map(mount => mount.containerPath);
|
|
398
419
|
}
|
|
399
420
|
}
|
|
421
|
+
// Detect Node.js installation from current process
|
|
422
|
+
const nodeInfo = detectNodeInfo();
|
|
423
|
+
// Get process information
|
|
424
|
+
const processInfo = {
|
|
425
|
+
pid: process.pid,
|
|
426
|
+
arch: process.arch,
|
|
427
|
+
platform: process.platform,
|
|
428
|
+
versions: process.versions
|
|
429
|
+
};
|
|
400
430
|
return {
|
|
401
431
|
platform,
|
|
402
432
|
platformName,
|
|
@@ -415,6 +445,9 @@ export function getSystemInfo() {
|
|
|
415
445
|
mountPoints,
|
|
416
446
|
containerEnvironment: getContainerEnvironment(containerDetection.containerType)
|
|
417
447
|
},
|
|
448
|
+
isDXT: !!process.env.MCP_DXT,
|
|
449
|
+
nodeInfo,
|
|
450
|
+
processInfo,
|
|
418
451
|
examplePaths
|
|
419
452
|
};
|
|
420
453
|
}
|
|
@@ -545,33 +578,51 @@ LINUX-SPECIFIC NOTES:
|
|
|
545
578
|
* Get common development tool guidance based on OS
|
|
546
579
|
*/
|
|
547
580
|
export function getDevelopmentToolGuidance(systemInfo) {
|
|
548
|
-
const { isWindows, isMacOS, isLinux, platformName } = systemInfo;
|
|
581
|
+
const { isWindows, isMacOS, isLinux, platformName, nodeInfo, processInfo } = systemInfo;
|
|
582
|
+
// Add detected Node.js info to guidance
|
|
583
|
+
const nodeGuidance = nodeInfo
|
|
584
|
+
? `Node.js: v${nodeInfo.version} (${nodeInfo.path})${nodeInfo.npmVersion ? ` | npm: v${nodeInfo.npmVersion}` : ''}`
|
|
585
|
+
: 'Node.js: Not detected';
|
|
586
|
+
// Add process environment info
|
|
587
|
+
const envInfo = `
|
|
588
|
+
Current Process Environment:
|
|
589
|
+
- Node: v${processInfo.versions.node}
|
|
590
|
+
- V8: v${processInfo.versions.v8}
|
|
591
|
+
- Architecture: ${processInfo.arch}
|
|
592
|
+
- Platform: ${processInfo.platform}
|
|
593
|
+
- Process ID: ${processInfo.pid}`;
|
|
549
594
|
if (isWindows) {
|
|
550
595
|
return `
|
|
551
596
|
COMMON WINDOWS DEVELOPMENT TOOLS:
|
|
552
|
-
-
|
|
597
|
+
- ${nodeGuidance}
|
|
553
598
|
- Python: May be 'python' or 'py' command, check both
|
|
554
599
|
- Git: Git Bash provides Unix-like environment
|
|
555
600
|
- WSL: Windows Subsystem for Linux available for Unix tools
|
|
556
|
-
- Visual Studio tools: cl, msbuild for C++ compilation
|
|
601
|
+
- Visual Studio tools: cl, msbuild for C++ compilation
|
|
602
|
+
|
|
603
|
+
${envInfo}`;
|
|
557
604
|
}
|
|
558
605
|
else if (isMacOS) {
|
|
559
606
|
return `
|
|
560
607
|
COMMON MACOS DEVELOPMENT TOOLS:
|
|
561
608
|
- Xcode Command Line Tools: Required for many development tools
|
|
562
609
|
- Homebrew: Primary package manager for development tools
|
|
610
|
+
- ${nodeGuidance}
|
|
563
611
|
- Python: Usually python3, check if python points to Python 2
|
|
564
|
-
-
|
|
565
|
-
|
|
612
|
+
- Ruby: System Ruby available, rbenv/rvm for version management
|
|
613
|
+
|
|
614
|
+
${envInfo}`;
|
|
566
615
|
}
|
|
567
616
|
else {
|
|
568
617
|
return `
|
|
569
618
|
COMMON LINUX DEVELOPMENT TOOLS:
|
|
570
619
|
- Package managers: Install tools via distribution package manager
|
|
571
620
|
- Python: Usually python3, python may point to Python 2
|
|
572
|
-
-
|
|
621
|
+
- ${nodeGuidance}
|
|
573
622
|
- Build tools: gcc, make typically available or easily installed
|
|
574
|
-
- Container tools: docker, podman common for development
|
|
623
|
+
- Container tools: docker, podman common for development
|
|
624
|
+
|
|
625
|
+
${envInfo}`;
|
|
575
626
|
}
|
|
576
627
|
}
|
|
577
628
|
/**
|
|
@@ -299,6 +299,21 @@ class UsageTracker {
|
|
|
299
299
|
* Check if user should see onboarding invitation - SIMPLE VERSION
|
|
300
300
|
*/
|
|
301
301
|
async shouldShowOnboarding() {
|
|
302
|
+
// Check if onboarding is disabled via command line argument
|
|
303
|
+
if (global.disableOnboarding) {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
// Check if client is desktop-commander (disable for this client)
|
|
307
|
+
try {
|
|
308
|
+
const { currentClient } = await import('../server.js');
|
|
309
|
+
if (currentClient?.name === 'desktop-commander') {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
// If we can't import server, continue with other checks
|
|
315
|
+
console.log('[ONBOARDING DEBUG] Could not check client name, continuing...');
|
|
316
|
+
}
|
|
302
317
|
const stats = await this.getStats();
|
|
303
318
|
const onboardingState = await this.getOnboardingState();
|
|
304
319
|
const now = Date.now();
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.2.
|
|
1
|
+
export declare const VERSION = "0.2.16";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.2.
|
|
1
|
+
export const VERSION = '0.2.16';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wonderwhy-er/desktop-commander",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.16",
|
|
4
4
|
"description": "MCP server for terminal operations and file editing",
|
|
5
5
|
"mcpName": "io.github.wonderwhy-er/desktop-commander",
|
|
6
6
|
"license": "MIT",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"link:local": "npm run build && npm link",
|
|
43
43
|
"unlink:local": "npm unlink",
|
|
44
44
|
"inspector": "npx @modelcontextprotocol/inspector dist/index.js",
|
|
45
|
+
"build:mcpb": "node scripts/build-mcpb.cjs",
|
|
45
46
|
"logs:view": "npm run build && node scripts/view-fuzzy-logs.js",
|
|
46
47
|
"logs:analyze": "npm run build && node scripts/analyze-fuzzy-logs.js",
|
|
47
48
|
"logs:clear": "npm run build && node scripts/clear-fuzzy-logs.js",
|