@gala-chain/launchpad-mcp-server 1.7.3 → 1.7.4

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 (53) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/docs/AI-AGENT-PATTERNS.md +555 -0
  3. package/docs/CONSTRAINTS-REFERENCE.md +454 -0
  4. package/docs/PROMPT-TOOL-MAPPING.md +352 -0
  5. package/docs/examples/default-values-pattern.md +240 -0
  6. package/docs/examples/tool-factory-pattern.md +217 -0
  7. package/jest.config.js +94 -0
  8. package/package.json +2 -2
  9. package/src/__tests__/integration/poolTools.integration.test.ts +185 -0
  10. package/src/constants/mcpToolNames.ts +141 -0
  11. package/src/index.ts +19 -0
  12. package/src/prompts/__tests__/promptStructure.test.ts +114 -0
  13. package/src/prompts/__tests__/registry.test.ts +143 -0
  14. package/src/prompts/analysis.ts +429 -0
  15. package/src/prompts/index.ts +123 -0
  16. package/src/prompts/portfolio.ts +242 -0
  17. package/src/prompts/trading.ts +191 -0
  18. package/src/prompts/utils/workflowTemplates.ts +344 -0
  19. package/src/schemas/common-schemas.ts +392 -0
  20. package/src/scripts/test-all-prompts.ts +184 -0
  21. package/src/server.ts +241 -0
  22. package/src/tools/balance/index.ts +174 -0
  23. package/src/tools/creation/index.ts +182 -0
  24. package/src/tools/index.ts +80 -0
  25. package/src/tools/pools/fetchAllPools.ts +47 -0
  26. package/src/tools/pools/fetchPoolDetails.ts +27 -0
  27. package/src/tools/pools/fetchPoolDetailsForCalculation.ts +22 -0
  28. package/src/tools/pools/fetchPools.ts +47 -0
  29. package/src/tools/pools/index.ts +240 -0
  30. package/src/tools/social/index.ts +64 -0
  31. package/src/tools/trading/index.ts +605 -0
  32. package/src/tools/transfers/index.ts +75 -0
  33. package/src/tools/utils/clearCache.ts +36 -0
  34. package/src/tools/utils/createWallet.ts +19 -0
  35. package/src/tools/utils/explainSdkUsage.ts +765 -0
  36. package/src/tools/utils/getAddress.ts +12 -0
  37. package/src/tools/utils/getCacheInfo.ts +14 -0
  38. package/src/tools/utils/getConfig.ts +11 -0
  39. package/src/tools/utils/getEthereumAddress.ts +12 -0
  40. package/src/tools/utils/getUrlByTokenName.ts +12 -0
  41. package/src/tools/utils/index.ts +25 -0
  42. package/src/tools/utils/isTokenGraduated.ts +16 -0
  43. package/src/types/mcp.ts +72 -0
  44. package/src/utils/__tests__/validation.test.ts +147 -0
  45. package/src/utils/constraints.ts +146 -0
  46. package/src/utils/default-values.ts +208 -0
  47. package/src/utils/error-handler.ts +69 -0
  48. package/src/utils/error-templates.ts +273 -0
  49. package/src/utils/response-formatter.ts +51 -0
  50. package/src/utils/tool-factory.ts +257 -0
  51. package/src/utils/tool-registry.ts +296 -0
  52. package/src/utils/validation.ts +336 -0
  53. package/tsconfig.json +23 -0
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Error Handler Utility
3
+ *
4
+ * Formats errors for MCP protocol responses with AI-friendly tips.
5
+ * Uses centralized error templates from error-templates.ts.
6
+ *
7
+ * @see src/utils/error-templates.ts
8
+ */
9
+
10
+ import type { MCPToolResponse } from '../types/mcp.js';
11
+ import { enhanceErrorMessage } from './error-templates.js';
12
+
13
+ /**
14
+ * Format error for MCP response with AI-friendly tips
15
+ */
16
+ export function formatError(error: unknown): MCPToolResponse {
17
+ const errorMessage = error instanceof Error ? error.message : String(error);
18
+
19
+ // Sanitize sensitive information from error messages
20
+ const sanitized = sanitizeError(errorMessage);
21
+
22
+ // Add AI-friendly tips using centralized templates
23
+ const withTips = enhanceErrorMessage(sanitized);
24
+
25
+ return {
26
+ content: [
27
+ {
28
+ type: 'text',
29
+ text: `Error: ${withTips}`,
30
+ },
31
+ ],
32
+ isError: true,
33
+ };
34
+ }
35
+
36
+ /**
37
+ * Sanitize error messages to remove sensitive information
38
+ */
39
+ function sanitizeError(message: string): string {
40
+ // Remove private keys
41
+ let sanitized = message.replace(/0x[a-fA-F0-9]{64}/g, '0x***');
42
+
43
+ // Remove eth| addresses but keep format visible
44
+ sanitized = sanitized.replace(/(eth\|)[a-fA-F0-9]{40}/g, '$1***');
45
+
46
+ // Remove 0x addresses but keep format visible
47
+ sanitized = sanitized.replace(/(0x)[a-fA-F0-9]{40}/g, '$1***');
48
+
49
+ return sanitized;
50
+ }
51
+
52
+ /**
53
+ * Wrap handler with error handling
54
+ *
55
+ * @template TArgs - Array of argument types
56
+ * @param handler - Handler function to wrap with error handling
57
+ * @returns Wrapped handler with automatic error formatting
58
+ */
59
+ export function withErrorHandling<TArgs extends unknown[]>(
60
+ handler: (...args: TArgs) => Promise<MCPToolResponse>
61
+ ): (...args: TArgs) => Promise<MCPToolResponse> {
62
+ return async (...args: TArgs): Promise<MCPToolResponse> => {
63
+ try {
64
+ return await handler(...args);
65
+ } catch (error) {
66
+ return formatError(error);
67
+ }
68
+ };
69
+ }
@@ -0,0 +1,273 @@
1
+ /**
2
+ * Error Message Templates
3
+ *
4
+ * Centralized error messages with AI-friendly tips for common error patterns.
5
+ * Eliminates duplication and ensures consistent error messaging.
6
+ *
7
+ * @see Phase 3.3 of refactoring plan
8
+ */
9
+
10
+ // =============================================================================
11
+ // Type Definitions
12
+ // =============================================================================
13
+
14
+ /**
15
+ * Error template with AI-friendly tip
16
+ */
17
+ export interface ErrorTemplate {
18
+ pattern: RegExp | string;
19
+ tip: string;
20
+ category: 'validation' | 'timeout' | 'format' | 'business-logic' | 'network';
21
+ }
22
+
23
+ // =============================================================================
24
+ // Validation Error Templates
25
+ // =============================================================================
26
+
27
+ /**
28
+ * Limit validation errors
29
+ */
30
+ export const LIMIT_ERRORS = {
31
+ trade: {
32
+ pattern: /Limit must be.*20/,
33
+ tip: `💡 AI TIP: Trade and user operations have a maximum limit of 20. Use:
34
+ - gala_launchpad_fetch_trades: limit ≤ 20
35
+ - gala_launchpad_fetch_tokens_held: limit ≤ 20
36
+ - gala_launchpad_fetch_tokens_created: limit ≤ 20
37
+
38
+ See docs/CONSTRAINTS-REFERENCE.md for details.`,
39
+ category: 'validation' as const,
40
+ },
41
+ comment: {
42
+ pattern: /Limit must be.*50/,
43
+ tip: `💡 AI TIP: Comment operations have a maximum limit of 50. Use:
44
+ - gala_launchpad_fetch_comments: limit ≤ 50
45
+
46
+ See docs/CONSTRAINTS-REFERENCE.md for details.`,
47
+ category: 'validation' as const,
48
+ },
49
+ pool: {
50
+ pattern: /Limit must be.*100/,
51
+ tip: `💡 AI TIP: Pool operations have a maximum limit of 100. Use:
52
+ - gala_launchpad_fetch_pools: limit ≤ 100
53
+
54
+ See docs/CONSTRAINTS-REFERENCE.md for details.`,
55
+ category: 'validation' as const,
56
+ },
57
+ } as const;
58
+
59
+ /**
60
+ * Token name validation errors
61
+ */
62
+ export const TOKEN_NAME_ERROR: ErrorTemplate = {
63
+ pattern: /token name.*(invalid|validation)/i,
64
+ tip: `💡 AI TIP: Token names must match pattern ^[a-z0-9_-]{2,20}$:
65
+ - Lowercase letters and numbers only
66
+ - Dashes and underscores allowed
67
+ - Length: 2-20 characters
68
+ - Valid examples: 'mytoken', 'test-token', 'token_123'
69
+ - Invalid: 'MyToken' (uppercase), 'a' (too short), 'my token' (space)`,
70
+ category: 'validation',
71
+ };
72
+
73
+ /**
74
+ * Token symbol validation errors
75
+ */
76
+ export const TOKEN_SYMBOL_ERROR: ErrorTemplate = {
77
+ pattern: /token symbol.*(invalid|validation)/i,
78
+ tip: `💡 AI TIP: Token symbols must match pattern ^[A-Z0-9]{2,10}$:
79
+ - Uppercase letters and numbers only
80
+ - No special characters
81
+ - Length: 2-10 characters
82
+ - Valid examples: 'MTK', 'TEST123', 'ABC'
83
+ - Invalid: 'mtk' (lowercase), 'A' (too short), 'MY-TOKEN' (dash)`,
84
+ category: 'validation',
85
+ };
86
+
87
+ /**
88
+ * Wallet address format errors
89
+ */
90
+ export const ADDRESS_FORMAT_ERROR: ErrorTemplate = {
91
+ pattern: /address.*(format|validation)/i,
92
+ tip: `💡 AI TIP: Wallet addresses must use format:
93
+ - Backend API: 'eth|{40-hex-chars}' (e.g., 'eth|abc123...')
94
+ - Convert from standard: address.startsWith('0x') ? \`eth|\${address.slice(2)}\` : address
95
+ - Most MCP tools expect 'eth|...' format`,
96
+ category: 'format',
97
+ };
98
+
99
+ // =============================================================================
100
+ // Trading Error Templates
101
+ // =============================================================================
102
+
103
+ /**
104
+ * WebSocket/trade timeout errors
105
+ */
106
+ export const TRADE_TIMEOUT_ERROR: ErrorTemplate = {
107
+ pattern: /(timeout|WebSocket)/i,
108
+ tip: `💡 AI TIP: Trade execution timeouts often indicate incorrect expectedAmount parameter.
109
+
110
+ ✅ CORRECT WORKFLOW:
111
+ 1. Call calculate_buy_amount() or calculate_sell_amount()
112
+ 2. Extract result.amount from response (e.g., "16843.7579794843252")
113
+ 3. Use result.amount as expectedAmount in buy() or sell()
114
+
115
+ ❌ WRONG: Using your input amount as expectedAmount
116
+ ✅ RIGHT: Using calculated result.amount as expectedAmount
117
+
118
+ See docs/AI-AGENT-PATTERNS.md section "Gotcha #1" for examples.`,
119
+ category: 'timeout',
120
+ };
121
+
122
+ /**
123
+ * Slippage/amount errors
124
+ */
125
+ export const SLIPPAGE_ERROR: ErrorTemplate = {
126
+ pattern: /(slippage|amount.*expected)/i,
127
+ tip: `💡 AI TIP: expectedAmount must be the calculated output from calculate functions, NOT your input amount.
128
+
129
+ Example:
130
+ const calc = await calculateBuyAmount({ amount: '10', type: 'native', ... });
131
+ // calc.amount = "16843.7579794843252" <- Use THIS as expectedAmount
132
+ await buy({ amount: '10', expectedAmount: calc.amount, ... });
133
+
134
+ See docs/AI-AGENT-PATTERNS.md for complete trading workflow.`,
135
+ category: 'business-logic',
136
+ };
137
+
138
+ /**
139
+ * Type parameter confusion
140
+ */
141
+ export const TRADE_TYPE_ERROR: ErrorTemplate = {
142
+ pattern: /type.*(native|token)/i,
143
+ tip: `💡 AI TIP: Trading type parameter:
144
+ - 'native': You specify GALA amount (most common)
145
+ Example: "I want to spend 10 GALA" → type: 'native', amount: '10'
146
+ - 'exact': You specify exact token amount
147
+ Example: "I want to buy exactly 1000 tokens" → type: 'exact', amount: '1000'
148
+
149
+ See docs/AI-AGENT-PATTERNS.md section "Gotcha #3" for details.`,
150
+ category: 'validation',
151
+ };
152
+
153
+ // =============================================================================
154
+ // Token Creation Error Templates
155
+ // =============================================================================
156
+
157
+ /**
158
+ * Social URL requirement errors
159
+ */
160
+ export const SOCIAL_URL_ERROR: ErrorTemplate = {
161
+ pattern: /(social|URL.*required)/i,
162
+ tip: `💡 AI TIP: Token launch requires at least ONE social URL:
163
+ - websiteUrl (e.g., 'https://mytoken.com')
164
+ - twitterUrl (e.g., 'https://twitter.com/mytoken')
165
+ - telegramUrl (e.g., 'https://t.me/mytoken')
166
+
167
+ Provide at least one in launchToken() call.`,
168
+ category: 'validation',
169
+ };
170
+
171
+ // =============================================================================
172
+ // Generic Error Templates
173
+ // =============================================================================
174
+
175
+ /**
176
+ * Generic validation error
177
+ */
178
+ export const GENERIC_VALIDATION_ERROR: ErrorTemplate = {
179
+ pattern: /(validation|invalid)/i,
180
+ tip: `💡 AI TIP: Check parameter formats in docs/AI-AGENT-PATTERNS.md
181
+ Common validation rules:
182
+ - tokenName: ^[a-z0-9_-]{2,20}$ (lowercase, 2-20 chars)
183
+ - tokenSymbol: ^[A-Z0-9]{2,10}$ (uppercase, 2-10 chars)
184
+ - address: 'eth|...' or '0x...' format (auto-normalized)
185
+ - amount: ^[0-9.]+$ (decimal string)
186
+ - limits: See CONSTRAINTS-REFERENCE.md`,
187
+ category: 'validation',
188
+ };
189
+
190
+ // =============================================================================
191
+ // Error Template Registry
192
+ // =============================================================================
193
+
194
+ /**
195
+ * All error templates in priority order (checked sequentially)
196
+ */
197
+ export const ERROR_TEMPLATES: ErrorTemplate[] = [
198
+ // Specific errors first (higher priority)
199
+ LIMIT_ERRORS.trade,
200
+ LIMIT_ERRORS.comment,
201
+ LIMIT_ERRORS.pool,
202
+ TOKEN_NAME_ERROR,
203
+ TOKEN_SYMBOL_ERROR,
204
+ ADDRESS_FORMAT_ERROR,
205
+ TRADE_TIMEOUT_ERROR,
206
+ SLIPPAGE_ERROR,
207
+ TRADE_TYPE_ERROR,
208
+ SOCIAL_URL_ERROR,
209
+
210
+ // Generic errors last (lower priority)
211
+ GENERIC_VALIDATION_ERROR,
212
+ ];
213
+
214
+ // =============================================================================
215
+ // Template Matching Functions
216
+ // =============================================================================
217
+
218
+ /**
219
+ * Finds the best matching error template for a message
220
+ */
221
+ export function findErrorTemplate(message: string): ErrorTemplate | null {
222
+ for (const template of ERROR_TEMPLATES) {
223
+ const pattern = template.pattern;
224
+
225
+ if (typeof pattern === 'string') {
226
+ if (message.includes(pattern)) {
227
+ return template;
228
+ }
229
+ } else if (pattern instanceof RegExp) {
230
+ if (pattern.test(message)) {
231
+ return template;
232
+ }
233
+ }
234
+ }
235
+
236
+ return null;
237
+ }
238
+
239
+ /**
240
+ * Gets the AI-friendly tip for an error message
241
+ */
242
+ export function getErrorTip(message: string): string | null {
243
+ const template = findErrorTemplate(message);
244
+ return template ? template.tip : null;
245
+ }
246
+
247
+ /**
248
+ * Applies AI-friendly tip to error message
249
+ */
250
+ export function enhanceErrorMessage(message: string): string {
251
+ const tip = getErrorTip(message);
252
+ return tip ? `${message}\n\n${tip}` : message;
253
+ }
254
+
255
+ /**
256
+ * Gets error category for an error message
257
+ */
258
+ export function getErrorCategory(message: string): string {
259
+ const template = findErrorTemplate(message);
260
+ return template ? template.category : 'unknown';
261
+ }
262
+
263
+ // =============================================================================
264
+ // Export All
265
+ // =============================================================================
266
+
267
+ export const errorTemplates = {
268
+ templates: ERROR_TEMPLATES,
269
+ findTemplate: findErrorTemplate,
270
+ getTip: getErrorTip,
271
+ enhance: enhanceErrorMessage,
272
+ getCategory: getErrorCategory,
273
+ };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Response Formatter Utility
3
+ *
4
+ * Formats SDK responses for MCP protocol
5
+ */
6
+
7
+ import type { MCPToolResponse } from '../types/mcp.js';
8
+
9
+ /**
10
+ * Format successful response
11
+ */
12
+ export function formatSuccess(data: any): MCPToolResponse {
13
+ return {
14
+ content: [
15
+ {
16
+ type: 'text',
17
+ text: JSON.stringify(data, null, 2),
18
+ },
19
+ ],
20
+ };
21
+ }
22
+
23
+ /**
24
+ * Format boolean response
25
+ */
26
+ export function formatBoolean(result: boolean, message?: string): MCPToolResponse {
27
+ const text = message || `Result: ${result}`;
28
+
29
+ return {
30
+ content: [
31
+ {
32
+ type: 'text',
33
+ text: JSON.stringify({ success: result, message: text }, null, 2),
34
+ },
35
+ ],
36
+ };
37
+ }
38
+
39
+ /**
40
+ * Format simple text response
41
+ */
42
+ export function formatText(text: string): MCPToolResponse {
43
+ return {
44
+ content: [
45
+ {
46
+ type: 'text',
47
+ text,
48
+ },
49
+ ],
50
+ };
51
+ }
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Tool Factory Pattern Utilities
3
+ *
4
+ * DRY utilities for creating MCP tools with common patterns.
5
+ * Eliminates duplication across 47 tool definitions.
6
+ *
7
+ * @see Phase 2.1 of refactoring plan
8
+ */
9
+
10
+ import type { MCPTool } from '../types/mcp.js';
11
+ import type { LaunchpadSDK } from '@gala-chain/launchpad-sdk';
12
+ import { withErrorHandling } from './error-handler.js';
13
+ import { formatSuccess, formatBoolean } from './response-formatter.js';
14
+ import { TOKEN_NAME_SCHEMA } from '../schemas/common-schemas.js';
15
+
16
+ // =============================================================================
17
+ // Type Definitions
18
+ // =============================================================================
19
+
20
+ /**
21
+ * Handler function that takes SDK and args, returns result
22
+ */
23
+ type ToolHandler<T = any> = (sdk: LaunchpadSDK, args: any) => Promise<T>;
24
+
25
+ /**
26
+ * Simple handler that only needs SDK and tokenName
27
+ * Can return the result or null
28
+ */
29
+ type SimpleTokenHandler<T = any> = (sdk: LaunchpadSDK, tokenName: string) => Promise<T | null>;
30
+
31
+ /**
32
+ * Boolean check handler that returns true/false
33
+ */
34
+ type BooleanCheckHandler = (sdk: LaunchpadSDK, value: string) => Promise<boolean>;
35
+
36
+ /**
37
+ * No-parameter handler that only needs SDK, returns result
38
+ */
39
+ type NoParamHandler<T = any> = (sdk: LaunchpadSDK) => T | Promise<T>;
40
+
41
+ // =============================================================================
42
+ // Factory Functions
43
+ // =============================================================================
44
+
45
+ /**
46
+ * Creates a simple fetch tool that takes tokenName and calls an SDK method
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * export const fetchPoolDetailsTool = createSimpleTokenFetchTool({
51
+ * name: 'gala_launchpad_fetch_pool_details',
52
+ * description: 'Get detailed pool state from GalaChain bonding curve',
53
+ * handler: (sdk, tokenName) => sdk.fetchPoolDetails(tokenName),
54
+ * });
55
+ * ```
56
+ */
57
+ export function createSimpleTokenFetchTool(config: {
58
+ name: string;
59
+ description: string;
60
+ handler: SimpleTokenHandler;
61
+ }): MCPTool {
62
+ return {
63
+ name: config.name,
64
+ description: config.description,
65
+ inputSchema: {
66
+ type: 'object',
67
+ properties: {
68
+ tokenName: TOKEN_NAME_SCHEMA,
69
+ },
70
+ required: ['tokenName'],
71
+ },
72
+ handler: withErrorHandling(async (sdk, args) => {
73
+ const result = await config.handler(sdk, args.tokenName);
74
+ return formatSuccess(result);
75
+ }),
76
+ };
77
+ }
78
+
79
+ /**
80
+ * Creates a boolean check tool (e.g., isTokenNameAvailable, isTokenSymbolAvailable)
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * export const checkTokenNameTool = createBooleanCheckTool({
85
+ * name: 'gala_launchpad_check_token_name',
86
+ * description: 'Check if token name is available',
87
+ * paramName: 'tokenName',
88
+ * paramSchema: TOKEN_NAME_SCHEMA,
89
+ * handler: (sdk, tokenName) => sdk.isTokenNameAvailable(tokenName),
90
+ * messages: {
91
+ * true: 'Token name is available',
92
+ * false: 'Token name is already taken',
93
+ * },
94
+ * });
95
+ * ```
96
+ */
97
+ export function createBooleanCheckTool(config: {
98
+ name: string;
99
+ description: string;
100
+ paramName: string;
101
+ paramSchema: any;
102
+ handler: BooleanCheckHandler;
103
+ messages: {
104
+ true: string;
105
+ false: string;
106
+ };
107
+ }): MCPTool {
108
+ return {
109
+ name: config.name,
110
+ description: config.description,
111
+ inputSchema: {
112
+ type: 'object',
113
+ properties: {
114
+ [config.paramName]: config.paramSchema,
115
+ },
116
+ required: [config.paramName],
117
+ },
118
+ handler: withErrorHandling(async (sdk, args) => {
119
+ const value = args[config.paramName];
120
+ const available = await config.handler(sdk, value);
121
+ return formatBoolean(
122
+ available,
123
+ available ? config.messages.true : config.messages.false
124
+ );
125
+ }),
126
+ };
127
+ }
128
+
129
+ /**
130
+ * Creates a generic fetch tool with custom input schema and handler
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * export const fetchPoolsTool = createFetchTool({
135
+ * name: 'gala_launchpad_fetch_pools',
136
+ * description: 'Fetch token pools from Gala Launchpad',
137
+ * inputSchema: {
138
+ * type: 'object',
139
+ * properties: {
140
+ * type: { type: 'string', enum: ['recent', 'popular'] },
141
+ * page: PAGE_SCHEMA,
142
+ * limit: createLimitSchema('pool', 20),
143
+ * },
144
+ * },
145
+ * handler: (sdk, args) => sdk.fetchPools({
146
+ * type: args.type || 'recent',
147
+ * page: args.page || 1,
148
+ * limit: args.limit || 20,
149
+ * }),
150
+ * });
151
+ * ```
152
+ */
153
+ export function createFetchTool(config: {
154
+ name: string;
155
+ description: string;
156
+ inputSchema: {
157
+ type: 'object';
158
+ properties: Record<string, any>;
159
+ required?: string[];
160
+ };
161
+ handler: ToolHandler;
162
+ }): MCPTool {
163
+ return {
164
+ name: config.name,
165
+ description: config.description,
166
+ inputSchema: config.inputSchema,
167
+ handler: withErrorHandling(async (sdk, args) => {
168
+ const result = await config.handler(sdk, args);
169
+ return formatSuccess(result);
170
+ }),
171
+ };
172
+ }
173
+
174
+ /**
175
+ * Creates a resolution tool that maps tokenName to some resolved value
176
+ *
177
+ * @example
178
+ * ```typescript
179
+ * export const resolveVaultAddressTool = createResolutionTool({
180
+ * name: 'gala_launchpad_resolve_vault_address',
181
+ * description: 'Get GalaChain vault address for a token',
182
+ * resolver: (sdk, tokenName) => sdk.resolveVaultAddress(tokenName),
183
+ * resultKey: 'vaultAddress',
184
+ * });
185
+ * ```
186
+ */
187
+ export function createResolutionTool(config: {
188
+ name: string;
189
+ description: string;
190
+ resolver: SimpleTokenHandler<string | any>;
191
+ resultKey: string;
192
+ }): MCPTool {
193
+ return {
194
+ name: config.name,
195
+ description: config.description,
196
+ inputSchema: {
197
+ type: 'object',
198
+ properties: {
199
+ tokenName: TOKEN_NAME_SCHEMA,
200
+ },
201
+ required: ['tokenName'],
202
+ },
203
+ handler: withErrorHandling(async (sdk, args) => {
204
+ const resolvedValue = await config.resolver(sdk, args.tokenName);
205
+ return formatSuccess({
206
+ tokenName: args.tokenName,
207
+ [config.resultKey]: resolvedValue,
208
+ });
209
+ }),
210
+ };
211
+ }
212
+
213
+ /**
214
+ * Creates a no-parameter tool that only needs SDK instance
215
+ *
216
+ * @example
217
+ * ```typescript
218
+ * export const getAddressTool = createNoParamTool({
219
+ * name: 'gala_launchpad_get_address',
220
+ * description: 'Get the GalaChain address format (eth|0x...) for the authenticated wallet.',
221
+ * handler: (sdk) => sdk.getAddress(),
222
+ * resultKey: 'address',
223
+ * });
224
+ * ```
225
+ */
226
+ export function createNoParamTool(config: {
227
+ name: string;
228
+ description: string;
229
+ handler: NoParamHandler;
230
+ resultKey?: string;
231
+ }): MCPTool {
232
+ return {
233
+ name: config.name,
234
+ description: config.description,
235
+ inputSchema: {
236
+ type: 'object',
237
+ properties: {},
238
+ },
239
+ handler: withErrorHandling(async (sdk) => {
240
+ const result = await config.handler(sdk);
241
+ // If resultKey provided, wrap in object; otherwise return result directly
242
+ return formatSuccess(config.resultKey ? { [config.resultKey]: result } : result);
243
+ }),
244
+ };
245
+ }
246
+
247
+ // =============================================================================
248
+ // Exports
249
+ // =============================================================================
250
+
251
+ export const toolFactory = {
252
+ createSimpleTokenFetchTool,
253
+ createBooleanCheckTool,
254
+ createFetchTool,
255
+ createResolutionTool,
256
+ createNoParamTool,
257
+ };