@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.
- package/CHANGELOG.md +24 -0
- package/docs/AI-AGENT-PATTERNS.md +555 -0
- package/docs/CONSTRAINTS-REFERENCE.md +454 -0
- package/docs/PROMPT-TOOL-MAPPING.md +352 -0
- package/docs/examples/default-values-pattern.md +240 -0
- package/docs/examples/tool-factory-pattern.md +217 -0
- package/jest.config.js +94 -0
- package/package.json +2 -2
- package/src/__tests__/integration/poolTools.integration.test.ts +185 -0
- package/src/constants/mcpToolNames.ts +141 -0
- package/src/index.ts +19 -0
- package/src/prompts/__tests__/promptStructure.test.ts +114 -0
- package/src/prompts/__tests__/registry.test.ts +143 -0
- package/src/prompts/analysis.ts +429 -0
- package/src/prompts/index.ts +123 -0
- package/src/prompts/portfolio.ts +242 -0
- package/src/prompts/trading.ts +191 -0
- package/src/prompts/utils/workflowTemplates.ts +344 -0
- package/src/schemas/common-schemas.ts +392 -0
- package/src/scripts/test-all-prompts.ts +184 -0
- package/src/server.ts +241 -0
- package/src/tools/balance/index.ts +174 -0
- package/src/tools/creation/index.ts +182 -0
- package/src/tools/index.ts +80 -0
- package/src/tools/pools/fetchAllPools.ts +47 -0
- package/src/tools/pools/fetchPoolDetails.ts +27 -0
- package/src/tools/pools/fetchPoolDetailsForCalculation.ts +22 -0
- package/src/tools/pools/fetchPools.ts +47 -0
- package/src/tools/pools/index.ts +240 -0
- package/src/tools/social/index.ts +64 -0
- package/src/tools/trading/index.ts +605 -0
- package/src/tools/transfers/index.ts +75 -0
- package/src/tools/utils/clearCache.ts +36 -0
- package/src/tools/utils/createWallet.ts +19 -0
- package/src/tools/utils/explainSdkUsage.ts +765 -0
- package/src/tools/utils/getAddress.ts +12 -0
- package/src/tools/utils/getCacheInfo.ts +14 -0
- package/src/tools/utils/getConfig.ts +11 -0
- package/src/tools/utils/getEthereumAddress.ts +12 -0
- package/src/tools/utils/getUrlByTokenName.ts +12 -0
- package/src/tools/utils/index.ts +25 -0
- package/src/tools/utils/isTokenGraduated.ts +16 -0
- package/src/types/mcp.ts +72 -0
- package/src/utils/__tests__/validation.test.ts +147 -0
- package/src/utils/constraints.ts +146 -0
- package/src/utils/default-values.ts +208 -0
- package/src/utils/error-handler.ts +69 -0
- package/src/utils/error-templates.ts +273 -0
- package/src/utils/response-formatter.ts +51 -0
- package/src/utils/tool-factory.ts +257 -0
- package/src/utils/tool-registry.ts +296 -0
- package/src/utils/validation.ts +336 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get Address Tool (45% code reduction via factory pattern)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createNoParamTool } from '../../utils/tool-factory.js';
|
|
6
|
+
|
|
7
|
+
export const getAddressTool = createNoParamTool({
|
|
8
|
+
name: 'gala_launchpad_get_address',
|
|
9
|
+
description: 'Get the GalaChain address format (eth|0x...) for the authenticated wallet.',
|
|
10
|
+
handler: (sdk) => sdk.getAddress(),
|
|
11
|
+
resultKey: 'address',
|
|
12
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get Cache Info Tool
|
|
3
|
+
*
|
|
4
|
+
* Returns statistics about the token metadata cache for monitoring and debugging.
|
|
5
|
+
* The cache persists entire MCP server lifetime and accumulates metadata across conversations.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createNoParamTool } from '../../utils/tool-factory.js';
|
|
9
|
+
|
|
10
|
+
export const getCacheInfoTool = createNoParamTool({
|
|
11
|
+
name: 'gala_launchpad_get_cache_info',
|
|
12
|
+
description: 'Get token metadata cache statistics including total tokens cached, cache size in bytes, and timestamp of oldest entry. The cache persists for the entire MCP server lifetime.',
|
|
13
|
+
handler: (sdk) => sdk.getCacheInfo(),
|
|
14
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get Config Tool (45% code reduction via factory pattern)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createNoParamTool } from '../../utils/tool-factory.js';
|
|
6
|
+
|
|
7
|
+
export const getConfigTool = createNoParamTool({
|
|
8
|
+
name: 'gala_launchpad_get_config',
|
|
9
|
+
description: 'Get the current SDK configuration including environment, base URLs, timeouts, feature flags, and effective slippage tolerance factors.',
|
|
10
|
+
handler: (sdk) => sdk.getConfig(),
|
|
11
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get Ethereum Address Tool (45% code reduction via factory pattern)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createNoParamTool } from '../../utils/tool-factory.js';
|
|
6
|
+
|
|
7
|
+
export const getEthereumAddressTool = createNoParamTool({
|
|
8
|
+
name: 'gala_launchpad_get_ethereum_address',
|
|
9
|
+
description: 'Get the standard Ethereum address format (0x...) for the authenticated wallet.',
|
|
10
|
+
handler: (sdk) => sdk.getEthereumAddress(),
|
|
11
|
+
resultKey: 'address',
|
|
12
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get URL by Token Name Tool (73% code reduction via factory pattern)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createResolutionTool } from '../../utils/tool-factory.js';
|
|
6
|
+
|
|
7
|
+
export const getUrlByTokenNameTool = createResolutionTool({
|
|
8
|
+
name: 'gala_launchpad_get_url_by_token_name',
|
|
9
|
+
description: 'Get the launchpad frontend URL for a specific token. Returns the complete URL for viewing/trading the token in the web interface.',
|
|
10
|
+
resolver: async (sdk, tokenName) => sdk.getUrlByTokenName(tokenName),
|
|
11
|
+
resultKey: 'url',
|
|
12
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility Tools
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createWalletTool } from './createWallet.js';
|
|
6
|
+
import { getAddressTool } from './getAddress.js';
|
|
7
|
+
import { getEthereumAddressTool } from './getEthereumAddress.js';
|
|
8
|
+
import { getConfigTool } from './getConfig.js';
|
|
9
|
+
import { getUrlByTokenNameTool } from './getUrlByTokenName.js';
|
|
10
|
+
import { explainSdkUsageTool } from './explainSdkUsage.js';
|
|
11
|
+
import { isTokenGraduatedTool } from './isTokenGraduated.js';
|
|
12
|
+
import { getCacheInfoTool } from './getCacheInfo.js';
|
|
13
|
+
import { clearCacheTool } from './clearCache.js';
|
|
14
|
+
|
|
15
|
+
export const utilityTools = [
|
|
16
|
+
createWalletTool,
|
|
17
|
+
getAddressTool,
|
|
18
|
+
getEthereumAddressTool,
|
|
19
|
+
getConfigTool,
|
|
20
|
+
getUrlByTokenNameTool,
|
|
21
|
+
explainSdkUsageTool,
|
|
22
|
+
isTokenGraduatedTool,
|
|
23
|
+
getCacheInfoTool,
|
|
24
|
+
clearCacheTool,
|
|
25
|
+
];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if token has graduated from bonding curve (73% code reduction via factory pattern)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createResolutionTool } from '../../utils/tool-factory.js';
|
|
6
|
+
|
|
7
|
+
export const isTokenGraduatedTool = createResolutionTool({
|
|
8
|
+
name: 'gala_launchpad_is_token_graduated',
|
|
9
|
+
description: `Check if a token has completed the bonding curve phase and graduated to full DEX trading.
|
|
10
|
+
|
|
11
|
+
RETURNS: Boolean indicating if pool saleStatus is "Completed"
|
|
12
|
+
|
|
13
|
+
USAGE: Useful for conditional logic before attempting graduation or checking pool state.`,
|
|
14
|
+
resolver: (sdk, tokenName) => sdk.isTokenGraduated(tokenName),
|
|
15
|
+
resultKey: 'graduated',
|
|
16
|
+
});
|
package/src/types/mcp.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Protocol Types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { LaunchpadSDK } from '@gala-chain/launchpad-sdk';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* MCP Tool Definition
|
|
9
|
+
*/
|
|
10
|
+
export interface MCPTool {
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
inputSchema: {
|
|
14
|
+
type: 'object';
|
|
15
|
+
properties: Record<string, any>;
|
|
16
|
+
required?: string[];
|
|
17
|
+
};
|
|
18
|
+
handler: (sdk: LaunchpadSDK, args: any) => Promise<MCPToolResponse>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* MCP Tool Response
|
|
23
|
+
*/
|
|
24
|
+
export interface MCPToolResponse {
|
|
25
|
+
content: Array<{
|
|
26
|
+
type: 'text' | 'image' | 'resource';
|
|
27
|
+
text?: string;
|
|
28
|
+
data?: string;
|
|
29
|
+
mimeType?: string;
|
|
30
|
+
}>;
|
|
31
|
+
isError?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Tool execution context
|
|
36
|
+
*/
|
|
37
|
+
export interface ToolContext {
|
|
38
|
+
sdk: LaunchpadSDK;
|
|
39
|
+
debug: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* MCP Prompt Argument Definition
|
|
44
|
+
*/
|
|
45
|
+
export interface MCPPromptArgument {
|
|
46
|
+
name: string;
|
|
47
|
+
description: string;
|
|
48
|
+
required: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* MCP Prompt Definition
|
|
53
|
+
*/
|
|
54
|
+
export interface MCPPrompt {
|
|
55
|
+
name: string;
|
|
56
|
+
description: string;
|
|
57
|
+
arguments?: MCPPromptArgument[];
|
|
58
|
+
handler: (args: Record<string, string>) => PromptMessage[];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Prompt Message (from MCP spec)
|
|
63
|
+
*/
|
|
64
|
+
export interface PromptMessage {
|
|
65
|
+
role: 'user' | 'assistant';
|
|
66
|
+
content: {
|
|
67
|
+
type: 'text' | 'image' | 'resource';
|
|
68
|
+
text?: string;
|
|
69
|
+
data?: string;
|
|
70
|
+
mimeType?: string;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation Utilities Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for input validation functions
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
validateTokenName,
|
|
9
|
+
validateNumericAmount,
|
|
10
|
+
validateSlippage,
|
|
11
|
+
validateAddress,
|
|
12
|
+
validateTokenSymbol,
|
|
13
|
+
validatePaginationLimit,
|
|
14
|
+
validateTokenList,
|
|
15
|
+
safeValidate,
|
|
16
|
+
ValidationError,
|
|
17
|
+
} from '../validation';
|
|
18
|
+
|
|
19
|
+
describe('Validation Utilities', () => {
|
|
20
|
+
describe('validateTokenName()', () => {
|
|
21
|
+
it('should accept valid token names', () => {
|
|
22
|
+
expect(() => validateTokenName('anime')).not.toThrow();
|
|
23
|
+
expect(() => validateTokenName('test123')).not.toThrow();
|
|
24
|
+
expect(() => validateTokenName('my-token')).not.toThrow();
|
|
25
|
+
expect(() => validateTokenName('my_token')).not.toThrow();
|
|
26
|
+
expect(() => validateTokenName('TEST-123')).not.toThrow();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should reject invalid token names', () => {
|
|
30
|
+
expect(() => validateTokenName('')).toThrow(ValidationError);
|
|
31
|
+
expect(() => validateTokenName('a')).toThrow(ValidationError);
|
|
32
|
+
expect(() => validateTokenName('verylongtokennamethatexceedstwentycharacters')).toThrow(ValidationError);
|
|
33
|
+
expect(() => validateTokenName('token@#$')).toThrow(ValidationError);
|
|
34
|
+
expect(() => validateTokenName('token with spaces')).toThrow(ValidationError);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('validateNumericAmount()', () => {
|
|
39
|
+
it('should accept valid numeric amounts', () => {
|
|
40
|
+
expect(() => validateNumericAmount('100', 'amount')).not.toThrow();
|
|
41
|
+
expect(() => validateNumericAmount('0.5', 'amount')).not.toThrow();
|
|
42
|
+
expect(() => validateNumericAmount('99999.99', 'amount')).not.toThrow();
|
|
43
|
+
expect(() => validateNumericAmount(100, 'amount')).not.toThrow();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should reject invalid numeric amounts', () => {
|
|
47
|
+
expect(() => validateNumericAmount('', 'amount')).toThrow(ValidationError);
|
|
48
|
+
expect(() => validateNumericAmount('abc', 'amount')).toThrow(ValidationError);
|
|
49
|
+
expect(() => validateNumericAmount('-5', 'amount')).toThrow(ValidationError);
|
|
50
|
+
expect(() => validateNumericAmount('0', 'amount')).toThrow(ValidationError);
|
|
51
|
+
expect(() => validateNumericAmount(Infinity, 'amount')).toThrow(ValidationError);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('validateSlippage()', () => {
|
|
56
|
+
it('should accept valid slippage values', () => {
|
|
57
|
+
expect(() => validateSlippage('1')).not.toThrow();
|
|
58
|
+
expect(() => validateSlippage('0.5')).not.toThrow();
|
|
59
|
+
expect(() => validateSlippage('50')).not.toThrow();
|
|
60
|
+
expect(() => validateSlippage('0.01')).not.toThrow();
|
|
61
|
+
expect(() => validateSlippage('100')).not.toThrow();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should reject invalid slippage values', () => {
|
|
65
|
+
expect(() => validateSlippage('0')).toThrow(ValidationError);
|
|
66
|
+
expect(() => validateSlippage('0.005')).toThrow(ValidationError);
|
|
67
|
+
expect(() => validateSlippage('101')).toThrow(ValidationError);
|
|
68
|
+
expect(() => validateSlippage('-1')).toThrow(ValidationError);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('validateAddress()', () => {
|
|
73
|
+
it('should accept valid addresses', () => {
|
|
74
|
+
expect(() => validateAddress('eth|0x1234567890abcdef1234567890abcdef12345678')).not.toThrow();
|
|
75
|
+
expect(() => validateAddress('0x1234567890abcdef1234567890abcdef12345678')).not.toThrow();
|
|
76
|
+
expect(() => validateAddress('0xABCDEF1234567890abcdef1234567890ABCDEF12')).not.toThrow();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should reject invalid addresses', () => {
|
|
80
|
+
expect(() => validateAddress('')).toThrow(ValidationError);
|
|
81
|
+
expect(() => validateAddress('invalid')).toThrow(ValidationError);
|
|
82
|
+
expect(() => validateAddress('0x123')).toThrow(ValidationError);
|
|
83
|
+
expect(() => validateAddress('eth|123')).toThrow(ValidationError);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('validateTokenSymbol()', () => {
|
|
88
|
+
it('should accept valid symbols', () => {
|
|
89
|
+
expect(() => validateTokenSymbol('GALA')).not.toThrow();
|
|
90
|
+
expect(() => validateTokenSymbol('TEST')).not.toThrow();
|
|
91
|
+
expect(() => validateTokenSymbol('A')).not.toThrow();
|
|
92
|
+
expect(() => validateTokenSymbol('ABCDEFGH')).not.toThrow();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should reject invalid symbols', () => {
|
|
96
|
+
expect(() => validateTokenSymbol('')).toThrow(ValidationError);
|
|
97
|
+
expect(() => validateTokenSymbol('test')).toThrow(ValidationError);
|
|
98
|
+
expect(() => validateTokenSymbol('TOOLONG123')).toThrow(ValidationError);
|
|
99
|
+
expect(() => validateTokenSymbol('TEST123')).toThrow(ValidationError);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('validatePaginationLimit()', () => {
|
|
104
|
+
it('should accept valid limits', () => {
|
|
105
|
+
expect(() => validatePaginationLimit('1')).not.toThrow();
|
|
106
|
+
expect(() => validatePaginationLimit('20')).not.toThrow();
|
|
107
|
+
expect(() => validatePaginationLimit('100')).not.toThrow();
|
|
108
|
+
expect(() => validatePaginationLimit(50)).not.toThrow();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should reject invalid limits', () => {
|
|
112
|
+
expect(() => validatePaginationLimit('0')).toThrow(ValidationError);
|
|
113
|
+
expect(() => validatePaginationLimit('101')).toThrow(ValidationError);
|
|
114
|
+
expect(() => validatePaginationLimit('-1')).toThrow(ValidationError);
|
|
115
|
+
expect(() => validatePaginationLimit('abc')).toThrow(ValidationError);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('validateTokenList()', () => {
|
|
120
|
+
it('should accept valid token lists', () => {
|
|
121
|
+
const result1 = validateTokenList('anime,test,dragon');
|
|
122
|
+
expect(result1).toEqual(['anime', 'test', 'dragon']);
|
|
123
|
+
|
|
124
|
+
const result2 = validateTokenList('token1');
|
|
125
|
+
expect(result2).toEqual(['token1']);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should reject invalid token lists', () => {
|
|
129
|
+
expect(() => validateTokenList('')).toThrow(ValidationError);
|
|
130
|
+
expect(() => validateTokenList('token1,invalid@#$')).toThrow(ValidationError);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe('safeValidate()', () => {
|
|
135
|
+
it('should return success for valid input', () => {
|
|
136
|
+
const result = safeValidate(() => validateTokenName('anime'));
|
|
137
|
+
expect(result.success).toBe(true);
|
|
138
|
+
expect(result.error).toBeUndefined();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should return error for invalid input', () => {
|
|
142
|
+
const result = safeValidate(() => validateTokenName('invalid@#$'));
|
|
143
|
+
expect(result.success).toBe(false);
|
|
144
|
+
expect(result.error).toBeDefined();
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
});
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Central Constraints Reference
|
|
3
|
+
*
|
|
4
|
+
* This file documents the pagination limits enforced by the SDK for different operations.
|
|
5
|
+
* These constants are imported from the SDK's internal constraint definitions and serve
|
|
6
|
+
* as the single source of truth for MCP tool schema validation.
|
|
7
|
+
*
|
|
8
|
+
* IMPORTANT: Always keep these in sync with the SDK's actual constraints:
|
|
9
|
+
* - TRADE_CONSTRAINTS.PAGINATION.MAX_LIMIT (trade.dto.ts)
|
|
10
|
+
* - USER_CONSTRAINTS.PAGINATION.MAX_LIMIT (user.dto.ts)
|
|
11
|
+
* - PAGINATION_CONSTRAINTS.MAX_LIMIT (launchpad.dto.ts)
|
|
12
|
+
* - COMMENT_CONSTRAINTS.PAGINATION.MAX_LIMIT (comment.dto.ts)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* MCP Tool Constraint Constants
|
|
17
|
+
*
|
|
18
|
+
* These values MUST match the SDK's internal constraint definitions to prevent
|
|
19
|
+
* validation errors when AI agents use the MCP tools.
|
|
20
|
+
*/
|
|
21
|
+
export const MCP_CONSTRAINTS = {
|
|
22
|
+
/**
|
|
23
|
+
* Trade operations limit (fetchTrades)
|
|
24
|
+
* Source: TRADE_CONSTRAINTS.PAGINATION.MAX_LIMIT
|
|
25
|
+
* SDK File: packages/sdk/src/types/trade.dto.ts:331
|
|
26
|
+
*/
|
|
27
|
+
TRADE_LIMIT: 20,
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* User operations limit (fetchTokensHeld, fetchTokensCreated)
|
|
31
|
+
* Source: USER_CONSTRAINTS.PAGINATION.MAX_LIMIT
|
|
32
|
+
* SDK File: packages/sdk/src/types/user.dto.ts:297
|
|
33
|
+
*/
|
|
34
|
+
USER_LIMIT: 20,
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* General pool operations limit (fetchPools)
|
|
38
|
+
* Source: PAGINATION_CONSTRAINTS.MAX_LIMIT
|
|
39
|
+
* SDK File: packages/sdk/src/types/launchpad.dto.ts:587
|
|
40
|
+
*/
|
|
41
|
+
POOL_LIMIT: 100,
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Comment operations limit (fetchComments)
|
|
45
|
+
* Source: COMMENT_CONSTRAINTS.PAGINATION.MAX_LIMIT
|
|
46
|
+
* SDK File: packages/sdk/src/types/comment.dto.ts:149
|
|
47
|
+
*/
|
|
48
|
+
COMMENT_LIMIT: 50,
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Minimum limit for all pagination operations
|
|
52
|
+
*/
|
|
53
|
+
MIN_LIMIT: 1,
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Minimum page number for all pagination operations
|
|
57
|
+
*/
|
|
58
|
+
MIN_PAGE: 1,
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Maximum page number for all pagination operations
|
|
62
|
+
*/
|
|
63
|
+
MAX_PAGE: 1000,
|
|
64
|
+
} as const;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Constraint usage reference for MCP tool developers
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* // Trading tools (fetchTrades)
|
|
71
|
+
* limit: {
|
|
72
|
+
* type: 'number',
|
|
73
|
+
* minimum: MCP_CONSTRAINTS.MIN_LIMIT,
|
|
74
|
+
* maximum: MCP_CONSTRAINTS.TRADE_LIMIT, // 20
|
|
75
|
+
* description: `Results per page (default: 20, maximum: ${MCP_CONSTRAINTS.TRADE_LIMIT})`
|
|
76
|
+
* }
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* // Balance/User tools (fetchTokensHeld, fetchTokensCreated)
|
|
80
|
+
* limit: {
|
|
81
|
+
* type: 'number',
|
|
82
|
+
* minimum: MCP_CONSTRAINTS.MIN_LIMIT,
|
|
83
|
+
* maximum: MCP_CONSTRAINTS.USER_LIMIT, // 20
|
|
84
|
+
* description: `Results per page (default: 20, maximum: ${MCP_CONSTRAINTS.USER_LIMIT})`
|
|
85
|
+
* }
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* // Pool tools (fetchPools)
|
|
89
|
+
* limit: {
|
|
90
|
+
* type: 'number',
|
|
91
|
+
* minimum: MCP_CONSTRAINTS.MIN_LIMIT,
|
|
92
|
+
* maximum: MCP_CONSTRAINTS.POOL_LIMIT, // 100
|
|
93
|
+
* description: `Results per page (default: 20, maximum: ${MCP_CONSTRAINTS.POOL_LIMIT})`
|
|
94
|
+
* }
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* // Social tools (fetchComments)
|
|
98
|
+
* limit: {
|
|
99
|
+
* type: 'number',
|
|
100
|
+
* minimum: MCP_CONSTRAINTS.MIN_LIMIT,
|
|
101
|
+
* maximum: MCP_CONSTRAINTS.COMMENT_LIMIT, // 50
|
|
102
|
+
* description: `Results per page (default: 20, maximum: ${MCP_CONSTRAINTS.COMMENT_LIMIT})`
|
|
103
|
+
* }
|
|
104
|
+
*/
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Validation helper to check if a limit value is valid for a specific operation type
|
|
108
|
+
*
|
|
109
|
+
* @param limit The limit value to validate
|
|
110
|
+
* @param operationType The type of operation ('trade' | 'user' | 'pool' | 'comment')
|
|
111
|
+
* @returns true if valid, false otherwise
|
|
112
|
+
*/
|
|
113
|
+
export function isValidLimit(
|
|
114
|
+
limit: number,
|
|
115
|
+
operationType: 'trade' | 'user' | 'pool' | 'comment'
|
|
116
|
+
): boolean {
|
|
117
|
+
if (!Number.isInteger(limit) || limit < MCP_CONSTRAINTS.MIN_LIMIT) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const maxLimits = {
|
|
122
|
+
trade: MCP_CONSTRAINTS.TRADE_LIMIT,
|
|
123
|
+
user: MCP_CONSTRAINTS.USER_LIMIT,
|
|
124
|
+
pool: MCP_CONSTRAINTS.POOL_LIMIT,
|
|
125
|
+
comment: MCP_CONSTRAINTS.COMMENT_LIMIT,
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
return limit <= maxLimits[operationType];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get the maximum limit for a specific operation type
|
|
133
|
+
*
|
|
134
|
+
* @param operationType The type of operation
|
|
135
|
+
* @returns The maximum limit value
|
|
136
|
+
*/
|
|
137
|
+
export function getMaxLimit(operationType: 'trade' | 'user' | 'pool' | 'comment'): number {
|
|
138
|
+
const maxLimits = {
|
|
139
|
+
trade: MCP_CONSTRAINTS.TRADE_LIMIT,
|
|
140
|
+
user: MCP_CONSTRAINTS.USER_LIMIT,
|
|
141
|
+
pool: MCP_CONSTRAINTS.POOL_LIMIT,
|
|
142
|
+
comment: MCP_CONSTRAINTS.COMMENT_LIMIT,
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
return maxLimits[operationType];
|
|
146
|
+
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default Value Utilities
|
|
3
|
+
*
|
|
4
|
+
* Centralized default values for tool parameters to eliminate magic numbers
|
|
5
|
+
* and ensure consistency across 47 MCP tools.
|
|
6
|
+
*
|
|
7
|
+
* @see Phase 2.2 of refactoring plan
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { MCP_CONSTRAINTS } from './constraints.js';
|
|
11
|
+
|
|
12
|
+
// =============================================================================
|
|
13
|
+
// Pagination Defaults
|
|
14
|
+
// =============================================================================
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Default pagination configuration
|
|
18
|
+
*/
|
|
19
|
+
export const DEFAULT_PAGINATION = {
|
|
20
|
+
page: 1,
|
|
21
|
+
limit: 20,
|
|
22
|
+
} as const;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Operation-specific default limits
|
|
26
|
+
*/
|
|
27
|
+
export const DEFAULT_LIMITS = {
|
|
28
|
+
trade: 20,
|
|
29
|
+
user: 20,
|
|
30
|
+
pool: 20,
|
|
31
|
+
comment: 20,
|
|
32
|
+
} as const;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Maximum limits per operation type (from MCP_CONSTRAINTS)
|
|
36
|
+
*/
|
|
37
|
+
export const MAX_LIMITS = {
|
|
38
|
+
trade: MCP_CONSTRAINTS.TRADE_LIMIT, // 20
|
|
39
|
+
user: MCP_CONSTRAINTS.USER_LIMIT, // 20
|
|
40
|
+
pool: MCP_CONSTRAINTS.POOL_LIMIT, // 100
|
|
41
|
+
comment: MCP_CONSTRAINTS.COMMENT_LIMIT, // 50
|
|
42
|
+
} as const;
|
|
43
|
+
|
|
44
|
+
// =============================================================================
|
|
45
|
+
// Trading Defaults
|
|
46
|
+
// =============================================================================
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Default slippage tolerance (1%)
|
|
50
|
+
*/
|
|
51
|
+
export const DEFAULT_SLIPPAGE_TOLERANCE = 0.01;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Default reverse bonding curve fee slippage tolerance (1%)
|
|
55
|
+
*/
|
|
56
|
+
export const DEFAULT_RBC_FEE_SLIPPAGE = 0.01;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Default pool type for fetchPools
|
|
60
|
+
*/
|
|
61
|
+
export const DEFAULT_POOL_TYPE = 'recent';
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Default sort order
|
|
65
|
+
*/
|
|
66
|
+
export const DEFAULT_SORT_ORDER = 'DESC';
|
|
67
|
+
|
|
68
|
+
// =============================================================================
|
|
69
|
+
// Volume Data Defaults
|
|
70
|
+
// =============================================================================
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Default resolution for volume data (1 hour)
|
|
74
|
+
*/
|
|
75
|
+
export const DEFAULT_VOLUME_RESOLUTION = '1h';
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Resolution mapping (string to seconds)
|
|
79
|
+
*/
|
|
80
|
+
export const RESOLUTION_MAP: Record<string, number> = {
|
|
81
|
+
'1m': 60,
|
|
82
|
+
'5m': 300,
|
|
83
|
+
'15m': 900,
|
|
84
|
+
'1h': 3600,
|
|
85
|
+
'4h': 14400,
|
|
86
|
+
'1d': 86400,
|
|
87
|
+
} as const;
|
|
88
|
+
|
|
89
|
+
// =============================================================================
|
|
90
|
+
// Utility Functions
|
|
91
|
+
// =============================================================================
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Applies default pagination values to args object
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* const params = applyPaginationDefaults(args);
|
|
99
|
+
* // { page: 1, limit: 20, ...otherArgs }
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export function applyPaginationDefaults<T extends Record<string, any>>(
|
|
103
|
+
args: T,
|
|
104
|
+
defaults: { page?: number; limit?: number } = DEFAULT_PAGINATION
|
|
105
|
+
): T & { page: number; limit: number } {
|
|
106
|
+
return {
|
|
107
|
+
...args,
|
|
108
|
+
page: args.page ?? defaults.page ?? DEFAULT_PAGINATION.page,
|
|
109
|
+
limit: args.limit ?? defaults.limit ?? DEFAULT_PAGINATION.limit,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Applies operation-specific pagination defaults
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* const params = applyOperationPaginationDefaults(args, 'pool');
|
|
119
|
+
* // Uses default limit of 20 for pool operations
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export function applyOperationPaginationDefaults<T extends Record<string, any>>(
|
|
123
|
+
args: T,
|
|
124
|
+
operationType: keyof typeof DEFAULT_LIMITS
|
|
125
|
+
): T & { page: number; limit: number } {
|
|
126
|
+
return applyPaginationDefaults(args, {
|
|
127
|
+
page: DEFAULT_PAGINATION.page,
|
|
128
|
+
limit: DEFAULT_LIMITS[operationType],
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Applies default slippage values to trading args
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* const params = applySlippageDefaults(args);
|
|
138
|
+
* // { slippageToleranceFactor: 0.01, maxAcceptableReverseBondingCurveFeeSlippageFactor: 0.01, ...args }
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export function applySlippageDefaults<T extends Record<string, any>>(
|
|
142
|
+
args: T,
|
|
143
|
+
defaults: {
|
|
144
|
+
slippageToleranceFactor?: number;
|
|
145
|
+
maxAcceptableReverseBondingCurveFeeSlippageFactor?: number;
|
|
146
|
+
} = {}
|
|
147
|
+
): T & {
|
|
148
|
+
slippageToleranceFactor: number;
|
|
149
|
+
maxAcceptableReverseBondingCurveFeeSlippageFactor: number;
|
|
150
|
+
} {
|
|
151
|
+
return {
|
|
152
|
+
...args,
|
|
153
|
+
slippageToleranceFactor:
|
|
154
|
+
args.slippageToleranceFactor ??
|
|
155
|
+
defaults.slippageToleranceFactor ??
|
|
156
|
+
DEFAULT_SLIPPAGE_TOLERANCE,
|
|
157
|
+
maxAcceptableReverseBondingCurveFeeSlippageFactor:
|
|
158
|
+
args.maxAcceptableReverseBondingCurveFeeSlippageFactor ??
|
|
159
|
+
defaults.maxAcceptableReverseBondingCurveFeeSlippageFactor ??
|
|
160
|
+
DEFAULT_RBC_FEE_SLIPPAGE,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Converts volume resolution string to seconds
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```typescript
|
|
169
|
+
* const seconds = resolutionToSeconds('1h', '1h');
|
|
170
|
+
* // 3600
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
export function resolutionToSeconds(
|
|
174
|
+
resolution: string | undefined,
|
|
175
|
+
defaultResolution: string = DEFAULT_VOLUME_RESOLUTION
|
|
176
|
+
): number {
|
|
177
|
+
return RESOLUTION_MAP[resolution ?? defaultResolution] ?? RESOLUTION_MAP[defaultResolution];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Converts ISO 8601 date string to Unix timestamp (seconds)
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```typescript
|
|
185
|
+
* const timestamp = dateToUnixTimestamp('2024-01-15T14:30:25Z');
|
|
186
|
+
* // 1705329025
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
export function dateToUnixTimestamp(isoDate: string | undefined): number | undefined {
|
|
190
|
+
if (!isoDate) return undefined;
|
|
191
|
+
return Math.floor(new Date(isoDate).getTime() / 1000);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// =============================================================================
|
|
195
|
+
// Export All
|
|
196
|
+
// =============================================================================
|
|
197
|
+
|
|
198
|
+
export const defaultValues = {
|
|
199
|
+
pagination: DEFAULT_PAGINATION,
|
|
200
|
+
limits: DEFAULT_LIMITS,
|
|
201
|
+
maxLimits: MAX_LIMITS,
|
|
202
|
+
slippageTolerance: DEFAULT_SLIPPAGE_TOLERANCE,
|
|
203
|
+
rbcFeeSlippage: DEFAULT_RBC_FEE_SLIPPAGE,
|
|
204
|
+
poolType: DEFAULT_POOL_TYPE,
|
|
205
|
+
sortOrder: DEFAULT_SORT_ORDER,
|
|
206
|
+
volumeResolution: DEFAULT_VOLUME_RESOLUTION,
|
|
207
|
+
resolutionMap: RESOLUTION_MAP,
|
|
208
|
+
};
|