@fundtracer/mcp 1.0.3 → 1.0.5
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 +84 -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,60 @@ 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
|
+
"x-auth-token": key,
|
|
265
|
+
"Content-Type": "application/json"
|
|
266
|
+
};
|
|
267
|
+
if (_mcpCtx?.userId) {
|
|
268
|
+
headers["X-MCP-UserId"] = _mcpCtx.userId;
|
|
269
|
+
}
|
|
236
270
|
return axios.create({
|
|
237
271
|
baseURL: API_BASE,
|
|
238
272
|
timeout: 6e4,
|
|
239
|
-
headers
|
|
240
|
-
Authorization: `Bearer ${key}`,
|
|
241
|
-
"Content-Type": "application/json"
|
|
242
|
-
}
|
|
273
|
+
headers
|
|
243
274
|
});
|
|
244
275
|
}
|
|
245
|
-
|
|
276
|
+
function withLogging(toolName, handler) {
|
|
277
|
+
return async (args, ctx) => {
|
|
278
|
+
_mcpCtx = ctx;
|
|
279
|
+
const start = Date.now();
|
|
280
|
+
try {
|
|
281
|
+
const result = await handler(args, ctx);
|
|
282
|
+
logMcpRequest({
|
|
283
|
+
userId: ctx.userId,
|
|
284
|
+
toolName,
|
|
285
|
+
args: JSON.stringify(args).substring(0, 500),
|
|
286
|
+
status: result.isError ? "error" : "success",
|
|
287
|
+
responsePreview: JSON.stringify(result).substring(0, 300),
|
|
288
|
+
duration: Date.now() - start,
|
|
289
|
+
createdAt: Date.now(),
|
|
290
|
+
keyPrefix: ctx.apiKeyPrefix
|
|
291
|
+
});
|
|
292
|
+
return result;
|
|
293
|
+
} catch (error) {
|
|
294
|
+
logMcpRequest({
|
|
295
|
+
userId: ctx.userId,
|
|
296
|
+
toolName,
|
|
297
|
+
args: JSON.stringify(args).substring(0, 500),
|
|
298
|
+
status: "error",
|
|
299
|
+
responsePreview: error.message.substring(0, 300),
|
|
300
|
+
duration: Date.now() - start,
|
|
301
|
+
createdAt: Date.now(),
|
|
302
|
+
keyPrefix: ctx.apiKeyPrefix
|
|
303
|
+
});
|
|
304
|
+
throw error;
|
|
305
|
+
} finally {
|
|
306
|
+
_mcpCtx = null;
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
var API_BASE, _mcpCtx, analyzeWallet, traceFunds, compareWallets, analyzeContract, detectSybilClusters, getPortfolio, getTransactions, lookupEntity, getGasPrices, getTokenInfo, TOOL_HANDLERS;
|
|
246
311
|
var init_api_handlers = __esm({
|
|
247
312
|
"src/mcp/api-handlers.ts"() {
|
|
313
|
+
init_mcpLogger();
|
|
248
314
|
API_BASE = process.env.FUNDTRACER_API_URL || "https://api.fundtracer.xyz";
|
|
315
|
+
_mcpCtx = null;
|
|
249
316
|
analyzeWallet = async (args, ctx) => {
|
|
250
317
|
const { address, chainId, transactionLimit } = args;
|
|
251
318
|
try {
|
|
@@ -399,16 +466,16 @@ var init_api_handlers = __esm({
|
|
|
399
466
|
}
|
|
400
467
|
};
|
|
401
468
|
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
|
|
469
|
+
analyze_wallet: withLogging("analyze_wallet", analyzeWallet),
|
|
470
|
+
trace_funds: withLogging("trace_funds", traceFunds),
|
|
471
|
+
compare_wallets: withLogging("compare_wallets", compareWallets),
|
|
472
|
+
analyze_contract: withLogging("analyze_contract", analyzeContract),
|
|
473
|
+
detect_sybil_clusters: withLogging("detect_sybil_clusters", detectSybilClusters),
|
|
474
|
+
get_portfolio: withLogging("get_portfolio", getPortfolio),
|
|
475
|
+
get_transactions: withLogging("get_transactions", getTransactions),
|
|
476
|
+
lookup_entity: withLogging("lookup_entity", lookupEntity),
|
|
477
|
+
get_gas_prices: withLogging("get_gas_prices", getGasPrices),
|
|
478
|
+
get_token_info: withLogging("get_token_info", getTokenInfo)
|
|
412
479
|
};
|
|
413
480
|
}
|
|
414
481
|
});
|
|
@@ -430,8 +497,8 @@ async function validateMcpApiKey(rawKey) {
|
|
|
430
497
|
return validateViaHttp(rawKey);
|
|
431
498
|
}
|
|
432
499
|
async function validateWithFirestore(rawKey) {
|
|
433
|
-
const { getFirestore } = await import("../firebase.js");
|
|
434
|
-
const db =
|
|
500
|
+
const { getFirestore: getFirestore2 } = await import("../firebase.js");
|
|
501
|
+
const db = getFirestore2();
|
|
435
502
|
if (!db) return null;
|
|
436
503
|
const keyDoc = await db.collection("apiKeys").doc(rawKey).get();
|
|
437
504
|
if (keyDoc.exists) {
|
package/package.json
CHANGED