chainhint-mcp 1.2.0 → 1.2.1
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/index.js +10 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -218,7 +218,7 @@ const server = new McpServer({
|
|
|
218
218
|
// ── Tool 1: check_wallet_risk ─────────────────────────────────────────────────
|
|
219
219
|
server.tool("check_wallet_risk", "Fast risk check for a crypto wallet address against ChainHint's 54M+ labeled address database (12 chains). Returns risk score 0-100, risk level (clean/low/medium/high/critical/sanctioned), entity name and category, labels, and sanctions hit. Use it to decide allow/warn/block before paying or interacting with a counterparty wallet. Free: 3 checks per day without a key; CHAINHINT_API_KEY (Agency plan) lifts it to 10,000/day. For a deeper report (risk factors, exposure, balance) use lookup_address.", {
|
|
220
220
|
address: z.string().describe("Wallet address to check (EVM 0x..., Bitcoin, or Solana)"),
|
|
221
|
-
chain: z.string().optional().describe("Blockchain: ethereum, bsc, polygon, arbitrum, optimism, base, avalanche,
|
|
221
|
+
chain: z.string().optional().describe("Blockchain: ethereum, bsc, polygon, arbitrum, optimism, base, avalanche, gnosis, bitcoin, solana, tron, ton (default: auto-detect from address format; the response chain is the address family for bitcoin/solana/tron/ton)"),
|
|
222
222
|
}, async ({ address, chain }) => {
|
|
223
223
|
try {
|
|
224
224
|
const params = { address };
|
|
@@ -281,7 +281,7 @@ server.tool("check_wallet_risk", "Fast risk check for a crypto wallet address ag
|
|
|
281
281
|
// ── Tool 2: lookup_address ────────────────────────────────────────────────────
|
|
282
282
|
server.tool("lookup_address", "Detailed lookup of a blockchain address: entity attribution, risk score with the factors behind it, sanctions and GoPlus security flags, counterparty exposure (where funds came from / went to, by category with named entities), balance, token count and transaction count. Free: 10 lookups per day without a key; CHAINHINT_API_KEY lifts it. Supports EVM chains, Bitcoin, Solana, TRON, TON.", {
|
|
283
283
|
address: z.string().describe("Blockchain address to look up"),
|
|
284
|
-
chain: z.string().optional().describe("Blockchain (ethereum, bsc, polygon, arbitrum, optimism, base, avalanche,
|
|
284
|
+
chain: z.string().optional().describe("Blockchain (ethereum, bsc, polygon, arbitrum, optimism, base, avalanche, gnosis, bitcoin, solana, tron, ton)"),
|
|
285
285
|
}, async ({ address, chain }) => {
|
|
286
286
|
try {
|
|
287
287
|
const params = { address };
|
|
@@ -416,6 +416,11 @@ server.tool("get_trace_status", "Fund-trace summary for a publicly tracked crypt
|
|
|
416
416
|
lines.push(`**Hops traced:** ${hops} · **Addresses:** ${nodes.length} · **Transfers:** ${edges.length}`);
|
|
417
417
|
}
|
|
418
418
|
const endpoints = inc.endpoints ?? [];
|
|
419
|
+
// A graph none of whose edges carries amount_usd was never valued (legacy
|
|
420
|
+
// Bitcoin rows): endpoint.amount_usd then holds the raw asset quantity and
|
|
421
|
+
// must not be printed as dollars (multi-chain audit 2026-09-03).
|
|
422
|
+
const graphPriced = edges.length === 0 || edges.some((e) => e.amount_usd != null && Number(e.amount_usd) > 0);
|
|
423
|
+
const money = (n) => (graphPriced ? usd(n) : "unpriced");
|
|
419
424
|
if (endpoints.length) {
|
|
420
425
|
const byType = new Map();
|
|
421
426
|
for (const e of endpoints) {
|
|
@@ -430,11 +435,11 @@ server.tool("get_trace_status", "Fund-trace summary for a publicly tracked crypt
|
|
|
430
435
|
}
|
|
431
436
|
const totalUsd = [...byType.values()].reduce((s, b) => s + b.usd, 0);
|
|
432
437
|
// Σ endpoint amounts counts every hop's inflow (multi-hop), so it is larger than the loss — name the base.
|
|
433
|
-
lines.push(``, `### Where the funds went (${endpoints.length} endpoints, ${usd(totalUsd)} observed at endpoints — not the loss figure)`);
|
|
438
|
+
lines.push(``, `### Where the funds went (${endpoints.length} endpoints, ${graphPriced ? `${usd(totalUsd)} observed at endpoints — not the loss figure` : "this trace carries no USD valuation"})`);
|
|
434
439
|
for (const [t, b] of [...byType.entries()].sort((a, b) => b[1].usd - a[1].usd)) {
|
|
435
440
|
const top = [...b.entities.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3).map(([n]) => n);
|
|
436
441
|
const pct = totalUsd > 0 ? ` (${((b.usd / totalUsd) * 100).toFixed(1)}%)` : "";
|
|
437
|
-
lines.push(`- **${t}**: ${
|
|
442
|
+
lines.push(`- **${t}**: ${money(b.usd)}${graphPriced ? pct : ""} across ${b.n} address(es)${top.length ? ` — ${top.join(", ")}` : ""}`);
|
|
438
443
|
}
|
|
439
444
|
const topEndpoints = [...endpoints]
|
|
440
445
|
.filter((e) => (e.amount_usd ?? 0) > 0)
|
|
@@ -444,7 +449,7 @@ server.tool("get_trace_status", "Fund-trace summary for a publicly tracked crypt
|
|
|
444
449
|
lines.push(`**Largest endpoints:**`);
|
|
445
450
|
for (const e of topEndpoints) {
|
|
446
451
|
const name = e.entity_name ?? e.entity ?? "unattributed";
|
|
447
|
-
lines.push(`- ${truncateAddr(e.address)} — ${name} (${endpointBucket(e.entity_category, e.type, e.entity_name ?? e.entity)}): ${
|
|
452
|
+
lines.push(`- ${truncateAddr(e.address)} — ${name} (${endpointBucket(e.entity_category, e.type, e.entity_name ?? e.entity)}): ${money(e.amount_usd)}`);
|
|
448
453
|
}
|
|
449
454
|
}
|
|
450
455
|
}
|