@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.
Files changed (3) hide show
  1. package/README.md +34 -34
  2. package/dist/index.js +551 -19
  3. package/package.json +19 -4
package/README.md CHANGED
@@ -1,34 +1,34 @@
1
- # @nullclear/mcp
2
-
3
- <!-- mcp-name: io.github.mithgalalfayez/nullclear -->
4
-
5
- [![Listed on mcpservers.org](https://mcpservers.org/badge.svg)](https://mcpservers.org/servers/nullclear-protocol/nullclear)
6
- [![NullClear Arbiter MCP server – quality and maintenance score on Glama](https://glama.ai/mcp/servers/Nullclear-Protocol/nullclear/badges/score.svg)](https://glama.ai/mcp/servers/Nullclear-Protocol/nullclear)
7
- [![NullClear Arbiter MCP server – quality and maintenance score on Glama](https://glama.ai/mcp/servers/Nullclear-Protocol/nullclear/badges/card.svg)](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
+ [![Listed on mcpservers.org](https://mcpservers.org/badge.svg)](https://mcpservers.org/servers/nullclear-protocol/nullclear)
6
+ [![NullClear Arbiter MCP server – quality and maintenance score on Glama](https://glama.ai/mcp/servers/Nullclear-Protocol/nullclear/badges/score.svg)](https://glama.ai/mcp/servers/Nullclear-Protocol/nullclear)
7
+ [![NullClear Arbiter MCP server – quality and maintenance score on Glama](https://glama.ai/mcp/servers/Nullclear-Protocol/nullclear/badges/card.svg)](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 SANDBOX_TEST_KEY = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
13
- var DEFAULT_BUYER_KEY = process.env.BUYER_PRIVATE_KEY || SANDBOX_TEST_KEY;
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.1.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: "nullclear_check_reputation",
31
- description: "Inspect an AI agent's trust score (0-100), clearing reliability, Sybil wash-trade penalty flags, and corporate KYA backing on Base",
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: ["agentId"],
115
+ required: ["tokenAddress"],
35
116
  properties: {
36
- agentId: {
117
+ tokenAddress: {
37
118
  type: "string",
38
- description: "The ERC-8004 agent token ID or registered identifier"
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 for Mainnet, 84532 for Sepolia)",
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. If the seller hallucinates or crashes, $0 is spent. Users can test immediately against https://api.nullclear.dev/v1/sandbox/market-feed (or fail over from https://api.nullclear.dev/v1/sandbox/hallucinating-seller to https://api.nullclear.dev/v1/sandbox/market-feed) with zero wallet setup.",
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 BUYER_PRIVATE_KEY environment variable)"
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 || DEFAULT_BUYER_KEY;
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
- message: "Response successfully validated against schema. Payment settled.",
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.1.1",
4
- "mcpName": "io.github.mithgalalfayez/nullclear",
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.1.1",
28
- "@nullclear/x402-arbiter": "1.1.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
  },