@moonbanking/mcp-server 0.5.6
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/.github/workflows/npm-publish.yml +137 -0
- package/README.md +77 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +693 -0
- package/dist/index.js.map +1 -0
- package/package.json +36 -0
- package/src/index.ts +778 -0
- package/tsconfig.json +27 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,778 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
|
+
import {
|
|
6
|
+
CallToolRequestSchema,
|
|
7
|
+
ListToolsRequestSchema,
|
|
8
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
9
|
+
import fetch from 'node-fetch';
|
|
10
|
+
|
|
11
|
+
// Configuration
|
|
12
|
+
const DEFAULT_BASE_URL = 'https://api.moonbanking.com/v1';
|
|
13
|
+
const BASE_URL = process.env.MOON_BANKING_INTERNAL_BASE_URL || DEFAULT_BASE_URL;
|
|
14
|
+
const API_KEY = process.env.MOON_BANKING_API_KEY;
|
|
15
|
+
|
|
16
|
+
if (!API_KEY) {
|
|
17
|
+
console.error('Error: MOON_BANKING_API_KEY environment variable is required');
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// API client helper
|
|
22
|
+
const apiCall = async (
|
|
23
|
+
method: string,
|
|
24
|
+
path: string,
|
|
25
|
+
options: {
|
|
26
|
+
params?: Record<string, unknown>;
|
|
27
|
+
body?: unknown;
|
|
28
|
+
} = {},
|
|
29
|
+
): Promise<unknown> => {
|
|
30
|
+
try {
|
|
31
|
+
// Build URL with query parameters
|
|
32
|
+
const url = new URL(`${BASE_URL}${path}`);
|
|
33
|
+
if (options.params) {
|
|
34
|
+
Object.entries(options.params).forEach(([key, value]) => {
|
|
35
|
+
if (value !== undefined && value !== null) {
|
|
36
|
+
url.searchParams.append(key, String(value));
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const fetchOptions: Parameters<typeof fetch>[1] = {
|
|
42
|
+
method,
|
|
43
|
+
headers: {
|
|
44
|
+
'Authorization': `Bearer ${API_KEY}`,
|
|
45
|
+
'Content-Type': 'application/json',
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
if (options.body && method !== 'GET' && method !== 'HEAD') {
|
|
50
|
+
fetchOptions.body = JSON.stringify(options.body);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const response = await fetch(url.toString(), fetchOptions);
|
|
54
|
+
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
const errorText = await response.text();
|
|
57
|
+
throw new Error(`API request failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const contentType = response.headers.get('content-type');
|
|
61
|
+
if (contentType && contentType.includes('application/json')) {
|
|
62
|
+
return await response.json();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return await response.text();
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error('API call error:', error);
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Tool definitions
|
|
73
|
+
const tools = [
|
|
74
|
+
{
|
|
75
|
+
"name": "bank-get",
|
|
76
|
+
"description": "This endpoint allows you to retrieve a paginated list of all banks. By default, a maximum of ten banks are shown per page. You can search banks by name, filter by country and description (including null/not_null status or semantic content search using vector embeddings), sort them by various fields, and include related data like scores and country information. When searching description content, results are ordered by semantic similarity.",
|
|
77
|
+
"inputSchema": {
|
|
78
|
+
"type": "object",
|
|
79
|
+
"properties": {
|
|
80
|
+
"limit": {
|
|
81
|
+
"type": "integer",
|
|
82
|
+
"description": "Number of items to return.",
|
|
83
|
+
"default": 10
|
|
84
|
+
},
|
|
85
|
+
"starting_after": {
|
|
86
|
+
"type": "string",
|
|
87
|
+
"description": "Cursor for forward pagination. Use the id of the last item from the previous page to get the next page."
|
|
88
|
+
},
|
|
89
|
+
"ending_before": {
|
|
90
|
+
"type": "string",
|
|
91
|
+
"description": "Cursor for backward pagination. Use the id of the first item from the current page to get the previous page."
|
|
92
|
+
},
|
|
93
|
+
"search": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"description": "Search banks by name."
|
|
96
|
+
},
|
|
97
|
+
"description": {
|
|
98
|
+
"type": "string",
|
|
99
|
+
"description": "Filter banks by description. Under the hood, this is a semantic search that uses vector embeddings, so you may get better results if you use general language. Besides a full text search, you can use \"null\" to return banks without descriptions or \"not_null\" to return banks with descriptions."
|
|
100
|
+
},
|
|
101
|
+
"sortBy": {
|
|
102
|
+
"type": "string",
|
|
103
|
+
"description": "Field to sort by.",
|
|
104
|
+
"enum": [
|
|
105
|
+
"name",
|
|
106
|
+
"rank",
|
|
107
|
+
"countryRank",
|
|
108
|
+
"storiesCount",
|
|
109
|
+
"countryId",
|
|
110
|
+
"overall_score",
|
|
111
|
+
"overall_total",
|
|
112
|
+
"overall_up",
|
|
113
|
+
"overall_down",
|
|
114
|
+
"cryptoFriendly_score",
|
|
115
|
+
"cryptoFriendly_total",
|
|
116
|
+
"cryptoFriendly_up",
|
|
117
|
+
"cryptoFriendly_down",
|
|
118
|
+
"customerService_score",
|
|
119
|
+
"customerService_total",
|
|
120
|
+
"customerService_up",
|
|
121
|
+
"customerService_down",
|
|
122
|
+
"feesPricing_score",
|
|
123
|
+
"feesPricing_total",
|
|
124
|
+
"feesPricing_up",
|
|
125
|
+
"feesPricing_down",
|
|
126
|
+
"digitalExperience_score",
|
|
127
|
+
"digitalExperience_total",
|
|
128
|
+
"digitalExperience_up",
|
|
129
|
+
"digitalExperience_down",
|
|
130
|
+
"securityTrust_score",
|
|
131
|
+
"securityTrust_total",
|
|
132
|
+
"securityTrust_up",
|
|
133
|
+
"securityTrust_down",
|
|
134
|
+
"accountFeatures_score",
|
|
135
|
+
"accountFeatures_total",
|
|
136
|
+
"accountFeatures_up",
|
|
137
|
+
"accountFeatures_down",
|
|
138
|
+
"branchAtmAccess_score",
|
|
139
|
+
"branchAtmAccess_total",
|
|
140
|
+
"branchAtmAccess_up",
|
|
141
|
+
"branchAtmAccess_down",
|
|
142
|
+
"internationalBanking_score",
|
|
143
|
+
"internationalBanking_total",
|
|
144
|
+
"internationalBanking_up",
|
|
145
|
+
"internationalBanking_down",
|
|
146
|
+
"businessBanking_score",
|
|
147
|
+
"businessBanking_total",
|
|
148
|
+
"businessBanking_up",
|
|
149
|
+
"businessBanking_down",
|
|
150
|
+
"processingSpeed_score",
|
|
151
|
+
"processingSpeed_total",
|
|
152
|
+
"processingSpeed_up",
|
|
153
|
+
"processingSpeed_down",
|
|
154
|
+
"transparency_score",
|
|
155
|
+
"transparency_total",
|
|
156
|
+
"transparency_up",
|
|
157
|
+
"transparency_down",
|
|
158
|
+
"innovation_score",
|
|
159
|
+
"innovation_total",
|
|
160
|
+
"innovation_up",
|
|
161
|
+
"innovation_down",
|
|
162
|
+
"investmentServices_score",
|
|
163
|
+
"investmentServices_total",
|
|
164
|
+
"investmentServices_up",
|
|
165
|
+
"investmentServices_down",
|
|
166
|
+
"lending_score",
|
|
167
|
+
"lending_total",
|
|
168
|
+
"lending_up",
|
|
169
|
+
"lending_down"
|
|
170
|
+
],
|
|
171
|
+
"default": "name"
|
|
172
|
+
},
|
|
173
|
+
"sortOrder": {
|
|
174
|
+
"type": "string",
|
|
175
|
+
"description": "Sort order. Either ascending or descending.",
|
|
176
|
+
"enum": [
|
|
177
|
+
"asc",
|
|
178
|
+
"desc"
|
|
179
|
+
],
|
|
180
|
+
"default": "asc"
|
|
181
|
+
},
|
|
182
|
+
"include": {
|
|
183
|
+
"type": "string",
|
|
184
|
+
"description": "An optional comma-separated list of fields to include in the response. Possible values: `scores`, `country`, `meta`"
|
|
185
|
+
},
|
|
186
|
+
"countryId": {
|
|
187
|
+
"type": "string",
|
|
188
|
+
"description": "Only return banks in the specified country. A country's ID is Moon Banking's unique identifier for the country."
|
|
189
|
+
},
|
|
190
|
+
"countryCode": {
|
|
191
|
+
"type": "string",
|
|
192
|
+
"description": "Only return banks in the specified country. A country's code is the ISO 3166-1 code for the country. If both `countryId` and `countryCode` are provided, `countryId` will be used."
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"name": "bank-getById",
|
|
199
|
+
"description": "This endpoint allows you to retrieve a specific bank by providing the bank ID. You can include related data like scores and country information in the response.",
|
|
200
|
+
"inputSchema": {
|
|
201
|
+
"type": "object",
|
|
202
|
+
"properties": {
|
|
203
|
+
"id": {
|
|
204
|
+
"type": "string",
|
|
205
|
+
"description": "The bank's auto-generated unique identifier."
|
|
206
|
+
},
|
|
207
|
+
"include": {
|
|
208
|
+
"type": "string",
|
|
209
|
+
"description": "An optional comma-separated list of fields to include in the response. Possible values: `scores`, `country`"
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
"required": [
|
|
213
|
+
"id"
|
|
214
|
+
]
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"name": "bankVote-get",
|
|
219
|
+
"description": "This endpoint allows you to retrieve a paginated list of bank votes. You can filter by bank ID, category, country, vote type (upvote or downvote), and other parameters.",
|
|
220
|
+
"inputSchema": {
|
|
221
|
+
"type": "object",
|
|
222
|
+
"properties": {
|
|
223
|
+
"limit": {
|
|
224
|
+
"type": "integer",
|
|
225
|
+
"description": "Number of items to return.",
|
|
226
|
+
"default": 10
|
|
227
|
+
},
|
|
228
|
+
"starting_after": {
|
|
229
|
+
"type": "string",
|
|
230
|
+
"description": "Cursor for forward pagination. Use the id of the last item from the previous page to get the next page."
|
|
231
|
+
},
|
|
232
|
+
"ending_before": {
|
|
233
|
+
"type": "string",
|
|
234
|
+
"description": "Cursor for backward pagination. Use the id of the first item from the current page to get the previous page."
|
|
235
|
+
},
|
|
236
|
+
"bankId": {
|
|
237
|
+
"type": "string",
|
|
238
|
+
"description": "The bank's auto-generated unique identifier."
|
|
239
|
+
},
|
|
240
|
+
"categories": {
|
|
241
|
+
"type": "string",
|
|
242
|
+
"description": "An optional comma-separated list of fields to include in the response. Possible values: `CRYPTO_FRIENDLY`, `CUSTOMER_SERVICE`, `FEES_PRICING`, `DIGITAL_EXPERIENCE`, `SECURITY_TRUST`, `ACCOUNT_FEATURES`, `BRANCH_ATM_ACCESS`, `INTERNATIONAL_BANKING`, `BUSINESS_BANKING`, `PROCESSING_SPEED`, `TRANSPARENCY`, `INNOVATION`, `INVESTMENT_SERVICES`, `LENDING`"
|
|
243
|
+
},
|
|
244
|
+
"isUp": {
|
|
245
|
+
"type": "boolean",
|
|
246
|
+
"description": "Whether to filter for upvotes (true) or downvotes (false)."
|
|
247
|
+
},
|
|
248
|
+
"countryCode": {
|
|
249
|
+
"type": "string",
|
|
250
|
+
"description": "The country's ISO 3166-1 code (2 characters)."
|
|
251
|
+
},
|
|
252
|
+
"sortBy": {
|
|
253
|
+
"type": "string",
|
|
254
|
+
"description": "Field to sort by.",
|
|
255
|
+
"enum": [
|
|
256
|
+
"createdAt"
|
|
257
|
+
],
|
|
258
|
+
"default": "createdAt"
|
|
259
|
+
},
|
|
260
|
+
"sortOrder": {
|
|
261
|
+
"type": "string",
|
|
262
|
+
"description": "Sort order. Either ascending or descending.",
|
|
263
|
+
"enum": [
|
|
264
|
+
"asc",
|
|
265
|
+
"desc"
|
|
266
|
+
],
|
|
267
|
+
"default": "desc"
|
|
268
|
+
},
|
|
269
|
+
"include": {
|
|
270
|
+
"type": "string",
|
|
271
|
+
"description": "An optional comma-separated list of fields to include in the response. Possible values: `bank`, `country`"
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
"name": "country-get",
|
|
278
|
+
"description": "This endpoint allows you to retrieve a paginated list of all countries. By default, a maximum of ten countries are shown per page. You can search countries by name or 2-letter code, sort them by various fields, and include related data like scores.",
|
|
279
|
+
"inputSchema": {
|
|
280
|
+
"type": "object",
|
|
281
|
+
"properties": {
|
|
282
|
+
"limit": {
|
|
283
|
+
"type": "integer",
|
|
284
|
+
"description": "Number of items to return.",
|
|
285
|
+
"default": 10
|
|
286
|
+
},
|
|
287
|
+
"starting_after": {
|
|
288
|
+
"type": "string",
|
|
289
|
+
"description": "Cursor for forward pagination. Use the id of the last item from the previous page to get the next page."
|
|
290
|
+
},
|
|
291
|
+
"ending_before": {
|
|
292
|
+
"type": "string",
|
|
293
|
+
"description": "Cursor for backward pagination. Use the id of the first item from the current page to get the previous page."
|
|
294
|
+
},
|
|
295
|
+
"search": {
|
|
296
|
+
"type": "string",
|
|
297
|
+
"description": "Search countries by name or 2-letter code."
|
|
298
|
+
},
|
|
299
|
+
"sortBy": {
|
|
300
|
+
"type": "string",
|
|
301
|
+
"description": "Field to sort by.",
|
|
302
|
+
"enum": [
|
|
303
|
+
"name",
|
|
304
|
+
"code",
|
|
305
|
+
"rank",
|
|
306
|
+
"banksCount",
|
|
307
|
+
"storiesCount",
|
|
308
|
+
"overall_score",
|
|
309
|
+
"overall_total",
|
|
310
|
+
"overall_up",
|
|
311
|
+
"overall_down",
|
|
312
|
+
"cryptoFriendly_score",
|
|
313
|
+
"cryptoFriendly_total",
|
|
314
|
+
"cryptoFriendly_up",
|
|
315
|
+
"cryptoFriendly_down",
|
|
316
|
+
"customerService_score",
|
|
317
|
+
"customerService_total",
|
|
318
|
+
"customerService_up",
|
|
319
|
+
"customerService_down",
|
|
320
|
+
"feesPricing_score",
|
|
321
|
+
"feesPricing_total",
|
|
322
|
+
"feesPricing_up",
|
|
323
|
+
"feesPricing_down",
|
|
324
|
+
"digitalExperience_score",
|
|
325
|
+
"digitalExperience_total",
|
|
326
|
+
"digitalExperience_up",
|
|
327
|
+
"digitalExperience_down",
|
|
328
|
+
"securityTrust_score",
|
|
329
|
+
"securityTrust_total",
|
|
330
|
+
"securityTrust_up",
|
|
331
|
+
"securityTrust_down",
|
|
332
|
+
"accountFeatures_score",
|
|
333
|
+
"accountFeatures_total",
|
|
334
|
+
"accountFeatures_up",
|
|
335
|
+
"accountFeatures_down",
|
|
336
|
+
"branchAtmAccess_score",
|
|
337
|
+
"branchAtmAccess_total",
|
|
338
|
+
"branchAtmAccess_up",
|
|
339
|
+
"branchAtmAccess_down",
|
|
340
|
+
"internationalBanking_score",
|
|
341
|
+
"internationalBanking_total",
|
|
342
|
+
"internationalBanking_up",
|
|
343
|
+
"internationalBanking_down",
|
|
344
|
+
"businessBanking_score",
|
|
345
|
+
"businessBanking_total",
|
|
346
|
+
"businessBanking_up",
|
|
347
|
+
"businessBanking_down",
|
|
348
|
+
"processingSpeed_score",
|
|
349
|
+
"processingSpeed_total",
|
|
350
|
+
"processingSpeed_up",
|
|
351
|
+
"processingSpeed_down",
|
|
352
|
+
"transparency_score",
|
|
353
|
+
"transparency_total",
|
|
354
|
+
"transparency_up",
|
|
355
|
+
"transparency_down",
|
|
356
|
+
"innovation_score",
|
|
357
|
+
"innovation_total",
|
|
358
|
+
"innovation_up",
|
|
359
|
+
"innovation_down",
|
|
360
|
+
"investmentServices_score",
|
|
361
|
+
"investmentServices_total",
|
|
362
|
+
"investmentServices_up",
|
|
363
|
+
"investmentServices_down",
|
|
364
|
+
"lending_score",
|
|
365
|
+
"lending_total",
|
|
366
|
+
"lending_up",
|
|
367
|
+
"lending_down"
|
|
368
|
+
],
|
|
369
|
+
"default": "name"
|
|
370
|
+
},
|
|
371
|
+
"sortOrder": {
|
|
372
|
+
"type": "string",
|
|
373
|
+
"description": "Sort order. Either ascending or descending.",
|
|
374
|
+
"enum": [
|
|
375
|
+
"asc",
|
|
376
|
+
"desc"
|
|
377
|
+
],
|
|
378
|
+
"default": "asc"
|
|
379
|
+
},
|
|
380
|
+
"include": {
|
|
381
|
+
"type": "string",
|
|
382
|
+
"description": "An optional comma-separated list of fields to include in the response. Possible values: `scores`"
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
"name": "country-getByCountryCode",
|
|
389
|
+
"description": "This endpoint allows you to retrieve a specific country by providing the 2-letter ISO country code. You can include related data like scores in the response.",
|
|
390
|
+
"inputSchema": {
|
|
391
|
+
"type": "object",
|
|
392
|
+
"properties": {
|
|
393
|
+
"code": {
|
|
394
|
+
"type": "string",
|
|
395
|
+
"description": "The country's ISO 3166-1 code (2 characters)."
|
|
396
|
+
},
|
|
397
|
+
"include": {
|
|
398
|
+
"type": "string",
|
|
399
|
+
"description": "An optional comma-separated list of fields to include in the response. Possible values: `scores`"
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
"required": [
|
|
403
|
+
"code"
|
|
404
|
+
]
|
|
405
|
+
}
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
"name": "story-get",
|
|
409
|
+
"description": "This endpoint allows you to retrieve a paginated list of all stories. By default, a maximum of ten stories are shown per page. You can search stories by text content, filter by bank ID, sort them by various fields, and include related data like bank and country information.",
|
|
410
|
+
"inputSchema": {
|
|
411
|
+
"type": "object",
|
|
412
|
+
"properties": {
|
|
413
|
+
"limit": {
|
|
414
|
+
"type": "integer",
|
|
415
|
+
"description": "Number of items to return.",
|
|
416
|
+
"default": 10
|
|
417
|
+
},
|
|
418
|
+
"starting_after": {
|
|
419
|
+
"type": "string",
|
|
420
|
+
"description": "Cursor for forward pagination. Use the id of the last item from the previous page to get the next page."
|
|
421
|
+
},
|
|
422
|
+
"ending_before": {
|
|
423
|
+
"type": "string",
|
|
424
|
+
"description": "Cursor for backward pagination. Use the id of the first item from the current page to get the previous page."
|
|
425
|
+
},
|
|
426
|
+
"search": {
|
|
427
|
+
"type": "string",
|
|
428
|
+
"description": "Search stories by text content."
|
|
429
|
+
},
|
|
430
|
+
"sortBy": {
|
|
431
|
+
"type": "string",
|
|
432
|
+
"description": "Field to sort by.",
|
|
433
|
+
"enum": [
|
|
434
|
+
"createdAt",
|
|
435
|
+
"thumbsUpCount"
|
|
436
|
+
],
|
|
437
|
+
"default": "createdAt"
|
|
438
|
+
},
|
|
439
|
+
"sortOrder": {
|
|
440
|
+
"type": "string",
|
|
441
|
+
"description": "Sort order. Either ascending or descending.",
|
|
442
|
+
"enum": [
|
|
443
|
+
"asc",
|
|
444
|
+
"desc"
|
|
445
|
+
],
|
|
446
|
+
"default": "asc"
|
|
447
|
+
},
|
|
448
|
+
"include": {
|
|
449
|
+
"type": "string",
|
|
450
|
+
"description": "An optional comma-separated list of fields to include in the response. Possible values: `bank`, `country`"
|
|
451
|
+
},
|
|
452
|
+
"countryCode": {
|
|
453
|
+
"type": "string",
|
|
454
|
+
"description": "The country's ISO 3166-1 code (2 characters)."
|
|
455
|
+
},
|
|
456
|
+
"bankId": {
|
|
457
|
+
"type": "string",
|
|
458
|
+
"description": "The bank's auto-generated unique identifier."
|
|
459
|
+
},
|
|
460
|
+
"tags": {
|
|
461
|
+
"type": "string",
|
|
462
|
+
"description": "An optional comma-separated list of fields to include in the response. Possible values: `CRYPTO_FRIENDLY`, `CUSTOMER_SERVICE`, `FEES_PRICING`, `DIGITAL_EXPERIENCE`, `SECURITY_TRUST`, `ACCOUNT_FEATURES`, `BRANCH_ATM_ACCESS`, `INTERNATIONAL_BANKING`, `BUSINESS_BANKING`, `PROCESSING_SPEED`, `TRANSPARENCY`, `INNOVATION`, `INVESTMENT_SERVICES`, `LENDING`"
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
"name": "story-getById",
|
|
469
|
+
"description": "This endpoint allows you to retrieve a specific story by providing the story ID. You can include related data like bank and country information in the response.",
|
|
470
|
+
"inputSchema": {
|
|
471
|
+
"type": "object",
|
|
472
|
+
"properties": {
|
|
473
|
+
"id": {
|
|
474
|
+
"type": "string",
|
|
475
|
+
"description": "The story's auto-generated unique identifier."
|
|
476
|
+
},
|
|
477
|
+
"include": {
|
|
478
|
+
"type": "string",
|
|
479
|
+
"description": "An optional comma-separated list of fields to include in the response. Possible values: `bank`, `country`"
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
"required": [
|
|
483
|
+
"id"
|
|
484
|
+
]
|
|
485
|
+
}
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
"name": "world-getOverview",
|
|
489
|
+
"description": "This endpoint allows you to retrieve global overview data that aggregates banks votes, stories and other data across all banks in all countries. You can include related data like scores in the response.",
|
|
490
|
+
"inputSchema": {
|
|
491
|
+
"type": "object",
|
|
492
|
+
"properties": {
|
|
493
|
+
"include": {
|
|
494
|
+
"type": "string",
|
|
495
|
+
"description": "An optional comma-separated list of fields to include in the response. Possible values: `scores`"
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
];
|
|
501
|
+
|
|
502
|
+
// Parse command line arguments for tool filtering
|
|
503
|
+
const args = process.argv.slice(2);
|
|
504
|
+
const selectedTools = new Set<string>();
|
|
505
|
+
|
|
506
|
+
args.forEach(arg => {
|
|
507
|
+
if (arg.startsWith('--tool=')) {
|
|
508
|
+
selectedTools.add(arg.substring('--tool='.length));
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
// Filter tools if specific ones were requested
|
|
513
|
+
const availableTools = selectedTools.size > 0
|
|
514
|
+
? tools.filter(tool => selectedTools.has(tool.name))
|
|
515
|
+
: tools;
|
|
516
|
+
|
|
517
|
+
// Create MCP server
|
|
518
|
+
const server = new Server(
|
|
519
|
+
{
|
|
520
|
+
name: 'moon banking api-mcp',
|
|
521
|
+
version: '2025-07-11',
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
capabilities: {
|
|
525
|
+
tools: {},
|
|
526
|
+
},
|
|
527
|
+
},
|
|
528
|
+
);
|
|
529
|
+
|
|
530
|
+
// Register tool list handler
|
|
531
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
532
|
+
tools: availableTools,
|
|
533
|
+
}));
|
|
534
|
+
|
|
535
|
+
// Register tool call handler
|
|
536
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
537
|
+
const { name, arguments: args = {} } = request.params;
|
|
538
|
+
|
|
539
|
+
try {
|
|
540
|
+
switch (name) {
|
|
541
|
+
case 'bank-get': {
|
|
542
|
+
const result = await apiCall(
|
|
543
|
+
'GET',
|
|
544
|
+
`/banks`,
|
|
545
|
+
{
|
|
546
|
+
params: {
|
|
547
|
+
limit: args.limit,
|
|
548
|
+
starting_after: args.starting_after,
|
|
549
|
+
ending_before: args.ending_before,
|
|
550
|
+
search: args.search,
|
|
551
|
+
description: args.description,
|
|
552
|
+
sortBy: args.sortBy,
|
|
553
|
+
sortOrder: args.sortOrder,
|
|
554
|
+
include: args.include,
|
|
555
|
+
countryId: args.countryId,
|
|
556
|
+
countryCode: args.countryCode,
|
|
557
|
+
},
|
|
558
|
+
|
|
559
|
+
},
|
|
560
|
+
);
|
|
561
|
+
|
|
562
|
+
return {
|
|
563
|
+
content: [
|
|
564
|
+
{
|
|
565
|
+
type: 'text',
|
|
566
|
+
text: JSON.stringify(result, null, 2),
|
|
567
|
+
},
|
|
568
|
+
],
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
case 'bank-getById': {
|
|
573
|
+
const result = await apiCall(
|
|
574
|
+
'GET',
|
|
575
|
+
`/banks/${args.id}`,
|
|
576
|
+
{
|
|
577
|
+
params: {
|
|
578
|
+
include: args.include,
|
|
579
|
+
},
|
|
580
|
+
|
|
581
|
+
},
|
|
582
|
+
);
|
|
583
|
+
|
|
584
|
+
return {
|
|
585
|
+
content: [
|
|
586
|
+
{
|
|
587
|
+
type: 'text',
|
|
588
|
+
text: JSON.stringify(result, null, 2),
|
|
589
|
+
},
|
|
590
|
+
],
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
case 'bankVote-get': {
|
|
595
|
+
const result = await apiCall(
|
|
596
|
+
'GET',
|
|
597
|
+
`/bank-votes`,
|
|
598
|
+
{
|
|
599
|
+
params: {
|
|
600
|
+
limit: args.limit,
|
|
601
|
+
starting_after: args.starting_after,
|
|
602
|
+
ending_before: args.ending_before,
|
|
603
|
+
bankId: args.bankId,
|
|
604
|
+
categories: args.categories,
|
|
605
|
+
isUp: args.isUp,
|
|
606
|
+
countryCode: args.countryCode,
|
|
607
|
+
sortBy: args.sortBy,
|
|
608
|
+
sortOrder: args.sortOrder,
|
|
609
|
+
include: args.include,
|
|
610
|
+
},
|
|
611
|
+
|
|
612
|
+
},
|
|
613
|
+
);
|
|
614
|
+
|
|
615
|
+
return {
|
|
616
|
+
content: [
|
|
617
|
+
{
|
|
618
|
+
type: 'text',
|
|
619
|
+
text: JSON.stringify(result, null, 2),
|
|
620
|
+
},
|
|
621
|
+
],
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
case 'country-get': {
|
|
626
|
+
const result = await apiCall(
|
|
627
|
+
'GET',
|
|
628
|
+
`/countries`,
|
|
629
|
+
{
|
|
630
|
+
params: {
|
|
631
|
+
limit: args.limit,
|
|
632
|
+
starting_after: args.starting_after,
|
|
633
|
+
ending_before: args.ending_before,
|
|
634
|
+
search: args.search,
|
|
635
|
+
sortBy: args.sortBy,
|
|
636
|
+
sortOrder: args.sortOrder,
|
|
637
|
+
include: args.include,
|
|
638
|
+
},
|
|
639
|
+
|
|
640
|
+
},
|
|
641
|
+
);
|
|
642
|
+
|
|
643
|
+
return {
|
|
644
|
+
content: [
|
|
645
|
+
{
|
|
646
|
+
type: 'text',
|
|
647
|
+
text: JSON.stringify(result, null, 2),
|
|
648
|
+
},
|
|
649
|
+
],
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
case 'country-getByCountryCode': {
|
|
654
|
+
const result = await apiCall(
|
|
655
|
+
'GET',
|
|
656
|
+
`/countries/${args.code}`,
|
|
657
|
+
{
|
|
658
|
+
params: {
|
|
659
|
+
include: args.include,
|
|
660
|
+
},
|
|
661
|
+
|
|
662
|
+
},
|
|
663
|
+
);
|
|
664
|
+
|
|
665
|
+
return {
|
|
666
|
+
content: [
|
|
667
|
+
{
|
|
668
|
+
type: 'text',
|
|
669
|
+
text: JSON.stringify(result, null, 2),
|
|
670
|
+
},
|
|
671
|
+
],
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
case 'story-get': {
|
|
676
|
+
const result = await apiCall(
|
|
677
|
+
'GET',
|
|
678
|
+
`/stories`,
|
|
679
|
+
{
|
|
680
|
+
params: {
|
|
681
|
+
limit: args.limit,
|
|
682
|
+
starting_after: args.starting_after,
|
|
683
|
+
ending_before: args.ending_before,
|
|
684
|
+
search: args.search,
|
|
685
|
+
sortBy: args.sortBy,
|
|
686
|
+
sortOrder: args.sortOrder,
|
|
687
|
+
include: args.include,
|
|
688
|
+
countryCode: args.countryCode,
|
|
689
|
+
bankId: args.bankId,
|
|
690
|
+
tags: args.tags,
|
|
691
|
+
},
|
|
692
|
+
|
|
693
|
+
},
|
|
694
|
+
);
|
|
695
|
+
|
|
696
|
+
return {
|
|
697
|
+
content: [
|
|
698
|
+
{
|
|
699
|
+
type: 'text',
|
|
700
|
+
text: JSON.stringify(result, null, 2),
|
|
701
|
+
},
|
|
702
|
+
],
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
case 'story-getById': {
|
|
707
|
+
const result = await apiCall(
|
|
708
|
+
'GET',
|
|
709
|
+
`/stories/${args.id}`,
|
|
710
|
+
{
|
|
711
|
+
params: {
|
|
712
|
+
include: args.include,
|
|
713
|
+
},
|
|
714
|
+
|
|
715
|
+
},
|
|
716
|
+
);
|
|
717
|
+
|
|
718
|
+
return {
|
|
719
|
+
content: [
|
|
720
|
+
{
|
|
721
|
+
type: 'text',
|
|
722
|
+
text: JSON.stringify(result, null, 2),
|
|
723
|
+
},
|
|
724
|
+
],
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
case 'world-getOverview': {
|
|
729
|
+
const result = await apiCall(
|
|
730
|
+
'GET',
|
|
731
|
+
`/world`,
|
|
732
|
+
{
|
|
733
|
+
params: {
|
|
734
|
+
include: args.include,
|
|
735
|
+
},
|
|
736
|
+
|
|
737
|
+
},
|
|
738
|
+
);
|
|
739
|
+
|
|
740
|
+
return {
|
|
741
|
+
content: [
|
|
742
|
+
{
|
|
743
|
+
type: 'text',
|
|
744
|
+
text: JSON.stringify(result, null, 2),
|
|
745
|
+
},
|
|
746
|
+
],
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
default:
|
|
750
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
751
|
+
}
|
|
752
|
+
} catch (error) {
|
|
753
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
754
|
+
return {
|
|
755
|
+
content: [
|
|
756
|
+
{
|
|
757
|
+
type: 'text',
|
|
758
|
+
text: `Error: ${errorMessage}`,
|
|
759
|
+
},
|
|
760
|
+
],
|
|
761
|
+
isError: true,
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
// Start server
|
|
767
|
+
const main = async (): Promise<void> => {
|
|
768
|
+
const transport = new StdioServerTransport();
|
|
769
|
+
await server.connect(transport);
|
|
770
|
+
console.error('Moon Banking API MCP server running on stdio');
|
|
771
|
+
console.error(`Base URL: ${BASE_URL}`);
|
|
772
|
+
console.error(`Available tools: ${availableTools.length}`);
|
|
773
|
+
};
|
|
774
|
+
|
|
775
|
+
main().catch((error) => {
|
|
776
|
+
console.error('Server error:', error);
|
|
777
|
+
process.exit(1);
|
|
778
|
+
});
|