@wonderwhy-er/desktop-commander 0.2.12 → 0.2.14

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.
@@ -0,0 +1,160 @@
1
+ import http from 'http';
2
+ import { URL } from 'url';
3
+ import { OAuthProvider } from './provider.js';
4
+ export class OAuthHttpServer {
5
+ constructor(config, mcpHandler) {
6
+ this.oauthProvider = new OAuthProvider(config);
7
+ this.mcpHandler = mcpHandler;
8
+ this.server = http.createServer(this.handleRequest.bind(this));
9
+ }
10
+ async handleRequest(req, res) {
11
+ const url = new URL(req.url, `http://${req.headers.host}`);
12
+ // Enable CORS
13
+ this.setCorsHeaders(res);
14
+ if (req.method === 'OPTIONS') {
15
+ res.writeHead(200);
16
+ res.end();
17
+ return;
18
+ }
19
+ try {
20
+ // OAuth endpoints
21
+ if (url.pathname === '/.well-known/oauth-authorization-server') {
22
+ return this.handleAuthServerMetadata(res);
23
+ }
24
+ if (url.pathname === '/authorize') {
25
+ return this.handleAuthorize(url, res);
26
+ }
27
+ if (url.pathname === '/token' && req.method === 'POST') {
28
+ return this.handleToken(req, res);
29
+ }
30
+ if (url.pathname === '/callback') {
31
+ return this.handleCallback(url, res);
32
+ }
33
+ // Protected MCP endpoints - require authentication
34
+ if (url.pathname.startsWith('/mcp') || url.pathname === '/sse') {
35
+ const authHeader = req.headers.authorization;
36
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
37
+ return this.sendUnauthorized(res);
38
+ }
39
+ const token = authHeader.substring(7);
40
+ const tokenData = this.oauthProvider.validateAccessToken(token);
41
+ if (!tokenData) {
42
+ return this.sendUnauthorized(res);
43
+ }
44
+ // Add user info to request for MCP handler
45
+ req.user = tokenData;
46
+ }
47
+ // Forward to MCP handler
48
+ this.mcpHandler(req, res);
49
+ }
50
+ catch (error) {
51
+ console.error('OAuth server error:', error);
52
+ res.writeHead(500, { 'Content-Type': 'application/json' });
53
+ res.end(JSON.stringify({ error: 'Internal server error' }));
54
+ }
55
+ }
56
+ setCorsHeaders(res) {
57
+ res.setHeader('Access-Control-Allow-Origin', '*');
58
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
59
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
60
+ res.setHeader('Access-Control-Expose-Headers', 'WWW-Authenticate');
61
+ }
62
+ handleAuthServerMetadata(res) {
63
+ const metadata = this.oauthProvider.getAuthorizationServerMetadata();
64
+ res.writeHead(200, { 'Content-Type': 'application/json' });
65
+ res.end(JSON.stringify(metadata, null, 2));
66
+ }
67
+ handleAuthorize(url, res) {
68
+ const params = {
69
+ response_type: url.searchParams.get('response_type'),
70
+ client_id: url.searchParams.get('client_id'),
71
+ redirect_uri: url.searchParams.get('redirect_uri'),
72
+ scope: url.searchParams.get('scope') || undefined,
73
+ state: url.searchParams.get('state') || undefined,
74
+ code_challenge: url.searchParams.get('code_challenge'),
75
+ code_challenge_method: url.searchParams.get('code_challenge_method')
76
+ };
77
+ const result = this.oauthProvider.handleAuthorizationRequest(params);
78
+ if (result.error) {
79
+ res.writeHead(400, { 'Content-Type': 'application/json' });
80
+ res.end(JSON.stringify({ error: result.error }));
81
+ return;
82
+ }
83
+ // Redirect to the callback URL with auth code
84
+ res.writeHead(302, { 'Location': result.authUrl });
85
+ res.end();
86
+ }
87
+ async handleToken(req, res) {
88
+ const body = await this.getRequestBody(req);
89
+ const params = new URLSearchParams(body);
90
+ const tokenRequest = {
91
+ grant_type: params.get('grant_type'),
92
+ code: params.get('code'),
93
+ redirect_uri: params.get('redirect_uri'),
94
+ client_id: params.get('client_id'),
95
+ code_verifier: params.get('code_verifier')
96
+ };
97
+ const result = await this.oauthProvider.handleTokenRequest(tokenRequest);
98
+ if ('error' in result) {
99
+ res.writeHead(400, { 'Content-Type': 'application/json' });
100
+ res.end(JSON.stringify(result));
101
+ return;
102
+ }
103
+ res.writeHead(200, { 'Content-Type': 'application/json' });
104
+ res.end(JSON.stringify(result));
105
+ }
106
+ handleCallback(url, res) {
107
+ const code = url.searchParams.get('code');
108
+ const state = url.searchParams.get('state');
109
+ // Simple success page
110
+ const html = `
111
+ <!DOCTYPE html>
112
+ <html>
113
+ <head><title>Authorization Successful</title></head>
114
+ <body>
115
+ <h1>Authorization Successful!</h1>
116
+ <p>You can now close this window.</p>
117
+ <script>
118
+ // Try to close the window (works if opened by script)
119
+ try { window.close(); } catch(e) {}
120
+
121
+ // Post message to parent if in iframe
122
+ if (window.opener) {
123
+ window.opener.postMessage({
124
+ type: 'oauth_success',
125
+ code: '${code}',
126
+ state: '${state}'
127
+ }, '*');
128
+ }
129
+ </script>
130
+ </body>
131
+ </html>
132
+ `;
133
+ res.writeHead(200, { 'Content-Type': 'text/html' });
134
+ res.end(html);
135
+ }
136
+ sendUnauthorized(res) {
137
+ res.writeHead(401, {
138
+ 'Content-Type': 'application/json',
139
+ 'WWW-Authenticate': 'Bearer realm="mcp", error="invalid_token"'
140
+ });
141
+ res.end(JSON.stringify({
142
+ error: 'unauthorized',
143
+ message: 'Valid access token required'
144
+ }));
145
+ }
146
+ async getRequestBody(req) {
147
+ return new Promise((resolve, reject) => {
148
+ let body = '';
149
+ req.on('data', chunk => body += chunk.toString());
150
+ req.on('end', () => resolve(body));
151
+ req.on('error', reject);
152
+ });
153
+ }
154
+ listen(port, callback) {
155
+ this.server.listen(port, callback);
156
+ }
157
+ close(callback) {
158
+ this.server.close(callback);
159
+ }
160
+ }
@@ -0,0 +1,54 @@
1
+ export interface OAuthConfig {
2
+ enabled: boolean;
3
+ clientId: string;
4
+ clientSecret: string;
5
+ redirectUri: string;
6
+ authorizationUrl: string;
7
+ tokenUrl: string;
8
+ scope: string;
9
+ issuer: string;
10
+ }
11
+ export interface AuthorizationServerMetadata {
12
+ issuer: string;
13
+ authorization_endpoint: string;
14
+ token_endpoint: string;
15
+ registration_endpoint?: string;
16
+ revocation_endpoint?: string;
17
+ jwks_uri?: string;
18
+ response_types_supported: string[];
19
+ grant_types_supported: string[];
20
+ token_endpoint_auth_methods_supported: string[];
21
+ code_challenge_methods_supported: string[];
22
+ scopes_supported?: string[];
23
+ }
24
+ export interface TokenResponse {
25
+ access_token: string;
26
+ token_type: string;
27
+ expires_in?: number;
28
+ refresh_token?: string;
29
+ scope?: string;
30
+ }
31
+ export interface AccessToken {
32
+ sub: string;
33
+ aud: string | string[];
34
+ iss: string;
35
+ exp: number;
36
+ iat: number;
37
+ scope?: string;
38
+ }
39
+ export interface AuthorizationRequest {
40
+ response_type: 'code';
41
+ client_id: string;
42
+ redirect_uri: string;
43
+ scope?: string;
44
+ state?: string;
45
+ code_challenge: string;
46
+ code_challenge_method: 'S256';
47
+ }
48
+ export interface TokenRequest {
49
+ grant_type: 'authorization_code';
50
+ code: string;
51
+ redirect_uri: string;
52
+ client_id: string;
53
+ code_verifier: string;
54
+ }
@@ -0,0 +1,2 @@
1
+ // OAuth 2.1 types for MCP authorization
2
+ export {};
@@ -30,6 +30,7 @@ export interface SearchSessionOptions {
30
30
  contextLines?: number;
31
31
  timeout?: number;
32
32
  earlyTermination?: boolean;
33
+ literalSearch?: boolean;
33
34
  }
34
35
  /**
35
36
  * Search Session Manager - handles ripgrep processes like terminal sessions
@@ -212,6 +212,10 @@ import { capture } from './utils/capture.js';
212
212
  if (options.searchType === 'content') {
213
213
  // Content search mode
214
214
  args.push('--json', '--line-number');
215
+ // Add literal search support for content searches
216
+ if (options.literalSearch) {
217
+ args.push('-F'); // Fixed string matching (literal)
218
+ }
215
219
  if (options.contextLines && options.contextLines > 0) {
216
220
  args.push('-C', options.contextLines.toString());
217
221
  }
package/dist/server.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
- import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ListPromptsRequestSchema, InitializeRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
2
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ListPromptsRequestSchema, InitializeRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
3
3
  import { zodToJsonSchema } from "zod-to-json-schema";
4
4
  import { getSystemInfo, getOSSpecificGuidance, getPathGuidance, getDevelopmentToolGuidance } from './utils/system-info.js';
5
5
  // Get system information once at startup
@@ -257,24 +257,72 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
257
257
  description: `
258
258
  Start a streaming search that can return results progressively.
259
259
 
260
+ SEARCH STRATEGY GUIDE:
261
+ Choose the right search type based on what the user is looking for:
262
+
263
+ USE searchType="files" WHEN:
264
+ - User asks for specific files: "find package.json", "locate config files"
265
+ - Pattern looks like a filename: "*.js", "README.md", "test-*.tsx"
266
+ - User wants to find files by name/extension: "all TypeScript files", "Python scripts"
267
+ - Looking for configuration/setup files: ".env", "dockerfile", "tsconfig.json"
268
+
269
+ USE searchType="content" WHEN:
270
+ - User asks about code/logic: "authentication logic", "error handling", "API calls"
271
+ - Looking for functions/variables: "getUserData function", "useState hook"
272
+ - Searching for text/comments: "TODO items", "FIXME comments", "documentation"
273
+ - Finding patterns in code: "console.log statements", "import statements"
274
+ - User describes functionality: "components that handle login", "files with database queries"
275
+
276
+ WHEN UNSURE OR USER REQUEST IS AMBIGUOUS:
277
+ Run TWO searches in parallel - one for files and one for content:
278
+
279
+ Example approach for ambiguous queries like "find authentication stuff":
280
+ 1. Start file search: searchType="files", pattern="auth"
281
+ 2. Simultaneously start content search: searchType="content", pattern="authentication"
282
+ 3. Present combined results: "Found 3 auth-related files and 8 files containing authentication code"
283
+
260
284
  SEARCH TYPES:
261
285
  - searchType="files": Find files by name (pattern matches file names)
262
286
  - searchType="content": Search inside files for text patterns
263
287
 
288
+ PATTERN MATCHING MODES:
289
+ - Default (literalSearch=false): Patterns are treated as regular expressions
290
+ - Literal (literalSearch=true): Patterns are treated as exact strings
291
+
292
+ WHEN TO USE literalSearch=true:
293
+ Use literal search when searching for code patterns with special characters:
294
+ - Function calls with parentheses and quotes
295
+ - Array access with brackets
296
+ - Object methods with dots and parentheses
297
+ - File paths with backslashes
298
+ - Any pattern containing: . * + ? ^ $ { } [ ] | \\ ( )
299
+
264
300
  IMPORTANT PARAMETERS:
265
301
  - pattern: What to search for (file names OR content text)
302
+ - literalSearch: Use exact string matching instead of regex (default: false)
266
303
  - filePattern: Optional filter to limit search to specific file types (e.g., "*.js", "package.json")
267
304
  - ignoreCase: Case-insensitive search (default: true). Works for both file names and content.
268
305
  - earlyTermination: Stop search early when exact filename match is found (optional: defaults to true for file searches, false for content searches)
269
306
 
270
- EXAMPLES:
271
- - Find package.json files: searchType="files", pattern="package.json", filePattern="package.json"
272
- - Find all JS files: searchType="files", pattern="*.js" (or use filePattern="*.js")
273
- - Search for "TODO" in code: searchType="content", pattern="TODO", filePattern="*.js|*.ts"
274
- - Case-sensitive file search: searchType="files", pattern="README", ignoreCase=false
275
- - Case-insensitive file search: searchType="files", pattern="readme", ignoreCase=true
276
- - Find exact file, stop after first match: searchType="files", pattern="config.json", earlyTermination=true
277
- - Find all matching files: searchType="files", pattern="test.js", earlyTermination=false
307
+ DECISION EXAMPLES:
308
+ - "find package.json" searchType="files", pattern="package.json" (specific file)
309
+ - "find authentication components" searchType="content", pattern="authentication" (looking for functionality)
310
+ - "locate all React components" searchType="files", pattern="*.tsx" or "*.jsx" (file pattern)
311
+ - "find TODO comments" searchType="content", pattern="TODO" (text in files)
312
+ - "show me login files" → AMBIGUOUS → run both: files with "login" AND content with "login"
313
+ - "find config" AMBIGUOUS run both: config files AND files containing config code
314
+
315
+ COMPREHENSIVE SEARCH EXAMPLES:
316
+ - Find package.json files: searchType="files", pattern="package.json"
317
+ - Find all JS files: searchType="files", pattern="*.js"
318
+ - Search for TODO in code: searchType="content", pattern="TODO", filePattern="*.js|*.ts"
319
+ - Search for exact code: searchType="content", pattern="toast.error('test')", literalSearch=true
320
+ - Ambiguous request "find auth stuff": Run two searches:
321
+ 1. searchType="files", pattern="auth"
322
+ 2. searchType="content", pattern="authentication"
323
+
324
+ PRO TIP: When user requests are ambiguous about whether they want files or content,
325
+ run both searches concurrently and combine results for comprehensive coverage.
278
326
 
279
327
  Unlike regular search tools, this starts a background search process and returns
280
328
  immediately with a session ID. Use get_more_search_results to get results as they
@@ -635,6 +683,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
635
683
  These IDs are for your reference only. Show users only the prompt titles and descriptions.
636
684
  The IDs will be provided in the response metadata for your use.
637
685
 
686
+ DESKTOP COMMANDER INTRODUCTION: If a user asks "what is Desktop Commander?" or similar questions
687
+ about what Desktop Commander can do, answer that there are example use cases and tutorials
688
+ available, then call get_prompts with action='list_prompts' and category='onboarding' to show them.
689
+
638
690
  ACTIONS:
639
691
  - list_categories: Show all available prompt categories
640
692
  - list_prompts: List prompts (optionally filtered by category)
@@ -673,6 +725,17 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
673
725
  if (name === 'set_config_value' && args && typeof args === 'object' && 'key' in args) {
674
726
  telemetryData.set_config_value_key_name = args.key;
675
727
  }
728
+ if (name === 'get_prompts' && args && typeof args === 'object') {
729
+ const promptArgs = args;
730
+ telemetryData.action = promptArgs.action;
731
+ if (promptArgs.category) {
732
+ telemetryData.category = promptArgs.category;
733
+ telemetryData.has_category_filter = true;
734
+ }
735
+ if (promptArgs.promptId) {
736
+ telemetryData.prompt_id = promptArgs.promptId;
737
+ }
738
+ }
676
739
  capture_call_tool('server_call_tool', telemetryData);
677
740
  // Track tool call
678
741
  trackToolCall(name, args);
@@ -719,6 +782,70 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
719
782
  case "get_prompts":
720
783
  try {
721
784
  result = await getPrompts(args || {});
785
+ // Capture detailed analytics for all successful get_prompts actions
786
+ if (args && typeof args === 'object' && !result.isError) {
787
+ const action = args.action;
788
+ try {
789
+ if (action === 'get_prompt' && args.promptId) {
790
+ // Existing get_prompt analytics
791
+ const { loadPromptsData } = await import('./tools/prompts.js');
792
+ const promptsData = await loadPromptsData();
793
+ const prompt = promptsData.prompts.find(p => p.id === args.promptId);
794
+ if (prompt) {
795
+ await capture('server_get_prompt', {
796
+ prompt_id: prompt.id,
797
+ prompt_title: prompt.title,
798
+ category: prompt.categories[0] || 'uncategorized',
799
+ author: prompt.author,
800
+ verified: prompt.verified
801
+ });
802
+ }
803
+ }
804
+ else if (action === 'list_categories') {
805
+ // New analytics for category browsing
806
+ const { loadPromptsData } = await import('./tools/prompts.js');
807
+ const promptsData = await loadPromptsData();
808
+ // Extract unique categories and count prompts in each
809
+ const categoryMap = new Map();
810
+ promptsData.prompts.forEach(prompt => {
811
+ prompt.categories.forEach(category => {
812
+ categoryMap.set(category, (categoryMap.get(category) || 0) + 1);
813
+ });
814
+ });
815
+ await capture('server_list_prompt_categories', {
816
+ total_categories: categoryMap.size,
817
+ total_prompts: promptsData.prompts.length,
818
+ categories_available: Array.from(categoryMap.keys())
819
+ });
820
+ }
821
+ else if (action === 'list_prompts') {
822
+ // New analytics for prompt list browsing
823
+ const { loadPromptsData } = await import('./tools/prompts.js');
824
+ const promptsData = await loadPromptsData();
825
+ const category = args.category;
826
+ let filteredPrompts = promptsData.prompts;
827
+ if (category) {
828
+ filteredPrompts = promptsData.prompts.filter(prompt => prompt.categories.includes(category));
829
+ }
830
+ await capture('server_list_category_prompts', {
831
+ category_filter: category || 'all',
832
+ has_category_filter: !!category,
833
+ prompts_shown: filteredPrompts.length,
834
+ total_prompts_available: promptsData.prompts.length,
835
+ prompt_ids_shown: filteredPrompts.map(p => p.id)
836
+ });
837
+ }
838
+ }
839
+ catch (error) {
840
+ // Don't fail the request if analytics fail
841
+ }
842
+ }
843
+ // Track if user used get_prompts after seeing onboarding invitation (for state management only)
844
+ const onboardingState = await usageTracker.getOnboardingState();
845
+ if (onboardingState.attemptsShown > 0 && !onboardingState.promptsUsed) {
846
+ // Mark that they used prompts after seeing onboarding (stops future onboarding messages)
847
+ await usageTracker.markOnboardingPromptsUsed();
848
+ }
722
849
  }
723
850
  catch (error) {
724
851
  capture('server_request_error', { message: `Error in get_prompts handler: ${error}` });
@@ -816,6 +943,40 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
816
943
  else {
817
944
  await usageTracker.trackSuccess(name);
818
945
  console.log(`[FEEDBACK DEBUG] Tool ${name} succeeded, checking feedback...`);
946
+ // Check if should show onboarding (before feedback - first-time users are priority)
947
+ const shouldShowOnboarding = await usageTracker.shouldShowOnboarding();
948
+ console.log(`[ONBOARDING DEBUG] Should show onboarding: ${shouldShowOnboarding}`);
949
+ if (shouldShowOnboarding) {
950
+ console.log(`[ONBOARDING DEBUG] Generating onboarding message...`);
951
+ const onboardingResult = await usageTracker.getOnboardingMessage();
952
+ console.log(`[ONBOARDING DEBUG] Generated variant: ${onboardingResult.variant}`);
953
+ // Capture onboarding prompt injection event
954
+ const stats = await usageTracker.getStats();
955
+ await capture('server_onboarding_shown', {
956
+ trigger_tool: name,
957
+ total_calls: stats.totalToolCalls,
958
+ successful_calls: stats.successfulCalls,
959
+ days_since_first_use: Math.floor((Date.now() - stats.firstUsed) / (1000 * 60 * 60 * 24)),
960
+ total_sessions: stats.totalSessions,
961
+ message_variant: onboardingResult.variant
962
+ });
963
+ // Inject onboarding message for the LLM
964
+ if (result.content && result.content.length > 0 && result.content[0].type === "text") {
965
+ const currentContent = result.content[0].text || '';
966
+ result.content[0].text = `${currentContent}${onboardingResult.message}`;
967
+ }
968
+ else {
969
+ result.content = [
970
+ ...(result.content || []),
971
+ {
972
+ type: "text",
973
+ text: onboardingResult.message
974
+ }
975
+ ];
976
+ }
977
+ // Mark that we've shown onboarding (to prevent spam)
978
+ await usageTracker.markOnboardingShown(onboardingResult.variant);
979
+ }
819
980
  // Check if should prompt for feedback (only on successful operations)
820
981
  const shouldPrompt = await usageTracker.shouldPromptForFeedback();
821
982
  console.log(`[FEEDBACK DEBUG] Should prompt for feedback: ${shouldPrompt}`);
@@ -869,3 +1030,5 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
869
1030
  };
870
1031
  }
871
1032
  });
1033
+ // Add no-op handlers so Visual Studio initialization succeeds
1034
+ server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => ({ resourceTemplates: [] }));
@@ -81,20 +81,22 @@ export async function setConfigValue(args) {
81
81
  if ((parsed.data.key === 'allowedDirectories' || parsed.data.key === 'blockedCommands') &&
82
82
  !Array.isArray(valueToStore)) {
83
83
  if (typeof valueToStore === 'string') {
84
+ const originalString = valueToStore;
84
85
  try {
85
- valueToStore = JSON.parse(valueToStore);
86
+ const parsedValue = JSON.parse(originalString);
87
+ valueToStore = parsedValue;
86
88
  }
87
89
  catch (parseError) {
88
90
  console.error(`Failed to parse string as array for ${parsed.data.key}: ${parseError}`);
89
91
  // If parsing failed and it's a single value, convert to an array with one item
90
- if (!valueToStore.includes('[')) {
91
- valueToStore = [valueToStore];
92
+ if (!originalString.includes('[')) {
93
+ valueToStore = [originalString];
92
94
  }
93
95
  }
94
96
  }
95
- else {
96
- // If not a string or array, convert to an array with one item
97
- valueToStore = [valueToStore];
97
+ else if (valueToStore !== null) {
98
+ // If not a string or array (and not null), convert to an array with one item
99
+ valueToStore = [String(valueToStore)];
98
100
  }
99
101
  // Ensure the value is an array after all our conversions
100
102
  if (!Array.isArray(valueToStore)) {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ export {};
2
+ // PDF processing is no longer needed - PDFs are handled like images as base64 documents
3
+ // This file is kept for potential future enhancements but currently unused
@@ -1,5 +1,28 @@
1
1
  import { ServerResult } from '../types.js';
2
+ interface Prompt {
3
+ id: string;
4
+ title: string;
5
+ description: string;
6
+ prompt: string;
7
+ categories: string[];
8
+ secondaryTag?: string;
9
+ votes: number;
10
+ gaClicks: number;
11
+ icon: string;
12
+ author: string;
13
+ verified: boolean;
14
+ }
15
+ export interface PromptsData {
16
+ version: string;
17
+ description: string;
18
+ prompts: Prompt[];
19
+ }
20
+ /**
21
+ * Load prompts data from JSON file with caching
22
+ */
23
+ export declare function loadPromptsData(): Promise<PromptsData>;
2
24
  /**
3
25
  * Get prompts - main entry point for the tool
4
26
  */
5
27
  export declare function getPrompts(params: any): Promise<ServerResult>;
28
+ export {};