@wonderwhy-er/desktop-commander 0.2.16 → 0.2.18-alpha.0

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.
Files changed (47) hide show
  1. package/README.md +3 -5
  2. package/dist/data/spec-kit-prompts.json +123 -0
  3. package/dist/handlers/filesystem-handlers.js +5 -2
  4. package/dist/handlers/history-handlers.d.ts +5 -0
  5. package/dist/handlers/history-handlers.js +35 -0
  6. package/dist/handlers/index.d.ts +1 -0
  7. package/dist/handlers/index.js +1 -0
  8. package/dist/http-index.d.ts +45 -0
  9. package/dist/http-index.js +51 -0
  10. package/dist/http-server-auto-tunnel.d.ts +1 -0
  11. package/dist/http-server-auto-tunnel.js +667 -0
  12. package/dist/http-server-named-tunnel.d.ts +2 -0
  13. package/dist/http-server-named-tunnel.js +167 -0
  14. package/dist/http-server-tunnel.d.ts +2 -0
  15. package/dist/http-server-tunnel.js +111 -0
  16. package/dist/http-server.d.ts +2 -0
  17. package/dist/http-server.js +270 -0
  18. package/dist/index.js +4 -0
  19. package/dist/oauth/auth-middleware.d.ts +20 -0
  20. package/dist/oauth/auth-middleware.js +62 -0
  21. package/dist/oauth/index.d.ts +3 -0
  22. package/dist/oauth/index.js +3 -0
  23. package/dist/oauth/oauth-manager.d.ts +80 -0
  24. package/dist/oauth/oauth-manager.js +179 -0
  25. package/dist/oauth/oauth-routes.d.ts +3 -0
  26. package/dist/oauth/oauth-routes.js +377 -0
  27. package/dist/server.js +316 -210
  28. package/dist/setup-claude-server.js +29 -5
  29. package/dist/terminal-manager.d.ts +1 -1
  30. package/dist/terminal-manager.js +56 -1
  31. package/dist/tools/config.js +15 -1
  32. package/dist/tools/feedback.js +2 -2
  33. package/dist/tools/filesystem.d.ts +1 -1
  34. package/dist/tools/filesystem.js +51 -3
  35. package/dist/tools/improved-process-tools.js +179 -58
  36. package/dist/tools/schemas.d.ts +25 -0
  37. package/dist/tools/schemas.js +10 -0
  38. package/dist/types.d.ts +19 -0
  39. package/dist/utils/feature-flags.d.ts +43 -0
  40. package/dist/utils/feature-flags.js +147 -0
  41. package/dist/utils/toolHistory.d.ts +73 -0
  42. package/dist/utils/toolHistory.js +192 -0
  43. package/dist/utils/usageTracker.d.ts +4 -0
  44. package/dist/utils/usageTracker.js +63 -37
  45. package/dist/version.d.ts +1 -1
  46. package/dist/version.js +1 -1
  47. package/package.json +6 -1
package/dist/server.js CHANGED
@@ -8,7 +8,7 @@ const OS_GUIDANCE = getOSSpecificGuidance(SYSTEM_INFO);
8
8
  const DEV_TOOL_GUIDANCE = getDevelopmentToolGuidance(SYSTEM_INFO);
9
9
  const PATH_GUIDANCE = `IMPORTANT: ${getPathGuidance(SYSTEM_INFO)} Relative paths may fail as they depend on the current working directory. Tilde paths (~/...) might not work in all contexts. Unless the user explicitly asks for relative paths, use absolute paths.`;
10
10
  const CMD_PREFIX_DESCRIPTION = `This command can be referenced as "DC: ..." or "use Desktop Commander to ..." in your instructions.`;
11
- import { StartProcessArgsSchema, ReadProcessOutputArgsSchema, InteractWithProcessArgsSchema, ForceTerminateArgsSchema, ListSessionsArgsSchema, KillProcessArgsSchema, ReadFileArgsSchema, ReadMultipleFilesArgsSchema, WriteFileArgsSchema, CreateDirectoryArgsSchema, ListDirectoryArgsSchema, MoveFileArgsSchema, GetFileInfoArgsSchema, GetConfigArgsSchema, SetConfigValueArgsSchema, ListProcessesArgsSchema, EditBlockArgsSchema, GetUsageStatsArgsSchema, GiveFeedbackArgsSchema, StartSearchArgsSchema, GetMoreSearchResultsArgsSchema, StopSearchArgsSchema, ListSearchesArgsSchema, GetPromptsArgsSchema, } from './tools/schemas.js';
11
+ import { StartProcessArgsSchema, ReadProcessOutputArgsSchema, InteractWithProcessArgsSchema, ForceTerminateArgsSchema, ListSessionsArgsSchema, KillProcessArgsSchema, ReadFileArgsSchema, ReadMultipleFilesArgsSchema, WriteFileArgsSchema, CreateDirectoryArgsSchema, ListDirectoryArgsSchema, MoveFileArgsSchema, GetFileInfoArgsSchema, GetConfigArgsSchema, SetConfigValueArgsSchema, ListProcessesArgsSchema, EditBlockArgsSchema, GetUsageStatsArgsSchema, GiveFeedbackArgsSchema, StartSearchArgsSchema, GetMoreSearchResultsArgsSchema, StopSearchArgsSchema, ListSearchesArgsSchema, GetPromptsArgsSchema, GetRecentToolCallsArgsSchema, } from './tools/schemas.js';
12
12
  import { getConfig, setConfigValue } from './tools/config.js';
13
13
  import { getUsageStats } from './tools/usage.js';
14
14
  import { giveFeedbackToDesktopCommander } from './tools/feedback.js';
@@ -16,6 +16,7 @@ import { getPrompts } from './tools/prompts.js';
16
16
  import { trackToolCall } from './utils/trackTools.js';
17
17
  import { usageTracker } from './utils/usageTracker.js';
18
18
  import { processDockerPrompt } from './utils/dockerPrompt.js';
19
+ import { toolHistory } from './utils/toolHistory.js';
19
20
  import { VERSION } from './version.js';
20
21
  import { capture, capture_call_tool } from "./utils/capture.js";
21
22
  import { logToStderr, logger } from './utils/logger.js';
@@ -95,15 +96,27 @@ server.setRequestHandler(InitializeRequestSchema, async (request) => {
95
96
  // Export current client info for access by other modules
96
97
  export { currentClient };
97
98
  deferLog('info', 'Setting up request handlers...');
99
+ /**
100
+ * Check if a tool should be included based on current client
101
+ */
102
+ function shouldIncludeTool(toolName) {
103
+ // Exclude give_feedback_to_desktop_commander for desktop-commander client
104
+ if (toolName === 'give_feedback_to_desktop_commander' && currentClient?.name === 'desktop-commander') {
105
+ return false;
106
+ }
107
+ // Add more conditional tool logic here as needed
108
+ // Example: if (toolName === 'some_tool' && currentClient?.name === 'some_client') return false;
109
+ return true;
110
+ }
98
111
  server.setRequestHandler(ListToolsRequestSchema, async () => {
99
112
  try {
100
113
  logToStderr('debug', 'Generating tools list...');
101
- return {
102
- tools: [
103
- // Configuration tools
104
- {
105
- name: "get_config",
106
- description: `
114
+ // Build complete tools array
115
+ const allTools = [
116
+ // Configuration tools
117
+ {
118
+ name: "get_config",
119
+ description: `
107
120
  Get the complete server configuration as JSON. Config includes fields for:
108
121
  - blockedCommands (array of blocked shell commands)
109
122
  - defaultShell (shell to use for commands)
@@ -116,15 +129,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
116
129
  - version (version of the DesktopCommander)
117
130
  - systemInfo (operating system and environment details)
118
131
  ${CMD_PREFIX_DESCRIPTION}`,
119
- inputSchema: zodToJsonSchema(GetConfigArgsSchema),
120
- annotations: {
121
- title: "Get Configuration",
122
- readOnlyHint: true,
123
- },
132
+ inputSchema: zodToJsonSchema(GetConfigArgsSchema),
133
+ annotations: {
134
+ title: "Get Configuration",
135
+ readOnlyHint: true,
124
136
  },
125
- {
126
- name: "set_config_value",
127
- description: `
137
+ },
138
+ {
139
+ name: "set_config_value",
140
+ description: `
128
141
  Set a specific configuration value by key.
129
142
 
130
143
  WARNING: Should be used in a separate chat from file operations and
@@ -142,18 +155,18 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
142
155
  to the entire file system, regardless of the operating system.
143
156
 
144
157
  ${CMD_PREFIX_DESCRIPTION}`,
145
- inputSchema: zodToJsonSchema(SetConfigValueArgsSchema),
146
- annotations: {
147
- title: "Set Configuration Value",
148
- readOnlyHint: false,
149
- destructiveHint: true,
150
- openWorldHint: false,
151
- },
158
+ inputSchema: zodToJsonSchema(SetConfigValueArgsSchema),
159
+ annotations: {
160
+ title: "Set Configuration Value",
161
+ readOnlyHint: false,
162
+ destructiveHint: true,
163
+ openWorldHint: false,
152
164
  },
153
- // Filesystem tools
154
- {
155
- name: "read_file",
156
- description: `
165
+ },
166
+ // Filesystem tools
167
+ {
168
+ name: "read_file",
169
+ description: `
157
170
  Read the contents of a file from the file system or a URL with optional offset and length parameters.
158
171
 
159
172
  Prefer this over 'execute_command' with cat/type for viewing files.
@@ -186,16 +199,16 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
186
199
 
187
200
  ${PATH_GUIDANCE}
188
201
  ${CMD_PREFIX_DESCRIPTION}`,
189
- inputSchema: zodToJsonSchema(ReadFileArgsSchema),
190
- annotations: {
191
- title: "Read File or URL",
192
- readOnlyHint: true,
193
- openWorldHint: true,
194
- },
202
+ inputSchema: zodToJsonSchema(ReadFileArgsSchema),
203
+ annotations: {
204
+ title: "Read File or URL",
205
+ readOnlyHint: true,
206
+ openWorldHint: true,
195
207
  },
196
- {
197
- name: "read_multiple_files",
198
- description: `
208
+ },
209
+ {
210
+ name: "read_multiple_files",
211
+ description: `
199
212
  Read the contents of multiple files simultaneously.
200
213
 
201
214
  Each file's content is returned with its path as a reference.
@@ -207,15 +220,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
207
220
 
208
221
  ${PATH_GUIDANCE}
209
222
  ${CMD_PREFIX_DESCRIPTION}`,
210
- inputSchema: zodToJsonSchema(ReadMultipleFilesArgsSchema),
211
- annotations: {
212
- title: "Read Multiple Files",
213
- readOnlyHint: true,
214
- },
223
+ inputSchema: zodToJsonSchema(ReadMultipleFilesArgsSchema),
224
+ annotations: {
225
+ title: "Read Multiple Files",
226
+ readOnlyHint: true,
215
227
  },
216
- {
217
- name: "write_file",
218
- description: `
228
+ },
229
+ {
230
+ name: "write_file",
231
+ description: `
219
232
  Write or append to file contents.
220
233
 
221
234
  CHUNKING IS STANDARD PRACTICE: Always write files in chunks of 25-30 lines maximum.
@@ -244,17 +257,17 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
244
257
 
245
258
  ${PATH_GUIDANCE}
246
259
  ${CMD_PREFIX_DESCRIPTION}`,
247
- inputSchema: zodToJsonSchema(WriteFileArgsSchema),
248
- annotations: {
249
- title: "Write File",
250
- readOnlyHint: false,
251
- destructiveHint: true,
252
- openWorldHint: false,
253
- },
260
+ inputSchema: zodToJsonSchema(WriteFileArgsSchema),
261
+ annotations: {
262
+ title: "Write File",
263
+ readOnlyHint: false,
264
+ destructiveHint: true,
265
+ openWorldHint: false,
254
266
  },
255
- {
256
- name: "create_directory",
257
- description: `
267
+ },
268
+ {
269
+ name: "create_directory",
270
+ description: `
258
271
  Create a new directory or ensure a directory exists.
259
272
 
260
273
  Can create multiple nested directories in one operation.
@@ -262,28 +275,49 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
262
275
 
263
276
  ${PATH_GUIDANCE}
264
277
  ${CMD_PREFIX_DESCRIPTION}`,
265
- inputSchema: zodToJsonSchema(CreateDirectoryArgsSchema),
266
- },
267
- {
268
- name: "list_directory",
269
- description: `
278
+ inputSchema: zodToJsonSchema(CreateDirectoryArgsSchema),
279
+ },
280
+ {
281
+ name: "list_directory",
282
+ description: `
270
283
  Get a detailed listing of all files and directories in a specified path.
271
284
 
272
285
  Use this instead of 'execute_command' with ls/dir commands.
273
286
  Results distinguish between files and directories with [FILE] and [DIR] prefixes.
287
+
288
+ Supports recursive listing with the 'depth' parameter (default: 2):
289
+ - depth=1: Only direct contents of the directory
290
+ - depth=2: Contents plus one level of subdirectories
291
+ - depth=3+: Multiple levels deep
292
+
293
+ CONTEXT OVERFLOW PROTECTION:
294
+ - Top-level directory shows ALL items
295
+ - Nested directories are limited to 100 items maximum per directory
296
+ - When a nested directory has more than 100 items, you'll see a warning like:
297
+ [WARNING] node_modules: 500 items hidden (showing first 100 of 600 total)
298
+ - This prevents overwhelming the context with large directories like node_modules
299
+
300
+ Results show full relative paths from the root directory being listed.
301
+ Example output with depth=2:
302
+ [DIR] src
303
+ [FILE] src/index.ts
304
+ [DIR] src/tools
305
+ [FILE] src/tools/filesystem.ts
306
+
307
+ If a directory cannot be accessed, it will show [DENIED] instead.
274
308
  Only works within allowed directories.
275
309
 
276
310
  ${PATH_GUIDANCE}
277
311
  ${CMD_PREFIX_DESCRIPTION}`,
278
- inputSchema: zodToJsonSchema(ListDirectoryArgsSchema),
279
- annotations: {
280
- title: "List Directory Contents",
281
- readOnlyHint: true,
282
- },
312
+ inputSchema: zodToJsonSchema(ListDirectoryArgsSchema),
313
+ annotations: {
314
+ title: "List Directory Contents",
315
+ readOnlyHint: true,
283
316
  },
284
- {
285
- name: "move_file",
286
- description: `
317
+ },
318
+ {
319
+ name: "move_file",
320
+ description: `
287
321
  Move or rename files and directories.
288
322
 
289
323
  Can move files between directories and rename them in a single operation.
@@ -291,17 +325,17 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
291
325
 
292
326
  ${PATH_GUIDANCE}
293
327
  ${CMD_PREFIX_DESCRIPTION}`,
294
- inputSchema: zodToJsonSchema(MoveFileArgsSchema),
295
- annotations: {
296
- title: "Move/Rename File",
297
- readOnlyHint: false,
298
- destructiveHint: true,
299
- openWorldHint: false,
300
- },
328
+ inputSchema: zodToJsonSchema(MoveFileArgsSchema),
329
+ annotations: {
330
+ title: "Move/Rename File",
331
+ readOnlyHint: false,
332
+ destructiveHint: true,
333
+ openWorldHint: false,
301
334
  },
302
- {
303
- name: "start_search",
304
- description: `
335
+ },
336
+ {
337
+ name: "start_search",
338
+ description: `
305
339
  Start a streaming search that can return results progressively.
306
340
 
307
341
  SEARCH STRATEGY GUIDE:
@@ -380,11 +414,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
380
414
 
381
415
  ${PATH_GUIDANCE}
382
416
  ${CMD_PREFIX_DESCRIPTION}`,
383
- inputSchema: zodToJsonSchema(StartSearchArgsSchema),
384
- },
385
- {
386
- name: "get_more_search_results",
387
- description: `
417
+ inputSchema: zodToJsonSchema(StartSearchArgsSchema),
418
+ },
419
+ {
420
+ name: "get_more_search_results",
421
+ description: `
388
422
  Get more results from an active search with offset-based pagination.
389
423
 
390
424
  Supports partial result reading with:
@@ -406,15 +440,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
406
440
  results from a search started with start_search.
407
441
 
408
442
  ${CMD_PREFIX_DESCRIPTION}`,
409
- inputSchema: zodToJsonSchema(GetMoreSearchResultsArgsSchema),
410
- annotations: {
411
- title: "Get Search Results",
412
- readOnlyHint: true,
413
- },
443
+ inputSchema: zodToJsonSchema(GetMoreSearchResultsArgsSchema),
444
+ annotations: {
445
+ title: "Get Search Results",
446
+ readOnlyHint: true,
414
447
  },
415
- {
416
- name: "stop_search",
417
- description: `
448
+ },
449
+ {
450
+ name: "stop_search",
451
+ description: `
418
452
  Stop an active search.
419
453
 
420
454
  Stops the background search process gracefully. Use this when you've found
@@ -425,11 +459,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
425
459
  automatically cleaned up after 5 minutes.
426
460
 
427
461
  ${CMD_PREFIX_DESCRIPTION}`,
428
- inputSchema: zodToJsonSchema(StopSearchArgsSchema),
429
- },
430
- {
431
- name: "list_searches",
432
- description: `
462
+ inputSchema: zodToJsonSchema(StopSearchArgsSchema),
463
+ },
464
+ {
465
+ name: "list_searches",
466
+ description: `
433
467
  List all active searches.
434
468
 
435
469
  Shows search IDs, search types, patterns, status, and runtime.
@@ -437,15 +471,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
437
471
  multiple concurrent searches.
438
472
 
439
473
  ${CMD_PREFIX_DESCRIPTION}`,
440
- inputSchema: zodToJsonSchema(ListSearchesArgsSchema),
441
- annotations: {
442
- title: "List Active Searches",
443
- readOnlyHint: true,
444
- },
474
+ inputSchema: zodToJsonSchema(ListSearchesArgsSchema),
475
+ annotations: {
476
+ title: "List Active Searches",
477
+ readOnlyHint: true,
445
478
  },
446
- {
447
- name: "get_file_info",
448
- description: `
479
+ },
480
+ {
481
+ name: "get_file_info",
482
+ description: `
449
483
  Retrieve detailed metadata about a file or directory including:
450
484
  - size
451
485
  - creation time
@@ -460,17 +494,17 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
460
494
 
461
495
  ${PATH_GUIDANCE}
462
496
  ${CMD_PREFIX_DESCRIPTION}`,
463
- inputSchema: zodToJsonSchema(GetFileInfoArgsSchema),
464
- annotations: {
465
- title: "Get File Information",
466
- readOnlyHint: true,
467
- },
497
+ inputSchema: zodToJsonSchema(GetFileInfoArgsSchema),
498
+ annotations: {
499
+ title: "Get File Information",
500
+ readOnlyHint: true,
468
501
  },
469
- // Note: list_allowed_directories removed - use get_config to check allowedDirectories
470
- // Text editing tools
471
- {
472
- name: "edit_block",
473
- description: `
502
+ },
503
+ // Note: list_allowed_directories removed - use get_config to check allowedDirectories
504
+ // Text editing tools
505
+ {
506
+ name: "edit_block",
507
+ description: `
474
508
  Apply surgical text replacements to files.
475
509
 
476
510
  BEST PRACTICE: Make multiple small, focused edits rather than one large edit.
@@ -503,18 +537,18 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
503
537
 
504
538
  ${PATH_GUIDANCE}
505
539
  ${CMD_PREFIX_DESCRIPTION}`,
506
- inputSchema: zodToJsonSchema(EditBlockArgsSchema),
507
- annotations: {
508
- title: "Edit Text Block",
509
- readOnlyHint: false,
510
- destructiveHint: true,
511
- openWorldHint: false,
512
- },
540
+ inputSchema: zodToJsonSchema(EditBlockArgsSchema),
541
+ annotations: {
542
+ title: "Edit Text Block",
543
+ readOnlyHint: false,
544
+ destructiveHint: true,
545
+ openWorldHint: false,
513
546
  },
514
- // Terminal tools
515
- {
516
- name: "start_process",
517
- description: `
547
+ },
548
+ // Terminal tools
549
+ {
550
+ name: "start_process",
551
+ description: `
518
552
  Start a new terminal process with intelligent state detection.
519
553
 
520
554
  PRIMARY TOOL FOR FILE ANALYSIS AND DATA PROCESSING
@@ -557,25 +591,33 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
557
591
 
558
592
  STATES DETECTED:
559
593
  Process waiting for input (shows prompt)
560
- Process finished execution
594
+ Process finished execution
561
595
  Process running (use read_process_output)
562
-
596
+
597
+ PERFORMANCE DEBUGGING (verbose_timing parameter):
598
+ Set verbose_timing: true to get detailed timing information including:
599
+ - Exit reason (early_exit_quick_pattern, early_exit_periodic_check, process_exit, timeout)
600
+ - Total duration and time to first output
601
+ - Complete timeline of all output events with timestamps
602
+ - Which detection mechanism triggered early exit
603
+ Use this to identify missed optimization opportunities and improve detection patterns.
604
+
563
605
  ALWAYS USE FOR: Local file analysis, CSV processing, data exploration, system commands
564
606
  NEVER USE ANALYSIS TOOL FOR: Local file access (analysis tool is browser-only and WILL FAIL)
565
-
607
+
566
608
  ${PATH_GUIDANCE}
567
609
  ${CMD_PREFIX_DESCRIPTION}`,
568
- inputSchema: zodToJsonSchema(StartProcessArgsSchema),
569
- annotations: {
570
- title: "Start Terminal Process",
571
- readOnlyHint: false,
572
- destructiveHint: true,
573
- openWorldHint: true,
574
- },
610
+ inputSchema: zodToJsonSchema(StartProcessArgsSchema),
611
+ annotations: {
612
+ title: "Start Terminal Process",
613
+ readOnlyHint: false,
614
+ destructiveHint: true,
615
+ openWorldHint: true,
575
616
  },
576
- {
577
- name: "read_process_output",
578
- description: `
617
+ },
618
+ {
619
+ name: "read_process_output",
620
+ description: `
579
621
  Read output from a running process with intelligent completion detection.
580
622
 
581
623
  Automatically detects when process is ready for more input instead of timing out.
@@ -596,17 +638,25 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
596
638
  Process waiting for input (ready for interact_with_process)
597
639
  Process finished execution
598
640
  Timeout reached (may still be running)
599
-
641
+
642
+ PERFORMANCE DEBUGGING (verbose_timing parameter):
643
+ Set verbose_timing: true to get detailed timing information including:
644
+ - Exit reason (early_exit_quick_pattern, early_exit_periodic_check, process_finished, timeout)
645
+ - Total duration and time to first output
646
+ - Complete timeline of all output events with timestamps
647
+ - Which detection mechanism triggered early exit
648
+ Use this to identify when timeouts could be reduced or detection patterns improved.
649
+
600
650
  ${CMD_PREFIX_DESCRIPTION}`,
601
- inputSchema: zodToJsonSchema(ReadProcessOutputArgsSchema),
602
- annotations: {
603
- title: "Read Process Output",
604
- readOnlyHint: true,
605
- },
651
+ inputSchema: zodToJsonSchema(ReadProcessOutputArgsSchema),
652
+ annotations: {
653
+ title: "Read Process Output",
654
+ readOnlyHint: true,
606
655
  },
607
- {
608
- name: "interact_with_process",
609
- description: `
656
+ },
657
+ {
658
+ name: "interact_with_process",
659
+ description: `
610
660
  Send input to a running process and automatically receive the response.
611
661
 
612
662
  CRITICAL: THIS IS THE PRIMARY TOOL FOR ALL LOCAL FILE ANALYSIS
@@ -647,38 +697,47 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
647
697
  - input: Code/command to execute
648
698
  - timeout_ms: Max wait (default: 8000ms)
649
699
  - wait_for_prompt: Auto-wait for response (default: true)
650
-
700
+ - verbose_timing: Enable detailed performance telemetry (default: false)
701
+
651
702
  Returns execution result with status indicators.
652
-
703
+
704
+ PERFORMANCE DEBUGGING (verbose_timing parameter):
705
+ Set verbose_timing: true to get detailed timing information including:
706
+ - Exit reason (early_exit_quick_pattern, early_exit_periodic_check, process_finished, timeout, no_wait)
707
+ - Total duration and time to first output
708
+ - Complete timeline of all output events with timestamps
709
+ - Which detection mechanism triggered early exit
710
+ Use this to identify slow interactions and optimize detection patterns.
711
+
653
712
  ALWAYS USE FOR: CSV analysis, JSON processing, file statistics, data visualization prep, ANY local file work
654
713
  NEVER USE ANALYSIS TOOL FOR: Local file access (it cannot read files from disk and WILL FAIL)
655
-
714
+
656
715
  ${CMD_PREFIX_DESCRIPTION}`,
657
- inputSchema: zodToJsonSchema(InteractWithProcessArgsSchema),
658
- annotations: {
659
- title: "Send Input to Process",
660
- readOnlyHint: false,
661
- destructiveHint: true,
662
- openWorldHint: true,
663
- },
716
+ inputSchema: zodToJsonSchema(InteractWithProcessArgsSchema),
717
+ annotations: {
718
+ title: "Send Input to Process",
719
+ readOnlyHint: false,
720
+ destructiveHint: true,
721
+ openWorldHint: true,
664
722
  },
665
- {
666
- name: "force_terminate",
667
- description: `
723
+ },
724
+ {
725
+ name: "force_terminate",
726
+ description: `
668
727
  Force terminate a running terminal session.
669
728
 
670
729
  ${CMD_PREFIX_DESCRIPTION}`,
671
- inputSchema: zodToJsonSchema(ForceTerminateArgsSchema),
672
- annotations: {
673
- title: "Force Terminate Process",
674
- readOnlyHint: false,
675
- destructiveHint: true,
676
- openWorldHint: false,
677
- },
730
+ inputSchema: zodToJsonSchema(ForceTerminateArgsSchema),
731
+ annotations: {
732
+ title: "Force Terminate Process",
733
+ readOnlyHint: false,
734
+ destructiveHint: true,
735
+ openWorldHint: false,
678
736
  },
679
- {
680
- name: "list_sessions",
681
- description: `
737
+ },
738
+ {
739
+ name: "list_sessions",
740
+ description: `
682
741
  List all active terminal sessions.
683
742
 
684
743
  Shows session status including:
@@ -692,59 +751,80 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
692
751
  - Long runtime with blocked status may indicate stuck process
693
752
 
694
753
  ${CMD_PREFIX_DESCRIPTION}`,
695
- inputSchema: zodToJsonSchema(ListSessionsArgsSchema),
696
- annotations: {
697
- title: "List Terminal Sessions",
698
- readOnlyHint: true,
699
- },
754
+ inputSchema: zodToJsonSchema(ListSessionsArgsSchema),
755
+ annotations: {
756
+ title: "List Terminal Sessions",
757
+ readOnlyHint: true,
700
758
  },
701
- {
702
- name: "list_processes",
703
- description: `
759
+ },
760
+ {
761
+ name: "list_processes",
762
+ description: `
704
763
  List all running processes.
705
764
 
706
765
  Returns process information including PID, command name, CPU usage, and memory usage.
707
766
 
708
767
  ${CMD_PREFIX_DESCRIPTION}`,
709
- inputSchema: zodToJsonSchema(ListProcessesArgsSchema),
710
- annotations: {
711
- title: "List Running Processes",
712
- readOnlyHint: true,
713
- },
768
+ inputSchema: zodToJsonSchema(ListProcessesArgsSchema),
769
+ annotations: {
770
+ title: "List Running Processes",
771
+ readOnlyHint: true,
714
772
  },
715
- {
716
- name: "kill_process",
717
- description: `
773
+ },
774
+ {
775
+ name: "kill_process",
776
+ description: `
718
777
  Terminate a running process by PID.
719
778
 
720
779
  Use with caution as this will forcefully terminate the specified process.
721
780
 
722
781
  ${CMD_PREFIX_DESCRIPTION}`,
723
- inputSchema: zodToJsonSchema(KillProcessArgsSchema),
724
- annotations: {
725
- title: "Kill Process",
726
- readOnlyHint: false,
727
- destructiveHint: true,
728
- openWorldHint: false,
729
- },
782
+ inputSchema: zodToJsonSchema(KillProcessArgsSchema),
783
+ annotations: {
784
+ title: "Kill Process",
785
+ readOnlyHint: false,
786
+ destructiveHint: true,
787
+ openWorldHint: false,
730
788
  },
731
- {
732
- name: "get_usage_stats",
733
- description: `
789
+ },
790
+ {
791
+ name: "get_usage_stats",
792
+ description: `
734
793
  Get usage statistics for debugging and analysis.
735
794
 
736
795
  Returns summary of tool usage, success/failure rates, and performance metrics.
737
796
 
738
797
  ${CMD_PREFIX_DESCRIPTION}`,
739
- inputSchema: zodToJsonSchema(GetUsageStatsArgsSchema),
740
- annotations: {
741
- title: "Get Usage Statistics",
742
- readOnlyHint: true,
743
- },
798
+ inputSchema: zodToJsonSchema(GetUsageStatsArgsSchema),
799
+ annotations: {
800
+ title: "Get Usage Statistics",
801
+ readOnlyHint: true,
744
802
  },
745
- {
746
- name: "give_feedback_to_desktop_commander",
747
- description: `
803
+ },
804
+ {
805
+ name: "get_recent_tool_calls",
806
+ description: `
807
+ Get recent tool call history with their arguments and outputs.
808
+ Returns chronological list of tool calls made during this session.
809
+
810
+ Useful for:
811
+ - Onboarding new chats about work already done
812
+ - Recovering context after chat history loss
813
+ - Debugging tool call sequences
814
+
815
+ Note: Does not track its own calls or other meta/query tools.
816
+ History kept in memory (last 1000 calls, lost on restart).
817
+
818
+ ${CMD_PREFIX_DESCRIPTION}`,
819
+ inputSchema: zodToJsonSchema(GetRecentToolCallsArgsSchema),
820
+ annotations: {
821
+ title: "Get Recent Tool Calls",
822
+ readOnlyHint: true,
823
+ },
824
+ },
825
+ {
826
+ name: "give_feedback_to_desktop_commander",
827
+ description: `
748
828
  Open feedback form in browser to provide feedback about Desktop Commander.
749
829
 
750
830
  IMPORTANT: This tool simply opens the feedback form - no pre-filling available.
@@ -777,11 +857,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
777
857
  No parameters are needed - just call the tool to open the form.
778
858
 
779
859
  ${CMD_PREFIX_DESCRIPTION}`,
780
- inputSchema: zodToJsonSchema(GiveFeedbackArgsSchema),
781
- },
782
- {
783
- name: "get_prompts",
784
- description: `
860
+ inputSchema: zodToJsonSchema(GiveFeedbackArgsSchema),
861
+ },
862
+ {
863
+ name: "get_prompts",
864
+ description: `
785
865
  Browse and retrieve curated Desktop Commander prompts for various tasks and workflows.
786
866
 
787
867
  IMPORTANT: When displaying prompt lists to users, do NOT show the internal prompt IDs (like 'onb_001').
@@ -811,9 +891,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
811
891
  Perfect for discovering proven workflows and getting started with Desktop Commander.
812
892
 
813
893
  ${CMD_PREFIX_DESCRIPTION}`,
814
- inputSchema: zodToJsonSchema(GetPromptsArgsSchema),
815
- },
816
- ],
894
+ inputSchema: zodToJsonSchema(GetPromptsArgsSchema),
895
+ },
896
+ ];
897
+ // Filter tools based on current client
898
+ const filteredTools = allTools.filter(tool => shouldIncludeTool(tool.name));
899
+ logToStderr('debug', `Returning ${filteredTools.length} tools (filtered from ${allTools.length} total) for client: ${currentClient?.name || 'unknown'}`);
900
+ return {
901
+ tools: filteredTools,
817
902
  };
818
903
  }
819
904
  catch (error) {
@@ -824,6 +909,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
824
909
  import * as handlers from './handlers/index.js';
825
910
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
826
911
  const { name, arguments: args } = request.params;
912
+ const startTime = Date.now();
827
913
  try {
828
914
  // Prepare telemetry data - add config key for set_config_value
829
915
  const telemetryData = { name };
@@ -960,6 +1046,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
960
1046
  };
961
1047
  }
962
1048
  break;
1049
+ case "get_recent_tool_calls":
1050
+ try {
1051
+ result = await handlers.handleGetRecentToolCalls(args);
1052
+ }
1053
+ catch (error) {
1054
+ capture('server_request_error', { message: `Error in get_recent_tool_calls handler: ${error}` });
1055
+ result = {
1056
+ content: [{ type: "text", text: `Error: Failed to get tool call history` }],
1057
+ isError: true,
1058
+ };
1059
+ }
1060
+ break;
963
1061
  case "give_feedback_to_desktop_commander":
964
1062
  try {
965
1063
  result = await giveFeedbackToDesktopCommander(args);
@@ -1040,6 +1138,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1040
1138
  isError: true,
1041
1139
  };
1042
1140
  }
1141
+ // Add tool call to history (exclude only get_recent_tool_calls to prevent recursion)
1142
+ const duration = Date.now() - startTime;
1143
+ const EXCLUDED_TOOLS = [
1144
+ 'get_recent_tool_calls'
1145
+ ];
1146
+ if (!EXCLUDED_TOOLS.includes(name)) {
1147
+ toolHistory.addCall(name, args, result, duration);
1148
+ }
1043
1149
  // Track success or failure based on result
1044
1150
  if (result.isError) {
1045
1151
  await usageTracker.trackFailure(name);