@fundtracer/mcp 1.0.3 → 1.0.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/fundtracer-mcp.js +83 -17
- package/package.json +1 -1
package/fundtracer-mcp.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
#!/usr/bin/env node
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
5
|
var __esm = (fn, res) => function __init() {
|
|
@@ -219,6 +220,31 @@ var init_tools = __esm({
|
|
|
219
220
|
}
|
|
220
221
|
});
|
|
221
222
|
|
|
223
|
+
// src/mcp/mcpLogger.ts
|
|
224
|
+
import { getFirestore } from "../firebase.js";
|
|
225
|
+
async function logMcpRequest(entry) {
|
|
226
|
+
try {
|
|
227
|
+
const db = getFirestore();
|
|
228
|
+
if (!db) {
|
|
229
|
+
console.warn("[MCP-LOGGER] getFirestore() returned null");
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
await db.collection("mcpLogs").add(entry);
|
|
233
|
+
console.log("[MCP-LOGGER] Logged:", entry.toolName, "for user:", entry.userId, "status:", entry.status);
|
|
234
|
+
} catch (err2) {
|
|
235
|
+
mcpLogWarnings++;
|
|
236
|
+
if (mcpLogWarnings <= 3 || mcpLogWarnings % 10 === 0) {
|
|
237
|
+
console.error("[MCP-LOGGER] Failed to log MCP request:", err2?.message || err2);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
var mcpLogWarnings;
|
|
242
|
+
var init_mcpLogger = __esm({
|
|
243
|
+
"src/mcp/mcpLogger.ts"() {
|
|
244
|
+
mcpLogWarnings = 0;
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
|
|
222
248
|
// src/mcp/api-handlers.ts
|
|
223
249
|
var api_handlers_exports = {};
|
|
224
250
|
__export(api_handlers_exports, {
|
|
@@ -233,19 +259,59 @@ function err(message) {
|
|
|
233
259
|
}
|
|
234
260
|
function api() {
|
|
235
261
|
const key = process.env.FUNDTRACER_MCP_API_KEY || "";
|
|
262
|
+
const headers = {
|
|
263
|
+
Authorization: `Bearer ${key}`,
|
|
264
|
+
"Content-Type": "application/json"
|
|
265
|
+
};
|
|
266
|
+
if (_mcpCtx?.userId) {
|
|
267
|
+
headers["X-MCP-UserId"] = _mcpCtx.userId;
|
|
268
|
+
}
|
|
236
269
|
return axios.create({
|
|
237
270
|
baseURL: API_BASE,
|
|
238
271
|
timeout: 6e4,
|
|
239
|
-
headers
|
|
240
|
-
Authorization: `Bearer ${key}`,
|
|
241
|
-
"Content-Type": "application/json"
|
|
242
|
-
}
|
|
272
|
+
headers
|
|
243
273
|
});
|
|
244
274
|
}
|
|
245
|
-
|
|
275
|
+
function withLogging(toolName, handler) {
|
|
276
|
+
return async (args, ctx) => {
|
|
277
|
+
_mcpCtx = ctx;
|
|
278
|
+
const start = Date.now();
|
|
279
|
+
try {
|
|
280
|
+
const result = await handler(args, ctx);
|
|
281
|
+
logMcpRequest({
|
|
282
|
+
userId: ctx.userId,
|
|
283
|
+
toolName,
|
|
284
|
+
args: JSON.stringify(args).substring(0, 500),
|
|
285
|
+
status: result.isError ? "error" : "success",
|
|
286
|
+
responsePreview: JSON.stringify(result).substring(0, 300),
|
|
287
|
+
duration: Date.now() - start,
|
|
288
|
+
createdAt: Date.now(),
|
|
289
|
+
keyPrefix: ctx.apiKeyPrefix
|
|
290
|
+
});
|
|
291
|
+
return result;
|
|
292
|
+
} catch (error) {
|
|
293
|
+
logMcpRequest({
|
|
294
|
+
userId: ctx.userId,
|
|
295
|
+
toolName,
|
|
296
|
+
args: JSON.stringify(args).substring(0, 500),
|
|
297
|
+
status: "error",
|
|
298
|
+
responsePreview: error.message.substring(0, 300),
|
|
299
|
+
duration: Date.now() - start,
|
|
300
|
+
createdAt: Date.now(),
|
|
301
|
+
keyPrefix: ctx.apiKeyPrefix
|
|
302
|
+
});
|
|
303
|
+
throw error;
|
|
304
|
+
} finally {
|
|
305
|
+
_mcpCtx = null;
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
var API_BASE, _mcpCtx, analyzeWallet, traceFunds, compareWallets, analyzeContract, detectSybilClusters, getPortfolio, getTransactions, lookupEntity, getGasPrices, getTokenInfo, TOOL_HANDLERS;
|
|
246
310
|
var init_api_handlers = __esm({
|
|
247
311
|
"src/mcp/api-handlers.ts"() {
|
|
312
|
+
init_mcpLogger();
|
|
248
313
|
API_BASE = process.env.FUNDTRACER_API_URL || "https://api.fundtracer.xyz";
|
|
314
|
+
_mcpCtx = null;
|
|
249
315
|
analyzeWallet = async (args, ctx) => {
|
|
250
316
|
const { address, chainId, transactionLimit } = args;
|
|
251
317
|
try {
|
|
@@ -399,16 +465,16 @@ var init_api_handlers = __esm({
|
|
|
399
465
|
}
|
|
400
466
|
};
|
|
401
467
|
TOOL_HANDLERS = {
|
|
402
|
-
analyze_wallet: analyzeWallet,
|
|
403
|
-
trace_funds: traceFunds,
|
|
404
|
-
compare_wallets: compareWallets,
|
|
405
|
-
analyze_contract: analyzeContract,
|
|
406
|
-
detect_sybil_clusters: detectSybilClusters,
|
|
407
|
-
get_portfolio: getPortfolio,
|
|
408
|
-
get_transactions: getTransactions,
|
|
409
|
-
lookup_entity: lookupEntity,
|
|
410
|
-
get_gas_prices: getGasPrices,
|
|
411
|
-
get_token_info: getTokenInfo
|
|
468
|
+
analyze_wallet: withLogging("analyze_wallet", analyzeWallet),
|
|
469
|
+
trace_funds: withLogging("trace_funds", traceFunds),
|
|
470
|
+
compare_wallets: withLogging("compare_wallets", compareWallets),
|
|
471
|
+
analyze_contract: withLogging("analyze_contract", analyzeContract),
|
|
472
|
+
detect_sybil_clusters: withLogging("detect_sybil_clusters", detectSybilClusters),
|
|
473
|
+
get_portfolio: withLogging("get_portfolio", getPortfolio),
|
|
474
|
+
get_transactions: withLogging("get_transactions", getTransactions),
|
|
475
|
+
lookup_entity: withLogging("lookup_entity", lookupEntity),
|
|
476
|
+
get_gas_prices: withLogging("get_gas_prices", getGasPrices),
|
|
477
|
+
get_token_info: withLogging("get_token_info", getTokenInfo)
|
|
412
478
|
};
|
|
413
479
|
}
|
|
414
480
|
});
|
|
@@ -430,8 +496,8 @@ async function validateMcpApiKey(rawKey) {
|
|
|
430
496
|
return validateViaHttp(rawKey);
|
|
431
497
|
}
|
|
432
498
|
async function validateWithFirestore(rawKey) {
|
|
433
|
-
const { getFirestore } = await import("../firebase.js");
|
|
434
|
-
const db =
|
|
499
|
+
const { getFirestore: getFirestore2 } = await import("../firebase.js");
|
|
500
|
+
const db = getFirestore2();
|
|
435
501
|
if (!db) return null;
|
|
436
502
|
const keyDoc = await db.collection("apiKeys").doc(rawKey).get();
|
|
437
503
|
if (keyDoc.exists) {
|
package/package.json
CHANGED