@nullclear/mcp 1.1.1 → 1.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 +34 -34
- package/dist/index.js +551 -19
- package/package.json +19 -4
package/README.md
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
# @nullclear/mcp
|
|
2
|
-
|
|
3
|
-
<!-- mcp-name: io.github.
|
|
4
|
-
|
|
5
|
-
[](https://mcpservers.org/servers/nullclear-protocol/nullclear)
|
|
6
|
-
[](https://glama.ai/mcp/servers/Nullclear-Protocol/nullclear)
|
|
7
|
-
[](https://glama.ai/mcp/servers/Nullclear-Protocol/nullclear)
|
|
8
|
-
|
|
9
|
-
Model Context Protocol (MCP) server enabling autonomous AI agents (Claude Desktop, Cursor, Gemini, OpenAI Agents) to safely transact over HTTP 402 with NullClear deferred escrow and reputation scoring.
|
|
10
|
-
|
|
11
|
-
## Exposed Tools
|
|
12
|
-
|
|
13
|
-
1. `nullclear_check_reputation`: Query an agent's on-chain trust score, clearing reliability, and Sybil wash-trade penalty flags.
|
|
14
|
-
2. `nullclear_escrow_x402_call`: Perform an HTTP 402 call with deferred non-custodial schema escrow, guaranteeing $0 spent if the counterparty agent fails or returns malformed data.
|
|
15
|
-
3. `nullclear_verify_kya_mandate`: Verify an agent's legal corporate liability backing and per-transaction limits.
|
|
16
|
-
|
|
17
|
-
## Configuration
|
|
18
|
-
|
|
19
|
-
Add to your MCP client config (e.g., `claude_desktop_config.json`):
|
|
20
|
-
|
|
21
|
-
```json
|
|
22
|
-
{
|
|
23
|
-
"mcpServers": {
|
|
24
|
-
"nullclear": {
|
|
25
|
-
"command": "node",
|
|
26
|
-
"args": ["/path/to/nullclear/packages/mcp-server/dist/index.js"],
|
|
27
|
-
"env": {
|
|
28
|
-
"ARBITER_URL": "https://arbiter.nullclear.dev",
|
|
29
|
-
"BUYER_PRIVATE_KEY": "0x..."
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
```
|
|
1
|
+
# @nullclear/mcp
|
|
2
|
+
|
|
3
|
+
<!-- mcp-name: io.github.Nullclear-Protocol/nullclear -->
|
|
4
|
+
|
|
5
|
+
[](https://mcpservers.org/servers/nullclear-protocol/nullclear)
|
|
6
|
+
[](https://glama.ai/mcp/servers/Nullclear-Protocol/nullclear)
|
|
7
|
+
[](https://glama.ai/mcp/servers/Nullclear-Protocol/nullclear)
|
|
8
|
+
|
|
9
|
+
Model Context Protocol (MCP) server enabling autonomous AI agents (Claude Desktop, Cursor, Gemini, OpenAI Agents) to safely transact over HTTP 402 with NullClear deferred escrow and reputation scoring.
|
|
10
|
+
|
|
11
|
+
## Exposed Tools
|
|
12
|
+
|
|
13
|
+
1. `nullclear_check_reputation`: Query an agent's on-chain trust score, clearing reliability, and Sybil wash-trade penalty flags.
|
|
14
|
+
2. `nullclear_escrow_x402_call`: Perform an HTTP 402 call with deferred non-custodial schema escrow, guaranteeing $0 spent if the counterparty agent fails or returns malformed data.
|
|
15
|
+
3. `nullclear_verify_kya_mandate`: Verify an agent's legal corporate liability backing and per-transaction limits.
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
Add to your MCP client config (e.g., `claude_desktop_config.json`):
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"mcpServers": {
|
|
24
|
+
"nullclear": {
|
|
25
|
+
"command": "node",
|
|
26
|
+
"args": ["/path/to/nullclear/packages/mcp-server/dist/index.js"],
|
|
27
|
+
"env": {
|
|
28
|
+
"ARBITER_URL": "https://arbiter.nullclear.dev",
|
|
29
|
+
"BUYER_PRIVATE_KEY": "0x..."
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
package/dist/index.js
CHANGED
|
@@ -5,49 +5,211 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
6
|
import {
|
|
7
7
|
CallToolRequestSchema,
|
|
8
|
-
ListToolsRequestSchema
|
|
8
|
+
ListToolsRequestSchema,
|
|
9
|
+
ListPromptsRequestSchema,
|
|
10
|
+
GetPromptRequestSchema,
|
|
11
|
+
ListResourcesRequestSchema,
|
|
12
|
+
ReadResourceRequestSchema
|
|
9
13
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
10
14
|
import { NullClearClient, createNullClearFetch, NullClearEscrowAbortedError } from "@nullclear/x402-arbiter";
|
|
11
|
-
var ARBITER_URL = process.env.ARBITER_URL || "https://api.nullclear.dev";
|
|
12
|
-
var
|
|
13
|
-
var
|
|
15
|
+
var ARBITER_URL = (process.env.ARBITER_URL || "https://api.nullclear.dev").replace(/\/$/, "");
|
|
16
|
+
var CONFIGURED_PRIVATE_KEY = process.env.NULLCLEAR_PRIVATE_KEY || process.env.BUYER_PRIVATE_KEY;
|
|
17
|
+
var MCP_SESSION_ID = `mcp_stdio_${process.pid}_${Math.random().toString(36).slice(2, 8)}`;
|
|
14
18
|
var client = new NullClearClient({ arbiterUrl: ARBITER_URL });
|
|
15
19
|
var server = new Server(
|
|
16
20
|
{
|
|
17
21
|
name: "nullclear-mcp-server",
|
|
18
|
-
version: "1.
|
|
22
|
+
version: "1.2.0"
|
|
19
23
|
},
|
|
20
24
|
{
|
|
21
25
|
capabilities: {
|
|
22
|
-
tools: {}
|
|
26
|
+
tools: {},
|
|
27
|
+
prompts: {},
|
|
28
|
+
resources: {}
|
|
23
29
|
}
|
|
24
30
|
}
|
|
25
31
|
);
|
|
32
|
+
async function callBazaarOrProxyWithFreeTrialFirst(endpointUrl, method = "GET", body) {
|
|
33
|
+
const headers = {
|
|
34
|
+
Accept: "application/json",
|
|
35
|
+
"x-nullclear-free-trial": "true",
|
|
36
|
+
"x-mcp-session": MCP_SESSION_ID
|
|
37
|
+
};
|
|
38
|
+
if (body !== void 0 && method !== "GET") {
|
|
39
|
+
headers["Content-Type"] = "application/json";
|
|
40
|
+
}
|
|
41
|
+
const trialRes = await fetch(endpointUrl, {
|
|
42
|
+
method,
|
|
43
|
+
headers,
|
|
44
|
+
body: body !== void 0 && method !== "GET" ? typeof body === "string" ? body : JSON.stringify(body) : void 0
|
|
45
|
+
});
|
|
46
|
+
if (trialRes.status === 200) {
|
|
47
|
+
const text = await trialRes.text();
|
|
48
|
+
let parsed = text;
|
|
49
|
+
try {
|
|
50
|
+
parsed = JSON.parse(text);
|
|
51
|
+
} catch {
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
status: 200,
|
|
55
|
+
data: parsed,
|
|
56
|
+
tier: trialRes.headers.get("x-nullclear-tier") || "free-trial",
|
|
57
|
+
remainingFreeCalls: trialRes.headers.get("x-nullclear-remaining-free-calls"),
|
|
58
|
+
receipt: trialRes.headers.get("X-NullClear-Attestation") || trialRes.headers.get("X-NullClear-Receipt-Id")
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (trialRes.status === 402 && CONFIGURED_PRIVATE_KEY) {
|
|
62
|
+
const nullclearFetch = createNullClearFetch({
|
|
63
|
+
accountOrPrivateKey: CONFIGURED_PRIVATE_KEY,
|
|
64
|
+
chainId: 8453,
|
|
65
|
+
arbiterUrl: ARBITER_URL
|
|
66
|
+
});
|
|
67
|
+
const paidRes = await nullclearFetch(endpointUrl, {
|
|
68
|
+
method,
|
|
69
|
+
headers: body !== void 0 && method !== "GET" ? { "Content-Type": "application/json" } : void 0,
|
|
70
|
+
body: body !== void 0 && method !== "GET" ? typeof body === "string" ? body : JSON.stringify(body) : void 0
|
|
71
|
+
});
|
|
72
|
+
const text = await paidRes.text();
|
|
73
|
+
let parsed = text;
|
|
74
|
+
try {
|
|
75
|
+
parsed = JSON.parse(text);
|
|
76
|
+
} catch {
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
status: paidRes.status,
|
|
80
|
+
data: parsed,
|
|
81
|
+
tier: "x402-paid",
|
|
82
|
+
remainingFreeCalls: "0",
|
|
83
|
+
receipt: paidRes.headers.get("X-NullClear-Attestation")
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const errText = await trialRes.text();
|
|
87
|
+
let errParsed = errText;
|
|
88
|
+
try {
|
|
89
|
+
errParsed = JSON.parse(errText);
|
|
90
|
+
} catch {
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
status: trialRes.status,
|
|
94
|
+
data: errParsed,
|
|
95
|
+
tier: "exhausted",
|
|
96
|
+
remainingFreeCalls: "0",
|
|
97
|
+
receipt: null
|
|
98
|
+
};
|
|
99
|
+
}
|
|
26
100
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
27
101
|
return {
|
|
28
102
|
tools: [
|
|
29
103
|
{
|
|
30
|
-
name: "
|
|
31
|
-
description: "
|
|
104
|
+
name: "nullclear_token_security_audit",
|
|
105
|
+
description: "Audit any Base ERC-20 token address for honeypots, buy/sell taxes, verified bytecode, and x402 compatibility via NullClear Bazaar. Works out-of-the-box with zero configuration (10 free daily calls included).",
|
|
106
|
+
annotations: {
|
|
107
|
+
title: "Base Token Honeypot & Security Audit",
|
|
108
|
+
readOnlyHint: true,
|
|
109
|
+
destructiveHint: false,
|
|
110
|
+
idempotentHint: true,
|
|
111
|
+
openWorldHint: true
|
|
112
|
+
},
|
|
32
113
|
inputSchema: {
|
|
33
114
|
type: "object",
|
|
34
|
-
required: ["
|
|
115
|
+
required: ["tokenAddress"],
|
|
35
116
|
properties: {
|
|
36
|
-
|
|
117
|
+
tokenAddress: {
|
|
37
118
|
type: "string",
|
|
38
|
-
description: "
|
|
119
|
+
description: "Base ERC-20 token contract address (e.g. '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' for USDC)",
|
|
120
|
+
default: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: "nullclear_wallet_risk_score",
|
|
127
|
+
description: "Check any wallet or agent address on Base for OFAC sanctions, Sybil wash-trading concentration flags, and ERC-8004 counterparty reputation. Works out-of-the-box with zero configuration (10 free daily calls included).",
|
|
128
|
+
annotations: {
|
|
129
|
+
title: "Wallet & Agent Sanctions / Sybil Risk Score",
|
|
130
|
+
readOnlyHint: true,
|
|
131
|
+
destructiveHint: false,
|
|
132
|
+
idempotentHint: true,
|
|
133
|
+
openWorldHint: true
|
|
134
|
+
},
|
|
135
|
+
inputSchema: {
|
|
136
|
+
type: "object",
|
|
137
|
+
required: ["walletAddress"],
|
|
138
|
+
properties: {
|
|
139
|
+
walletAddress: {
|
|
140
|
+
type: "string",
|
|
141
|
+
description: "0x wallet address or ERC-8004 agent ID to inspect"
|
|
39
142
|
},
|
|
40
143
|
chainId: {
|
|
41
144
|
type: "number",
|
|
42
|
-
description: "Base chain ID (8453
|
|
145
|
+
description: "Base chain ID (default 8453)",
|
|
43
146
|
default: 8453
|
|
44
147
|
}
|
|
45
148
|
}
|
|
46
149
|
}
|
|
47
150
|
},
|
|
151
|
+
{
|
|
152
|
+
name: "nullclear_crypto_market_oracle",
|
|
153
|
+
description: "Fetch multi-exchange spread-verified crypto spot prices (ETH/USDC, BTC/USDC, SOL/USDC, BASE/USDC) with cryptographic NullClear invariant receipts. Works out-of-the-box with zero configuration (10 free daily calls included).",
|
|
154
|
+
annotations: {
|
|
155
|
+
title: "Spread-Verified Crypto Market Price Oracle",
|
|
156
|
+
readOnlyHint: true,
|
|
157
|
+
destructiveHint: false,
|
|
158
|
+
idempotentHint: true,
|
|
159
|
+
openWorldHint: true
|
|
160
|
+
},
|
|
161
|
+
inputSchema: {
|
|
162
|
+
type: "object",
|
|
163
|
+
required: ["pair"],
|
|
164
|
+
properties: {
|
|
165
|
+
pair: {
|
|
166
|
+
type: "string",
|
|
167
|
+
description: "Trading pair symbol (e.g. 'ETH/USDC', 'BTC/USDC', 'SOL/USDC')",
|
|
168
|
+
default: "ETH/USDC"
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
name: "nullclear_safe_fetch",
|
|
175
|
+
description: "Zero-config drop-in URL fetcher with automatic Canonical LLM Refusal Guard, HTTP 5xx crash guard, empty-JSON guard, and cryptographic execution receipt. Protects agents from hallucinated or broken API responses.",
|
|
176
|
+
annotations: {
|
|
177
|
+
title: "Auto-Guarded URL Fetcher (Zero Schema Required)",
|
|
178
|
+
readOnlyHint: true,
|
|
179
|
+
destructiveHint: false,
|
|
180
|
+
idempotentHint: true,
|
|
181
|
+
openWorldHint: true
|
|
182
|
+
},
|
|
183
|
+
inputSchema: {
|
|
184
|
+
type: "object",
|
|
185
|
+
required: ["url"],
|
|
186
|
+
properties: {
|
|
187
|
+
url: {
|
|
188
|
+
type: "string",
|
|
189
|
+
description: "Target HTTPS URL to fetch and verify through NullClear Auto-Guard"
|
|
190
|
+
},
|
|
191
|
+
method: {
|
|
192
|
+
type: "string",
|
|
193
|
+
enum: ["GET", "POST"],
|
|
194
|
+
default: "GET"
|
|
195
|
+
},
|
|
196
|
+
body: {
|
|
197
|
+
type: "string",
|
|
198
|
+
description: "Optional JSON string body for POST requests"
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
},
|
|
48
203
|
{
|
|
49
204
|
name: "nullclear_escrow_x402_call",
|
|
50
|
-
description: "Execute an x402-gated HTTP API call through NullClear deferred schema escrow. The arbiter guarantees payment is only settled if upstream returns valid data matching your schema contract.
|
|
205
|
+
description: "Execute an x402-gated HTTP API call through NullClear deferred schema escrow. The arbiter guarantees payment is only settled if upstream returns valid data matching your schema contract. Works out-of-the-box with 10 free daily trial calls before requiring NULLCLEAR_PRIVATE_KEY.",
|
|
206
|
+
annotations: {
|
|
207
|
+
title: "Execute Escrowed x402 Call with Invariants",
|
|
208
|
+
readOnlyHint: false,
|
|
209
|
+
destructiveHint: false,
|
|
210
|
+
idempotentHint: false,
|
|
211
|
+
openWorldHint: true
|
|
212
|
+
},
|
|
51
213
|
inputSchema: {
|
|
52
214
|
type: "object",
|
|
53
215
|
required: ["targetUrl"],
|
|
@@ -86,7 +248,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
86
248
|
type: "object",
|
|
87
249
|
required: ["path"],
|
|
88
250
|
properties: {
|
|
89
|
-
path: { type: "string" },
|
|
251
|
+
path: { type: "string", description: "Dot-notation property path" },
|
|
90
252
|
gt: { type: "number" },
|
|
91
253
|
gte: { type: "number" },
|
|
92
254
|
lt: { type: "number" },
|
|
@@ -124,13 +286,39 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
124
286
|
type: "object",
|
|
125
287
|
description: "Outbound spend firewall limits (maxPerCallAtomic, maxDailyWalletAtomic)",
|
|
126
288
|
properties: {
|
|
127
|
-
maxPerCallAtomic: { type: "string" },
|
|
128
|
-
maxDailyWalletAtomic: { type: "string" }
|
|
289
|
+
maxPerCallAtomic: { type: "string", description: "Max atomic USDC spend allowed per call" },
|
|
290
|
+
maxDailyWalletAtomic: { type: "string", description: "Max rolling daily atomic USDC spend allowed" }
|
|
129
291
|
}
|
|
130
292
|
},
|
|
131
293
|
buyerPrivateKey: {
|
|
132
294
|
type: "string",
|
|
133
|
-
description: "Optional buyer private key (defaults to
|
|
295
|
+
description: "Optional buyer private key (defaults to Sponsored Free Tier, then NULLCLEAR_PRIVATE_KEY)"
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
name: "nullclear_check_reputation",
|
|
302
|
+
description: "Inspect an AI agent's trust score (0-100), clearing reliability, Sybil wash-trade penalty flags, and corporate KYA backing on Base",
|
|
303
|
+
annotations: {
|
|
304
|
+
title: "Inspect AI Agent Trust & Sybil Score",
|
|
305
|
+
readOnlyHint: true,
|
|
306
|
+
destructiveHint: false,
|
|
307
|
+
idempotentHint: true,
|
|
308
|
+
openWorldHint: true
|
|
309
|
+
},
|
|
310
|
+
inputSchema: {
|
|
311
|
+
type: "object",
|
|
312
|
+
required: ["agentId"],
|
|
313
|
+
properties: {
|
|
314
|
+
agentId: {
|
|
315
|
+
type: "string",
|
|
316
|
+
description: "The ERC-8004 agent token ID or registered identifier (e.g. '124595')"
|
|
317
|
+
},
|
|
318
|
+
chainId: {
|
|
319
|
+
type: "number",
|
|
320
|
+
description: "Base chain ID (8453 for Mainnet, 84532 for Sepolia)",
|
|
321
|
+
default: 8453
|
|
134
322
|
}
|
|
135
323
|
}
|
|
136
324
|
}
|
|
@@ -138,6 +326,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
138
326
|
{
|
|
139
327
|
name: "nullclear_verify_kya_mandate",
|
|
140
328
|
description: "Verify an agent's Know Your Agent (KYA) corporate liability mandate, active validity, and whether a proposed transaction amount is within corporate limits",
|
|
329
|
+
annotations: {
|
|
330
|
+
title: "Verify Corporate KYA Mandate & Limits",
|
|
331
|
+
readOnlyHint: true,
|
|
332
|
+
destructiveHint: false,
|
|
333
|
+
idempotentHint: true,
|
|
334
|
+
openWorldHint: true
|
|
335
|
+
},
|
|
141
336
|
inputSchema: {
|
|
142
337
|
type: "object",
|
|
143
338
|
required: ["agentId", "transactionAmountUsd"],
|
|
@@ -161,9 +356,327 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
161
356
|
]
|
|
162
357
|
};
|
|
163
358
|
});
|
|
359
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
360
|
+
return {
|
|
361
|
+
prompts: [
|
|
362
|
+
{
|
|
363
|
+
name: "safe-x402-payment",
|
|
364
|
+
description: "Generate safety invariants and schema-escrow directives for an autonomous agent paying an upstream x402 seller.",
|
|
365
|
+
arguments: [
|
|
366
|
+
{
|
|
367
|
+
name: "targetUrl",
|
|
368
|
+
description: "Upstream API endpoint demanding x402 payment",
|
|
369
|
+
required: true
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
name: "sellerAgentId",
|
|
373
|
+
description: "Seller's ERC-8004 agent token ID to verify reputation",
|
|
374
|
+
required: false
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
name: "maxSpendAtomic",
|
|
378
|
+
description: "Maximum atomic USDC units authorized (default: 10000 = $0.01 USDC)",
|
|
379
|
+
required: false
|
|
380
|
+
}
|
|
381
|
+
]
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
name: "audit-erc8004-agent",
|
|
385
|
+
description: "Conduct an end-to-end trust audit on an ERC-8004 agent on Base including Sybil risk and corporate KYA backing.",
|
|
386
|
+
arguments: [
|
|
387
|
+
{
|
|
388
|
+
name: "agentId",
|
|
389
|
+
description: "ERC-8004 agent token ID (e.g. '124595')",
|
|
390
|
+
required: true
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
name: "chainId",
|
|
394
|
+
description: "Base chain ID (default: 8453)",
|
|
395
|
+
required: false
|
|
396
|
+
}
|
|
397
|
+
]
|
|
398
|
+
}
|
|
399
|
+
]
|
|
400
|
+
};
|
|
401
|
+
});
|
|
402
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
403
|
+
const { name, arguments: promptArgs } = request.params;
|
|
404
|
+
if (name === "safe-x402-payment") {
|
|
405
|
+
const targetUrl = promptArgs?.targetUrl || "https://api.nullclear.dev/v1/sandbox/market-feed";
|
|
406
|
+
const sellerAgentId = promptArgs?.sellerAgentId || "unknown";
|
|
407
|
+
const maxSpendAtomic = promptArgs?.maxSpendAtomic || "10000";
|
|
408
|
+
return {
|
|
409
|
+
description: "Safe x402 Escrow Clearing Directive",
|
|
410
|
+
messages: [
|
|
411
|
+
{
|
|
412
|
+
role: "user",
|
|
413
|
+
content: {
|
|
414
|
+
type: "text",
|
|
415
|
+
text: `You are preparing to execute an autonomous payment to an x402 service at ${targetUrl}.
|
|
416
|
+
|
|
417
|
+
Mandatory Safety Rules:
|
|
418
|
+
1. NEVER send unconditional payments directly to unverified endpoints.
|
|
419
|
+
2. Invoke the MCP tool 'nullclear_escrow_x402_call' with targetUrl="${targetUrl}", sellerAgentId="${sellerAgentId}", minTrustScore=50, and spendPolicy={ maxPerCallAtomic: "${maxSpendAtomic}" }.
|
|
420
|
+
3. Supply an explicit JSON schema and deep numeric invariants to validate the seller's response before settlement.
|
|
421
|
+
4. If the seller hallucinates, returns an LLM refusal, or crashes, the arbiter voids the payment automatically and $0.00 is charged.`
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
]
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
if (name === "audit-erc8004-agent") {
|
|
428
|
+
const agentId = promptArgs?.agentId || "124595";
|
|
429
|
+
const chainId = promptArgs?.chainId || "8453";
|
|
430
|
+
return {
|
|
431
|
+
description: "ERC-8004 Agent Trust & Sybil Audit",
|
|
432
|
+
messages: [
|
|
433
|
+
{
|
|
434
|
+
role: "user",
|
|
435
|
+
content: {
|
|
436
|
+
type: "text",
|
|
437
|
+
text: `Perform a comprehensive security audit of ERC-8004 agent #${agentId} on chain ${chainId}.
|
|
438
|
+
1. Run MCP tool 'nullclear_check_reputation' with agentId="${agentId}", chainId=${chainId}.
|
|
439
|
+
2. Run MCP tool 'nullclear_verify_kya_mandate' with agentId="${agentId}", chainId=${chainId}, transactionAmountUsd=1.0.
|
|
440
|
+
3. Analyze the composite trust score, letter grade (A-F), Sybil wash-trading risk flags, and corporate liability coverage.
|
|
441
|
+
4. Provide a clear recommendation on whether this agent is safe for autonomous financial counterparty interactions.`
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
]
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
throw new Error(`Unknown prompt: ${name}`);
|
|
448
|
+
});
|
|
449
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
450
|
+
return {
|
|
451
|
+
resources: [
|
|
452
|
+
{
|
|
453
|
+
uri: "nullclear://stats/live",
|
|
454
|
+
name: "NullClear Live Protocol Telemetry",
|
|
455
|
+
mimeType: "application/json",
|
|
456
|
+
description: "Live protocol metrics: total clearings, verified settlements, voided hallucinations, and indexed agents"
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
uri: "nullclear://docs/quickstart",
|
|
460
|
+
name: "NullClear Quickstart Guide",
|
|
461
|
+
mimeType: "text/markdown",
|
|
462
|
+
description: "Zero-loss x402 deferred schema escrow guide for autonomous AI agents on Base Mainnet"
|
|
463
|
+
}
|
|
464
|
+
]
|
|
465
|
+
};
|
|
466
|
+
});
|
|
467
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
468
|
+
const { uri } = request.params;
|
|
469
|
+
if (uri === "nullclear://stats/live") {
|
|
470
|
+
try {
|
|
471
|
+
const res = await fetch(`${ARBITER_URL}/v1/stats`);
|
|
472
|
+
const data = await res.json();
|
|
473
|
+
return {
|
|
474
|
+
contents: [
|
|
475
|
+
{
|
|
476
|
+
uri,
|
|
477
|
+
mimeType: "application/json",
|
|
478
|
+
text: JSON.stringify(data, null, 2)
|
|
479
|
+
}
|
|
480
|
+
]
|
|
481
|
+
};
|
|
482
|
+
} catch {
|
|
483
|
+
return {
|
|
484
|
+
contents: [
|
|
485
|
+
{
|
|
486
|
+
uri,
|
|
487
|
+
mimeType: "application/json",
|
|
488
|
+
text: JSON.stringify({
|
|
489
|
+
totalClearings: 0,
|
|
490
|
+
validSettlements: 0,
|
|
491
|
+
voidedHallucinations: 0,
|
|
492
|
+
totalAgentsIndexed: 1,
|
|
493
|
+
status: "active"
|
|
494
|
+
}, null, 2)
|
|
495
|
+
}
|
|
496
|
+
]
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
if (uri === "nullclear://docs/quickstart") {
|
|
501
|
+
return {
|
|
502
|
+
contents: [
|
|
503
|
+
{
|
|
504
|
+
uri,
|
|
505
|
+
mimeType: "text/markdown",
|
|
506
|
+
text: `# NullClear Arbiter Quickstart
|
|
507
|
+
|
|
508
|
+
NullClear is the autonomous deferred clearing and reputation protocol for AI agent commerce on Base Mainnet.
|
|
509
|
+
|
|
510
|
+
### Zero-Config Free Trial
|
|
511
|
+
All MCP tools work out-of-the-box with **10 free daily calls**\u2014no wallet or private key needed to get started.
|
|
512
|
+
|
|
513
|
+
### First-Class Capability Tools
|
|
514
|
+
- \`nullclear_token_security_audit\`: Audit any Base token for honeypots, taxes, and bytecode verification.
|
|
515
|
+
- \`nullclear_wallet_risk_score\`: Check any wallet or agent for sanctions, Sybil wash-trading, and ERC-8004 reputation.
|
|
516
|
+
- \`nullclear_crypto_market_oracle\`: Multi-exchange spread-verified price feed (ETH, BTC, SOL).
|
|
517
|
+
- \`nullclear_safe_fetch\`: Drop-in URL fetcher with Canonical LLM Refusal Guard & crash protection.
|
|
518
|
+
- \`nullclear_escrow_x402_call\`: Execute deferred schema escrow with numeric bounds and LLM refusal guards.
|
|
519
|
+
`
|
|
520
|
+
}
|
|
521
|
+
]
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
throw new Error(`Resource not found: ${uri}`);
|
|
525
|
+
});
|
|
164
526
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
165
527
|
const { name, arguments: args } = request.params;
|
|
166
528
|
try {
|
|
529
|
+
if (name === "nullclear_token_security_audit") {
|
|
530
|
+
const tokenAddress = String(args?.tokenAddress || "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913");
|
|
531
|
+
const url = `${ARBITER_URL}/v1/bazaar/token-security?tokenAddress=${encodeURIComponent(tokenAddress)}`;
|
|
532
|
+
const res = await callBazaarOrProxyWithFreeTrialFirst(url, "GET");
|
|
533
|
+
if (res.status === 402) {
|
|
534
|
+
return {
|
|
535
|
+
content: [
|
|
536
|
+
{
|
|
537
|
+
type: "text",
|
|
538
|
+
text: JSON.stringify(
|
|
539
|
+
{
|
|
540
|
+
status: "free_trial_exhausted",
|
|
541
|
+
message: "You have used all 10 daily free trial calls. Set NULLCLEAR_PRIVATE_KEY in your MCP environment variables to continue with automatic $0.005 USDC x402 settlement.",
|
|
542
|
+
tokenAddress,
|
|
543
|
+
details: res.data
|
|
544
|
+
},
|
|
545
|
+
null,
|
|
546
|
+
2
|
|
547
|
+
)
|
|
548
|
+
}
|
|
549
|
+
]
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
return {
|
|
553
|
+
content: [
|
|
554
|
+
{
|
|
555
|
+
type: "text",
|
|
556
|
+
text: JSON.stringify(
|
|
557
|
+
{
|
|
558
|
+
status: "success",
|
|
559
|
+
tier: res.tier,
|
|
560
|
+
remainingFreeCalls: res.remainingFreeCalls,
|
|
561
|
+
receipt: res.receipt,
|
|
562
|
+
result: res.data
|
|
563
|
+
},
|
|
564
|
+
null,
|
|
565
|
+
2
|
|
566
|
+
)
|
|
567
|
+
}
|
|
568
|
+
]
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
if (name === "nullclear_wallet_risk_score") {
|
|
572
|
+
const walletAddress = String(args?.walletAddress || "0xB586eFcCa41dF27ad3873BEcA54da0c30bf04d5c");
|
|
573
|
+
const chainId = Number(args?.chainId || 8453);
|
|
574
|
+
const url = `${ARBITER_URL}/v1/bazaar/wallet-risk?walletAddress=${encodeURIComponent(walletAddress)}&chainId=${chainId}`;
|
|
575
|
+
const res = await callBazaarOrProxyWithFreeTrialFirst(url, "GET");
|
|
576
|
+
if (res.status === 402) {
|
|
577
|
+
return {
|
|
578
|
+
content: [
|
|
579
|
+
{
|
|
580
|
+
type: "text",
|
|
581
|
+
text: JSON.stringify(
|
|
582
|
+
{
|
|
583
|
+
status: "free_trial_exhausted",
|
|
584
|
+
message: "You have used all 10 daily free trial calls. Set NULLCLEAR_PRIVATE_KEY in your MCP environment variables to continue with automatic $0.005 USDC x402 settlement.",
|
|
585
|
+
walletAddress,
|
|
586
|
+
details: res.data
|
|
587
|
+
},
|
|
588
|
+
null,
|
|
589
|
+
2
|
|
590
|
+
)
|
|
591
|
+
}
|
|
592
|
+
]
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
return {
|
|
596
|
+
content: [
|
|
597
|
+
{
|
|
598
|
+
type: "text",
|
|
599
|
+
text: JSON.stringify(
|
|
600
|
+
{
|
|
601
|
+
status: "success",
|
|
602
|
+
tier: res.tier,
|
|
603
|
+
remainingFreeCalls: res.remainingFreeCalls,
|
|
604
|
+
receipt: res.receipt,
|
|
605
|
+
result: res.data
|
|
606
|
+
},
|
|
607
|
+
null,
|
|
608
|
+
2
|
|
609
|
+
)
|
|
610
|
+
}
|
|
611
|
+
]
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
if (name === "nullclear_crypto_market_oracle") {
|
|
615
|
+
const pair = String(args?.pair || "ETH/USDC");
|
|
616
|
+
const url = `${ARBITER_URL}/v1/bazaar/market-oracle?pair=${encodeURIComponent(pair)}`;
|
|
617
|
+
const res = await callBazaarOrProxyWithFreeTrialFirst(url, "GET");
|
|
618
|
+
if (res.status === 402) {
|
|
619
|
+
return {
|
|
620
|
+
content: [
|
|
621
|
+
{
|
|
622
|
+
type: "text",
|
|
623
|
+
text: JSON.stringify(
|
|
624
|
+
{
|
|
625
|
+
status: "free_trial_exhausted",
|
|
626
|
+
message: "You have used all 10 daily free trial calls. Set NULLCLEAR_PRIVATE_KEY in your MCP environment variables to continue with automatic $0.01 USDC x402 settlement.",
|
|
627
|
+
pair,
|
|
628
|
+
details: res.data
|
|
629
|
+
},
|
|
630
|
+
null,
|
|
631
|
+
2
|
|
632
|
+
)
|
|
633
|
+
}
|
|
634
|
+
]
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
return {
|
|
638
|
+
content: [
|
|
639
|
+
{
|
|
640
|
+
type: "text",
|
|
641
|
+
text: JSON.stringify(
|
|
642
|
+
{
|
|
643
|
+
status: "success",
|
|
644
|
+
tier: res.tier,
|
|
645
|
+
remainingFreeCalls: res.remainingFreeCalls,
|
|
646
|
+
receipt: res.receipt,
|
|
647
|
+
result: res.data
|
|
648
|
+
},
|
|
649
|
+
null,
|
|
650
|
+
2
|
|
651
|
+
)
|
|
652
|
+
}
|
|
653
|
+
]
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
if (name === "nullclear_safe_fetch") {
|
|
657
|
+
const targetUrl = String(args?.url || "");
|
|
658
|
+
const method = args?.method || "GET";
|
|
659
|
+
const proxyUrl = `${ARBITER_URL}/${targetUrl}`;
|
|
660
|
+
const res = await callBazaarOrProxyWithFreeTrialFirst(proxyUrl, method, args?.body);
|
|
661
|
+
return {
|
|
662
|
+
content: [
|
|
663
|
+
{
|
|
664
|
+
type: "text",
|
|
665
|
+
text: JSON.stringify(
|
|
666
|
+
{
|
|
667
|
+
status: res.status === 200 ? "verified_success" : "auto_guard_blocked",
|
|
668
|
+
httpStatus: res.status,
|
|
669
|
+
verified: res.status === 200,
|
|
670
|
+
receipt: res.receipt,
|
|
671
|
+
data: res.data
|
|
672
|
+
},
|
|
673
|
+
null,
|
|
674
|
+
2
|
|
675
|
+
)
|
|
676
|
+
}
|
|
677
|
+
]
|
|
678
|
+
};
|
|
679
|
+
}
|
|
167
680
|
if (name === "nullclear_check_reputation") {
|
|
168
681
|
const agentId = String(args?.agentId);
|
|
169
682
|
const chainId = Number(args?.chainId || 8453);
|
|
@@ -202,7 +715,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
202
715
|
const rejectRefusals = args?.rejectRefusals !== void 0 ? Boolean(args.rejectRefusals) : true;
|
|
203
716
|
const fallbacks = args?.fallbacks || void 0;
|
|
204
717
|
const spendPolicy = args?.spendPolicy || void 0;
|
|
205
|
-
const buyerPrivateKey = args?.buyerPrivateKey ||
|
|
718
|
+
const buyerPrivateKey = args?.buyerPrivateKey || CONFIGURED_PRIVATE_KEY;
|
|
206
719
|
const nullclearFetch = createNullClearFetch({
|
|
207
720
|
accountOrPrivateKey: buyerPrivateKey,
|
|
208
721
|
chainId: 8453,
|
|
@@ -237,7 +750,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
237
750
|
text: JSON.stringify(
|
|
238
751
|
{
|
|
239
752
|
status: "cleared_and_settled",
|
|
240
|
-
|
|
753
|
+
tier: buyerPrivateKey ? "x402-paid" : "free-trial",
|
|
754
|
+
message: "Response successfully validated against schema. Payment cleared.",
|
|
241
755
|
attestation: response.headers.get("X-NullClear-Attestation") || "verified",
|
|
242
756
|
data: parsedData
|
|
243
757
|
},
|
|
@@ -249,6 +763,24 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
249
763
|
};
|
|
250
764
|
} catch (err) {
|
|
251
765
|
if (err instanceof NullClearEscrowAbortedError) {
|
|
766
|
+
if (err.stage === "FREE_TRIAL_EXHAUSTED") {
|
|
767
|
+
return {
|
|
768
|
+
content: [
|
|
769
|
+
{
|
|
770
|
+
type: "text",
|
|
771
|
+
text: JSON.stringify(
|
|
772
|
+
{
|
|
773
|
+
status: "free_trial_exhausted",
|
|
774
|
+
message: "Daily 10 free trial calls exhausted. Set NULLCLEAR_PRIVATE_KEY in your MCP configuration to continue with automatic zero-loss x402 settlement.",
|
|
775
|
+
stage: err.stage
|
|
776
|
+
},
|
|
777
|
+
null,
|
|
778
|
+
2
|
|
779
|
+
)
|
|
780
|
+
}
|
|
781
|
+
]
|
|
782
|
+
};
|
|
783
|
+
}
|
|
252
784
|
return {
|
|
253
785
|
content: [
|
|
254
786
|
{
|
package/package.json
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nullclear/mcp",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"mcpName": "io.github.
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"mcpName": "io.github.Nullclear-Protocol/nullclear",
|
|
5
5
|
"description": "Model Context Protocol server for autonomous agents using NullClear",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"author": "NullClear Protocol <contact@nullclear.dev>",
|
|
7
8
|
"homepage": "https://nullclear.dev",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"mcp",
|
|
11
|
+
"model-context-protocol",
|
|
12
|
+
"x402",
|
|
13
|
+
"erc-8004",
|
|
14
|
+
"agent-payments",
|
|
15
|
+
"escrow",
|
|
16
|
+
"reputation",
|
|
17
|
+
"base",
|
|
18
|
+
"smithery"
|
|
19
|
+
],
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/Nullclear-Protocol/nullclear/issues"
|
|
22
|
+
},
|
|
8
23
|
"repository": {
|
|
9
24
|
"type": "git",
|
|
10
25
|
"url": "https://github.com/Nullclear-Protocol/nullclear.git"
|
|
@@ -24,8 +39,8 @@
|
|
|
24
39
|
},
|
|
25
40
|
"dependencies": {
|
|
26
41
|
"@modelcontextprotocol/sdk": "^1.6.1",
|
|
27
|
-
"@nullclear/shared": "1.
|
|
28
|
-
"@nullclear/x402-arbiter": "1.
|
|
42
|
+
"@nullclear/shared": "1.2.0",
|
|
43
|
+
"@nullclear/x402-arbiter": "1.2.0",
|
|
29
44
|
"viem": "^2.23.0",
|
|
30
45
|
"zod": "^3.24.2"
|
|
31
46
|
},
|