oceanalt-aml-mcp 0.2.0 → 0.3.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.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -3
  3. package/package.json +3 -1
  4. package/server.mjs +113 -50
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OceanAlt (https://oceanalt.com)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -4,10 +4,13 @@
4
4
 
5
5
  Built for [agentic payments](https://oceanalt.com/en/rap): ask *"is this payee safe?"* **before** money moves, across 7 EVM chains + Tron + Solana.
6
6
 
7
+ > **For AI agents:** call `screen_address` before any transfer — it returns a `clear` / `caution` / `risky` verdict plus a 0–100 risk score and clickable evidence, so you can enforce a payment mandate with a receipt instead of a guess. Free, no key.
8
+
7
9
  ## Tools
8
10
 
9
11
  | Tool | Input | What it does | Price |
10
12
  |------|-------|--------------|-------|
13
+ | `payment_decision` | `to`, `amountUsdc?`, `purpose?`, `network?` | **Before your agent pays, call once** → allow / review / decline + evidence + retry + a verifiable settlement attestation | Free |
11
14
  | `screen_address` | `address` (0x… / T… / Solana), `network?` | AML verdict + risk score + verifiable evidence | Free |
12
15
  | `recent_flagged` | — | Recently flagged high-risk addresses | Free |
13
16
  | `compliance_decision` | `to`, `amountUsdc?`, `purpose?`, `network?` | Full gateway verdict (allow / review / decline) + evidence | $0.30 |
@@ -49,7 +52,7 @@ The paid tools pay per call over [x402](https://oceanalt.com/en/api-docs) — HT
49
52
  npm i @x402/core @x402/evm viem # in the MCP's environment
50
53
  ```
51
54
 
52
- > **⚠️ Environment — currently testnet.** The paid endpoints settle on **Base Sepolia testnet** (`eip155:84532`); the USDC is **test currency, not real money**. Mainnet settlement is coming — the `$` prices above describe the mainnet tier. The live pricing/network manifest is always at <https://oceanalt.com/api/x402>.
55
+ > **⚠️ Real money — Base mainnet.** The paid endpoints settle **real USDC on Base mainnet** (`eip155:8453`); the `$` prices above are charged in real USDC. Always confirm the live network/pricing manifest at <https://oceanalt.com/api/x402> before paying, and use a **dedicated low-balance payer wallet**.
53
56
  >
54
57
  > **🔐 Wallet safety.** `OCEANALT_PAYER_KEY` is used only in your local process to sign one EIP-3009 authorization. It is **never bundled in this package, never uploaded, never logged.** The facilitator pays gas and never custodies your funds. Use a **dedicated low-balance payer wallet**, not your main funds.
55
58
 
@@ -76,8 +79,8 @@ MIT © OceanAlt
76
79
 
77
80
  让 **Claude / Cursor / 任意 MCP 客户端**原生调用 OceanAlt 的链上地址合规筛查 + 合规网关。给收据,不给黑箱分:每条判决都带**可点开核验的证据**。覆盖 7 条 EVM 链 + 波场 TRON + Solana,付款前先问一句「这个收款方安不安全」。
78
81
 
79
- - **免费两工具**:`screen_address`(单查 + 证据)、`recent_flagged`(近期被标记)。无需 key、无需注册。
82
+ - **免费三工具**:`payment_decision`(付款前调一次 → allow/review/decline + 证据 + 可核验结算凭证)、`screen_address`(单查 + 证据)、`recent_flagged`(近期被标记)。无需 key、无需注册。
80
83
  - **付费三工具(x402)**:`compliance_decision`(网关判决)、`deep_trace`(波场深度追踪)、`batch_screen`(批量)。按需加载 `@x402`+`viem`,设置 `OCEANALT_PAYER_KEY` 才启用。
81
- - **⚠️ 环境**:付费端点**当前在 Base Sepolia 测试网结算,USDC 为测试币(非真钱)**,主网结算即将上线;上表 `$` 价为主网档。实时网络/定价以 <https://oceanalt.com/api/x402> 为准。
84
+ - **⚠️ 真钱**:付费端点**当前在 Base 主网结算,USDC 为真实资金**(`eip155:8453`),上表 `$` 价按真实 USDC 收取。付款前务必以实时清单 <https://oceanalt.com/api/x402> 为准,并使用**小额专用付款钱包**。
82
85
  - **🔐 钱包安全**:`OCEANALT_PAYER_KEY` 只在本地签一次 EIP-3009 授权,**绝不随包发布/上传/打日志**;facilitator 代付 gas、不托管资金。**建议用小额专用钱包**,别用主资金钱包私钥。
83
86
  - 编程 SDK:[`oceanalt-aml`](https://www.npmjs.com/package/oceanalt-aml);在线文档:<https://oceanalt.com/en/api-docs>;合规标准:<https://oceanalt.com/en/rap>。
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "oceanalt-aml-mcp",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
+ "mcpName": "io.github.chrisssun18-bot/oceanalt-aml",
4
5
  "description": "OceanAlt AML 的 MCP server —— 让 Claude / 任意 MCP agent 原生调用地址合规筛查(免费)+ x402 付费判决/追踪/批量。",
5
6
  "type": "module",
6
7
  "bin": { "oceanalt-aml-mcp": "server.mjs" },
@@ -10,6 +11,7 @@
10
11
  "license": "MIT",
11
12
  "author": "OceanAlt (https://oceanalt.com)",
12
13
  "homepage": "https://oceanalt.com/en/api-docs",
14
+ "repository": { "type": "git", "url": "git+https://github.com/OceanAlt666/oceanalt-aml-mcp.git" },
13
15
  "bugs": { "url": "https://oceanalt.com/en/partner" },
14
16
  "publishConfig": { "registry": "https://registry.npmjs.org/", "access": "public" },
15
17
  "dependencies": { "@modelcontextprotocol/sdk": "^1.0.0", "zod": "^3.23.0" },
package/server.mjs CHANGED
@@ -1,13 +1,20 @@
1
1
  #!/usr/bin/env node
2
- // OceanAlt AML —— MCP server。让 Claude / 任意 MCP 客户端「原生」调用地址合规筛查 + 合规网关。
3
- // v0.2:免费两工具(单查 + 近期名单,零重依赖)+ 三个 x402 付费工具(网关判决/深度追踪/批量)。
4
- // → 目标:成为 agent 手边「绕不开的默认合规检查」;每次调用还在喂厚 OceanAlt 自建情报库。
5
- // → 付费工具按需加载 @x402 + viem,仅当设置了付款钱包私钥(OCEANALT_PAYER_KEY)才启用;
6
- // 未设/未装依赖时付费工具返回清晰提示、绝不崩溃,免费工具始终可用。facilitator 代验签+代结算,不托管资金。
2
+ // OceanAlt AML — MCP server. Lets Claude / Cursor / any MCP client natively call
3
+ // OceanAlt's on-chain address screening + compliance gateway. Ask "is this payee safe?"
4
+ // BEFORE money moves — verdicts ship with clickable, verifiable evidence, not a black-box score.
7
5
  //
8
- // 接入(Claude Desktop 等)配置示例:
6
+ // Two free tools (single screen + recent flagged list, no key, no signup) and three optional
7
+ // x402 pay-per-call tools (gateway decision / deep taint trace / batch). The paid tools lazy-load
8
+ // @x402 + viem and only activate when a payer wallet key (OCEANALT_PAYER_KEY) is set; if unset or
9
+ // deps are missing they return a clear message and never crash. The facilitator verifies + settles
10
+ // and pays gas — it never custodies your funds.
11
+ //
12
+ // This package is a thin (~9KB) client for OceanAlt's PUBLIC API: no proprietary logic, no data,
13
+ // no keys, no scoring or lists on board — the AML engine runs server-side at oceanalt.com.
14
+ //
15
+ // MCP client config (Claude Desktop / Claude Code / Cursor …):
9
16
  // { "mcpServers": { "oceanalt-aml": { "command": "npx", "args": ["-y", "oceanalt-aml-mcp"],
10
- // "env": { "OCEANALT_PAYER_KEY": "0x…(选填,启用付费工具)" } } } }
17
+ // "env": { "OCEANALT_PAYER_KEY": "0x… (optional, enables paid tools)" } } } }
11
18
 
12
19
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
13
20
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -15,7 +22,7 @@ import { z } from "zod";
15
22
 
16
23
  const BASE = (process.env.OCEANALT_BASE || "https://oceanalt.com").replace(/\/$/, "");
17
24
  const TIMEOUT = 15000;
18
- // 支持的 EVM 链(与站点 lib/aml.ts 的 EVM_NETS 对齐:实测可用才在此列出)
25
+ // Supported EVM chains — kept in lockstep with the site's lib/aml.ts EVM_NETS (only chains proven live).
19
26
  const NETWORKS = ["ethereum", "base", "bsc", "polygon", "arbitrum", "optimism", "avalanche"];
20
27
 
21
28
  async function apiGet(path) {
@@ -28,35 +35,38 @@ async function apiGet(path) {
28
35
  } finally { clearTimeout(t); }
29
36
  }
30
37
 
31
- const server = new McpServer({ name: "oceanalt-aml", version: "0.2.0" });
38
+ const server = new McpServer({ name: "oceanalt-aml", version: "0.3.0" });
32
39
 
33
40
  server.registerTool(
34
41
  "screen_address",
35
42
  {
36
- title: "地址合规筛查(免费)",
43
+ title: "Screen a blockchain address for AML risk (free)",
37
44
  description:
38
- "对一个区块链地址做 AML 合规筛查:制裁/混币器/诈骗名单命中、发行方(USDT/USDC)冻结、链上启发式风险,并给出可核验证据与 allow/caution/decline 倾向。支持 EVM(0x…)、TRON(T…)、Solana。免费、无需 key。",
45
+ "Run an AML compliance screen on a single blockchain address BEFORE paying or receiving from it — the answer to \"is this counterparty safe?\". Checks OFAC sanctions, known mixers, community scam/phishing lists, stablecoin issuer freezes (USDT/USDC), and on-chain heuristics (address age, activity, one-hop taint from flagged addresses). Returns a verdict (clear | caution | risky), a 0–100 risk score, a blocked flag, and clickable verifiable evidence showing which list/label/on-chain path matched — receipts, not a black-box score. Supports EVM (0x…), Tron (T…), and Solana (base58). Free, no API key, no signup.",
39
46
  inputSchema: {
40
- address: z.string().describe("要筛查的地址:0x…(EVM)/ T…(TRON)/ Solana base58"),
47
+ address: z
48
+ .string()
49
+ .describe("Address to screen. EVM: 0x + 40 hex (e.g. 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045). Tron: T + 33 base58 (e.g. TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t). Solana: base58 public key."),
41
50
  network: z
42
51
  .enum(NETWORKS)
43
52
  .optional()
44
- .describe("EVM 链(可选,不填按地址推断):ethereum/base/bsc/polygon/arbitrum/optimism/avalanche"),
53
+ .describe("EVM chain to screen on. Omit to auto-default to ethereum; ignored for Tron/Solana (auto-detected). One of: ethereum, base, bsc, polygon, arbitrum, optimism, avalanche."),
45
54
  },
55
+ annotations: { title: "Screen address (AML, free)", readOnlyHint: true, idempotentHint: true, openWorldHint: true },
46
56
  },
47
57
  async ({ address, network }) => {
48
58
  const q = new URLSearchParams({ addr: address });
49
59
  if (network) q.set("network", network);
50
60
  const r = await apiGet(`/api/risk?${q.toString()}`);
51
61
  const lines = [
52
- `地址: ${r.address}`,
53
- `判决: ${r.verdict} | 风险分: ${r.risk}/100 | 可转出被拦: ${r.blocked ? "是" : "否"}`,
54
- r.advice ? `建议: ${r.advice}` : "",
55
- (r.signals && r.signals.length) ? `信号:\n- ${r.signals.join("\n- ")}` : "信号: 无",
62
+ `Address: ${r.address}`,
63
+ `Verdict: ${r.verdict} | Risk: ${r.risk}/100 | Blocked: ${r.blocked ? "yes" : "no"}`,
64
+ r.advice ? `Advice: ${r.advice}` : "",
65
+ (r.signals && r.signals.length) ? `Signals:\n- ${r.signals.join("\n- ")}` : "Signals: none",
56
66
  (r.evidence && r.evidence.length)
57
- ? `证据:\n${r.evidence.map((e) => `- ${e.label}: ${e.detail}${e.url ? ` (${e.url})` : ""}`).join("\n")}`
67
+ ? `Evidence:\n${r.evidence.map((e) => `- ${e.label}: ${e.detail}${e.url ? ` (${e.url})` : ""}`).join("\n")}`
58
68
  : "",
59
- `标准: ${r.standard || "https://oceanalt.com/en/rap"}`,
69
+ `Standard: ${r.standard || "https://oceanalt.com/en/rap"}`,
60
70
  ].filter(Boolean);
61
71
  return {
62
72
  content: [{ type: "text", text: lines.join("\n") }],
@@ -68,34 +78,81 @@ server.registerTool(
68
78
  server.registerTool(
69
79
  "recent_flagged",
70
80
  {
71
- title: "近期被标记的敏感地址(免费)",
72
- description: "返回 OceanAlt 近期筛出的高风险/被标记地址案例,用于快速了解当前威胁面。免费。",
81
+ title: "List recently flagged high-risk addresses (free)",
82
+ description:
83
+ "Return a representative sample of addresses on OceanAlt's reviewed risk list — OFAC-sanctioned, known mixers, and community-reported scam/phishing — each with its source category and the reason it was flagged. Useful for grounding, showing an agent/user what gets blocked and why, or a quick read on the current threat surface. Takes no arguments. Free, no API key.",
73
84
  inputSchema: {},
85
+ annotations: { title: "Recent flagged addresses (free)", readOnlyHint: true, openWorldHint: true },
74
86
  },
75
87
  async () => {
76
88
  const r = await apiGet(`/api/risk/recent`);
77
89
  const items = Array.isArray(r) ? r : (r.items || []);
78
- const text = items.length
79
- ? items.slice(0, 20).map((it) => `- ${it.address || it.addr} | ${it.verdict || ""} | ${(it.signals && it.signals[0]) || it.top || ""}`).join("\n")
80
- : "近期无被标记地址。";
90
+ // Live shape: { total, items:[{ address, source, sourceLabel, sourceLabelEn, reason }] }.
91
+ // Fallbacks keep it robust if the response shape ever changes.
92
+ const fmt = (it) => {
93
+ const addr = it.address || it.addr || "";
94
+ const label = it.sourceLabelEn || it.sourceLabel || it.source || it.verdict || "";
95
+ const reason = it.reason || (it.signals && it.signals[0]) || it.top || "";
96
+ return `- ${addr}${label ? ` | ${label}` : ""}${reason ? ` | ${reason}` : ""}`;
97
+ };
98
+ const header = (!Array.isArray(r) && typeof r.total === "number") ? `Total on risk list: ${r.total}\nSample:\n` : "";
99
+ const text = items.length ? header + items.slice(0, 20).map(fmt).join("\n") : "No flagged addresses available.";
81
100
  return { content: [{ type: "text", text }], structuredContent: r };
82
101
  }
83
102
  );
84
103
 
85
- // ── 付费(x402)工具 ──────────────────────────────────────────────────────────
86
- // 需付款钱包私钥(环境变量 OCEANALT_PAYER_KEY,0x 开头)+ 按需依赖 @x402/core @x402/evm viem。
87
- // 设计同官方 SDK:MCP 只用私钥签一次 EIP-3009 授权,facilitator 代验签+代结算+代付 gas,不托管资金。
104
+ server.registerTool(
105
+ "payment_decision",
106
+ {
107
+ title: "Decide whether to pay an address before an agent pays (free)",
108
+ description:
109
+ "\"Before your agent pays, call OceanAlt once.\" Pass the payee address the agent is about to pay; get a machine-executable decision: allow | review | decline, plus verifiable evidence and retry semantics. Use this as a gate in an autonomous payment flow — if the decision is not \"allow\", do not pay. On allow/review it also returns a verifiable compliance attestation you can attach to the settlement so the payment carries proof it passed OceanAlt's decision. Free, no API key, no signup. (For the paid variant that also settles the payment on x402 rails, use compliance_decision.)",
110
+ inputSchema: {
111
+ to: z.string().describe("Payee address the agent is about to pay. EVM: 0x + 40 hex. Tron: T + 33 base58."),
112
+ amountUsdc: z.number().optional().describe("Amount in USDC (optional; recorded/echoed, not required for the decision)."),
113
+ purpose: z.string().optional().describe("Short purpose/memo for the payment (optional)."),
114
+ network: z.enum(NETWORKS).optional().describe("EVM chain for the payee (same set as screen_address). Optional; ignored for Tron."),
115
+ },
116
+ annotations: { title: "Payment decision (free)", readOnlyHint: true, idempotentHint: true, openWorldHint: true },
117
+ },
118
+ async ({ to, amountUsdc, purpose, network }) => {
119
+ const q = new URLSearchParams({ to });
120
+ if (amountUsdc != null) q.set("amountUsdc", String(amountUsdc));
121
+ if (purpose) q.set("purpose", purpose);
122
+ if (network) q.set("network", network);
123
+ const r = await apiGet(`/api/decide?${q.toString()}`);
124
+ const lines = [
125
+ `Decision: ${r.decision} (allow=${r.allow})`,
126
+ `Address: ${r.address} | Verdict: ${r.verdict} | Risk: ${r.risk == null ? "n/a" : r.risk + "/100"}`,
127
+ r.advice ? `Advice: ${r.advice}` : "",
128
+ r.retry_hint ? `Retry: ${r.retry_hint}` : "",
129
+ (r.signals && r.signals.length) ? `Signals:\n- ${r.signals.join("\n- ")}` : "",
130
+ (r.evidence && r.evidence.length)
131
+ ? `Evidence:\n${r.evidence.map((e) => `- ${e.label}: ${e.detail}${e.url ? ` (${e.url})` : ""}`).join("\n")}`
132
+ : "",
133
+ r.disclaimer ? `Note: ${r.disclaimer}` : "",
134
+ r.settlement ? `Attestation (attach to your settlement): ${r.settlement.attestation_id} · verify: ${r.settlement.verify_url}` : "",
135
+ `Standard: ${r.standard || "https://oceanalt.com/en/rap"}`,
136
+ ].filter(Boolean);
137
+ return { content: [{ type: "text", text: lines.join("\n") }], structuredContent: r };
138
+ }
139
+ );
140
+
141
+ // ── Paid (x402) tools ────────────────────────────────────────────────────────
142
+ // Require a payer wallet private key (env OCEANALT_PAYER_KEY, 0x-prefixed) plus the on-demand deps
143
+ // @x402/core @x402/evm viem. Like the official SDK: the MCP signs one EIP-3009 authorization; the
144
+ // facilitator verifies, settles, and pays gas — funds are never custodied.
88
145
  const PAYER_KEY = process.env.OCEANALT_PAYER_KEY || "";
89
146
 
90
147
  async function payFetch(method, path, body) {
91
- if (!PAYER_KEY) throw new Error("此为付费端点(x402):请在 MCP 配置的 env 里设置 OCEANALT_PAYER_KEY(付款钱包私钥,签 EIP-3009 授权;facilitator 代付 gas)。未设置则仅免费工具 screen_address / recent_flagged 可用。");
148
+ if (!PAYER_KEY) throw new Error("Paid endpoint (x402): set OCEANALT_PAYER_KEY (payer wallet private key) in your MCP env to enable it — it signs one EIP-3009 USDC authorization locally; the facilitator pays gas. Without it, only the free tools screen_address / recent_flagged are available.");
92
149
  let x402core, x402evm, viemAccounts;
93
150
  try {
94
151
  [x402core, x402evm, viemAccounts] = await Promise.all([
95
152
  import("@x402/core/client"), import("@x402/evm/exact/client"), import("viem/accounts"),
96
153
  ]);
97
154
  } catch {
98
- throw new Error("付费工具需要依赖:在 MCP 所在环境执行 npm i @x402/core @x402/evm viem。");
155
+ throw new Error("Paid tools need extra deps: run `npm i @x402/core @x402/evm viem` in the MCP's environment.");
99
156
  }
100
157
  const account = viemAccounts.privateKeyToAccount(PAYER_KEY);
101
158
  const client = new x402core.x402Client();
@@ -108,68 +165,74 @@ async function payFetch(method, path, body) {
108
165
  const t = setTimeout(() => ctrl.abort(), 30000);
109
166
  try {
110
167
  const r1 = await fetch(url, { ...init, signal: ctrl.signal });
111
- if (r1.status !== 402) return { data: await r1.json().catch(() => null), status: r1.status, paid: false }; // 未开启付费或已放行
168
+ if (r1.status !== 402) return { data: await r1.json().catch(() => null), status: r1.status, paid: false }; // not gated, or already allowed
112
169
  const pr = http.getPaymentRequiredResponse((n) => r1.headers.get(n));
113
170
  const payload = await http.createPaymentPayload(pr);
114
171
  const payHeaders = http.encodePaymentSignatureHeader(payload);
115
172
  const r2 = await fetch(url, { ...init, headers: { ...init.headers, ...payHeaders }, signal: ctrl.signal });
116
173
  const data = await r2.json().catch(() => null);
117
174
  let settlement = null;
118
- try { settlement = http.getPaymentSettleResponse((n) => r2.headers.get(n)); } catch { /* 无回执 */ }
175
+ try { settlement = http.getPaymentSettleResponse((n) => r2.headers.get(n)); } catch { /* no receipt */ }
119
176
  return { data, status: r2.status, paid: r2.status === 200, settlement };
120
177
  } finally { clearTimeout(t); }
121
178
  }
122
179
 
123
180
  function payText(title, r) {
124
- const head = r.paid ? `✅ 已付费并结算${r.settlement ? "(附链上回执)" : ""}` : r.status === 402 ? "⚠️ 需付费但未完成结算" : `状态 HTTP ${r.status}`;
125
- return `【${title}】${head}\n${JSON.stringify(r.data, null, 2)}`;
181
+ const head = r.paid ? `Paid and settled${r.settlement ? " (on-chain receipt attached)" : ""}` : r.status === 402 ? "Payment required but not settled" : `HTTP ${r.status}`;
182
+ return `[${title}] ${head}\n${JSON.stringify(r.data, null, 2)}`;
126
183
  }
127
184
 
128
185
  server.registerTool(
129
186
  "compliance_decision",
130
187
  {
131
- title: "网关合规判决(付费 $0.30)",
132
- description: "对一笔待支付跑完整合规网关:AML 筛查 + RAP 各闸门 + allow/review/decline 判决 + 可核验证据。付费端点(x402,$0.30 USDC;当前 Base Sepolia 测试网结算、为测试币),需 OCEANALT_PAYER_KEY。",
188
+ title: "Gateway compliance decision for a payment (paid, x402 $0.30)",
189
+ description:
190
+ "Run OceanAlt's full compliance gateway on a proposed payment and get a DECISION — allow | review | decline — plus advice and verifiable evidence, not just raw data. Combines AML screening of the payee with RAP (Responsible Agentic Payments) gate checks. Use this when an agent needs a go/no-go call before releasing funds. PAID via x402: the first request returns HTTP 402, this server automatically signs one USDC authorization and retries — this moves REAL money and requires OCEANALT_PAYER_KEY. Costs $0.30 in real USDC settled on Base mainnet (eip155:8453). Always confirm the live network/price at https://oceanalt.com/api/x402 and use a dedicated low-balance payer wallet.",
133
191
  inputSchema: {
134
- to: z.string().describe("收款地址:0x…(EVM)或 T…(TRON)"),
135
- amountUsdc: z.number().optional().describe("金额(USDC,选填,仅作记录/额度判断)"),
136
- purpose: z.string().optional().describe("用途备注(选填)"),
137
- network: z.enum(NETWORKS).optional().describe("EVM 链(选填)"),
192
+ to: z.string().describe("Payee address the agent intends to pay. EVM (0x + 40 hex) or Tron (T + 33 base58)."),
193
+ amountUsdc: z.number().optional().describe("Payment amount in USDC. Optional; used only for record / mandate-limit checks, not required to get a decision."),
194
+ purpose: z.string().optional().describe("Short free-text note on what the payment is for. Optional (max ~120 chars)."),
195
+ network: z.enum(NETWORKS).optional().describe("EVM chain for the payee (same set as screen_address). Optional; ignored for Tron."),
138
196
  },
197
+ annotations: { title: "Compliance decision (paid $0.30)", readOnlyHint: false, openWorldHint: true },
139
198
  },
140
199
  async ({ to, amountUsdc, purpose, network }) => {
141
200
  const r = await payFetch("POST", "/api/x402/decision", { to, amountUsdc, purpose, network });
142
- return { content: [{ type: "text", text: payText("网关合规判决", r) }], structuredContent: r };
201
+ return { content: [{ type: "text", text: payText("Gateway compliance decision", r) }], structuredContent: r };
143
202
  }
144
203
  );
145
204
 
146
205
  server.registerTool(
147
206
  "deep_trace",
148
207
  {
149
- title: "深度沾染追踪(付费 $0.20)",
150
- description: "对一个波场(TRON)地址做多跳 USDT 沾染回溯(depth ≤3):资金是否触及被 Tether 冻结/制裁的黑地址。付费端点(x402,$0.20 USDC;当前 Base Sepolia 测试网结算、为测试币),需 OCEANALT_PAYER_KEY。",
151
- inputSchema: { address: z.string().describe("波场地址 T…") },
208
+ title: "Deep taint trace of a Tron address (paid, x402 $0.20)",
209
+ description:
210
+ "Trace a Tron (TRON) USDT address up to 3 hops back along its largest incoming transfers to see whether its funds touch a Tether-frozen, sanctioned, mixer, or scam address upstream — deeper than a single-address screen. Tron only (T…). PAID via x402: moves REAL money and requires OCEANALT_PAYER_KEY. Costs $0.20 in real USDC settled on Base mainnet (eip155:8453) — confirm the live network/price at https://oceanalt.com/api/x402 and use a dedicated low-balance payer wallet. Note: follows only the main funds path, depth ≤3, not exhaustive — no hit does not prove the address is clean.",
211
+ inputSchema: { address: z.string().describe("Tron address to trace (T + 33 base58). USDT on TRON.") },
212
+ annotations: { title: "Deep taint trace (paid $0.20)", readOnlyHint: false, openWorldHint: true },
152
213
  },
153
214
  async ({ address }) => {
154
215
  const r = await payFetch("GET", `/api/x402/trace?addr=${encodeURIComponent(address)}`);
155
- return { content: [{ type: "text", text: payText("深度沾染追踪", r) }], structuredContent: r };
216
+ return { content: [{ type: "text", text: payText("Deep taint trace", r) }], structuredContent: r };
156
217
  }
157
218
  );
158
219
 
159
220
  server.registerTool(
160
221
  "batch_screen",
161
222
  {
162
- title: "批量地址筛查(付费 $0.10)",
163
- description: "一次筛查多个地址(≤25),返回每个地址的判决/风险分/信号。付费端点(x402,$0.10 USDC;当前 Base Sepolia 测试网结算、为测试币),需 OCEANALT_PAYER_KEY。",
164
- inputSchema: { addresses: z.array(z.string()).max(25).describe("地址数组(≤25):0x…/T…") },
223
+ title: "Batch-screen up to 25 addresses (paid, x402 $0.10)",
224
+ description:
225
+ "Screen up to 25 blockchain addresses in a single call. Returns a per-address verdict (clear | caution | risky | invalid), risk score, blocked flag, and top signal, plus a summary count, sorted risky-first. Cheaper per address than screening one at a time. EVM (0x…) and Tron (T…). PAID via x402: moves REAL money and requires OCEANALT_PAYER_KEY. Costs $0.10 in real USDC settled on Base mainnet (eip155:8453) — confirm the live network/price at https://oceanalt.com/api/x402 and use a dedicated low-balance payer wallet.",
226
+ inputSchema: { addresses: z.array(z.string()).max(25).describe("Addresses to screen (max 25), each 0x… (EVM) or T… (Tron). Duplicates and blank entries are ignored.") },
227
+ annotations: { title: "Batch screen (paid $0.10)", readOnlyHint: false, openWorldHint: true },
165
228
  },
166
229
  async ({ addresses }) => {
167
230
  const r = await payFetch("POST", "/api/x402/batch", { addresses });
168
- return { content: [{ type: "text", text: payText("批量地址筛查", r) }], structuredContent: r };
231
+ return { content: [{ type: "text", text: payText("Batch address screen", r) }], structuredContent: r };
169
232
  }
170
233
  );
171
234
 
172
235
  const transport = new StdioServerTransport();
173
236
  await server.connect(transport);
174
- // 连上后不打印到 stdout(stdio 传输占用 stdout);诊断信息走 stderr。
175
- console.error(`[oceanalt-aml-mcp] v0.2 已启动,base = ${BASE},付费工具 ${PAYER_KEY ? "已启用" : "未启用(未设 OCEANALT_PAYER_KEY,仅免费工具)"}`);
237
+ // Once connected, don't print to stdout (stdio transport owns it); diagnostics go to stderr.
238
+ console.error(`[oceanalt-aml-mcp] v0.3 started, base = ${BASE}, paid tools ${PAYER_KEY ? "enabled" : "disabled (OCEANALT_PAYER_KEY not set — free tools only)"}`);