@autonomaai/mcp-client 1.0.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.
- package/dist/client.d.ts +269 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +493 -0
- package/dist/client.js.map +1 -0
- package/dist/hummingbot-api.d.ts +99 -0
- package/dist/hummingbot-api.d.ts.map +1 -0
- package/dist/hummingbot-api.js +217 -0
- package/dist/hummingbot-api.js.map +1 -0
- package/dist/index.d.ts +94 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +177 -0
- package/dist/index.js.map +1 -0
- package/dist/tool-utils.d.ts +18 -0
- package/dist/tool-utils.d.ts.map +1 -0
- package/dist/tool-utils.js +36 -0
- package/dist/tool-utils.js.map +1 -0
- package/dist/types.d.ts +834 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/package.json +52 -0
- package/src/client.ts +780 -0
- package/src/hummingbot-api.ts +323 -0
- package/src/index.ts +208 -0
- package/src/tool-utils.ts +48 -0
- package/src/types.ts +972 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hummingbot API Client
|
|
3
|
+
*
|
|
4
|
+
* Direct HTTP client for the official Hummingbot API (hummingbot/hummingbot-api)
|
|
5
|
+
* Uses Basic Auth and maps to real API endpoints
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Use btoa for Base64 encoding (works in both Node.js and browser)
|
|
9
|
+
declare const process: { env: Record<string, string | undefined> } | undefined;
|
|
10
|
+
|
|
11
|
+
export interface HummingbotAPIConfig {
|
|
12
|
+
baseUrl: string;
|
|
13
|
+
username: string;
|
|
14
|
+
password: string;
|
|
15
|
+
timeout?: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface BotOrchestrationStatus {
|
|
19
|
+
status: string;
|
|
20
|
+
data: Record<string, any>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface BotRunsStats {
|
|
24
|
+
total: number;
|
|
25
|
+
running: number;
|
|
26
|
+
stopped: number;
|
|
27
|
+
archived: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface Connector {
|
|
31
|
+
name: string;
|
|
32
|
+
type: 'spot' | 'perpetual';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface Account {
|
|
36
|
+
name: string;
|
|
37
|
+
credentials: string[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export class HummingbotAPIClient {
|
|
41
|
+
private config: Required<HummingbotAPIConfig>;
|
|
42
|
+
private authHeader: string;
|
|
43
|
+
|
|
44
|
+
constructor(config: HummingbotAPIConfig) {
|
|
45
|
+
this.config = {
|
|
46
|
+
timeout: 30000,
|
|
47
|
+
...config
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Create Basic Auth header using btoa (universal)
|
|
51
|
+
const credentials = btoa(`${config.username}:${config.password}`);
|
|
52
|
+
this.authHeader = `Basic ${credentials}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private async request<T>(
|
|
56
|
+
endpoint: string,
|
|
57
|
+
options: {
|
|
58
|
+
method?: string;
|
|
59
|
+
body?: any;
|
|
60
|
+
} = {}
|
|
61
|
+
): Promise<T> {
|
|
62
|
+
const { method = 'GET', body } = options;
|
|
63
|
+
const url = `${this.config.baseUrl}${endpoint}`;
|
|
64
|
+
|
|
65
|
+
const response = await fetch(url, {
|
|
66
|
+
method,
|
|
67
|
+
headers: {
|
|
68
|
+
'Content-Type': 'application/json',
|
|
69
|
+
'Authorization': this.authHeader
|
|
70
|
+
},
|
|
71
|
+
body: body ? JSON.stringify(body) : undefined
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if (!response.ok) {
|
|
75
|
+
const errorText = await response.text();
|
|
76
|
+
throw new Error(`Hummingbot API error ${response.status}: ${errorText}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const contentType = response.headers.get('content-type');
|
|
80
|
+
if (contentType?.includes('application/json')) {
|
|
81
|
+
return await response.json() as T;
|
|
82
|
+
}
|
|
83
|
+
return await response.text() as unknown as T;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// =============================================================================
|
|
87
|
+
// Root & Health
|
|
88
|
+
// =============================================================================
|
|
89
|
+
|
|
90
|
+
async getInfo(): Promise<{ name: string; version: string; status: string }> {
|
|
91
|
+
return this.request('/');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// =============================================================================
|
|
95
|
+
// Accounts
|
|
96
|
+
// =============================================================================
|
|
97
|
+
|
|
98
|
+
async getAccounts(): Promise<string[]> {
|
|
99
|
+
return this.request('/accounts/');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async addAccount(name: string): Promise<any> {
|
|
103
|
+
return this.request('/accounts/add-account', {
|
|
104
|
+
method: 'POST',
|
|
105
|
+
body: { account_name: name }
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async getAccountCredentials(accountName: string): Promise<string[]> {
|
|
110
|
+
return this.request(`/accounts/${accountName}/credentials`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async addCredential(accountName: string, connectorName: string, credentials: Record<string, string>): Promise<any> {
|
|
114
|
+
return this.request(`/accounts/add-credential/${accountName}/${connectorName}`, {
|
|
115
|
+
method: 'POST',
|
|
116
|
+
body: credentials
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// =============================================================================
|
|
121
|
+
// Connectors
|
|
122
|
+
// =============================================================================
|
|
123
|
+
|
|
124
|
+
async getConnectors(): Promise<string[]> {
|
|
125
|
+
return this.request('/connectors/');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async getConnectorConfigMap(connectorName: string): Promise<Record<string, any>> {
|
|
129
|
+
return this.request(`/connectors/${connectorName}/config-map`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async getConnectorOrderTypes(connectorName: string): Promise<string[]> {
|
|
133
|
+
return this.request(`/connectors/${connectorName}/order-types`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async getConnectorTradingRules(connectorName: string): Promise<any> {
|
|
137
|
+
return this.request(`/connectors/${connectorName}/trading-rules`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// =============================================================================
|
|
141
|
+
// Bot Orchestration
|
|
142
|
+
// =============================================================================
|
|
143
|
+
|
|
144
|
+
async getBotOrchestrationStatus(): Promise<BotOrchestrationStatus> {
|
|
145
|
+
return this.request('/bot-orchestration/status');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async getBotRuns(): Promise<any[]> {
|
|
149
|
+
return this.request('/bot-orchestration/bot-runs');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async getBotRunsStats(): Promise<BotRunsStats> {
|
|
153
|
+
return this.request('/bot-orchestration/bot-runs/stats');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async startBot(config: {
|
|
157
|
+
bot_name: string;
|
|
158
|
+
controllers_config?: Record<string, any>[];
|
|
159
|
+
script?: string;
|
|
160
|
+
script_config?: Record<string, any>;
|
|
161
|
+
}): Promise<any> {
|
|
162
|
+
return this.request('/bot-orchestration/start-bot', {
|
|
163
|
+
method: 'POST',
|
|
164
|
+
body: config
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async stopBot(botName: string): Promise<any> {
|
|
169
|
+
return this.request('/bot-orchestration/stop-bot', {
|
|
170
|
+
method: 'POST',
|
|
171
|
+
body: { bot_name: botName }
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async getBotHistory(botName: string): Promise<any> {
|
|
176
|
+
return this.request(`/bot-orchestration/${botName}/history`);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async getBotStatus(botName: string): Promise<any> {
|
|
180
|
+
return this.request(`/bot-orchestration/${botName}/status`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// =============================================================================
|
|
184
|
+
// Controllers
|
|
185
|
+
// =============================================================================
|
|
186
|
+
|
|
187
|
+
async getControllers(): Promise<any[]> {
|
|
188
|
+
return this.request('/controllers/');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async getControllerConfigs(): Promise<any[]> {
|
|
192
|
+
return this.request('/controllers/configs/');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async getControllerConfig(configName: string): Promise<any> {
|
|
196
|
+
return this.request(`/controllers/configs/${configName}`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async getController(controllerType: string, controllerName: string): Promise<any> {
|
|
200
|
+
return this.request(`/controllers/${controllerType}/${controllerName}`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async getControllerConfigTemplate(controllerType: string, controllerName: string): Promise<any> {
|
|
204
|
+
return this.request(`/controllers/${controllerType}/${controllerName}/config/template`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async validateControllerConfig(controllerType: string, controllerName: string, config: any): Promise<any> {
|
|
208
|
+
return this.request(`/controllers/${controllerType}/${controllerName}/config/validate`, {
|
|
209
|
+
method: 'POST',
|
|
210
|
+
body: config
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// =============================================================================
|
|
215
|
+
// Backtesting
|
|
216
|
+
// =============================================================================
|
|
217
|
+
|
|
218
|
+
async runBacktest(config: {
|
|
219
|
+
controller_type: string;
|
|
220
|
+
controller_name: string;
|
|
221
|
+
controller_config: Record<string, any>;
|
|
222
|
+
start_time?: number;
|
|
223
|
+
end_time?: number;
|
|
224
|
+
backtesting_resolution?: string;
|
|
225
|
+
trade_cost?: number;
|
|
226
|
+
}): Promise<any> {
|
|
227
|
+
return this.request('/backtesting/run-backtesting', {
|
|
228
|
+
method: 'POST',
|
|
229
|
+
body: config
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// =============================================================================
|
|
234
|
+
// Market Data
|
|
235
|
+
// =============================================================================
|
|
236
|
+
|
|
237
|
+
async getMarketData(config: {
|
|
238
|
+
connector_name: string;
|
|
239
|
+
trading_pair: string;
|
|
240
|
+
}): Promise<any> {
|
|
241
|
+
return this.request('/market-data/', {
|
|
242
|
+
method: 'POST',
|
|
243
|
+
body: config
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
async getCandlesData(config: {
|
|
248
|
+
connector_name: string;
|
|
249
|
+
trading_pair: string;
|
|
250
|
+
interval?: string;
|
|
251
|
+
max_records?: number;
|
|
252
|
+
}): Promise<any> {
|
|
253
|
+
return this.request('/market-data/candles', {
|
|
254
|
+
method: 'POST',
|
|
255
|
+
body: config
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// =============================================================================
|
|
260
|
+
// Docker Management
|
|
261
|
+
// =============================================================================
|
|
262
|
+
|
|
263
|
+
async getActiveContainers(): Promise<any[]> {
|
|
264
|
+
return this.request('/docker/active-containers');
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async getAvailableImages(): Promise<any[]> {
|
|
268
|
+
return this.request('/docker/available-images/');
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
async isDockerRunning(): Promise<boolean> {
|
|
272
|
+
return this.request('/docker/running');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// =============================================================================
|
|
276
|
+
// Archived Bots
|
|
277
|
+
// =============================================================================
|
|
278
|
+
|
|
279
|
+
async getArchivedBots(): Promise<string[]> {
|
|
280
|
+
return this.request('/archived-bots/');
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
async getArchivedBotPerformance(dbPath: string): Promise<any> {
|
|
284
|
+
return this.request(`/archived-bots/${encodeURIComponent(dbPath)}/performance`);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async getArchivedBotSummary(dbPath: string): Promise<any> {
|
|
288
|
+
return this.request(`/archived-bots/${encodeURIComponent(dbPath)}/summary`);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async getArchivedBotTrades(dbPath: string): Promise<any[]> {
|
|
292
|
+
return this.request(`/archived-bots/${encodeURIComponent(dbPath)}/trades`);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
async getArchivedBotOrders(dbPath: string): Promise<any[]> {
|
|
296
|
+
return this.request(`/archived-bots/${encodeURIComponent(dbPath)}/orders`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Helper to safely get env var
|
|
301
|
+
function getEnv(key: string, defaultValue: string): string {
|
|
302
|
+
try {
|
|
303
|
+
return (typeof process !== 'undefined' && process?.env?.[key]) || defaultValue;
|
|
304
|
+
} catch {
|
|
305
|
+
return defaultValue;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Factory function to create a Hummingbot API client
|
|
311
|
+
*/
|
|
312
|
+
export function createHummingbotAPIClient(config?: Partial<HummingbotAPIConfig>): HummingbotAPIClient {
|
|
313
|
+
const baseUrl = config?.baseUrl || getEnv('HUMMINGBOT_API_URL', 'http://localhost:8000');
|
|
314
|
+
const username = config?.username || getEnv('HUMMINGBOT_USERNAME', 'admin');
|
|
315
|
+
const password = config?.password || getEnv('HUMMINGBOT_PASSWORD', 'admin');
|
|
316
|
+
|
|
317
|
+
return new HummingbotAPIClient({
|
|
318
|
+
baseUrl,
|
|
319
|
+
username,
|
|
320
|
+
password,
|
|
321
|
+
timeout: config?.timeout || 30000
|
|
322
|
+
});
|
|
323
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* autonoma MCP Client Library
|
|
3
|
+
*
|
|
4
|
+
* Unified client library for interacting with MCP servers across the
|
|
5
|
+
* autonoma trading ecosystem.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Export the main client class and error
|
|
9
|
+
export { MCPClient, MCPClientError } from './client';
|
|
10
|
+
|
|
11
|
+
// Export the Hummingbot API client (direct HTTP with Basic Auth)
|
|
12
|
+
export { HummingbotAPIClient, createHummingbotAPIClient } from './hummingbot-api';
|
|
13
|
+
export type { HummingbotAPIConfig, BotOrchestrationStatus, BotRunsStats } from './hummingbot-api';
|
|
14
|
+
|
|
15
|
+
// Export all types
|
|
16
|
+
export * from './types';
|
|
17
|
+
export * from './tool-utils';
|
|
18
|
+
|
|
19
|
+
// Convenience factory function
|
|
20
|
+
import { MCPClient } from './client';
|
|
21
|
+
import { MCPClientConfig } from './types';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Create a new MCP client instance
|
|
25
|
+
*/
|
|
26
|
+
export function createMCPClient(config: MCPClientConfig): MCPClient {
|
|
27
|
+
return new MCPClient(config);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Configuration helper to safely access environment variables
|
|
31
|
+
function getEnvOrDefault(key: string, defaultValue: string): string {
|
|
32
|
+
try {
|
|
33
|
+
// @ts-ignore - process may not be available in all environments
|
|
34
|
+
return typeof process !== 'undefined' && process.env?.[key] || defaultValue;
|
|
35
|
+
} catch {
|
|
36
|
+
return defaultValue;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Create a new MCP client with common defaults for Hummingbot
|
|
42
|
+
*/
|
|
43
|
+
export function createHummingbotClient(baseUrl: string = getEnvOrDefault('HUMMINGBOT_MCP_URL', 'http://localhost:8000')): MCPClient {
|
|
44
|
+
return new MCPClient({
|
|
45
|
+
baseUrl,
|
|
46
|
+
timeout: 30000,
|
|
47
|
+
retries: 3,
|
|
48
|
+
retryDelay: 1000,
|
|
49
|
+
enableLogging: false
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Create a new MCP client for the DexScreener Solana service
|
|
57
|
+
* Supports both HTTP and stdio-based MCP tools
|
|
58
|
+
*/
|
|
59
|
+
export function createDexscreenerClient(baseUrl: string = getEnvOrDefault('DEXSCREENER_MCP_URL', 'http://localhost:3010')): MCPClient {
|
|
60
|
+
return new MCPClient({
|
|
61
|
+
baseUrl,
|
|
62
|
+
timeout: 10000,
|
|
63
|
+
retries: 3,
|
|
64
|
+
retryDelay: 1000,
|
|
65
|
+
enableLogging: false
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Create a new MCP client for the RAG service
|
|
71
|
+
*/
|
|
72
|
+
export function createRAGClient(baseUrl: string = getEnvOrDefault('RAG_MCP_URL', 'http://localhost:3002')): MCPClient {
|
|
73
|
+
return new MCPClient({
|
|
74
|
+
baseUrl,
|
|
75
|
+
timeout: 20000,
|
|
76
|
+
retries: 2,
|
|
77
|
+
retryDelay: 1000,
|
|
78
|
+
enableLogging: false
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Create a new MCP client for the APY Strategy service
|
|
84
|
+
* Supports comprehensive DeFi yield optimization tools
|
|
85
|
+
*/
|
|
86
|
+
export function createAPYStrategyClient(baseUrl: string = getEnvOrDefault('APY_STRATEGY_MCP_URL', 'http://localhost:3008')): MCPClient {
|
|
87
|
+
return new MCPClient({
|
|
88
|
+
baseUrl,
|
|
89
|
+
timeout: 25000,
|
|
90
|
+
retries: 3,
|
|
91
|
+
retryDelay: 1500,
|
|
92
|
+
enableLogging: false
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Create a unified MCP client with access to all autonoma services
|
|
98
|
+
* Provides comprehensive access to RAG, Data Collector, DexScreener, and APY Strategy tools
|
|
99
|
+
*/
|
|
100
|
+
export function createUnifiedMCPClient(config?: {
|
|
101
|
+
ragServerUrl?: string;
|
|
102
|
+
dexscreenerUrl?: string;
|
|
103
|
+
apyStrategyUrl?: string;
|
|
104
|
+
hummingbotUrl?: string;
|
|
105
|
+
}): {
|
|
106
|
+
ragClient: MCPClient;
|
|
107
|
+
dexscreenerClient: MCPClient;
|
|
108
|
+
apyStrategyClient: MCPClient;
|
|
109
|
+
hummingbotClient: MCPClient;
|
|
110
|
+
} {
|
|
111
|
+
const {
|
|
112
|
+
ragServerUrl = 'http://localhost:8001',
|
|
113
|
+
dexscreenerUrl = 'http://localhost:3000',
|
|
114
|
+
apyStrategyUrl = 'http://localhost:8003',
|
|
115
|
+
hummingbotUrl = 'http://localhost:8080'
|
|
116
|
+
} = config || {};
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
ragClient: createRAGClient(ragServerUrl),
|
|
120
|
+
dexscreenerClient: createDexscreenerClient(dexscreenerUrl),
|
|
121
|
+
apyStrategyClient: createAPYStrategyClient(apyStrategyUrl),
|
|
122
|
+
hummingbotClient: createHummingbotClient(hummingbotUrl)
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Create a unified MCP tools interface with all services
|
|
128
|
+
* Provides a single interface to access all 38+ MCP tools across services
|
|
129
|
+
*/
|
|
130
|
+
export class UnifiedMCPTools {
|
|
131
|
+
public ragTools: MCPClient;
|
|
132
|
+
public dexscreenerTools: MCPClient;
|
|
133
|
+
public apyStrategyTools: MCPClient;
|
|
134
|
+
public hummingbotTools: MCPClient;
|
|
135
|
+
|
|
136
|
+
constructor(config?: {
|
|
137
|
+
ragServerUrl?: string;
|
|
138
|
+
dexscreenerUrl?: string;
|
|
139
|
+
apyStrategyUrl?: string;
|
|
140
|
+
hummingbotUrl?: string;
|
|
141
|
+
}) {
|
|
142
|
+
const clients = createUnifiedMCPClient(config);
|
|
143
|
+
this.ragTools = clients.ragClient;
|
|
144
|
+
this.dexscreenerTools = clients.dexscreenerClient;
|
|
145
|
+
this.apyStrategyTools = clients.apyStrategyClient;
|
|
146
|
+
this.hummingbotTools = clients.hummingbotClient;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Get health status from all services
|
|
151
|
+
*/
|
|
152
|
+
async getHealthStatus(): Promise<{
|
|
153
|
+
rag: any;
|
|
154
|
+
dexscreener: any;
|
|
155
|
+
apyStrategy: any;
|
|
156
|
+
hummingbot: any;
|
|
157
|
+
}> {
|
|
158
|
+
const [rag, dexscreener, apyStrategy, hummingbot] = await Promise.allSettled([
|
|
159
|
+
this.ragTools.getHealth(),
|
|
160
|
+
this.dexscreenerTools.getHealth(),
|
|
161
|
+
this.apyStrategyTools.getHealth(),
|
|
162
|
+
this.hummingbotTools.getHealth()
|
|
163
|
+
]);
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
rag: rag.status === 'fulfilled' ? rag.value : { error: rag.reason?.message },
|
|
167
|
+
dexscreener: dexscreener.status === 'fulfilled' ? dexscreener.value : { error: dexscreener.reason?.message },
|
|
168
|
+
apyStrategy: apyStrategy.status === 'fulfilled' ? apyStrategy.value : { error: apyStrategy.reason?.message },
|
|
169
|
+
hummingbot: hummingbot.status === 'fulfilled' ? hummingbot.value : { error: hummingbot.reason?.message }
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* List all available tools across all services
|
|
175
|
+
*/
|
|
176
|
+
async listAllTools(): Promise<{
|
|
177
|
+
rag: any;
|
|
178
|
+
dexscreener: any;
|
|
179
|
+
apyStrategy: any;
|
|
180
|
+
hummingbot: any;
|
|
181
|
+
}> {
|
|
182
|
+
const [rag, dexscreener, apyStrategy, hummingbot] = await Promise.allSettled([
|
|
183
|
+
this.ragTools.listTools(),
|
|
184
|
+
this.dexscreenerTools.listTools(),
|
|
185
|
+
this.apyStrategyTools.listTools(),
|
|
186
|
+
this.hummingbotTools.listTools()
|
|
187
|
+
]);
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
rag: rag.status === 'fulfilled' ? rag.value : { error: rag.reason?.message },
|
|
191
|
+
dexscreener: dexscreener.status === 'fulfilled' ? dexscreener.value : { error: dexscreener.reason?.message },
|
|
192
|
+
apyStrategy: apyStrategy.status === 'fulfilled' ? apyStrategy.value : { error: apyStrategy.reason?.message },
|
|
193
|
+
hummingbot: hummingbot.status === 'fulfilled' ? hummingbot.value : { error: hummingbot.reason?.message }
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Create a unified MCP tools instance
|
|
200
|
+
*/
|
|
201
|
+
export function createUnifiedMCPTools(config?: {
|
|
202
|
+
ragServerUrl?: string;
|
|
203
|
+
dexscreenerUrl?: string;
|
|
204
|
+
apyStrategyUrl?: string;
|
|
205
|
+
hummingbotUrl?: string;
|
|
206
|
+
}): UnifiedMCPTools {
|
|
207
|
+
return new UnifiedMCPTools(config);
|
|
208
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility helpers for MCP tool execution, exposed as part of the MCP client package.
|
|
3
|
+
* Provides consistent payload shaping and error/response normalization for any caller.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface MCPToolExecutionResult {
|
|
7
|
+
success: boolean;
|
|
8
|
+
response?: any;
|
|
9
|
+
error?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface MCPClientLike {
|
|
13
|
+
callTool(payload: { name: string; arguments?: Record<string, any> }): Promise<any>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function executeMCPTool(
|
|
17
|
+
client: MCPClientLike | null | undefined,
|
|
18
|
+
toolName: string,
|
|
19
|
+
args?: Record<string, any>
|
|
20
|
+
): Promise<MCPToolExecutionResult> {
|
|
21
|
+
if (!client) {
|
|
22
|
+
return {
|
|
23
|
+
success: false,
|
|
24
|
+
error: 'MCP client is not configured'
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const payload = await client.callTool({
|
|
30
|
+
name: toolName,
|
|
31
|
+
arguments: args || {}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const isError = payload?.isError || false;
|
|
35
|
+
return {
|
|
36
|
+
success: !isError,
|
|
37
|
+
response: payload,
|
|
38
|
+
error: isError
|
|
39
|
+
? payload?.meta?.error || 'MCP tool reported an error'
|
|
40
|
+
: undefined
|
|
41
|
+
};
|
|
42
|
+
} catch (error) {
|
|
43
|
+
return {
|
|
44
|
+
success: false,
|
|
45
|
+
error: error instanceof Error ? error.message : 'Unknown MCP error'
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|