@forgemeshlabs/anomaly-mcp 0.1.1 → 0.2.0
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 +36 -25
- package/dist/index.js +1 -1
- package/dist/tools.d.ts +49 -18
- package/dist/tools.js +78 -56
- package/package.json +1 -1
- package/server.json +2 -2
package/README.md
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
# Anomaly Tracker MCP
|
|
2
2
|
|
|
3
|
-
Blockchain event sequence anomaly detection for
|
|
3
|
+
Blockchain event sequence anomaly detection for AI agents. Detects unusual financial event patterns across Ethereum, Base, and Arbitrum using NASA-derived sequence mining. Returns a story label and anomaly score, not just a number.
|
|
4
4
|
|
|
5
|
-
This MCP server gives AI agents access to the ForgeMesh Anomaly Tracker API
|
|
5
|
+
This MCP server gives AI agents access to the ForgeMesh Anomaly Tracker API via 5 tools — chain-wide anomaly scanning, single-token analysis, whale alerts, model health, and API status.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
`https://anomaly.forgemesh.io`
|
|
10
|
-
|
|
11
|
-
Architecture:
|
|
7
|
+
Thin client architecture:
|
|
12
8
|
|
|
13
9
|
`Agent/MCP client -> this MCP server -> ForgeMesh Anomaly Tracker API`
|
|
14
10
|
|
|
11
|
+
Hosted API: `https://anomaly.forgemesh.io`
|
|
12
|
+
|
|
15
13
|
## Install
|
|
16
14
|
|
|
17
15
|
```bash
|
|
@@ -44,36 +42,49 @@ npx -y @forgemeshlabs/anomaly-mcp
|
|
|
44
42
|
|
|
45
43
|
| Tool | Description | Cost |
|
|
46
44
|
| --- | --- | --- |
|
|
47
|
-
| `
|
|
48
|
-
| `
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
51
|
-
| `
|
|
45
|
+
| `health_check` | API health and uptime | Free |
|
|
46
|
+
| `anomaly_scan` | Chain-wide sequence anomaly scan — scores event windows for unusual patterns | $0.05 USDC |
|
|
47
|
+
| `token_scan` | Single-token anomaly scan — scores transfer patterns for one token | $0.03 USDC |
|
|
48
|
+
| `whale_alerts` | Recent whale movements, CEX flows, bridge activity, stablecoin mints/burns | $0.02 USDC |
|
|
49
|
+
| `model_status` | SequenceMiner model health and training stats per chain | $0.01 USDC |
|
|
50
|
+
|
|
51
|
+
### anomaly_scan
|
|
52
|
+
|
|
53
|
+
Scan a blockchain for sequence anomalies across all monitored addresses.
|
|
54
|
+
|
|
55
|
+
- **chain**: `ethereum`, `base`, or `arbitrum` (default: ethereum)
|
|
56
|
+
- **window**: `1h`, `4h`, `24h`, or `168h` (default: 24h)
|
|
57
|
+
|
|
58
|
+
Returns: `sequence_score` (0-100), `story` (human label), `novelty`, `peak_window`, `possible_failure_modes`
|
|
59
|
+
|
|
60
|
+
### token_scan
|
|
61
|
+
|
|
62
|
+
Anomaly scan for a single token's recent transfer patterns.
|
|
63
|
+
|
|
64
|
+
- **token** (required): Contract address (`0x...`) or symbol — `usdt`, `usdc`, `weth`, `wbtc`, `link`, `uni`, `aave`, `steth`, `pepe`, `dai`, `cbeth`, `arb`
|
|
65
|
+
- **chain**: `ethereum`, `base`, or `arbitrum` (default: ethereum)
|
|
66
|
+
- **window**: `1h`, `4h`, `24h`, or `168h` (default: 24h)
|
|
67
|
+
|
|
68
|
+
Returns: `sequence_score`, `story`, `novelty`, `peak_window`, `transfers` (recent transfer events with source/direction)
|
|
52
69
|
|
|
53
|
-
|
|
70
|
+
### whale_alerts
|
|
54
71
|
|
|
55
|
-
|
|
72
|
+
Recent whale movements from 12+ monitored addresses: Binance, Coinbase, Kraken, OKX, Bybit, Arbitrum/Optimism/Polygon bridges, Tether Treasury, Circle.
|
|
56
73
|
|
|
57
|
-
- **
|
|
58
|
-
- **
|
|
59
|
-
- **window**: Lookback period: `1h`, `4h`, `24h`, or `168h`
|
|
74
|
+
- **chain**: `ethereum`, `base`, or `arbitrum` (default: ethereum)
|
|
75
|
+
- **hours**: 1-168 (default: 4)
|
|
60
76
|
|
|
61
|
-
Returns:
|
|
62
|
-
- **sequence_score**: 0 (normal) to 100 (highly anomalous)
|
|
63
|
-
- **story**: Human-readable label like "Supply Expansion", "Exchange Drain", "Normal Activity"
|
|
64
|
-
- **novelty**: `low`, `medium`, `high`, or `extreme`
|
|
65
|
-
- **peak_window**: The most anomalous symbol sequence found
|
|
66
|
-
- **possible_failure_modes**: What could go wrong if this pattern continues
|
|
77
|
+
Returns: `alerts` array with `symbol`, `source`, `amount_eth`/`amount_usd`, `timestamp`
|
|
67
78
|
|
|
68
79
|
## Symbol Alphabet
|
|
69
80
|
|
|
70
|
-
The financial domain tracks 16 event types
|
|
81
|
+
The financial domain tracks 16 event types:
|
|
71
82
|
|
|
72
83
|
`WHALE_BUY`, `WHALE_SELL`, `CEX_INFLOW`, `CEX_OUTFLOW`, `BRIDGE_IN`, `BRIDGE_OUT`, `DEX_SWAP`, `DEX_LIQUIDITY_ADD`, `DEX_LIQUIDITY_REMOVE`, `STABLECOIN_MINT`, `STABLECOIN_REDEEM`, `STABLECOIN_BURN`, `TOKEN_MINT`, `TOKEN_BURN`, `FUNDING_SPIKE`, `LIQUIDATION`
|
|
73
84
|
|
|
74
85
|
## Payment
|
|
75
86
|
|
|
76
|
-
Paid
|
|
87
|
+
Paid tools use x402 protocol. Agents pay per call in USDC on Base mainnet. No API key needed.
|
|
77
88
|
|
|
78
89
|
By default, paid endpoints return x402 challenge metadata (pricing, network, wallet) without settling. To settle payments, configure a wallet private key in your agent's x402 client.
|
|
79
90
|
|
package/dist/index.js
CHANGED
package/dist/tools.d.ts
CHANGED
|
@@ -4,11 +4,11 @@ export declare const tools: ({
|
|
|
4
4
|
inputSchema: {
|
|
5
5
|
type: "object";
|
|
6
6
|
properties: {
|
|
7
|
-
file?: undefined;
|
|
8
|
-
endpoint?: undefined;
|
|
9
|
-
domain?: undefined;
|
|
10
7
|
chain?: undefined;
|
|
11
8
|
window?: undefined;
|
|
9
|
+
token?: undefined;
|
|
10
|
+
hours?: undefined;
|
|
11
|
+
address?: undefined;
|
|
12
12
|
};
|
|
13
13
|
required?: undefined;
|
|
14
14
|
};
|
|
@@ -18,17 +18,21 @@ export declare const tools: ({
|
|
|
18
18
|
inputSchema: {
|
|
19
19
|
type: "object";
|
|
20
20
|
properties: {
|
|
21
|
-
|
|
21
|
+
chain: {
|
|
22
22
|
type: string;
|
|
23
23
|
enum: string[];
|
|
24
24
|
description: string;
|
|
25
25
|
};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
window: {
|
|
27
|
+
type: string;
|
|
28
|
+
enum: string[];
|
|
29
|
+
description: string;
|
|
30
|
+
};
|
|
31
|
+
token?: undefined;
|
|
32
|
+
hours?: undefined;
|
|
33
|
+
address?: undefined;
|
|
30
34
|
};
|
|
31
|
-
required
|
|
35
|
+
required?: undefined;
|
|
32
36
|
};
|
|
33
37
|
} | {
|
|
34
38
|
name: string;
|
|
@@ -36,15 +40,22 @@ export declare const tools: ({
|
|
|
36
40
|
inputSchema: {
|
|
37
41
|
type: "object";
|
|
38
42
|
properties: {
|
|
39
|
-
|
|
43
|
+
token: {
|
|
44
|
+
type: string;
|
|
45
|
+
description: string;
|
|
46
|
+
};
|
|
47
|
+
chain: {
|
|
40
48
|
type: string;
|
|
41
49
|
enum: string[];
|
|
42
50
|
description: string;
|
|
43
51
|
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
52
|
+
window: {
|
|
53
|
+
type: string;
|
|
54
|
+
enum: string[];
|
|
55
|
+
description: string;
|
|
56
|
+
};
|
|
57
|
+
hours?: undefined;
|
|
58
|
+
address?: undefined;
|
|
48
59
|
};
|
|
49
60
|
required: string[];
|
|
50
61
|
};
|
|
@@ -54,11 +65,31 @@ export declare const tools: ({
|
|
|
54
65
|
inputSchema: {
|
|
55
66
|
type: "object";
|
|
56
67
|
properties: {
|
|
57
|
-
|
|
68
|
+
chain: {
|
|
58
69
|
type: string;
|
|
59
70
|
enum: string[];
|
|
60
71
|
description: string;
|
|
61
72
|
};
|
|
73
|
+
hours: {
|
|
74
|
+
type: string;
|
|
75
|
+
description: string;
|
|
76
|
+
};
|
|
77
|
+
window?: undefined;
|
|
78
|
+
token?: undefined;
|
|
79
|
+
address?: undefined;
|
|
80
|
+
};
|
|
81
|
+
required?: undefined;
|
|
82
|
+
};
|
|
83
|
+
} | {
|
|
84
|
+
name: string;
|
|
85
|
+
description: string;
|
|
86
|
+
inputSchema: {
|
|
87
|
+
type: "object";
|
|
88
|
+
properties: {
|
|
89
|
+
address: {
|
|
90
|
+
type: string;
|
|
91
|
+
description: string;
|
|
92
|
+
};
|
|
62
93
|
chain: {
|
|
63
94
|
type: string;
|
|
64
95
|
enum: string[];
|
|
@@ -69,10 +100,10 @@ export declare const tools: ({
|
|
|
69
100
|
enum: string[];
|
|
70
101
|
description: string;
|
|
71
102
|
};
|
|
72
|
-
|
|
73
|
-
|
|
103
|
+
token?: undefined;
|
|
104
|
+
hours?: undefined;
|
|
74
105
|
};
|
|
75
|
-
required
|
|
106
|
+
required: string[];
|
|
76
107
|
};
|
|
77
108
|
})[];
|
|
78
109
|
export declare function callTool(name: string, args: Record<string, unknown>): Promise<unknown>;
|
package/dist/tools.js
CHANGED
|
@@ -1,67 +1,98 @@
|
|
|
1
1
|
const API_BASE = process.env.ANOMALY_API_BASE || "https://anomaly.forgemesh.io";
|
|
2
2
|
export const tools = [
|
|
3
3
|
{
|
|
4
|
-
name: "
|
|
5
|
-
description: "Check ForgeMesh Anomaly Tracker API health.",
|
|
4
|
+
name: "health_check",
|
|
5
|
+
description: "Check ForgeMesh Anomaly Tracker API health and uptime.",
|
|
6
6
|
inputSchema: { type: "object", properties: {} }
|
|
7
7
|
},
|
|
8
8
|
{
|
|
9
|
-
name: "
|
|
10
|
-
description: "
|
|
9
|
+
name: "anomaly_scan",
|
|
10
|
+
description: "Scan a blockchain for sequence anomalies — unusual patterns of whale movements, exchange flows, bridge activity, and stablecoin mints/burns. Returns a story label, anomaly score (0-100), novelty level, and the peak anomalous symbol window. Costs $0.05 USDC on Base mainnet.",
|
|
11
11
|
inputSchema: {
|
|
12
12
|
type: "object",
|
|
13
13
|
properties: {
|
|
14
|
-
|
|
14
|
+
chain: {
|
|
15
|
+
type: "string",
|
|
16
|
+
enum: ["ethereum", "base", "arbitrum"],
|
|
17
|
+
description: "Blockchain to analyze (default: ethereum)"
|
|
18
|
+
},
|
|
19
|
+
window: {
|
|
15
20
|
type: "string",
|
|
16
|
-
enum: ["
|
|
17
|
-
description: "
|
|
21
|
+
enum: ["1h", "4h", "24h", "168h"],
|
|
22
|
+
description: "Lookback window (default: 24h)"
|
|
18
23
|
}
|
|
19
|
-
}
|
|
20
|
-
required: ["file"]
|
|
24
|
+
}
|
|
21
25
|
}
|
|
22
26
|
},
|
|
23
27
|
{
|
|
24
|
-
name: "
|
|
25
|
-
description: "
|
|
28
|
+
name: "token_scan",
|
|
29
|
+
description: "Anomaly scan for a single token — scores recent transfer patterns for unusual activity (large CEX flows, whale accumulation, token mints/burns). Pass a contract address or well-known symbol. Costs $0.03 USDC on Base mainnet.",
|
|
26
30
|
inputSchema: {
|
|
27
31
|
type: "object",
|
|
28
32
|
properties: {
|
|
29
|
-
|
|
33
|
+
token: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "Token contract address (0x...) or symbol: usdt, usdc, weth, wbtc, link, uni, aave, steth, pepe, dai, cbeth, arb"
|
|
36
|
+
},
|
|
37
|
+
chain: {
|
|
38
|
+
type: "string",
|
|
39
|
+
enum: ["ethereum", "base", "arbitrum"],
|
|
40
|
+
description: "Blockchain to analyze (default: ethereum)"
|
|
41
|
+
},
|
|
42
|
+
window: {
|
|
30
43
|
type: "string",
|
|
31
|
-
enum: ["
|
|
32
|
-
description: "
|
|
44
|
+
enum: ["1h", "4h", "24h", "168h"],
|
|
45
|
+
description: "Lookback window (default: 24h)"
|
|
33
46
|
}
|
|
34
47
|
},
|
|
35
|
-
required: ["
|
|
48
|
+
required: ["token"]
|
|
36
49
|
}
|
|
37
50
|
},
|
|
38
51
|
{
|
|
39
|
-
name: "
|
|
40
|
-
description: "
|
|
52
|
+
name: "whale_alerts",
|
|
53
|
+
description: "Get recent whale movements, CEX inflows/outflows, bridge activity, and stablecoin mints/burns from monitored addresses (Binance, Coinbase, Kraken, OKX, Bybit, major bridges, Tether, Circle). Costs $0.02 USDC on Base mainnet.",
|
|
41
54
|
inputSchema: {
|
|
42
55
|
type: "object",
|
|
43
56
|
properties: {
|
|
44
|
-
|
|
57
|
+
chain: {
|
|
45
58
|
type: "string",
|
|
46
|
-
enum: ["
|
|
47
|
-
description: "
|
|
59
|
+
enum: ["ethereum", "base", "arbitrum"],
|
|
60
|
+
description: "Blockchain to monitor (default: ethereum)"
|
|
61
|
+
},
|
|
62
|
+
hours: {
|
|
63
|
+
type: "integer",
|
|
64
|
+
description: "Lookback window in hours, 1-168 (default: 4)"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: "address_scan",
|
|
71
|
+
description: "Scan any wallet address for anomalous transaction patterns. Classifies each transaction by checking counterparties against known CEX wallets, bridges, and stablecoin issuers. Costs $0.03 USDC on Base mainnet.",
|
|
72
|
+
inputSchema: {
|
|
73
|
+
type: "object",
|
|
74
|
+
properties: {
|
|
75
|
+
address: {
|
|
76
|
+
type: "string",
|
|
77
|
+
description: "Wallet address to scan (0x...)"
|
|
48
78
|
},
|
|
49
79
|
chain: {
|
|
50
80
|
type: "string",
|
|
51
81
|
enum: ["ethereum", "base", "arbitrum"],
|
|
52
|
-
description: "Blockchain to
|
|
82
|
+
description: "Blockchain to scan (default: ethereum)"
|
|
53
83
|
},
|
|
54
84
|
window: {
|
|
55
85
|
type: "string",
|
|
56
86
|
enum: ["1h", "4h", "24h", "168h"],
|
|
57
87
|
description: "Lookback window (default: 24h)"
|
|
58
88
|
}
|
|
59
|
-
}
|
|
89
|
+
},
|
|
90
|
+
required: ["address"]
|
|
60
91
|
}
|
|
61
92
|
},
|
|
62
93
|
{
|
|
63
|
-
name: "
|
|
64
|
-
description: "Get SequenceMiner model health and training stats per chain. Costs $0.01 USDC on Base mainnet.",
|
|
94
|
+
name: "model_status",
|
|
95
|
+
description: "Get SequenceMiner model health and training stats per chain — training sequence count and last retrain time. Costs $0.01 USDC on Base mainnet.",
|
|
65
96
|
inputSchema: {
|
|
66
97
|
type: "object",
|
|
67
98
|
properties: {}
|
|
@@ -75,7 +106,7 @@ async function apiGet(path) {
|
|
|
75
106
|
let decoded = null;
|
|
76
107
|
if (challenge) {
|
|
77
108
|
try {
|
|
78
|
-
decoded = JSON.parse(
|
|
109
|
+
decoded = JSON.parse(atob(challenge));
|
|
79
110
|
}
|
|
80
111
|
catch { }
|
|
81
112
|
}
|
|
@@ -98,7 +129,7 @@ async function apiPost(path, body) {
|
|
|
98
129
|
let decoded = null;
|
|
99
130
|
if (challenge) {
|
|
100
131
|
try {
|
|
101
|
-
decoded = JSON.parse(
|
|
132
|
+
decoded = JSON.parse(atob(challenge));
|
|
102
133
|
}
|
|
103
134
|
catch { }
|
|
104
135
|
}
|
|
@@ -112,41 +143,32 @@ async function apiPost(path, body) {
|
|
|
112
143
|
}
|
|
113
144
|
export async function callTool(name, args) {
|
|
114
145
|
switch (name) {
|
|
115
|
-
case "
|
|
146
|
+
case "health_check":
|
|
116
147
|
return apiGet("/health");
|
|
117
|
-
case "
|
|
118
|
-
const file = args.file;
|
|
119
|
-
const pathMap = {
|
|
120
|
-
"llms.txt": "/llms.txt",
|
|
121
|
-
"openapi.json": "/openapi.json",
|
|
122
|
-
"x402.json": "/.well-known/x402.json"
|
|
123
|
-
};
|
|
124
|
-
const path = pathMap[file];
|
|
125
|
-
if (!path)
|
|
126
|
-
return { error: "Unknown file. Use: llms.txt, openapi.json, or x402.json" };
|
|
127
|
-
if (file === "llms.txt") {
|
|
128
|
-
const res = await fetch(`${API_BASE}${path}`);
|
|
129
|
-
return { content: await res.text() };
|
|
130
|
-
}
|
|
131
|
-
return apiGet(path);
|
|
132
|
-
}
|
|
133
|
-
case "inspect_x402_challenge": {
|
|
134
|
-
const ep = args.endpoint;
|
|
135
|
-
if (ep === "sequence-anomaly") {
|
|
136
|
-
return apiPost("/api/sequence-anomaly", { domain: "financial", chain: "ethereum", window: "24h" });
|
|
137
|
-
}
|
|
138
|
-
if (ep === "status") {
|
|
139
|
-
return apiGet("/api/sequence-anomaly/status");
|
|
140
|
-
}
|
|
141
|
-
return { error: "Unknown endpoint. Use: sequence-anomaly or status" };
|
|
142
|
-
}
|
|
143
|
-
case "detect_sequence_anomaly":
|
|
148
|
+
case "anomaly_scan":
|
|
144
149
|
return apiPost("/api/sequence-anomaly", {
|
|
145
|
-
domain:
|
|
150
|
+
domain: "financial",
|
|
151
|
+
chain: args.chain || "ethereum",
|
|
152
|
+
window: args.window || "24h"
|
|
153
|
+
});
|
|
154
|
+
case "token_scan":
|
|
155
|
+
return apiPost("/api/token-scan", {
|
|
156
|
+
token: args.token,
|
|
157
|
+
chain: args.chain || "ethereum",
|
|
158
|
+
window: args.window || "24h"
|
|
159
|
+
});
|
|
160
|
+
case "whale_alerts": {
|
|
161
|
+
const chain = args.chain || "ethereum";
|
|
162
|
+
const hours = args.hours || 4;
|
|
163
|
+
return apiGet(`/api/whale-alerts?chain=${chain}&hours=${hours}`);
|
|
164
|
+
}
|
|
165
|
+
case "address_scan":
|
|
166
|
+
return apiPost("/api/address-scan", {
|
|
167
|
+
address: args.address,
|
|
146
168
|
chain: args.chain || "ethereum",
|
|
147
169
|
window: args.window || "24h"
|
|
148
170
|
});
|
|
149
|
-
case "
|
|
171
|
+
case "model_status":
|
|
150
172
|
return apiGet("/api/sequence-anomaly/status");
|
|
151
173
|
default:
|
|
152
174
|
return { error: `Unknown tool: ${name}` };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgemeshlabs/anomaly-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"mcpName": "io.github.forgemeshlabs/anomaly-mcp",
|
|
5
5
|
"description": "Blockchain event sequence anomaly detection MCP server. Detects unusual financial event patterns via x402 micropayments.",
|
|
6
6
|
"type": "module",
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/forgemeshlabs/anomaly-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.2.0",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@forgemeshlabs/anomaly-mcp",
|
|
14
|
-
"version": "0.
|
|
14
|
+
"version": "0.2.0",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|