@wonderwhy-er/desktop-commander 0.2.14 → 0.2.15

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 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:
@@ -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
- // Send initialization notification
26
- this.sendLogNotification('info', ['Enhanced FilteredStdioServerTransport initialized']);
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`]);
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
- logToStderr('info', 'Loading configuration...');
34
+ deferLog('info', 'Loading configuration...');
23
35
  await configManager.loadConfig();
24
- logToStderr('info', 'Configuration loaded successfully');
36
+ deferLog('info', 'Configuration loaded successfully');
25
37
  }
26
38
  catch (configError) {
27
- logToStderr('error', `Failed to load configuration: ${configError instanceof Error ? configError.message : String(configError)}`);
39
+ deferLog('error', `Failed to load configuration: ${configError instanceof Error ? configError.message : String(configError)}`);
28
40
  if (configError instanceof Error && configError.stack) {
29
- logToStderr('debug', `Stack trace: ${configError.stack}`);
41
+ deferLog('debug', `Stack trace: ${configError.stack}`);
30
42
  }
31
- logToStderr('warning', 'Continuing with in-memory configuration only');
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
- logToStderr('info', 'Connecting server...');
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
- // Use the transport to send a proper JSON-RPC notification
73
- transport.sendLog('info', 'MCP fully initialized, notifications enabled');
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/server.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ export declare function flushDeferredMessages(): void;
2
3
  export declare const server: Server<{
3
4
  method: string;
4
5
  params?: {
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
- logToStderr('info', 'Loading server.ts');
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
- // Send JSON-RPC notification about client connection
61
- logToStderr('info', `Client connected: ${currentClient.name} v${currentClient.version}`);
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
- logToStderr('info', 'Setting up request handlers...');
97
+ deferLog('info', 'Setting up request handlers...');
86
98
  server.setRequestHandler(ListToolsRequestSchema, async () => {
87
99
  try {
88
100
  logToStderr('debug', 'Generating tools list...');
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;
@@ -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.14";
1
+ export declare const VERSION = "0.2.15";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = '0.2.14';
1
+ export const VERSION = '0.2.15';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wonderwhy-er/desktop-commander",
3
- "version": "0.2.14",
3
+ "version": "0.2.15",
4
4
  "description": "MCP server for terminal operations and file editing",
5
5
  "mcpName": "io.github.wonderwhy-er/desktop-commander",
6
6
  "license": "MIT",