chain-insights 0.2.32 → 0.3.3
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/README.md +40 -14
- package/dist/cases-Cp9DUbEV.mjs +6 -0
- package/dist/{cases-c0iV-XLI.cjs → cases-sTY5aXav.cjs} +3 -3
- package/dist/cli.cjs +122 -66
- package/dist/cli.mjs +122 -66
- package/dist/cli.mjs.map +1 -1
- package/dist/{viz-Da9YWN_I.cjs → data-extractor-Cavd7wHk.cjs} +11 -34
- package/dist/{viz-DkJyqlUu.mjs → data-extractor-DZUJu1Bz.mjs} +3 -32
- package/dist/data-extractor-DZUJu1Bz.mjs.map +1 -0
- package/dist/{dossier-Br62hCG7.cjs → dossier-BXy57V4-.cjs} +13 -1
- package/dist/{dossier-Bl0NkJKC.mjs → dossier-Bjpcbcxa.mjs} +4 -2
- package/dist/{dossier-Bl0NkJKC.mjs.map → dossier-Bjpcbcxa.mjs.map} +1 -1
- package/dist/export-BqTCO9lP.mjs +591 -0
- package/dist/export-BqTCO9lP.mjs.map +1 -0
- package/dist/export-DsXgtCwO.cjs +592 -0
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{init-DBC9Ml33.mjs → init-DLBL_nVG.mjs} +27 -1
- package/dist/{init-DBC9Ml33.mjs.map → init-DLBL_nVG.mjs.map} +1 -1
- package/dist/{init-CFaUWgjK.cjs → init-zqbd7i-_.cjs} +26 -0
- package/dist/mcp-proxy.cjs +215 -77
- package/dist/mcp-proxy.d.cts.map +1 -1
- package/dist/mcp-proxy.d.mts.map +1 -1
- package/dist/mcp-proxy.mjs +215 -77
- package/dist/mcp-proxy.mjs.map +1 -1
- package/dist/{public-tools-BwguvIsf.cjs → public-tools-BvMb3H2P.cjs} +701 -1479
- package/dist/{public-tools-DoRNhMn9.mjs → public-tools-wJoAFDFa.mjs} +700 -1479
- package/dist/public-tools-wJoAFDFa.mjs.map +1 -0
- package/dist/{resolver-D7VBb0uB.mjs → resolver-2jXNtWQO.mjs} +12 -29
- package/dist/resolver-2jXNtWQO.mjs.map +1 -0
- package/dist/{resolver-BUU7ZgW-.cjs → resolver-CZdQwKvh.cjs} +11 -28
- package/dist/{runner-BCDeBYsR.cjs → runner-BhZ4lnF1.cjs} +2 -2
- package/dist/{runner-CTFK0Qcg.mjs → runner-DIJSbkjc.mjs} +3 -3
- package/dist/{runner-CTFK0Qcg.mjs.map → runner-DIJSbkjc.mjs.map} +1 -1
- package/dist/{selector-CTUiQrzI.mjs → selector-CF2o5gxN.mjs} +2 -2
- package/dist/{selector-CTUiQrzI.mjs.map → selector-CF2o5gxN.mjs.map} +1 -1
- package/dist/{selector-DBS2jYH4.cjs → selector-DfAMZEC9.cjs} +1 -1
- package/dist/{session-DwyikazY.cjs → session-BT7VpbAd.cjs} +13 -1
- package/dist/{session-Bha3zFrx.mjs → session-DROyhebe.mjs} +4 -2
- package/dist/{session-Bha3zFrx.mjs.map → session-DROyhebe.mjs.map} +1 -1
- package/dist/{store-BT2SCcQr.mjs → store-CTtqQtaE.mjs} +10 -4
- package/dist/{store-BT2SCcQr.mjs.map → store-CTtqQtaE.mjs.map} +1 -1
- package/dist/{store-DogLawSj.cjs → store-CqPfs47P.cjs} +37 -7
- package/dist/{tool-visibility-BHRFLXuU.mjs → tool-visibility-BpyZHRBi.mjs} +4 -2
- package/dist/tool-visibility-BpyZHRBi.mjs.map +1 -0
- package/dist/{tool-visibility-iAVQV3t0.cjs → tool-visibility-Buq7YdUZ.cjs} +3 -1
- package/dist/viz-5y24S5X1.mjs +35 -0
- package/dist/viz-5y24S5X1.mjs.map +1 -0
- package/dist/viz-Dqp3C5kb.cjs +44 -0
- package/docs/contributing.md +3 -2
- package/docs/graph-tools.md +125 -117
- package/docs/investigation-workspaces.md +14 -0
- package/docs/mcp-proxy.md +15 -2
- package/package.json +1 -1
- package/skills/chain-insights-cypher/SKILL.md +6 -0
- package/skills/chain-insights-developer-experience/SKILL.md +26 -6
- package/skills/chain-insights-investigation/SKILL.md +64 -48
- package/skills/chain-insights-trace-funds/SKILL.md +80 -197
- package/skills/test-chain-insights-graphrag-mcp/SKILL.md +1 -1
- package/skills/test-chain-insights-graphrag-mcp/scripts/run-uat.sh +4 -4
- package/dist/cases-qjPtbnUd.mjs +0 -6
- package/dist/public-tools-DoRNhMn9.mjs.map +0 -1
- package/dist/resolver-D7VBb0uB.mjs.map +0 -1
- package/dist/tool-visibility-BHRFLXuU.mjs.map +0 -1
- package/dist/viz-DkJyqlUu.mjs.map +0 -1
package/dist/mcp-proxy.cjs
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
const require_chunk = require("./chunk-DakpK96I.cjs");
|
|
3
3
|
const require_version = require("./version-CO9Or_YV.cjs");
|
|
4
4
|
const require_client = require("./client-Db6IV1tv.cjs");
|
|
5
|
-
const require_tool_visibility = require("./tool-visibility-
|
|
5
|
+
const require_tool_visibility = require("./tool-visibility-Buq7YdUZ.cjs");
|
|
6
6
|
let node_url = require("node:url");
|
|
7
7
|
let node_path = require("node:path");
|
|
8
8
|
node_path = require_chunk.__toESM(node_path, 1);
|
|
@@ -24,17 +24,19 @@ const LOCAL_TOOL_NAMES = new Set([
|
|
|
24
24
|
"case_resume",
|
|
25
25
|
"case_add_evidence",
|
|
26
26
|
"case_verify_evidence",
|
|
27
|
+
"case_export",
|
|
27
28
|
"case_update_dossier",
|
|
28
29
|
"case_start_session",
|
|
29
30
|
"case_end_session"
|
|
30
31
|
]);
|
|
31
|
-
const PUBLIC_GRAPHRAG_PROMPT_NAMES = new Set(["address-risk", "
|
|
32
|
+
const PUBLIC_GRAPHRAG_PROMPT_NAMES = new Set(["address-risk", "trace-tools"]);
|
|
32
33
|
const GRAPH_RESOURCE_URI = "ui://chain-insights/graph";
|
|
33
34
|
const GRAPH_APP_TOOL_NAMES = new Set([
|
|
34
35
|
"address_risk",
|
|
35
|
-
"scam_topology",
|
|
36
36
|
"stake_insights",
|
|
37
|
-
"
|
|
37
|
+
"trace_victim_funds",
|
|
38
|
+
"trace_suspect_funds",
|
|
39
|
+
"trace_deposit_sources"
|
|
38
40
|
]);
|
|
39
41
|
const GRAPH_ARRAY_KEYS = [
|
|
40
42
|
"nodes",
|
|
@@ -43,25 +45,28 @@ const GRAPH_ARRAY_KEYS = [
|
|
|
43
45
|
"edge_anchors"
|
|
44
46
|
];
|
|
45
47
|
const __dirname$1 = node_path.default.dirname((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
|
|
46
|
-
const COMMA_SEPARATED_ADDRESS_FIELDS = new Set([
|
|
48
|
+
const COMMA_SEPARATED_ADDRESS_FIELDS = new Set([
|
|
49
|
+
"victim_addresses",
|
|
50
|
+
"known_suspect_addresses",
|
|
51
|
+
"suspect_addresses",
|
|
52
|
+
"deposit_addresses"
|
|
53
|
+
]);
|
|
47
54
|
const KNOWN_PUBLIC_TOOL_REQUIRED_ARGS = {
|
|
48
55
|
address_risk: ["address", "network"],
|
|
49
|
-
scam_topology: [
|
|
50
|
-
"victim_address",
|
|
51
|
-
"incident_timestamp_ms",
|
|
52
|
-
"network"
|
|
53
|
-
],
|
|
54
56
|
stake_insights: ["network"],
|
|
55
|
-
|
|
57
|
+
trace_victim_funds: ["victim_addresses", "network"],
|
|
58
|
+
trace_suspect_funds: ["suspect_addresses", "network"],
|
|
59
|
+
trace_deposit_sources: ["deposit_addresses", "network"],
|
|
56
60
|
graph_query: ["query", "network"],
|
|
57
61
|
graph_query_batch: ["network", "queries"]
|
|
58
62
|
};
|
|
59
63
|
const KNOWN_PUBLIC_TOOL_DESCRIPTIONS = {
|
|
60
64
|
network_capabilities: "Return supported Chain Insights networks, capability layers, tool availability, data retention windows, and freshness. Use this before choosing network-specific tools.",
|
|
61
65
|
address_risk: "Screen one full blockchain address for AML risk, behavior patterns, neighborhood context, exchange exposure, and optional comparison with compare_address. This includes the exchange-behavior analysis formerly covered by money_flows_between_exchanges. Use this as the first tool for a single-address investigation. The tool returns an investigator-ready summary; preserve full addresses exactly.",
|
|
62
|
-
scam_topology: "Build victim-incident laundering topology from one victim/source address and the earliest known incident timestamp. Traversal uses one explicit activity policy: node_relative_only by default, or global_incident_only when requested. Repeated targets are kept as non-expanding convergence edges. Returns ML-ready scam_labels plus review context and a track_funds-compatible graph report: primary flows, deposits, reverse_leads. Victims, exchange endpoints, and generic labeled context nodes are not automatic scam labels; preserve full addresses exactly.",
|
|
63
66
|
stake_insights: "Explain Bittensor staking behavior around one full address, coldkey, or hotkey. Requires network plus exactly one of address, coldkey, or hotkey. Returns net staked/unstaked amounts, active coldkey-hotkey-netuid relationships, aggregate stake movement amounts, top counterparties, first/last activity, source backend, query evidence, and optional graph report metadata.",
|
|
64
|
-
|
|
67
|
+
trace_victim_funds: "Trace victim/source funds forward through intermediaries to exchange deposit candidates. Use only when the input addresses are victims or trusted stolen-source addresses; do not use for suspected deposit addresses because traceback belongs to trace_deposit_sources. Exchange hot wallets are terminal only, never candidate deposits. Returns chain-insights.trace.v1 and preserves full addresses exactly.",
|
|
68
|
+
trace_suspect_funds: "Trace suspected scammer, mule, operator, or laundering-ring funds forward to cashout topology. Use when the input addresses are suspect-controlled seeds; incident_timestamp_ms is optional. Do not use for victim/source addresses or suspected deposit endpoints. Exchange hot wallets are terminal only, never candidate suspects or intermediates. Returns chain-insights.trace.v1 and preserves full addresses exactly.",
|
|
69
|
+
trace_deposit_sources: "Trace backward from suspected deposit/cashout addresses to upstream sources, shared funders, and convergence. Use only when the input addresses are suspected non-exchange deposit endpoints; do not treat these seeds as scammers and do not continue forward from discovered suspects here. Exchange hot wallets are excluded as seeds and upstream sources. Returns chain-insights.trace.v1 and preserves full addresses exactly.",
|
|
65
70
|
graph_query: "Run a read-only GQL/Cypher query through the Chain Insights graph endpoint. Use USE live_topology for recent topology, USE archive_topology for historical topology, and USE facts for labels, features, risk scores, assets, and enrichment. Cross-layer correlated joins may be limited by the active graph endpoint; preserve full addresses exactly.",
|
|
66
71
|
graph_query_batch: "Run multiple read-only GQL/Cypher queries through the Chain Insights graph endpoint in one paid batch. Prefer this for related topology/facts reads."
|
|
67
72
|
};
|
|
@@ -76,9 +81,10 @@ const CHAIN_INSIGHTS_WORKFLOW = [
|
|
|
76
81
|
"Workflow:",
|
|
77
82
|
"1. If the user is starting or continuing an investigation, use case_open or case_list/case_resume first.",
|
|
78
83
|
"2. Do not call investigation tools until required arguments are known. Network is required; use network_capabilities to check supported networks, data layers, retention, and freshness, or ask the user if missing.",
|
|
79
|
-
"3. Use address_risk
|
|
84
|
+
"3. Use address_risk for single-address enrichment. Use trace_victim_funds for victim/source forward tracing, trace_deposit_sources for reverse traceback from suspected deposit endpoints, and trace_suspect_funds for suspect-controlled outbound laundering/cashout topology. Use stake_insights for Bittensor staking behavior. Use graph_query(_batch) only when the high-level trace tools do not answer the exact question.",
|
|
80
85
|
"4. After a material result, preserve it with case_add_evidence when a case is active or ask whether to create/select a case.",
|
|
81
|
-
"5. Use case_update_dossier for durable address/entity findings and case_start_session/case_end_session for session notes."
|
|
86
|
+
"5. Use case_update_dossier for durable address/entity findings and case_start_session/case_end_session for session notes.",
|
|
87
|
+
"6. When a case reaches a useful checkpoint, use case_verify_evidence and case_export to produce Obsidian, LLMWiki, Codex, Claude Code, and ChatGPT-ready files."
|
|
82
88
|
].join("\n");
|
|
83
89
|
const GRAPH_SCHEMA_HINTS = [
|
|
84
90
|
"Graph query hints for network=bittensor:",
|
|
@@ -89,6 +95,7 @@ const GRAPH_SCHEMA_HINTS = [
|
|
|
89
95
|
"- Risk and ML properties may appear as live hints, but source-of-truth risk rows are RiskScore facts.",
|
|
90
96
|
"- Common relationships include FLOWS_TO, OPERATED_FROM, SERVED_FROM, REGISTERED_NEURON, BELONGS_TO, SYBIL_CLUSTER, LAYERING_HOP, BURST_ACTIVITY, CYCLE_PARTICIPANT, SMURFING_CLUSTER.",
|
|
91
97
|
"- FLOWS_TO properties are scoped to the selected topology graph and commonly carry amount_sum, amount_usd_sum, tx_count, first_seen_timestamp, last_seen_timestamp, first_tx_id, last_tx_id. Confirm available fields through runtime schema before relying on them.",
|
|
98
|
+
"- Traversal rule: for BFS, fixed-hop fallback, shortest-path, or manual FLOWS_TO traversal, exchange hot wallets are terminal endpoints only. Do not expand from, through, or classify exchange nodes as deposit, suspect, or intermediate candidates; filter every non-terminal node with is_exchange IS NULL.",
|
|
92
99
|
"- Start schema discovery with endpoint-safe property reads: MATCH (n:Address) WHERE n.address IS NOT NULL RETURN n.labels AS labels, n.address AS address LIMIT 20",
|
|
93
100
|
"- Relationship discovery: MATCH (:Address)-[r:FLOWS_TO]->(:Address) RETURN r.amount_sum AS amount_sum, r.amount_usd_sum AS amount_usd_sum LIMIT 20",
|
|
94
101
|
"- graph_query uses the active Chain Insights graph endpoint. Use USE live_topology for recent topology, USE archive_topology for historical topology, and USE facts for labels, features, risk scores, assets, and enrichment.",
|
|
@@ -152,20 +159,27 @@ function knownPublicToolInputSchema(toolName) {
|
|
|
152
159
|
compare_address: zod.string().optional().describe("Optional second full address for comparison"),
|
|
153
160
|
include_attachments: zod.boolean().optional().describe("Include graph app report metadata")
|
|
154
161
|
};
|
|
155
|
-
case "
|
|
156
|
-
|
|
162
|
+
case "trace_victim_funds": return {
|
|
163
|
+
victim_addresses: zod.string().min(1).describe("Comma-separated full victim/source addresses. Min 1, max 5."),
|
|
157
164
|
network: zod.string().min(1).describe(NETWORK_DESCRIPTION),
|
|
158
|
-
|
|
165
|
+
known_suspect_addresses: zod.string().optional().describe("Optional known suspect addresses for context only. They are not reverse-traced by this tool. Max 5."),
|
|
166
|
+
incident_timestamp_ms: zod.number().min(0).optional().describe("Optional incident timestamp in milliseconds."),
|
|
159
167
|
include_attachments: zod.boolean().optional().describe("Include graph app report metadata")
|
|
160
168
|
};
|
|
161
|
-
case "
|
|
169
|
+
case "trace_suspect_funds": return {
|
|
162
170
|
network: zod.string().min(1).describe(NETWORK_DESCRIPTION),
|
|
163
|
-
|
|
164
|
-
incident_timestamp_ms: zod.number().min(0).describe("
|
|
165
|
-
max_hops: zod.number().int().min(1).max(
|
|
166
|
-
activity_policy: zod.enum(["node_relative_only", "global_incident_only"]).optional().describe("Traversal activity policy. Default node_relative_only."),
|
|
171
|
+
suspect_addresses: zod.string().min(1).describe("Comma-separated full suspected scammer, mule, operator, or laundering-ring addresses. Min 1, max 5."),
|
|
172
|
+
incident_timestamp_ms: zod.number().min(0).optional().describe("Optional incident timestamp in milliseconds. This tool also works without a timestamp."),
|
|
173
|
+
max_hops: zod.number().int().min(1).max(5).optional().describe("Maximum forward trace hops. Default 3."),
|
|
167
174
|
case_id: zod.string().optional().describe("Optional Chain Insights case ID. When provided, compact evidence is appended to the case manifest.")
|
|
168
175
|
};
|
|
176
|
+
case "trace_deposit_sources": return {
|
|
177
|
+
network: zod.string().min(1).describe(NETWORK_DESCRIPTION),
|
|
178
|
+
deposit_addresses: zod.string().min(1).describe("Comma-separated full suspected deposit/cashout addresses. Min 1, max 5."),
|
|
179
|
+
max_hops: zod.number().int().min(1).max(5).optional().describe("Maximum reverse traceback hops. Default 2."),
|
|
180
|
+
case_id: zod.string().optional().describe("Optional Chain Insights case ID. When provided, compact evidence is appended to the case manifest."),
|
|
181
|
+
include_attachments: zod.boolean().optional().describe("Include graph app report metadata")
|
|
182
|
+
};
|
|
169
183
|
case "stake_insights": return {
|
|
170
184
|
network: zod.string().min(1).describe(NETWORK_DESCRIPTION),
|
|
171
185
|
address: zod.string().optional().describe("Full Bittensor address to inspect as either coldkey or hotkey. Provide exactly one of address, coldkey, or hotkey."),
|
|
@@ -421,24 +435,27 @@ function registerLocalPrompts(server, remotePromptNames) {
|
|
|
421
435
|
"",
|
|
422
436
|
"Present the summary as-is. Do not add analysis, verdicts, or risk assessments; the tool output already contains the risk assessment."
|
|
423
437
|
].join("\n"), "Address risk screening"));
|
|
424
|
-
if (!remotePromptNames.has("
|
|
425
|
-
title: "
|
|
426
|
-
description: "
|
|
438
|
+
if (!remotePromptNames.has("trace-tools")) server.registerPrompt("trace-tools", {
|
|
439
|
+
title: "Trace Tools",
|
|
440
|
+
description: "Choose trace_victim_funds, trace_deposit_sources, or trace_suspect_funds based on the evidence role.",
|
|
427
441
|
argsSchema: {
|
|
428
|
-
|
|
429
|
-
|
|
442
|
+
addresses: zod.string().describe("Input addresses, comma-separated full addresses"),
|
|
443
|
+
role: zod.enum([
|
|
444
|
+
"victim",
|
|
445
|
+
"suspect",
|
|
446
|
+
"deposit"
|
|
447
|
+
]).describe("Role of the supplied addresses"),
|
|
430
448
|
network: zod.string().describe(NETWORK_DESCRIPTION)
|
|
431
449
|
}
|
|
432
|
-
}, async ({
|
|
433
|
-
const untrusted = untrusted_addresses?.trim() ? `\nKnown untrusted addresses:\n${untrusted_addresses}\n` : "";
|
|
450
|
+
}, async ({ addresses, role, network }) => {
|
|
434
451
|
return promptResult([
|
|
435
|
-
`Use Chain Insights
|
|
452
|
+
`Use Chain Insights ${role === "deposit" ? "trace_deposit_sources" : `trace_${role}_funds`} on ${network}.`,
|
|
453
|
+
"",
|
|
454
|
+
"Full addresses:",
|
|
455
|
+
addresses,
|
|
436
456
|
"",
|
|
437
|
-
"
|
|
438
|
-
|
|
439
|
-
untrusted,
|
|
440
|
-
"Present the summary as-is and include recommended next actions exactly as returned."
|
|
441
|
-
].join("\n"), "Trace stolen funds");
|
|
457
|
+
role === "deposit" ? "For deposit role, use trace_deposit_sources rather than trace_deposit_funds." : "Present the summary as-is and use continuation.recommended_next_tools for follow-up."
|
|
458
|
+
].join("\n"), "Trace role-specific funds");
|
|
442
459
|
});
|
|
443
460
|
server.registerPrompt("graph-query", {
|
|
444
461
|
title: "Federated Graph Query",
|
|
@@ -758,13 +775,13 @@ async function createProxy() {
|
|
|
758
775
|
}
|
|
759
776
|
}, async ({ name, tags, description }) => {
|
|
760
777
|
try {
|
|
761
|
-
const { CaseStore } = await Promise.resolve().then(() => require("./cases-
|
|
778
|
+
const { CaseStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
762
779
|
const created = await CaseStore.create({
|
|
763
780
|
name,
|
|
764
781
|
tags: parseTags(tags),
|
|
765
782
|
description: description ?? ""
|
|
766
783
|
});
|
|
767
|
-
const { casesRoot } = await Promise.resolve().then(() => require("./store-
|
|
784
|
+
const { casesRoot } = await Promise.resolve().then(() => require("./store-CqPfs47P.cjs")).then((n) => n.store_exports);
|
|
768
785
|
return {
|
|
769
786
|
content: [{
|
|
770
787
|
type: "text",
|
|
@@ -798,7 +815,7 @@ async function createProxy() {
|
|
|
798
815
|
}
|
|
799
816
|
}, async ({ status }) => {
|
|
800
817
|
try {
|
|
801
|
-
const { CaseStore } = await Promise.resolve().then(() => require("./cases-
|
|
818
|
+
const { CaseStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
802
819
|
const cases = await CaseStore.list();
|
|
803
820
|
const filtered = status ? cases.filter((entry) => entry.status === status) : cases;
|
|
804
821
|
return {
|
|
@@ -823,7 +840,7 @@ async function createProxy() {
|
|
|
823
840
|
}
|
|
824
841
|
}, async ({ case_id }) => {
|
|
825
842
|
try {
|
|
826
|
-
const { CaseStore } = await Promise.resolve().then(() => require("./cases-
|
|
843
|
+
const { CaseStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
827
844
|
const context = await CaseStore.loadContext(case_id);
|
|
828
845
|
return {
|
|
829
846
|
content: [{
|
|
@@ -837,7 +854,7 @@ async function createProxy() {
|
|
|
837
854
|
}
|
|
838
855
|
});
|
|
839
856
|
server.registerTool("case_add_evidence", {
|
|
840
|
-
description: "Append a tool result or analyst note to a local case evidence manifest. Use after address_risk,
|
|
857
|
+
description: "Append a tool result or analyst note to a local case evidence manifest. Use after address_risk, trace_victim_funds, trace_suspect_funds, trace_deposit_sources, graph_query, or manual findings that should be preserved.",
|
|
841
858
|
inputSchema: {
|
|
842
859
|
case_id: zod.string().min(1).describe("Chain Insights case ID"),
|
|
843
860
|
source: zod.string().min(1).describe("Source tool or evidence origin"),
|
|
@@ -852,7 +869,7 @@ async function createProxy() {
|
|
|
852
869
|
}
|
|
853
870
|
}, async ({ case_id, source, content, query_params }) => {
|
|
854
871
|
try {
|
|
855
|
-
const { EvidenceStore } = await Promise.resolve().then(() => require("./cases-
|
|
872
|
+
const { EvidenceStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
856
873
|
const saved = await EvidenceStore.append(case_id, {
|
|
857
874
|
source,
|
|
858
875
|
content,
|
|
@@ -880,7 +897,7 @@ async function createProxy() {
|
|
|
880
897
|
}
|
|
881
898
|
}, async ({ case_id }) => {
|
|
882
899
|
try {
|
|
883
|
-
const { EvidenceStore } = await Promise.resolve().then(() => require("./cases-
|
|
900
|
+
const { EvidenceStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
884
901
|
const result = await EvidenceStore.verifyManifest(case_id);
|
|
885
902
|
return {
|
|
886
903
|
content: [{
|
|
@@ -893,6 +910,51 @@ async function createProxy() {
|
|
|
893
910
|
return caseToolError("Evidence verify", err);
|
|
894
911
|
}
|
|
895
912
|
});
|
|
913
|
+
server.registerTool("case_export", {
|
|
914
|
+
description: "Export a Chain Insights case to an Obsidian, LLMWiki, Codex, Claude Code, and ChatGPT-friendly local bundle.",
|
|
915
|
+
inputSchema: {
|
|
916
|
+
case_id: zod.string().min(1).describe("Chain Insights case ID to export"),
|
|
917
|
+
target: zod.enum(["obsidian-llmwiki"]).optional().describe("Export target. Default obsidian-llmwiki."),
|
|
918
|
+
mode: zod.enum([
|
|
919
|
+
"private",
|
|
920
|
+
"partner",
|
|
921
|
+
"public"
|
|
922
|
+
]).optional().describe("Redaction mode. Default private."),
|
|
923
|
+
output_dir: zod.string().optional().describe("Optional output directory. Defaults to published/<case-slug>.")
|
|
924
|
+
},
|
|
925
|
+
annotations: {
|
|
926
|
+
readOnlyHint: false,
|
|
927
|
+
destructiveHint: false,
|
|
928
|
+
idempotentHint: false,
|
|
929
|
+
openWorldHint: false
|
|
930
|
+
}
|
|
931
|
+
}, async ({ case_id, target, mode, output_dir }) => {
|
|
932
|
+
try {
|
|
933
|
+
const { exportCase } = await Promise.resolve().then(() => require("./export-DsXgtCwO.cjs"));
|
|
934
|
+
const result = await exportCase({
|
|
935
|
+
caseId: case_id,
|
|
936
|
+
target: target ?? "obsidian-llmwiki",
|
|
937
|
+
mode: mode ?? "private",
|
|
938
|
+
outputDir: output_dir
|
|
939
|
+
});
|
|
940
|
+
return {
|
|
941
|
+
content: [{
|
|
942
|
+
type: "text",
|
|
943
|
+
text: [
|
|
944
|
+
`Case exported: ${result.outputDir}`,
|
|
945
|
+
`Manifest: ${result.manifestPath}`,
|
|
946
|
+
`Files: ${result.fileCount}`,
|
|
947
|
+
`Open first: ${result.nextFile}`,
|
|
948
|
+
...result.warnings.map((warning) => `Warning: ${warning}`)
|
|
949
|
+
].join("\n")
|
|
950
|
+
}],
|
|
951
|
+
structuredContent: result,
|
|
952
|
+
isError: false
|
|
953
|
+
};
|
|
954
|
+
} catch (err) {
|
|
955
|
+
return caseToolError("Case export", err);
|
|
956
|
+
}
|
|
957
|
+
});
|
|
896
958
|
server.registerTool("case_update_dossier", {
|
|
897
959
|
description: "Append a finding to an address/entity dossier inside a local Chain Insights case.",
|
|
898
960
|
inputSchema: {
|
|
@@ -915,7 +977,7 @@ async function createProxy() {
|
|
|
915
977
|
}
|
|
916
978
|
}, async ({ case_id, address, finding, entity_type }) => {
|
|
917
979
|
try {
|
|
918
|
-
const { DossierStore } = await Promise.resolve().then(() => require("./cases-
|
|
980
|
+
const { DossierStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
919
981
|
await DossierStore.appendFinding(case_id, address, finding, entity_type ?? "unknown");
|
|
920
982
|
return {
|
|
921
983
|
content: [{
|
|
@@ -943,7 +1005,7 @@ async function createProxy() {
|
|
|
943
1005
|
}
|
|
944
1006
|
}, async ({ case_id }) => {
|
|
945
1007
|
try {
|
|
946
|
-
const { SessionStore } = await Promise.resolve().then(() => require("./cases-
|
|
1008
|
+
const { SessionStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
947
1009
|
const session = await SessionStore.start(case_id);
|
|
948
1010
|
return {
|
|
949
1011
|
content: [{
|
|
@@ -971,7 +1033,7 @@ async function createProxy() {
|
|
|
971
1033
|
}
|
|
972
1034
|
}, async ({ case_id, findings, next_steps }) => {
|
|
973
1035
|
try {
|
|
974
|
-
const { SessionStore } = await Promise.resolve().then(() => require("./cases-
|
|
1036
|
+
const { SessionStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
975
1037
|
await SessionStore.end(case_id, {
|
|
976
1038
|
findings: findings ?? "",
|
|
977
1039
|
nextSteps: next_steps ?? ""
|
|
@@ -1016,7 +1078,7 @@ async function createProxy() {
|
|
|
1016
1078
|
}],
|
|
1017
1079
|
isError: true
|
|
1018
1080
|
};
|
|
1019
|
-
const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-
|
|
1081
|
+
const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-BvMb3H2P.cjs"));
|
|
1020
1082
|
const { writeGraphReport } = await Promise.resolve().then(() => require("./graph-reports-B3mkLP8Z.cjs"));
|
|
1021
1083
|
const { ensureArtifactServer } = await Promise.resolve().then(() => require("./artifact-server-XbN16DwU.cjs"));
|
|
1022
1084
|
const result = await addressRisk(remoteClient, {
|
|
@@ -1058,15 +1120,16 @@ async function createProxy() {
|
|
|
1058
1120
|
};
|
|
1059
1121
|
}
|
|
1060
1122
|
});
|
|
1061
|
-
if (!remoteToolNames.has("
|
|
1062
|
-
title: "
|
|
1063
|
-
description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS.
|
|
1123
|
+
if (!remoteToolNames.has("trace_victim_funds")) (0, _modelcontextprotocol_ext_apps_server.registerAppTool)(server, "trace_victim_funds", {
|
|
1124
|
+
title: "Trace Victim Funds",
|
|
1125
|
+
description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS.trace_victim_funds,
|
|
1064
1126
|
inputSchema: {
|
|
1065
|
-
|
|
1127
|
+
victim_addresses: zod.union([zod.string().min(1), zod.array(zod.string().min(1))]).describe("Comma-separated full victim/source addresses, or an array. Min 1, max 5."),
|
|
1066
1128
|
network: zod.string().min(1).describe(NETWORK_DESCRIPTION),
|
|
1067
|
-
|
|
1129
|
+
known_suspect_addresses: zod.union([zod.string(), zod.array(zod.string())]).optional().describe("Known suspect addresses for context only. This tool does not reverse-trace them. Max 5."),
|
|
1068
1130
|
include_attachments: zod.boolean().optional().describe("Include graph app report metadata"),
|
|
1069
1131
|
case_id: zod.string().optional().describe("Optional Chain Insights case ID. When provided, compact evidence is appended to the case manifest."),
|
|
1132
|
+
incident_timestamp_ms: zod.number().min(0).optional().describe("Optional incident timestamp in milliseconds."),
|
|
1070
1133
|
max_hops: zod.number().int().min(1).max(5).optional(),
|
|
1071
1134
|
per_address_limit: zod.number().int().min(1).max(10).optional(),
|
|
1072
1135
|
min_amount_sum: zod.number().min(0).optional()
|
|
@@ -1078,7 +1141,7 @@ async function createProxy() {
|
|
|
1078
1141
|
idempotentHint: false,
|
|
1079
1142
|
openWorldHint: true
|
|
1080
1143
|
}
|
|
1081
|
-
}, async ({
|
|
1144
|
+
}, async ({ victim_addresses, known_suspect_addresses, network, case_id, incident_timestamp_ms, max_hops, per_address_limit, min_amount_sum }) => {
|
|
1082
1145
|
try {
|
|
1083
1146
|
if (!remoteConnected) return {
|
|
1084
1147
|
content: [{
|
|
@@ -1087,21 +1150,22 @@ async function createProxy() {
|
|
|
1087
1150
|
}],
|
|
1088
1151
|
isError: true
|
|
1089
1152
|
};
|
|
1090
|
-
const {
|
|
1153
|
+
const { traceVictimFunds } = await Promise.resolve().then(() => require("./public-tools-BvMb3H2P.cjs"));
|
|
1091
1154
|
const { writeGraphReport } = await Promise.resolve().then(() => require("./graph-reports-B3mkLP8Z.cjs"));
|
|
1092
1155
|
const { ensureArtifactServer } = await Promise.resolve().then(() => require("./artifact-server-XbN16DwU.cjs"));
|
|
1093
|
-
const result = await
|
|
1094
|
-
|
|
1095
|
-
|
|
1156
|
+
const result = await traceVictimFunds(remoteClient, config, {
|
|
1157
|
+
victimAddresses: victim_addresses,
|
|
1158
|
+
knownSuspectAddresses: known_suspect_addresses,
|
|
1096
1159
|
network,
|
|
1097
1160
|
caseId: case_id,
|
|
1161
|
+
incidentTimestampMs: incident_timestamp_ms,
|
|
1098
1162
|
maxHops: max_hops,
|
|
1099
1163
|
perAddressLimit: per_address_limit,
|
|
1100
1164
|
minAmountSum: min_amount_sum
|
|
1101
1165
|
});
|
|
1102
1166
|
const report = await writeGraphReport(result.graphData, {
|
|
1103
1167
|
serverPort: config.serverPort,
|
|
1104
|
-
slug: `
|
|
1168
|
+
slug: `trace-victim-funds-${network}`
|
|
1105
1169
|
});
|
|
1106
1170
|
await ensureArtifactServer(config.serverPort);
|
|
1107
1171
|
return {
|
|
@@ -1127,22 +1191,24 @@ async function createProxy() {
|
|
|
1127
1191
|
return {
|
|
1128
1192
|
content: [{
|
|
1129
1193
|
type: "text",
|
|
1130
|
-
text: `
|
|
1194
|
+
text: `Trace victim funds failed: ${err.message}`
|
|
1131
1195
|
}],
|
|
1132
1196
|
isError: true
|
|
1133
1197
|
};
|
|
1134
1198
|
}
|
|
1135
1199
|
});
|
|
1136
|
-
if (!remoteToolNames.has("
|
|
1137
|
-
title: "
|
|
1138
|
-
description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS.
|
|
1200
|
+
if (!remoteToolNames.has("trace_suspect_funds")) (0, _modelcontextprotocol_ext_apps_server.registerAppTool)(server, "trace_suspect_funds", {
|
|
1201
|
+
title: "Trace Suspect Funds",
|
|
1202
|
+
description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS.trace_suspect_funds,
|
|
1139
1203
|
inputSchema: {
|
|
1140
1204
|
network: zod.string().min(1).describe(NETWORK_DESCRIPTION),
|
|
1141
|
-
|
|
1142
|
-
incident_timestamp_ms: zod.number().min(0).describe("
|
|
1143
|
-
max_hops: zod.number().int().min(1).max(
|
|
1144
|
-
|
|
1145
|
-
|
|
1205
|
+
suspect_addresses: zod.union([zod.string().min(1), zod.array(zod.string().min(1))]).describe("Comma-separated full suspect-controlled addresses, or an array. Min 1, max 5."),
|
|
1206
|
+
incident_timestamp_ms: zod.number().min(0).optional().describe("Optional incident timestamp in milliseconds. This tool works without it."),
|
|
1207
|
+
max_hops: zod.number().int().min(1).max(5).optional().describe("Maximum forward trace hops. Default 3."),
|
|
1208
|
+
per_address_limit: zod.number().int().min(1).max(10).optional(),
|
|
1209
|
+
min_amount_sum: zod.number().min(0).optional(),
|
|
1210
|
+
case_id: zod.string().optional().describe("Optional Chain Insights case ID. When provided, compact evidence is appended to the case manifest."),
|
|
1211
|
+
include_attachments: zod.boolean().optional().describe("Include graph app report metadata")
|
|
1146
1212
|
},
|
|
1147
1213
|
_meta: { ui: { resourceUri: GRAPH_RESOURCE_URI } },
|
|
1148
1214
|
annotations: {
|
|
@@ -1151,7 +1217,7 @@ async function createProxy() {
|
|
|
1151
1217
|
idempotentHint: false,
|
|
1152
1218
|
openWorldHint: true
|
|
1153
1219
|
}
|
|
1154
|
-
}, async ({
|
|
1220
|
+
}, async ({ suspect_addresses, incident_timestamp_ms, network, max_hops, per_address_limit, min_amount_sum, case_id }) => {
|
|
1155
1221
|
try {
|
|
1156
1222
|
if (!remoteConnected) return {
|
|
1157
1223
|
content: [{
|
|
@@ -1160,20 +1226,90 @@ async function createProxy() {
|
|
|
1160
1226
|
}],
|
|
1161
1227
|
isError: true
|
|
1162
1228
|
};
|
|
1163
|
-
const {
|
|
1229
|
+
const { traceSuspectFunds } = await Promise.resolve().then(() => require("./public-tools-BvMb3H2P.cjs"));
|
|
1164
1230
|
const { writeGraphReport } = await Promise.resolve().then(() => require("./graph-reports-B3mkLP8Z.cjs"));
|
|
1165
1231
|
const { ensureArtifactServer } = await Promise.resolve().then(() => require("./artifact-server-XbN16DwU.cjs"));
|
|
1166
|
-
const result = await
|
|
1167
|
-
|
|
1232
|
+
const result = await traceSuspectFunds(remoteClient, config, {
|
|
1233
|
+
suspectAddresses: suspect_addresses,
|
|
1168
1234
|
network,
|
|
1169
1235
|
maxHops: max_hops,
|
|
1236
|
+
perAddressLimit: per_address_limit,
|
|
1237
|
+
minAmountSum: min_amount_sum,
|
|
1170
1238
|
incidentTimestampMs: incident_timestamp_ms,
|
|
1171
|
-
activityPolicyMode: activity_policy,
|
|
1172
1239
|
caseId: case_id
|
|
1173
1240
|
});
|
|
1174
1241
|
const report = await writeGraphReport(result.graphData, {
|
|
1175
1242
|
serverPort: config.serverPort,
|
|
1176
|
-
slug: `
|
|
1243
|
+
slug: `trace-suspect-funds-${network}`
|
|
1244
|
+
});
|
|
1245
|
+
await ensureArtifactServer(config.serverPort);
|
|
1246
|
+
return {
|
|
1247
|
+
content: [{
|
|
1248
|
+
type: "text",
|
|
1249
|
+
text: result.summaryText
|
|
1250
|
+
}],
|
|
1251
|
+
structuredContent: result.structuredContent,
|
|
1252
|
+
_meta: { chainInsights: { graph: {
|
|
1253
|
+
schema: report.schema,
|
|
1254
|
+
url: report.url
|
|
1255
|
+
} } },
|
|
1256
|
+
isError: false
|
|
1257
|
+
};
|
|
1258
|
+
} catch (err) {
|
|
1259
|
+
if (err instanceof require_client.PaymentRequiredError) return {
|
|
1260
|
+
content: [{
|
|
1261
|
+
type: "text",
|
|
1262
|
+
text: err.message
|
|
1263
|
+
}],
|
|
1264
|
+
isError: true
|
|
1265
|
+
};
|
|
1266
|
+
return {
|
|
1267
|
+
content: [{
|
|
1268
|
+
type: "text",
|
|
1269
|
+
text: `Trace suspect funds failed: ${err.message}`
|
|
1270
|
+
}],
|
|
1271
|
+
isError: true
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
});
|
|
1275
|
+
if (!remoteToolNames.has("trace_deposit_sources")) (0, _modelcontextprotocol_ext_apps_server.registerAppTool)(server, "trace_deposit_sources", {
|
|
1276
|
+
title: "Trace Deposit Sources",
|
|
1277
|
+
description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS.trace_deposit_sources,
|
|
1278
|
+
inputSchema: {
|
|
1279
|
+
network: zod.string().min(1).describe(NETWORK_DESCRIPTION),
|
|
1280
|
+
deposit_addresses: zod.union([zod.string().min(1), zod.array(zod.string().min(1))]).describe("Comma-separated full suspected deposit/cashout addresses, or an array. Min 1, max 5."),
|
|
1281
|
+
max_hops: zod.number().int().min(1).max(5).optional().describe("Maximum reverse traceback hops. Default 2."),
|
|
1282
|
+
case_id: zod.string().optional().describe("Optional Chain Insights case ID. When provided, compact evidence is appended to the case manifest."),
|
|
1283
|
+
include_attachments: zod.boolean().optional().describe("Include graph app report metadata")
|
|
1284
|
+
},
|
|
1285
|
+
_meta: { ui: { resourceUri: GRAPH_RESOURCE_URI } },
|
|
1286
|
+
annotations: {
|
|
1287
|
+
readOnlyHint: false,
|
|
1288
|
+
destructiveHint: false,
|
|
1289
|
+
idempotentHint: false,
|
|
1290
|
+
openWorldHint: true
|
|
1291
|
+
}
|
|
1292
|
+
}, async ({ deposit_addresses, network, max_hops, case_id }) => {
|
|
1293
|
+
try {
|
|
1294
|
+
if (!remoteConnected) return {
|
|
1295
|
+
content: [{
|
|
1296
|
+
type: "text",
|
|
1297
|
+
text: `${remoteUnavailableMessage ?? `Graph MCP is not connected at ${graphMcpEndpoint}`}. Restart the Chain Insights MCP proxy after the endpoint is reachable.`
|
|
1298
|
+
}],
|
|
1299
|
+
isError: true
|
|
1300
|
+
};
|
|
1301
|
+
const { traceDepositSources } = await Promise.resolve().then(() => require("./public-tools-BvMb3H2P.cjs"));
|
|
1302
|
+
const { writeGraphReport } = await Promise.resolve().then(() => require("./graph-reports-B3mkLP8Z.cjs"));
|
|
1303
|
+
const { ensureArtifactServer } = await Promise.resolve().then(() => require("./artifact-server-XbN16DwU.cjs"));
|
|
1304
|
+
const result = await traceDepositSources(remoteClient, config, {
|
|
1305
|
+
depositAddresses: deposit_addresses,
|
|
1306
|
+
network,
|
|
1307
|
+
maxHops: max_hops,
|
|
1308
|
+
caseId: case_id
|
|
1309
|
+
});
|
|
1310
|
+
const report = await writeGraphReport(result.graphData, {
|
|
1311
|
+
serverPort: config.serverPort,
|
|
1312
|
+
slug: `trace-deposit-sources-${network}`
|
|
1177
1313
|
});
|
|
1178
1314
|
await ensureArtifactServer(config.serverPort);
|
|
1179
1315
|
return {
|
|
@@ -1199,7 +1335,7 @@ async function createProxy() {
|
|
|
1199
1335
|
return {
|
|
1200
1336
|
content: [{
|
|
1201
1337
|
type: "text",
|
|
1202
|
-
text: `
|
|
1338
|
+
text: `Trace deposit sources failed: ${err.message}`
|
|
1203
1339
|
}],
|
|
1204
1340
|
isError: true
|
|
1205
1341
|
};
|
|
@@ -1237,7 +1373,7 @@ async function createProxy() {
|
|
|
1237
1373
|
}],
|
|
1238
1374
|
isError: true
|
|
1239
1375
|
};
|
|
1240
|
-
const { stakeInsights } = await Promise.resolve().then(() => require("./public-tools-
|
|
1376
|
+
const { stakeInsights } = await Promise.resolve().then(() => require("./public-tools-BvMb3H2P.cjs"));
|
|
1241
1377
|
const { writeGraphReport } = await Promise.resolve().then(() => require("./graph-reports-B3mkLP8Z.cjs"));
|
|
1242
1378
|
const { ensureArtifactServer } = await Promise.resolve().then(() => require("./artifact-server-XbN16DwU.cjs"));
|
|
1243
1379
|
const result = await stakeInsights(remoteClient, {
|
|
@@ -1302,8 +1438,9 @@ async function createProxy() {
|
|
|
1302
1438
|
"- network_capabilities: inspect supported networks, data layers, tool availability, retention windows, and freshness.",
|
|
1303
1439
|
"- address_risk: screen a full address for AML risk, behavior, neighborhood, exchange exposure, and optional compare_address connection checks.",
|
|
1304
1440
|
"- stake_insights: explain Bittensor staking around one address, coldkey, or hotkey with net stake, movement amounts, counterparties, backend, and query evidence.",
|
|
1305
|
-
"-
|
|
1306
|
-
"-
|
|
1441
|
+
"- trace_victim_funds: trace up to five victim/source addresses forward to exchange deposit candidates.",
|
|
1442
|
+
"- trace_deposit_sources: trace backward from suspected deposit/cashout addresses to upstream funders and shared-source convergence.",
|
|
1443
|
+
"- trace_suspect_funds: trace up to five suspected scammer, mule, operator, or laundering-ring addresses forward to cashout topology.",
|
|
1307
1444
|
"- graph_query: run read-only GQL/Cypher through the universal graph endpoint. Use USE live_topology, USE archive_topology, or USE facts.",
|
|
1308
1445
|
"- graph_query_batch: run related read-only graph-language queries through one paid graph call.",
|
|
1309
1446
|
"",
|
|
@@ -1313,6 +1450,7 @@ async function createProxy() {
|
|
|
1313
1450
|
"- case_resume: load case context, evidence count, dossiers, and latest session.",
|
|
1314
1451
|
"- case_add_evidence: append a report or note to the case evidence manifest.",
|
|
1315
1452
|
"- case_verify_evidence: verify saved evidence integrity.",
|
|
1453
|
+
"- case_export: export a case for Obsidian, LLMWiki, Codex, Claude Code, and ChatGPT.",
|
|
1316
1454
|
"- case_update_dossier: add a finding to an address/entity dossier.",
|
|
1317
1455
|
"- case_start_session and case_end_session: record session notes.",
|
|
1318
1456
|
"",
|
package/dist/mcp-proxy.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-proxy.d.cts","names":[],"sources":["../src/mcp/proxy.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"mcp-proxy.d.cts","names":[],"sources":["../src/mcp/proxy.ts"],"mappings":";;AAkzBA;;;;AAA4C;;iBAAtB,WAAA,CAAA,GAAe,OAAO"}
|
package/dist/mcp-proxy.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-proxy.d.mts","names":[],"sources":["../src/mcp/proxy.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"mcp-proxy.d.mts","names":[],"sources":["../src/mcp/proxy.ts"],"mappings":";;AAkzBA;;;;AAA4C;;iBAAtB,WAAA,CAAA,GAAe,OAAO"}
|