chain-insights 0.3.7 → 0.3.11
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 +5 -0
- package/dist/{app-BxojXjtB.cjs → app-DjJn3irw.cjs} +1 -1
- package/dist/{app-CRd39JJ8.mjs → app-norpwdou.mjs} +2 -2
- package/dist/{app-CRd39JJ8.mjs.map → app-norpwdou.mjs.map} +1 -1
- package/dist/{artifact-server-XbN16DwU.cjs → artifact-server-C6_gtIql.cjs} +1 -1
- package/dist/{artifact-server-CP6LXQ9d.mjs → artifact-server-DHPM0lxS.mjs} +2 -2
- package/dist/{artifact-server-CP6LXQ9d.mjs.map → artifact-server-DHPM0lxS.mjs.map} +1 -1
- package/dist/{capabilities-BC3Y5EOi.mjs → capabilities-BCvkTkIu.mjs} +3 -6
- package/dist/capabilities-BCvkTkIu.mjs.map +1 -0
- package/dist/{capabilities-D5PSx9Hj.cjs → capabilities-DOa6EFO-.cjs} +2 -5
- package/dist/cli.cjs +58 -31
- package/dist/cli.mjs +58 -31
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-D4JE7fFF.mjs → client-BgmHjBHQ.mjs} +15 -7
- package/dist/client-BgmHjBHQ.mjs.map +1 -0
- package/dist/{client-Db6IV1tv.cjs → client-Y_zqKqJT.cjs} +19 -5
- package/dist/{config-Drgc2HuF.mjs → config-C6zM8Xir.mjs} +3 -3
- package/dist/{config-Drgc2HuF.mjs.map → config-C6zM8Xir.mjs.map} +1 -1
- package/dist/{config-BwVx19Og.cjs → config-CkW404Cs.cjs} +2 -2
- package/dist/index.cjs +4 -4
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4 -4
- package/dist/{init-CKQ6F07J.mjs → init-uAmPfio2.mjs} +2 -2
- package/dist/{init-CKQ6F07J.mjs.map → init-uAmPfio2.mjs.map} +1 -1
- package/dist/{init-Dhw8F23z.cjs → init-vj2v5PMP.cjs} +1 -1
- package/dist/{mcp-endpoint-DHs1cRFH.mjs → mcp-endpoint-QQ5Lbqc2.mjs} +5 -2
- package/dist/mcp-endpoint-QQ5Lbqc2.mjs.map +1 -0
- package/dist/{mcp-endpoint-BaV8h_lq.cjs → mcp-endpoint-cQIZSjkK.cjs} +4 -1
- package/dist/mcp-proxy.cjs +444 -410
- package/dist/mcp-proxy.d.cts +3 -1
- package/dist/mcp-proxy.d.cts.map +1 -1
- package/dist/mcp-proxy.d.mts +3 -1
- package/dist/mcp-proxy.d.mts.map +1 -1
- package/dist/mcp-proxy.mjs +444 -411
- package/dist/mcp-proxy.mjs.map +1 -1
- package/dist/{public-tools-xfVNz9NE.cjs → public-tools-BY3PTw6x.cjs} +59 -31
- package/dist/{public-tools-CyUZEz9B.mjs → public-tools-CvlZcysd.mjs} +60 -32
- package/dist/public-tools-CvlZcysd.mjs.map +1 -0
- package/dist/{runner-DWuSy1Se.mjs → runner-B9fXAP0t.mjs} +3 -3
- package/dist/{runner-DWuSy1Se.mjs.map → runner-B9fXAP0t.mjs.map} +1 -1
- package/dist/{runner-CVo41fjz.cjs → runner-CcZCrrkn.cjs} +2 -2
- package/dist/{schema-BFEWhzg7.mjs → schema-D_qwaQA5.mjs} +2 -2
- package/dist/{schema-BFEWhzg7.mjs.map → schema-D_qwaQA5.mjs.map} +1 -1
- package/dist/{schema-Vl9yuOFO.cjs → schema-Dr6JXSOF.cjs} +1 -1
- package/dist/{server-BXLX2j_A.mjs → server-86dyCsJO.mjs} +2 -2
- package/dist/{server-BXLX2j_A.mjs.map → server-86dyCsJO.mjs.map} +1 -1
- package/dist/{server-BqVdWath.cjs → server-B2NFmnCM.cjs} +1 -1
- package/dist/update-BJoXYucO.cjs +145 -0
- package/dist/update-CJUfGCxs.mjs +145 -0
- package/dist/update-CJUfGCxs.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/capabilities-BC3Y5EOi.mjs.map +0 -1
- package/dist/client-D4JE7fFF.mjs.map +0 -1
- package/dist/mcp-endpoint-DHs1cRFH.mjs.map +0 -1
- package/dist/public-tools-CyUZEz9B.mjs.map +0 -1
package/dist/mcp-proxy.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as PACKAGE_VERSION } from "./version-BA3J8hu4.mjs";
|
|
2
|
-
import { t as PaymentRequiredError } from "./client-
|
|
2
|
+
import { t as PaymentRequiredError } from "./client-BgmHjBHQ.mjs";
|
|
3
3
|
import { t as HIDDEN_REMOTE_TOOL_NAMES } from "./tool-visibility-BpyZHRBi.mjs";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import path from "node:path";
|
|
@@ -41,6 +41,12 @@ const GRAPH_ARRAY_KEYS = [
|
|
|
41
41
|
"edge_anchors"
|
|
42
42
|
];
|
|
43
43
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
44
|
+
function resolveMcpProxyMode(env = process.env) {
|
|
45
|
+
const raw = env["CHAIN_INSIGHTS_MCP_PROXY_MODE"]?.trim().toLowerCase();
|
|
46
|
+
if (!raw || raw === "workspace") return "workspace";
|
|
47
|
+
if (raw === "stateless" || raw === "no-workspace" || raw === "workspace-less") return "stateless";
|
|
48
|
+
throw new Error(`CHAIN_INSIGHTS_MCP_PROXY_MODE must be workspace or stateless; got "${raw}"`);
|
|
49
|
+
}
|
|
44
50
|
const COMMA_SEPARATED_ADDRESS_FIELDS = new Set([
|
|
45
51
|
"victim_addresses",
|
|
46
52
|
"known_suspect_addresses",
|
|
@@ -113,6 +119,13 @@ const SERVER_INSTRUCTIONS = [
|
|
|
113
119
|
GRAPH_SCHEMA_HINTS,
|
|
114
120
|
"Presentation rules: preserve tool summaries as returned; never truncate blockchain addresses; use case tools to preserve evidence when a case exists."
|
|
115
121
|
].join("\n\n");
|
|
122
|
+
const STATELESS_SERVER_INSTRUCTIONS = [
|
|
123
|
+
"Chain Insights is running as a stateless AML proxy for a host application.",
|
|
124
|
+
"Do not use local case, evidence, dossier, session, wallet, or graph report workflows in this mode.",
|
|
125
|
+
"Use network_capabilities first when network support is unknown, then call address_risk, stake_insights, trace_victim_funds, trace_suspect_funds, trace_deposit_sources, graph_query, or graph_query_batch as needed.",
|
|
126
|
+
GRAPH_SCHEMA_HINTS,
|
|
127
|
+
"Presentation rules: preserve tool summaries as returned; never truncate blockchain addresses."
|
|
128
|
+
].join("\n\n");
|
|
116
129
|
function readGraphAppHtml() {
|
|
117
130
|
const candidates = [
|
|
118
131
|
path.resolve(__dirname, "templates", "graph.html"),
|
|
@@ -566,12 +579,12 @@ function getRemoteGraphPayload(result) {
|
|
|
566
579
|
if (!data || typeof data !== "object" || Array.isArray(data)) throw new Error("Invalid remote graph payload");
|
|
567
580
|
return data;
|
|
568
581
|
}
|
|
569
|
-
async function normalizeRemoteToolResult(result, config, toolName = "remote-graph") {
|
|
582
|
+
async function normalizeRemoteToolResult(result, config, toolName = "remote-graph", includeAttachments = true) {
|
|
570
583
|
const graphPayload = getRemoteGraphPayload(result);
|
|
571
584
|
const meta = { ...result._meta ?? {} };
|
|
572
|
-
if (graphPayload) {
|
|
585
|
+
if (graphPayload && includeAttachments) {
|
|
573
586
|
const { writeGraphReport } = await import("./graph-reports-BDELxmpi.mjs");
|
|
574
|
-
const { ensureArtifactServer } = await import("./artifact-server-
|
|
587
|
+
const { ensureArtifactServer } = await import("./artifact-server-DHPM0lxS.mjs");
|
|
575
588
|
const report = await writeGraphReport(graphPayload, {
|
|
576
589
|
serverPort: config.serverPort,
|
|
577
590
|
slug: toolName || "remote-graph"
|
|
@@ -592,6 +605,26 @@ async function normalizeRemoteToolResult(result, config, toolName = "remote-grap
|
|
|
592
605
|
isError: result.isError
|
|
593
606
|
};
|
|
594
607
|
}
|
|
608
|
+
function shouldIncludeAttachments(args, workspaceArtifactsEnabled) {
|
|
609
|
+
return workspaceArtifactsEnabled && args["include_attachments"] !== false;
|
|
610
|
+
}
|
|
611
|
+
async function writeLocalGraphMeta(graphData, config, slug, includeAttachments) {
|
|
612
|
+
if (!includeAttachments) return void 0;
|
|
613
|
+
const { writeGraphReport } = await import("./graph-reports-BDELxmpi.mjs");
|
|
614
|
+
const { ensureArtifactServer } = await import("./artifact-server-DHPM0lxS.mjs");
|
|
615
|
+
const report = await writeGraphReport(graphData, {
|
|
616
|
+
serverPort: config.serverPort,
|
|
617
|
+
slug
|
|
618
|
+
});
|
|
619
|
+
await ensureArtifactServer(config.serverPort);
|
|
620
|
+
return {
|
|
621
|
+
schema: report.schema,
|
|
622
|
+
url: report.url
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
function graphMetaResult(graph) {
|
|
626
|
+
return graph ? { chainInsights: { graph } } : void 0;
|
|
627
|
+
}
|
|
595
628
|
/**
|
|
596
629
|
* Core proxy logic — exported so tests can inject dependencies directly.
|
|
597
630
|
* The IIFE at the bottom calls this with real dependencies.
|
|
@@ -600,20 +633,23 @@ async function normalizeRemoteToolResult(result, config, toolName = "remote-grap
|
|
|
600
633
|
* All diagnostic output goes to console.error() or process.stderr.write().
|
|
601
634
|
*/
|
|
602
635
|
async function createProxy() {
|
|
603
|
-
const { loadConfig } = await import("./config-
|
|
636
|
+
const { loadConfig } = await import("./config-C6zM8Xir.mjs").then((n) => n.t);
|
|
604
637
|
const { activeDataDir, findActiveWorkspace } = await import("./active-ByNgjuAg.mjs").then((n) => n.n);
|
|
605
|
-
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-
|
|
638
|
+
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-BgmHjBHQ.mjs").then((n) => n.r);
|
|
606
639
|
const { loadSchema, saveSchema } = await import("./schema-cache-DwDvPy4e.mjs");
|
|
640
|
+
const proxyMode = resolveMcpProxyMode();
|
|
641
|
+
const workspaceArtifactsEnabled = proxyMode === "workspace";
|
|
607
642
|
const loadedConfig = await loadConfig();
|
|
608
|
-
const activeWorkspace = findActiveWorkspace();
|
|
643
|
+
const activeWorkspace = workspaceArtifactsEnabled ? findActiveWorkspace() : null;
|
|
609
644
|
const config = {
|
|
610
645
|
...loadedConfig,
|
|
611
|
-
dataDir: activeDataDir(loadedConfig.dataDir)
|
|
646
|
+
dataDir: workspaceArtifactsEnabled ? activeDataDir(loadedConfig.dataDir) : loadedConfig.dataDir
|
|
612
647
|
};
|
|
613
648
|
const logger = createMcpLogger(config);
|
|
614
649
|
await logger.info("proxy.start", {
|
|
615
650
|
data_dir: config.dataDir,
|
|
616
651
|
workspace_root: activeWorkspace?.root,
|
|
652
|
+
proxy_mode: proxyMode,
|
|
617
653
|
graph_mcp_mode: config.graphMcpMode,
|
|
618
654
|
graph_mcp_endpoint: resolveGraphMcpEndpoint(config),
|
|
619
655
|
log_path: logger.filePath
|
|
@@ -690,7 +726,7 @@ async function createProxy() {
|
|
|
690
726
|
const server = new McpServer({
|
|
691
727
|
name: "chain-insights",
|
|
692
728
|
version: PACKAGE_VERSION
|
|
693
|
-
}, { instructions: SERVER_INSTRUCTIONS });
|
|
729
|
+
}, { instructions: workspaceArtifactsEnabled ? SERVER_INSTRUCTIONS : STATELESS_SERVER_INSTRUCTIONS });
|
|
694
730
|
installToolLogging(server, logger);
|
|
695
731
|
const remotePrompts = [];
|
|
696
732
|
if (remoteConnected) try {
|
|
@@ -718,337 +754,339 @@ async function createProxy() {
|
|
|
718
754
|
if (typeof tags === "string") return tags.split(",").map((tag) => tag.trim()).filter(Boolean);
|
|
719
755
|
return [];
|
|
720
756
|
};
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
757
|
+
if (workspaceArtifactsEnabled) {
|
|
758
|
+
server.registerTool("balance", {
|
|
759
|
+
description: "Show the local Chain Insights payment wallet address and Base USDC balance.",
|
|
760
|
+
inputSchema: z.object({}).passthrough()
|
|
761
|
+
}, async () => {
|
|
762
|
+
try {
|
|
763
|
+
const { getWalletAccount, getWalletBalanceText } = await import("./tools-v6kcdojg.mjs").then((n) => n.c);
|
|
764
|
+
return {
|
|
765
|
+
content: [{
|
|
766
|
+
type: "text",
|
|
767
|
+
text: await getWalletBalanceText(await getWalletAccount())
|
|
768
|
+
}],
|
|
769
|
+
isError: false
|
|
770
|
+
};
|
|
771
|
+
} catch (err) {
|
|
772
|
+
return {
|
|
773
|
+
content: [{
|
|
774
|
+
type: "text",
|
|
775
|
+
text: `Balance failed: ${err.message}`
|
|
776
|
+
}],
|
|
777
|
+
isError: true
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
});
|
|
781
|
+
registerAppResource(server, "Fund Flow Graph", GRAPH_RESOURCE_URI, {
|
|
782
|
+
description: "Interactive D3 force-directed graph for fund flow and pattern visualization. It loads local graph report URLs returned in _meta.chainInsights.graph.url.",
|
|
783
|
+
_meta: { ui: { csp: {
|
|
784
|
+
resourceDomains: graphArtifactOrigins(config),
|
|
785
|
+
connectDomains: graphArtifactOrigins(config)
|
|
786
|
+
} } }
|
|
787
|
+
}, async () => ({ contents: [{
|
|
788
|
+
uri: GRAPH_RESOURCE_URI,
|
|
789
|
+
mimeType: RESOURCE_MIME_TYPE,
|
|
790
|
+
text: readGraphAppHtml(),
|
|
791
|
+
_meta: { ui: { csp: {
|
|
792
|
+
resourceDomains: graphArtifactOrigins(config),
|
|
793
|
+
connectDomains: graphArtifactOrigins(config)
|
|
794
|
+
} } }
|
|
795
|
+
}] }));
|
|
796
|
+
server.registerTool("case_open", {
|
|
797
|
+
description: "Create a local Chain Insights investigation case. Use this before saving evidence, dossiers, or session notes for a new investigation.",
|
|
798
|
+
inputSchema: {
|
|
799
|
+
name: z.string().min(1).describe("Case name"),
|
|
800
|
+
tags: z.union([z.string(), z.array(z.string())]).optional().describe("Comma-separated tags or string array"),
|
|
801
|
+
description: z.string().optional().describe("Brief investigation description")
|
|
802
|
+
},
|
|
803
|
+
annotations: {
|
|
804
|
+
readOnlyHint: false,
|
|
805
|
+
destructiveHint: false,
|
|
806
|
+
idempotentHint: false,
|
|
807
|
+
openWorldHint: false
|
|
808
|
+
}
|
|
809
|
+
}, async ({ name, tags, description }) => {
|
|
810
|
+
try {
|
|
811
|
+
const { CaseStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
812
|
+
const created = await CaseStore.create({
|
|
813
|
+
name,
|
|
814
|
+
tags: parseTags(tags),
|
|
815
|
+
description: description ?? ""
|
|
816
|
+
});
|
|
817
|
+
const { casesRoot } = await import("./store-C2B_AssI.mjs").then((n) => n.n);
|
|
818
|
+
return {
|
|
819
|
+
content: [{
|
|
820
|
+
type: "text",
|
|
821
|
+
text: JSON.stringify({
|
|
822
|
+
case_id: created.id,
|
|
823
|
+
name: created.name,
|
|
824
|
+
status: created.status,
|
|
825
|
+
tags: created.tags,
|
|
826
|
+
directory: `${path.join(casesRoot(), created.id)}/`
|
|
827
|
+
}, null, 2)
|
|
828
|
+
}],
|
|
829
|
+
isError: false
|
|
830
|
+
};
|
|
831
|
+
} catch (err) {
|
|
832
|
+
return caseToolError("Case open", err);
|
|
833
|
+
}
|
|
834
|
+
});
|
|
835
|
+
server.registerTool("case_list", {
|
|
836
|
+
description: "List local Chain Insights investigation cases. Use before resuming when the user does not provide a case ID.",
|
|
837
|
+
inputSchema: { status: z.enum([
|
|
838
|
+
"open",
|
|
839
|
+
"active",
|
|
840
|
+
"suspended",
|
|
841
|
+
"closed"
|
|
842
|
+
]).optional().describe("Optional status filter") },
|
|
843
|
+
annotations: {
|
|
844
|
+
readOnlyHint: true,
|
|
845
|
+
destructiveHint: false,
|
|
846
|
+
idempotentHint: true,
|
|
847
|
+
openWorldHint: false
|
|
848
|
+
}
|
|
849
|
+
}, async ({ status }) => {
|
|
850
|
+
try {
|
|
851
|
+
const { CaseStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
852
|
+
const cases = await CaseStore.list();
|
|
853
|
+
const filtered = status ? cases.filter((entry) => entry.status === status) : cases;
|
|
854
|
+
return {
|
|
855
|
+
content: [{
|
|
856
|
+
type: "text",
|
|
857
|
+
text: JSON.stringify({ cases: filtered }, null, 2)
|
|
858
|
+
}],
|
|
859
|
+
isError: false
|
|
860
|
+
};
|
|
861
|
+
} catch (err) {
|
|
862
|
+
return caseToolError("Case list", err);
|
|
863
|
+
}
|
|
864
|
+
});
|
|
865
|
+
server.registerTool("case_resume", {
|
|
866
|
+
description: "Load local Chain Insights case context: metadata, evidence count, dossier summaries, and latest session notes.",
|
|
867
|
+
inputSchema: { case_id: z.string().min(1).describe("Chain Insights case ID") },
|
|
868
|
+
annotations: {
|
|
869
|
+
readOnlyHint: true,
|
|
870
|
+
destructiveHint: false,
|
|
871
|
+
idempotentHint: true,
|
|
872
|
+
openWorldHint: false
|
|
873
|
+
}
|
|
874
|
+
}, async ({ case_id }) => {
|
|
875
|
+
try {
|
|
876
|
+
const { CaseStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
877
|
+
const context = await CaseStore.loadContext(case_id);
|
|
878
|
+
return {
|
|
879
|
+
content: [{
|
|
880
|
+
type: "text",
|
|
881
|
+
text: JSON.stringify(context, null, 2)
|
|
882
|
+
}],
|
|
883
|
+
isError: false
|
|
884
|
+
};
|
|
885
|
+
} catch (err) {
|
|
886
|
+
return caseToolError("Case resume", err);
|
|
887
|
+
}
|
|
888
|
+
});
|
|
889
|
+
server.registerTool("case_add_evidence", {
|
|
890
|
+
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.",
|
|
891
|
+
inputSchema: {
|
|
892
|
+
case_id: z.string().min(1).describe("Chain Insights case ID"),
|
|
893
|
+
source: z.string().min(1).describe("Source tool or evidence origin"),
|
|
894
|
+
content: z.string().min(1).describe("Evidence markdown/text to store"),
|
|
895
|
+
query_params: z.string().optional().describe("Original query parameters, for example \"network=bittensor address=...\"")
|
|
896
|
+
},
|
|
897
|
+
annotations: {
|
|
898
|
+
readOnlyHint: false,
|
|
899
|
+
destructiveHint: false,
|
|
900
|
+
idempotentHint: false,
|
|
901
|
+
openWorldHint: false
|
|
902
|
+
}
|
|
903
|
+
}, async ({ case_id, source, content, query_params }) => {
|
|
904
|
+
try {
|
|
905
|
+
const { EvidenceStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
906
|
+
const saved = await EvidenceStore.append(case_id, {
|
|
907
|
+
source,
|
|
908
|
+
content,
|
|
909
|
+
queryParams: query_params ?? ""
|
|
910
|
+
});
|
|
911
|
+
return {
|
|
912
|
+
content: [{
|
|
913
|
+
type: "text",
|
|
914
|
+
text: JSON.stringify(saved, null, 2)
|
|
915
|
+
}],
|
|
916
|
+
isError: false
|
|
917
|
+
};
|
|
918
|
+
} catch (err) {
|
|
919
|
+
return caseToolError("Evidence append", err);
|
|
920
|
+
}
|
|
921
|
+
});
|
|
922
|
+
server.registerTool("case_verify_evidence", {
|
|
923
|
+
description: "Verify a local case evidence manifest and report tampered or missing evidence files.",
|
|
924
|
+
inputSchema: { case_id: z.string().min(1).describe("Chain Insights case ID") },
|
|
925
|
+
annotations: {
|
|
926
|
+
readOnlyHint: true,
|
|
927
|
+
destructiveHint: false,
|
|
928
|
+
idempotentHint: true,
|
|
929
|
+
openWorldHint: false
|
|
930
|
+
}
|
|
931
|
+
}, async ({ case_id }) => {
|
|
932
|
+
try {
|
|
933
|
+
const { EvidenceStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
934
|
+
const result = await EvidenceStore.verifyManifest(case_id);
|
|
935
|
+
return {
|
|
936
|
+
content: [{
|
|
937
|
+
type: "text",
|
|
938
|
+
text: JSON.stringify(result, null, 2)
|
|
939
|
+
}],
|
|
940
|
+
isError: false
|
|
941
|
+
};
|
|
942
|
+
} catch (err) {
|
|
943
|
+
return caseToolError("Evidence verify", err);
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
server.registerTool("case_export", {
|
|
947
|
+
description: "Export a Chain Insights case to an Obsidian, LLM Wiki, Codex, Claude Code, and ChatGPT-friendly handoff bundle.",
|
|
948
|
+
inputSchema: {
|
|
949
|
+
case_id: z.string().min(1).describe("Chain Insights case ID to export"),
|
|
950
|
+
target: z.enum(["obsidian-llmwiki"]).optional().describe("Export target. Default obsidian-llmwiki."),
|
|
951
|
+
mode: z.enum([
|
|
952
|
+
"private",
|
|
953
|
+
"partner",
|
|
954
|
+
"public"
|
|
955
|
+
]).optional().describe("Redaction mode. Default private."),
|
|
956
|
+
output_dir: z.string().optional().describe("Optional output directory. Defaults to published/<case-slug>.")
|
|
957
|
+
},
|
|
958
|
+
annotations: {
|
|
959
|
+
readOnlyHint: false,
|
|
960
|
+
destructiveHint: false,
|
|
961
|
+
idempotentHint: false,
|
|
962
|
+
openWorldHint: false
|
|
963
|
+
}
|
|
964
|
+
}, async ({ case_id, target, mode, output_dir }) => {
|
|
965
|
+
try {
|
|
966
|
+
const { exportCase } = await import("./export-CBhcJuZ6.mjs");
|
|
967
|
+
const result = await exportCase({
|
|
968
|
+
caseId: case_id,
|
|
969
|
+
target: target ?? "obsidian-llmwiki",
|
|
970
|
+
mode: mode ?? "private",
|
|
971
|
+
outputDir: output_dir
|
|
972
|
+
});
|
|
973
|
+
return {
|
|
974
|
+
content: [{
|
|
975
|
+
type: "text",
|
|
976
|
+
text: [
|
|
977
|
+
`Case exported: ${result.outputDir}`,
|
|
978
|
+
`Manifest: ${result.manifestPath}`,
|
|
979
|
+
`Files: ${result.fileCount}`,
|
|
980
|
+
`Open first: ${result.nextFile}`,
|
|
981
|
+
...result.warnings.map((warning) => `Warning: ${warning}`)
|
|
982
|
+
].join("\n")
|
|
983
|
+
}],
|
|
984
|
+
structuredContent: result,
|
|
985
|
+
isError: false
|
|
986
|
+
};
|
|
987
|
+
} catch (err) {
|
|
988
|
+
return caseToolError("Case export", err);
|
|
989
|
+
}
|
|
990
|
+
});
|
|
991
|
+
server.registerTool("case_update_dossier", {
|
|
992
|
+
description: "Append a finding to an address/entity dossier inside a local Chain Insights case.",
|
|
993
|
+
inputSchema: {
|
|
994
|
+
case_id: z.string().min(1).describe("Chain Insights case ID"),
|
|
995
|
+
address: z.string().min(1).describe("Full address or entity identifier"),
|
|
996
|
+
finding: z.string().min(1).describe("Finding to append"),
|
|
997
|
+
entity_type: z.enum([
|
|
998
|
+
"eoa",
|
|
999
|
+
"contract",
|
|
1000
|
+
"exchange",
|
|
1001
|
+
"mixer",
|
|
1002
|
+
"unknown"
|
|
1003
|
+
]).optional().describe("Entity type")
|
|
1004
|
+
},
|
|
1005
|
+
annotations: {
|
|
1006
|
+
readOnlyHint: false,
|
|
1007
|
+
destructiveHint: false,
|
|
1008
|
+
idempotentHint: false,
|
|
1009
|
+
openWorldHint: false
|
|
1010
|
+
}
|
|
1011
|
+
}, async ({ case_id, address, finding, entity_type }) => {
|
|
1012
|
+
try {
|
|
1013
|
+
const { DossierStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
1014
|
+
await DossierStore.appendFinding(case_id, address, finding, entity_type ?? "unknown");
|
|
1015
|
+
return {
|
|
1016
|
+
content: [{
|
|
1017
|
+
type: "text",
|
|
1018
|
+
text: JSON.stringify({
|
|
1019
|
+
case_id,
|
|
1020
|
+
address,
|
|
1021
|
+
updated: true
|
|
1022
|
+
}, null, 2)
|
|
1023
|
+
}],
|
|
1024
|
+
isError: false
|
|
1025
|
+
};
|
|
1026
|
+
} catch (err) {
|
|
1027
|
+
return caseToolError("Dossier update", err);
|
|
1028
|
+
}
|
|
1029
|
+
});
|
|
1030
|
+
server.registerTool("case_start_session", {
|
|
1031
|
+
description: "Start a local investigation session file for a Chain Insights case.",
|
|
1032
|
+
inputSchema: { case_id: z.string().min(1).describe("Chain Insights case ID") },
|
|
1033
|
+
annotations: {
|
|
1034
|
+
readOnlyHint: false,
|
|
1035
|
+
destructiveHint: false,
|
|
1036
|
+
idempotentHint: false,
|
|
1037
|
+
openWorldHint: false
|
|
1038
|
+
}
|
|
1039
|
+
}, async ({ case_id }) => {
|
|
1040
|
+
try {
|
|
1041
|
+
const { SessionStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
1042
|
+
const session = await SessionStore.start(case_id);
|
|
1043
|
+
return {
|
|
1044
|
+
content: [{
|
|
1045
|
+
type: "text",
|
|
1046
|
+
text: JSON.stringify(session, null, 2)
|
|
1047
|
+
}],
|
|
1048
|
+
isError: false
|
|
1049
|
+
};
|
|
1050
|
+
} catch (err) {
|
|
1051
|
+
return caseToolError("Session start", err);
|
|
1052
|
+
}
|
|
1053
|
+
});
|
|
1054
|
+
server.registerTool("case_end_session", {
|
|
1055
|
+
description: "End the latest local investigation session for a Chain Insights case with findings and next steps.",
|
|
1056
|
+
inputSchema: {
|
|
1057
|
+
case_id: z.string().min(1).describe("Chain Insights case ID"),
|
|
1058
|
+
findings: z.string().optional().describe("Key findings from this session"),
|
|
1059
|
+
next_steps: z.string().optional().describe("Next investigation steps")
|
|
1060
|
+
},
|
|
1061
|
+
annotations: {
|
|
1062
|
+
readOnlyHint: false,
|
|
1063
|
+
destructiveHint: false,
|
|
1064
|
+
idempotentHint: false,
|
|
1065
|
+
openWorldHint: false
|
|
1066
|
+
}
|
|
1067
|
+
}, async ({ case_id, findings, next_steps }) => {
|
|
1068
|
+
try {
|
|
1069
|
+
const { SessionStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
1070
|
+
await SessionStore.end(case_id, {
|
|
1071
|
+
findings: findings ?? "",
|
|
1072
|
+
nextSteps: next_steps ?? ""
|
|
1073
|
+
});
|
|
1074
|
+
await SessionStore.archiveOldSessions(case_id);
|
|
1075
|
+
return {
|
|
1076
|
+
content: [{
|
|
1077
|
+
type: "text",
|
|
1078
|
+
text: JSON.stringify({
|
|
1079
|
+
case_id,
|
|
1080
|
+
ended: true
|
|
1081
|
+
}, null, 2)
|
|
1082
|
+
}],
|
|
1083
|
+
isError: false
|
|
1084
|
+
};
|
|
1085
|
+
} catch (err) {
|
|
1086
|
+
return caseToolError("Session end", err);
|
|
1087
|
+
}
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1052
1090
|
if (!remoteToolNames.has("address_risk")) registerAppTool(server, "address_risk", {
|
|
1053
1091
|
title: "Address Risk",
|
|
1054
1092
|
description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS.address_risk,
|
|
@@ -1065,7 +1103,7 @@ async function createProxy() {
|
|
|
1065
1103
|
idempotentHint: true,
|
|
1066
1104
|
openWorldHint: true
|
|
1067
1105
|
}
|
|
1068
|
-
}, async ({ address, network, compare_address }) => {
|
|
1106
|
+
}, async ({ address, network, compare_address, include_attachments }) => {
|
|
1069
1107
|
try {
|
|
1070
1108
|
if (!remoteConnected) return {
|
|
1071
1109
|
content: [{
|
|
@@ -1074,29 +1112,20 @@ async function createProxy() {
|
|
|
1074
1112
|
}],
|
|
1075
1113
|
isError: true
|
|
1076
1114
|
};
|
|
1077
|
-
const { addressRisk } = await import("./public-tools-
|
|
1078
|
-
const { writeGraphReport } = await import("./graph-reports-BDELxmpi.mjs");
|
|
1079
|
-
const { ensureArtifactServer } = await import("./artifact-server-CP6LXQ9d.mjs");
|
|
1115
|
+
const { addressRisk } = await import("./public-tools-CvlZcysd.mjs");
|
|
1080
1116
|
const result = await addressRisk(remoteClient, {
|
|
1081
1117
|
address,
|
|
1082
1118
|
network,
|
|
1083
1119
|
compareAddress: compare_address
|
|
1084
1120
|
});
|
|
1085
|
-
const
|
|
1086
|
-
serverPort: config.serverPort,
|
|
1087
|
-
slug: `address-risk-${network}-${address}`
|
|
1088
|
-
});
|
|
1089
|
-
await ensureArtifactServer(config.serverPort);
|
|
1121
|
+
const graph = await writeLocalGraphMeta(result.graphData, config, `address-risk-${network}-${address}`, shouldIncludeAttachments({ include_attachments }, workspaceArtifactsEnabled));
|
|
1090
1122
|
return {
|
|
1091
1123
|
content: [{
|
|
1092
1124
|
type: "text",
|
|
1093
1125
|
text: result.summaryText
|
|
1094
1126
|
}],
|
|
1095
1127
|
structuredContent: result.structuredContent,
|
|
1096
|
-
_meta:
|
|
1097
|
-
schema: report.schema,
|
|
1098
|
-
url: report.url
|
|
1099
|
-
} } },
|
|
1128
|
+
_meta: graphMetaResult(graph),
|
|
1100
1129
|
isError: false
|
|
1101
1130
|
};
|
|
1102
1131
|
} catch (err) {
|
|
@@ -1137,7 +1166,7 @@ async function createProxy() {
|
|
|
1137
1166
|
idempotentHint: false,
|
|
1138
1167
|
openWorldHint: true
|
|
1139
1168
|
}
|
|
1140
|
-
}, async ({ victim_addresses, known_suspect_addresses, network, case_id, incident_timestamp_ms, max_hops, per_address_limit, min_amount_sum }) => {
|
|
1169
|
+
}, async ({ victim_addresses, known_suspect_addresses, network, case_id, incident_timestamp_ms, max_hops, per_address_limit, min_amount_sum, include_attachments }) => {
|
|
1141
1170
|
try {
|
|
1142
1171
|
if (!remoteConnected) return {
|
|
1143
1172
|
content: [{
|
|
@@ -1146,9 +1175,14 @@ async function createProxy() {
|
|
|
1146
1175
|
}],
|
|
1147
1176
|
isError: true
|
|
1148
1177
|
};
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1178
|
+
if (!workspaceArtifactsEnabled && case_id) return {
|
|
1179
|
+
content: [{
|
|
1180
|
+
type: "text",
|
|
1181
|
+
text: "case_id requires Chain Insights workspace mode; omit case_id when CHAIN_INSIGHTS_MCP_PROXY_MODE=stateless."
|
|
1182
|
+
}],
|
|
1183
|
+
isError: true
|
|
1184
|
+
};
|
|
1185
|
+
const { traceVictimFunds } = await import("./public-tools-CvlZcysd.mjs");
|
|
1152
1186
|
const result = await traceVictimFunds(remoteClient, config, {
|
|
1153
1187
|
victimAddresses: victim_addresses,
|
|
1154
1188
|
knownSuspectAddresses: known_suspect_addresses,
|
|
@@ -1157,23 +1191,17 @@ async function createProxy() {
|
|
|
1157
1191
|
incidentTimestampMs: incident_timestamp_ms,
|
|
1158
1192
|
maxHops: max_hops,
|
|
1159
1193
|
perAddressLimit: per_address_limit,
|
|
1160
|
-
minAmountSum: min_amount_sum
|
|
1161
|
-
|
|
1162
|
-
const report = await writeGraphReport(result.graphData, {
|
|
1163
|
-
serverPort: config.serverPort,
|
|
1164
|
-
slug: `trace-victim-funds-${network}`
|
|
1194
|
+
minAmountSum: min_amount_sum,
|
|
1195
|
+
writeArtifacts: workspaceArtifactsEnabled
|
|
1165
1196
|
});
|
|
1166
|
-
await
|
|
1197
|
+
const graph = await writeLocalGraphMeta(result.graphData, config, `trace-victim-funds-${network}`, shouldIncludeAttachments({ include_attachments }, workspaceArtifactsEnabled));
|
|
1167
1198
|
return {
|
|
1168
1199
|
content: [{
|
|
1169
1200
|
type: "text",
|
|
1170
1201
|
text: result.summaryText
|
|
1171
1202
|
}],
|
|
1172
1203
|
structuredContent: result.structuredContent,
|
|
1173
|
-
_meta:
|
|
1174
|
-
schema: report.schema,
|
|
1175
|
-
url: report.url
|
|
1176
|
-
} } },
|
|
1204
|
+
_meta: graphMetaResult(graph),
|
|
1177
1205
|
isError: false
|
|
1178
1206
|
};
|
|
1179
1207
|
} catch (err) {
|
|
@@ -1213,7 +1241,7 @@ async function createProxy() {
|
|
|
1213
1241
|
idempotentHint: false,
|
|
1214
1242
|
openWorldHint: true
|
|
1215
1243
|
}
|
|
1216
|
-
}, async ({ suspect_addresses, incident_timestamp_ms, network, max_hops, per_address_limit, min_amount_sum, case_id }) => {
|
|
1244
|
+
}, async ({ suspect_addresses, incident_timestamp_ms, network, max_hops, per_address_limit, min_amount_sum, case_id, include_attachments }) => {
|
|
1217
1245
|
try {
|
|
1218
1246
|
if (!remoteConnected) return {
|
|
1219
1247
|
content: [{
|
|
@@ -1222,9 +1250,14 @@ async function createProxy() {
|
|
|
1222
1250
|
}],
|
|
1223
1251
|
isError: true
|
|
1224
1252
|
};
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1253
|
+
if (!workspaceArtifactsEnabled && case_id) return {
|
|
1254
|
+
content: [{
|
|
1255
|
+
type: "text",
|
|
1256
|
+
text: "case_id requires Chain Insights workspace mode; omit case_id when CHAIN_INSIGHTS_MCP_PROXY_MODE=stateless."
|
|
1257
|
+
}],
|
|
1258
|
+
isError: true
|
|
1259
|
+
};
|
|
1260
|
+
const { traceSuspectFunds } = await import("./public-tools-CvlZcysd.mjs");
|
|
1228
1261
|
const result = await traceSuspectFunds(remoteClient, config, {
|
|
1229
1262
|
suspectAddresses: suspect_addresses,
|
|
1230
1263
|
network,
|
|
@@ -1232,23 +1265,17 @@ async function createProxy() {
|
|
|
1232
1265
|
perAddressLimit: per_address_limit,
|
|
1233
1266
|
minAmountSum: min_amount_sum,
|
|
1234
1267
|
incidentTimestampMs: incident_timestamp_ms,
|
|
1235
|
-
caseId: case_id
|
|
1236
|
-
|
|
1237
|
-
const report = await writeGraphReport(result.graphData, {
|
|
1238
|
-
serverPort: config.serverPort,
|
|
1239
|
-
slug: `trace-suspect-funds-${network}`
|
|
1268
|
+
caseId: case_id,
|
|
1269
|
+
writeArtifacts: workspaceArtifactsEnabled
|
|
1240
1270
|
});
|
|
1241
|
-
await
|
|
1271
|
+
const graph = await writeLocalGraphMeta(result.graphData, config, `trace-suspect-funds-${network}`, shouldIncludeAttachments({ include_attachments }, workspaceArtifactsEnabled));
|
|
1242
1272
|
return {
|
|
1243
1273
|
content: [{
|
|
1244
1274
|
type: "text",
|
|
1245
1275
|
text: result.summaryText
|
|
1246
1276
|
}],
|
|
1247
1277
|
structuredContent: result.structuredContent,
|
|
1248
|
-
_meta:
|
|
1249
|
-
schema: report.schema,
|
|
1250
|
-
url: report.url
|
|
1251
|
-
} } },
|
|
1278
|
+
_meta: graphMetaResult(graph),
|
|
1252
1279
|
isError: false
|
|
1253
1280
|
};
|
|
1254
1281
|
} catch (err) {
|
|
@@ -1285,7 +1312,7 @@ async function createProxy() {
|
|
|
1285
1312
|
idempotentHint: false,
|
|
1286
1313
|
openWorldHint: true
|
|
1287
1314
|
}
|
|
1288
|
-
}, async ({ deposit_addresses, network, max_hops, case_id }) => {
|
|
1315
|
+
}, async ({ deposit_addresses, network, max_hops, case_id, include_attachments }) => {
|
|
1289
1316
|
try {
|
|
1290
1317
|
if (!remoteConnected) return {
|
|
1291
1318
|
content: [{
|
|
@@ -1294,30 +1321,29 @@ async function createProxy() {
|
|
|
1294
1321
|
}],
|
|
1295
1322
|
isError: true
|
|
1296
1323
|
};
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1324
|
+
if (!workspaceArtifactsEnabled && case_id) return {
|
|
1325
|
+
content: [{
|
|
1326
|
+
type: "text",
|
|
1327
|
+
text: "case_id requires Chain Insights workspace mode; omit case_id when CHAIN_INSIGHTS_MCP_PROXY_MODE=stateless."
|
|
1328
|
+
}],
|
|
1329
|
+
isError: true
|
|
1330
|
+
};
|
|
1331
|
+
const { traceDepositSources } = await import("./public-tools-CvlZcysd.mjs");
|
|
1300
1332
|
const result = await traceDepositSources(remoteClient, config, {
|
|
1301
1333
|
depositAddresses: deposit_addresses,
|
|
1302
1334
|
network,
|
|
1303
1335
|
maxHops: max_hops,
|
|
1304
|
-
caseId: case_id
|
|
1305
|
-
|
|
1306
|
-
const report = await writeGraphReport(result.graphData, {
|
|
1307
|
-
serverPort: config.serverPort,
|
|
1308
|
-
slug: `trace-deposit-sources-${network}`
|
|
1336
|
+
caseId: case_id,
|
|
1337
|
+
writeArtifacts: workspaceArtifactsEnabled
|
|
1309
1338
|
});
|
|
1310
|
-
await
|
|
1339
|
+
const graph = await writeLocalGraphMeta(result.graphData, config, `trace-deposit-sources-${network}`, shouldIncludeAttachments({ include_attachments }, workspaceArtifactsEnabled));
|
|
1311
1340
|
return {
|
|
1312
1341
|
content: [{
|
|
1313
1342
|
type: "text",
|
|
1314
1343
|
text: result.summaryText
|
|
1315
1344
|
}],
|
|
1316
1345
|
structuredContent: result.structuredContent,
|
|
1317
|
-
_meta:
|
|
1318
|
-
schema: report.schema,
|
|
1319
|
-
url: report.url
|
|
1320
|
-
} } },
|
|
1346
|
+
_meta: graphMetaResult(graph),
|
|
1321
1347
|
isError: false
|
|
1322
1348
|
};
|
|
1323
1349
|
} catch (err) {
|
|
@@ -1360,7 +1386,7 @@ async function createProxy() {
|
|
|
1360
1386
|
idempotentHint: true,
|
|
1361
1387
|
openWorldHint: true
|
|
1362
1388
|
}
|
|
1363
|
-
}, async ({ network, address, coldkey, hotkey, netuid, start_timestamp_ms, end_timestamp_ms, start_block, end_block, depth }) => {
|
|
1389
|
+
}, async ({ network, address, coldkey, hotkey, netuid, start_timestamp_ms, end_timestamp_ms, start_block, end_block, depth, include_attachments }) => {
|
|
1364
1390
|
try {
|
|
1365
1391
|
if (!remoteConnected) return {
|
|
1366
1392
|
content: [{
|
|
@@ -1369,9 +1395,7 @@ async function createProxy() {
|
|
|
1369
1395
|
}],
|
|
1370
1396
|
isError: true
|
|
1371
1397
|
};
|
|
1372
|
-
const { stakeInsights } = await import("./public-tools-
|
|
1373
|
-
const { writeGraphReport } = await import("./graph-reports-BDELxmpi.mjs");
|
|
1374
|
-
const { ensureArtifactServer } = await import("./artifact-server-CP6LXQ9d.mjs");
|
|
1398
|
+
const { stakeInsights } = await import("./public-tools-CvlZcysd.mjs");
|
|
1375
1399
|
const result = await stakeInsights(remoteClient, {
|
|
1376
1400
|
network,
|
|
1377
1401
|
address,
|
|
@@ -1385,21 +1409,14 @@ async function createProxy() {
|
|
|
1385
1409
|
depth
|
|
1386
1410
|
});
|
|
1387
1411
|
const subject = address ?? coldkey ?? hotkey ?? "subject";
|
|
1388
|
-
const
|
|
1389
|
-
serverPort: config.serverPort,
|
|
1390
|
-
slug: `stake-insights-${network}-${subject}`
|
|
1391
|
-
});
|
|
1392
|
-
await ensureArtifactServer(config.serverPort);
|
|
1412
|
+
const graph = await writeLocalGraphMeta(result.graphData, config, `stake-insights-${network}-${subject}`, shouldIncludeAttachments({ include_attachments }, workspaceArtifactsEnabled));
|
|
1393
1413
|
return {
|
|
1394
1414
|
content: [{
|
|
1395
1415
|
type: "text",
|
|
1396
1416
|
text: result.summaryText
|
|
1397
1417
|
}],
|
|
1398
1418
|
structuredContent: result.structuredContent,
|
|
1399
|
-
_meta:
|
|
1400
|
-
schema: report.schema,
|
|
1401
|
-
url: report.url
|
|
1402
|
-
} } },
|
|
1419
|
+
_meta: graphMetaResult(graph),
|
|
1403
1420
|
isError: false
|
|
1404
1421
|
};
|
|
1405
1422
|
} catch (err) {
|
|
@@ -1425,7 +1442,7 @@ async function createProxy() {
|
|
|
1425
1442
|
}, async () => ({
|
|
1426
1443
|
content: [{
|
|
1427
1444
|
type: "text",
|
|
1428
|
-
text: [
|
|
1445
|
+
text: workspaceArtifactsEnabled ? [
|
|
1429
1446
|
"Chain Insights AML investigation workspace for AI agents. Workspaces are Obsidian-compatible vaults backed by plain local files.",
|
|
1430
1447
|
"",
|
|
1431
1448
|
CHAIN_INSIGHTS_WORKFLOW,
|
|
@@ -1457,6 +1474,22 @@ async function createProxy() {
|
|
|
1457
1474
|
GRAPH_REPORT_HINTS,
|
|
1458
1475
|
"",
|
|
1459
1476
|
GRAPH_SCHEMA_HINTS
|
|
1477
|
+
].join("\n") : [
|
|
1478
|
+
"Chain Insights stateless AML proxy for host applications.",
|
|
1479
|
+
"",
|
|
1480
|
+
"Local workspace, case, evidence, dossier, session, wallet, and graph report attachment tools are disabled in this mode.",
|
|
1481
|
+
"",
|
|
1482
|
+
"Available graph-backed tools:",
|
|
1483
|
+
"- network_capabilities: inspect supported networks, data layers, tool availability, retention windows, and freshness.",
|
|
1484
|
+
"- address_risk: screen a full address for AML risk, behavior, neighborhood, exchange exposure, and optional compare_address connection checks.",
|
|
1485
|
+
"- stake_insights: explain Bittensor staking around one address, coldkey, or hotkey with net stake, movement amounts, counterparties, backend, and query evidence.",
|
|
1486
|
+
"- trace_victim_funds: trace up to five victim/source addresses forward to exchange deposit candidates.",
|
|
1487
|
+
"- trace_deposit_sources: trace backward from suspected deposit/cashout addresses to upstream funders and shared-source convergence.",
|
|
1488
|
+
"- trace_suspect_funds: trace up to five suspected scammer, mule, operator, or laundering-ring addresses forward to cashout topology.",
|
|
1489
|
+
"- graph_query: run read-only GQL/Cypher through the universal graph endpoint. Use USE live_topology, USE archive_topology, or USE facts.",
|
|
1490
|
+
"- graph_query_batch: run related read-only graph-language queries through one paid graph call.",
|
|
1491
|
+
"",
|
|
1492
|
+
GRAPH_SCHEMA_HINTS
|
|
1460
1493
|
].join("\n")
|
|
1461
1494
|
}],
|
|
1462
1495
|
isError: false
|
|
@@ -1488,7 +1521,7 @@ async function createProxy() {
|
|
|
1488
1521
|
arguments: normalizedArgs
|
|
1489
1522
|
};
|
|
1490
1523
|
const requestOptions = remoteToolRequestOptions(tool.name);
|
|
1491
|
-
return await normalizeRemoteToolResult(requestOptions ? await remoteClient.callTool(request, void 0, requestOptions) : await remoteClient.callTool(request), config, tool.name);
|
|
1524
|
+
return await normalizeRemoteToolResult(requestOptions ? await remoteClient.callTool(request, void 0, requestOptions) : await remoteClient.callTool(request), config, tool.name, shouldIncludeAttachments(normalizedArgs, workspaceArtifactsEnabled));
|
|
1492
1525
|
} catch (err) {
|
|
1493
1526
|
if (err instanceof PaymentRequiredError) return {
|
|
1494
1527
|
content: [{
|
|
@@ -1545,6 +1578,6 @@ if (process.argv[1] && import.meta.url.includes(process.argv[1].replace(/\\/g, "
|
|
|
1545
1578
|
process.exit(1);
|
|
1546
1579
|
});
|
|
1547
1580
|
//#endregion
|
|
1548
|
-
export { createProxy };
|
|
1581
|
+
export { createProxy, resolveMcpProxyMode };
|
|
1549
1582
|
|
|
1550
1583
|
//# sourceMappingURL=mcp-proxy.mjs.map
|