aegis-x402-mcp 1.0.2 → 1.0.4
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 +8 -6
- package/dist/index.d.ts +16 -1
- package/dist/index.js +73 -13
- package/dist/test.js +173 -6
- package/package.json +6 -4
- package/server.json +42 -0
package/README.md
CHANGED
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
Tools like `aegis_token_preview` and `aegis_recent_audits` work instantly out-of-the-box with zero configuration or keys.
|
|
34
34
|
|
|
35
35
|
2. **Tier 2 — Prepaid Credit Token (Recommended for Humans):**
|
|
36
|
-
Top up in 1-click at [https://aegis-audit-x402.project-easy-x.workers.dev/pay](https://aegis-audit-x402.project-easy-x.workers.dev/pay) to get a credit token `
|
|
37
|
-
Add `AEGIS_CREDIT_TOKEN` in your config. No wallet
|
|
36
|
+
Top up in 1-click at [https://aegis-audit-x402.project-easy-x.workers.dev/pay](https://aegis-audit-x402.project-easy-x.workers.dev/pay) to get a signed 24-hour credit token `aegis_credit_...`.
|
|
37
|
+
Add `AEGIS_CREDIT_TOKEN` in your config. No local wallet key or per-call signing required.
|
|
38
38
|
|
|
39
39
|
3. **Tier 3 — Autonomous Agentic Wallet (For Autonomous Trading Bots & Power Users):**
|
|
40
40
|
Add `AEGIS_PRIVATE_KEY` in your config.
|
|
@@ -59,7 +59,7 @@ Add this configuration to your `claude_desktop_config.json`:
|
|
|
59
59
|
"command": "npx",
|
|
60
60
|
"args": ["-y", "aegis-x402-mcp"],
|
|
61
61
|
"env": {
|
|
62
|
-
"AEGIS_CREDIT_TOKEN": "
|
|
62
|
+
"AEGIS_CREDIT_TOKEN": "aegis_credit_your_token_or_leave_empty_for_free_tier"
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
}
|
|
@@ -77,7 +77,7 @@ Create or update `.cursor/mcp.json` in your project root:
|
|
|
77
77
|
"command": "npx",
|
|
78
78
|
"args": ["-y", "aegis-x402-mcp"],
|
|
79
79
|
"env": {
|
|
80
|
-
"AEGIS_CREDIT_TOKEN": "
|
|
80
|
+
"AEGIS_CREDIT_TOKEN": "aegis_credit_your_token"
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
}
|
|
@@ -106,8 +106,10 @@ Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
|
106
106
|
| Variable | Description |
|
|
107
107
|
|---|---|
|
|
108
108
|
| `AEGIS_GATEWAY_URL` | Gateway URL (defaults to `https://aegis-audit-x402.project-easy-x.workers.dev`). |
|
|
109
|
-
| `
|
|
110
|
-
| `
|
|
109
|
+
| `AEGIS_CREDIT_TOKEN` | Tier-bound 24h prepaid credit token generated from `/pay` or prior `X-Aegis-Credit-Token` settlement headers. |
|
|
110
|
+
| `AEGIS_PRIVATE_KEY` | Optional local EVM private key (`0x...`) used in-process to sign EIP-3009 USDC authorizations on Base without keys ever leaving your machine. |
|
|
111
|
+
| `AEGIS_API_KEY` | Alias for `AEGIS_CREDIT_TOKEN` / prepaid enterprise API key. |
|
|
112
|
+
| `X402_PAYMENT_HEADER` | Pre-signed base64 EIP-3009 payment header or authorization token. |
|
|
111
113
|
|
|
112
114
|
---
|
|
113
115
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
export
|
|
2
|
+
export declare const ALLOWED_PAYTO: string;
|
|
3
|
+
export declare const BASE_USDC: string;
|
|
4
|
+
export declare function parseChainIdFromNetwork(network?: string): number;
|
|
5
|
+
/**
|
|
6
|
+
* Signs EIP-3009 TransferWithAuthorization locally inside the user's MCP process.
|
|
7
|
+
* Keys never leave the local machine.
|
|
8
|
+
* Protected by strict recipient allowlist guard: only signs toward official Aegis address.
|
|
9
|
+
*/
|
|
10
|
+
export declare function signEip3009Payment(privateKeyHex: string, accepts: any, resource?: any): Promise<string>;
|
|
11
|
+
/**
|
|
12
|
+
* 3-Tier Execution Pipeline:
|
|
13
|
+
* Tier 1: Zero-config free tools execute immediately.
|
|
14
|
+
* Tier 2: Prepaid credit token (AEGIS_CREDIT_TOKEN / AEGIS_API_KEY) in env.
|
|
15
|
+
* Tier 3: Local wallet signing (AEGIS_PRIVATE_KEY) in env -> signs 402 challenge and retries seamlessly.
|
|
16
|
+
*/
|
|
17
|
+
export declare function fetchFromAegis(endpoint: string, options?: RequestInit): Promise<any>;
|
package/dist/index.js
CHANGED
|
@@ -9,14 +9,18 @@ const GATEWAY_URL = process.env.AEGIS_GATEWAY_URL || 'https://aegis-audit-x402.p
|
|
|
9
9
|
const API_KEY = process.env.AEGIS_API_KEY || process.env.AEGIS_CREDIT_TOKEN || '';
|
|
10
10
|
const PRIVATE_KEY = process.env.AEGIS_PRIVATE_KEY || '';
|
|
11
11
|
const PAYMENT_HEADER = process.env.X402_PAYMENT_HEADER || '';
|
|
12
|
-
const ALLOWED_PAYTO = '0x111ef680B6EFdd859FbEc473b907aCe95F0D1acB'.toLowerCase();
|
|
13
|
-
const BASE_USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'.toLowerCase();
|
|
12
|
+
export const ALLOWED_PAYTO = '0x111ef680B6EFdd859FbEc473b907aCe95F0D1acB'.toLowerCase();
|
|
13
|
+
export const BASE_USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'.toLowerCase();
|
|
14
|
+
export function parseChainIdFromNetwork(network) {
|
|
15
|
+
const match = String(network || '').match(/^eip155:(\d+)$/);
|
|
16
|
+
return match ? Number(match[1]) : 8453;
|
|
17
|
+
}
|
|
14
18
|
/**
|
|
15
19
|
* Signs EIP-3009 TransferWithAuthorization locally inside the user's MCP process.
|
|
16
20
|
* Keys never leave the local machine.
|
|
17
21
|
* Protected by strict recipient allowlist guard: only signs toward official Aegis address.
|
|
18
22
|
*/
|
|
19
|
-
async function signEip3009Payment(privateKeyHex, accepts, resource) {
|
|
23
|
+
export async function signEip3009Payment(privateKeyHex, accepts, resource) {
|
|
20
24
|
const cleanKey = privateKeyHex.trim().startsWith('0x')
|
|
21
25
|
? privateKeyHex.trim()
|
|
22
26
|
: `0x${privateKeyHex.trim()}`;
|
|
@@ -33,10 +37,11 @@ async function signEip3009Payment(privateKeyHex, accepts, resource) {
|
|
|
33
37
|
const fromChecksum = getAddress(account.address);
|
|
34
38
|
const toChecksum = getAddress(accepts.payTo || accepts.recipient);
|
|
35
39
|
const assetChecksum = getAddress(accepts.asset || BASE_USDC);
|
|
40
|
+
const chainId = parseChainIdFromNetwork(accepts.network);
|
|
36
41
|
const domain = {
|
|
37
42
|
name: accepts.extra?.name || 'USD Coin',
|
|
38
43
|
version: accepts.extra?.version || '2',
|
|
39
|
-
chainId
|
|
44
|
+
chainId,
|
|
40
45
|
verifyingContract: assetChecksum,
|
|
41
46
|
};
|
|
42
47
|
const types = {
|
|
@@ -89,7 +94,7 @@ async function signEip3009Payment(privateKeyHex, accepts, resource) {
|
|
|
89
94
|
* Tier 2: Prepaid credit token (AEGIS_CREDIT_TOKEN / AEGIS_API_KEY) in env.
|
|
90
95
|
* Tier 3: Local wallet signing (AEGIS_PRIVATE_KEY) in env -> signs 402 challenge and retries seamlessly.
|
|
91
96
|
*/
|
|
92
|
-
async function fetchFromAegis(endpoint, options = {}) {
|
|
97
|
+
export async function fetchFromAegis(endpoint, options = {}) {
|
|
93
98
|
const url = `${GATEWAY_URL}${endpoint}`;
|
|
94
99
|
const headers = {
|
|
95
100
|
'Accept': 'application/json',
|
|
@@ -120,9 +125,22 @@ async function fetchFromAegis(endpoint, options = {}) {
|
|
|
120
125
|
if (retryRes.ok) {
|
|
121
126
|
return retryRes.json();
|
|
122
127
|
}
|
|
128
|
+
const retryBody = await retryRes.json().catch(async () => ({ raw: await retryRes.text().catch(() => '') }));
|
|
129
|
+
return {
|
|
130
|
+
status: 'UPSTREAM_ERROR',
|
|
131
|
+
statusCode: retryRes.status,
|
|
132
|
+
charged: false,
|
|
133
|
+
message: retryBody?.message || retryBody?.error || retryRes.statusText || 'Payment retry failed',
|
|
134
|
+
details: retryBody,
|
|
135
|
+
};
|
|
123
136
|
}
|
|
124
137
|
catch (signErr) {
|
|
125
|
-
|
|
138
|
+
return {
|
|
139
|
+
status: 'UPSTREAM_ERROR',
|
|
140
|
+
statusCode: 500,
|
|
141
|
+
charged: false,
|
|
142
|
+
message: `Local EIP-3009 signing failed: ${signErr?.message || String(signErr)}`,
|
|
143
|
+
};
|
|
126
144
|
}
|
|
127
145
|
}
|
|
128
146
|
// Friendly, structured notification for the LLM without crashing
|
|
@@ -132,8 +150,8 @@ async function fetchFromAegis(endpoint, options = {}) {
|
|
|
132
150
|
statusCode: 402,
|
|
133
151
|
price,
|
|
134
152
|
payTo: accepts?.recipient || accepts?.payTo || ALLOWED_PAYTO,
|
|
135
|
-
network: 'eip155:8453
|
|
136
|
-
message: `[AEGIS x402 PAYMENT REQUIRED] This tool costs ${price} on Base
|
|
153
|
+
network: `${accepts?.network || 'eip155:8453'}`,
|
|
154
|
+
message: `[AEGIS x402 PAYMENT REQUIRED] This tool costs ${price} on Base.`,
|
|
137
155
|
setupInstructions: {
|
|
138
156
|
optionA_prepaidCredits: 'Top up in 1-click at https://aegis-audit-x402.project-easy-x.workers.dev/pay and add AEGIS_CREDIT_TOKEN in your MCP settings (zero signing required).',
|
|
139
157
|
optionB_agenticWallet: 'Add AEGIS_PRIVATE_KEY in your MCP config; the local process will sign EIP-3009 gasless settlements on-demand without keys ever leaving your machine.',
|
|
@@ -141,11 +159,21 @@ async function fetchFromAegis(endpoint, options = {}) {
|
|
|
141
159
|
paymentDetails: paymentReq,
|
|
142
160
|
};
|
|
143
161
|
}
|
|
162
|
+
if (!res.ok) {
|
|
163
|
+
const errBody = await res.json().catch(async () => ({ raw: await res.text().catch(() => '') }));
|
|
164
|
+
return {
|
|
165
|
+
status: 'UPSTREAM_ERROR',
|
|
166
|
+
statusCode: res.status,
|
|
167
|
+
charged: false,
|
|
168
|
+
message: errBody?.message || errBody?.error || res.statusText || 'Aegis gateway request failed',
|
|
169
|
+
details: errBody,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
144
172
|
return res.json();
|
|
145
173
|
}
|
|
146
174
|
const server = new Server({
|
|
147
175
|
name: 'aegis-x402-mcp',
|
|
148
|
-
version: '1.0.
|
|
176
|
+
version: '1.0.4',
|
|
149
177
|
}, {
|
|
150
178
|
capabilities: {
|
|
151
179
|
tools: {},
|
|
@@ -270,6 +298,24 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
270
298
|
required: ['url'],
|
|
271
299
|
},
|
|
272
300
|
},
|
|
301
|
+
{
|
|
302
|
+
name: 'aegis_grounded_chat',
|
|
303
|
+
description: 'USE WHEN: Running OpenAI-compatible LLM reasoning grounded in live Base/Ethereum/Solana on-chain security telemetry ($0.005 USDC on Base).',
|
|
304
|
+
inputSchema: {
|
|
305
|
+
type: 'object',
|
|
306
|
+
properties: {
|
|
307
|
+
prompt: {
|
|
308
|
+
type: 'string',
|
|
309
|
+
description: 'Security or DeFi analysis question to run with live on-chain token context',
|
|
310
|
+
},
|
|
311
|
+
model: {
|
|
312
|
+
type: 'string',
|
|
313
|
+
description: 'Optional model identifier (defaults to aegis-llama-3.3-70b-grounded)',
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
required: ['prompt'],
|
|
317
|
+
},
|
|
318
|
+
},
|
|
273
319
|
{
|
|
274
320
|
name: 'aegis_recent_audits',
|
|
275
321
|
description: 'USE WHEN: Monitoring the real-time stream of recently scanned tokens on Base, Ethereum, and Solana (FREE).',
|
|
@@ -336,6 +382,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
336
382
|
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
337
383
|
};
|
|
338
384
|
}
|
|
385
|
+
if (name === 'aegis_grounded_chat') {
|
|
386
|
+
const prompt = String(args?.prompt || 'Analyze Base USDC safety.');
|
|
387
|
+
const model = String(args?.model || 'aegis-llama-3.3-70b-grounded');
|
|
388
|
+
const data = await fetchFromAegis('/v1/chat/completions', {
|
|
389
|
+
method: 'POST',
|
|
390
|
+
headers: { 'Content-Type': 'application/json' },
|
|
391
|
+
body: JSON.stringify({ model, messages: [{ role: 'user', content: prompt }] }),
|
|
392
|
+
});
|
|
393
|
+
return {
|
|
394
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
395
|
+
};
|
|
396
|
+
}
|
|
339
397
|
if (name === 'aegis_recent_audits') {
|
|
340
398
|
const data = await fetchFromAegis('/api/v1/recent');
|
|
341
399
|
return {
|
|
@@ -355,7 +413,9 @@ async function run() {
|
|
|
355
413
|
const transport = new StdioServerTransport();
|
|
356
414
|
await server.connect(transport);
|
|
357
415
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
416
|
+
if (process.env.AEGIS_MCP_TEST !== '1') {
|
|
417
|
+
run().catch((error) => {
|
|
418
|
+
console.error('Fatal error running aegis-x402-mcp server:', error);
|
|
419
|
+
process.exit(1);
|
|
420
|
+
});
|
|
421
|
+
}
|
package/dist/test.js
CHANGED
|
@@ -1,10 +1,177 @@
|
|
|
1
1
|
import test from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
import { verifyTypedData, getAddress } from 'viem';
|
|
7
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
8
|
+
process.env.AEGIS_MCP_TEST = '1';
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
11
|
+
test('official payTo allowlist enforces official Aegis receiver address', async () => {
|
|
12
|
+
const { ALLOWED_PAYTO, BASE_USDC } = await import('./index.js');
|
|
13
|
+
assert.equal(ALLOWED_PAYTO, '0x111ef680b6efdd859fbec473b907ace95f0d1acb');
|
|
14
|
+
assert.equal(BASE_USDC, '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913');
|
|
5
15
|
});
|
|
6
|
-
test('
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
assert.
|
|
16
|
+
test('signEip3009Payment refuses rogue payTo recipient via SECURITY_RECIPIENT_GUARD', async () => {
|
|
17
|
+
const { signEip3009Payment } = await import('./index.js');
|
|
18
|
+
const testPk = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
|
|
19
|
+
await assert.rejects(async () => signEip3009Payment(testPk, {
|
|
20
|
+
scheme: 'exact',
|
|
21
|
+
network: 'eip155:8453',
|
|
22
|
+
amount: '200000',
|
|
23
|
+
asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
24
|
+
payTo: '0x000000000000000000000000000000000000dEaD',
|
|
25
|
+
}), /SECURITY_RECIPIENT_GUARD/);
|
|
26
|
+
});
|
|
27
|
+
test('signEip3009Payment builds valid x402 v2 EIP-3009 authorization recoverable via EIP-712', async () => {
|
|
28
|
+
const { signEip3009Payment } = await import('./index.js');
|
|
29
|
+
const testPk = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
|
|
30
|
+
const expectedAccount = privateKeyToAccount(testPk);
|
|
31
|
+
const accepts = {
|
|
32
|
+
scheme: 'exact',
|
|
33
|
+
network: 'eip155:8453',
|
|
34
|
+
amount: '200000',
|
|
35
|
+
asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
36
|
+
payTo: '0x111ef680B6EFdd859FbEc473b907aCe95F0D1acB',
|
|
37
|
+
maxTimeoutSeconds: 300,
|
|
38
|
+
extra: { name: 'USD Coin', version: '2' },
|
|
39
|
+
};
|
|
40
|
+
const b64 = await signEip3009Payment(testPk, accepts, {
|
|
41
|
+
url: 'https://aegis-audit-x402.project-easy-x.workers.dev/api/v1/preflight/bundle',
|
|
42
|
+
});
|
|
43
|
+
const decoded = JSON.parse(Buffer.from(b64, 'base64').toString('utf-8'));
|
|
44
|
+
assert.equal(decoded.x402Version, 2);
|
|
45
|
+
assert.ok(decoded.payload.authorization, 'authorization block must exist');
|
|
46
|
+
assert.ok(decoded.payload.signature, 'EIP-712 signature must exist');
|
|
47
|
+
assert.equal(decoded.accepted.payTo, '0x111ef680B6EFdd859FbEc473b907aCe95F0D1acB');
|
|
48
|
+
assert.equal(decoded.payload.authorization.value, '200000');
|
|
49
|
+
const auth = decoded.payload.authorization;
|
|
50
|
+
const isValid = await verifyTypedData({
|
|
51
|
+
address: expectedAccount.address,
|
|
52
|
+
domain: {
|
|
53
|
+
name: 'USD Coin',
|
|
54
|
+
version: '2',
|
|
55
|
+
chainId: 8453,
|
|
56
|
+
verifyingContract: getAddress(accepts.asset),
|
|
57
|
+
},
|
|
58
|
+
types: {
|
|
59
|
+
TransferWithAuthorization: [
|
|
60
|
+
{ name: 'from', type: 'address' },
|
|
61
|
+
{ name: 'to', type: 'address' },
|
|
62
|
+
{ name: 'value', type: 'uint256' },
|
|
63
|
+
{ name: 'validAfter', type: 'uint256' },
|
|
64
|
+
{ name: 'validBefore', type: 'uint256' },
|
|
65
|
+
{ name: 'nonce', type: 'bytes32' },
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
primaryType: 'TransferWithAuthorization',
|
|
69
|
+
message: {
|
|
70
|
+
from: getAddress(auth.from),
|
|
71
|
+
to: getAddress(auth.to),
|
|
72
|
+
value: BigInt(auth.value),
|
|
73
|
+
validAfter: BigInt(auth.validAfter),
|
|
74
|
+
validBefore: BigInt(auth.validBefore),
|
|
75
|
+
nonce: auth.nonce,
|
|
76
|
+
},
|
|
77
|
+
signature: decoded.payload.signature,
|
|
78
|
+
});
|
|
79
|
+
assert.equal(isValid, true, 'EIP-712 TransferWithAuthorization signature must verify cleanly');
|
|
80
|
+
});
|
|
81
|
+
test('MCP stdio handshake (SDK 1.32.2) initializes cleanly and exposes all 7 tools', async () => {
|
|
82
|
+
const serverPath = join(__dirname, 'index.js');
|
|
83
|
+
const env = { ...process.env };
|
|
84
|
+
delete env.AEGIS_MCP_TEST;
|
|
85
|
+
const child = spawn(process.execPath, [serverPath], {
|
|
86
|
+
env,
|
|
87
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
88
|
+
});
|
|
89
|
+
const responses = [];
|
|
90
|
+
let buffer = '';
|
|
91
|
+
await new Promise((resolve, reject) => {
|
|
92
|
+
const timer = setTimeout(() => {
|
|
93
|
+
child.kill();
|
|
94
|
+
reject(new Error('MCP stdio handshake timed out'));
|
|
95
|
+
}, 6000);
|
|
96
|
+
child.stdout.on('data', (chunk) => {
|
|
97
|
+
buffer += chunk.toString('utf-8');
|
|
98
|
+
const lines = buffer.split('\n');
|
|
99
|
+
buffer = lines.pop() || '';
|
|
100
|
+
for (const line of lines) {
|
|
101
|
+
const trimmed = line.trim();
|
|
102
|
+
if (!trimmed)
|
|
103
|
+
continue;
|
|
104
|
+
try {
|
|
105
|
+
const msg = JSON.parse(trimmed);
|
|
106
|
+
responses.push(msg);
|
|
107
|
+
if (msg.id === 1) {
|
|
108
|
+
child.stdin.write(JSON.stringify({ jsonrpc: '2.0', method: 'notifications/initialized' }) + '\n');
|
|
109
|
+
child.stdin.write(JSON.stringify({ jsonrpc: '2.0', id: 2, method: 'tools/list', params: {} }) + '\n');
|
|
110
|
+
}
|
|
111
|
+
else if (msg.id === 2) {
|
|
112
|
+
clearTimeout(timer);
|
|
113
|
+
child.kill();
|
|
114
|
+
resolve();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// ignore non-JSON lines
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
child.on('error', (err) => {
|
|
123
|
+
clearTimeout(timer);
|
|
124
|
+
reject(err);
|
|
125
|
+
});
|
|
126
|
+
child.stdin.write(JSON.stringify({
|
|
127
|
+
jsonrpc: '2.0',
|
|
128
|
+
id: 1,
|
|
129
|
+
method: 'initialize',
|
|
130
|
+
params: {
|
|
131
|
+
protocolVersion: '2025-06-18',
|
|
132
|
+
capabilities: {},
|
|
133
|
+
clientInfo: { name: 'aegis-ci-test', version: '1.0.4' },
|
|
134
|
+
},
|
|
135
|
+
}) + '\n');
|
|
136
|
+
});
|
|
137
|
+
const initRes = responses.find((r) => r.id === 1);
|
|
138
|
+
assert.ok(initRes?.result?.serverInfo, 'initialize must return serverInfo');
|
|
139
|
+
assert.equal(initRes.result.serverInfo.name, 'aegis-x402-mcp');
|
|
140
|
+
assert.equal(initRes.result.serverInfo.version, '1.0.4');
|
|
141
|
+
const listRes = responses.find((r) => r.id === 2);
|
|
142
|
+
const tools = listRes?.result?.tools || [];
|
|
143
|
+
assert.equal(tools.length, 8, 'Must expose all 8 Aegis MCP tools');
|
|
144
|
+
const names = tools.map((t) => t.name);
|
|
145
|
+
assert.ok(names.includes('aegis_preflight_bundle'));
|
|
146
|
+
assert.ok(names.includes('aegis_priority_audit'));
|
|
147
|
+
assert.ok(names.includes('aegis_token_audit'));
|
|
148
|
+
assert.ok(names.includes('aegis_token_preview'));
|
|
149
|
+
assert.ok(names.includes('aegis_wallet_kya'));
|
|
150
|
+
assert.ok(names.includes('aegis_web_scrape'));
|
|
151
|
+
assert.ok(names.includes('aegis_grounded_chat'));
|
|
152
|
+
assert.ok(names.includes('aegis_recent_audits'));
|
|
153
|
+
});
|
|
154
|
+
test('parseChainIdFromNetwork resolves mainnet, sepolia, and safe fallback', async () => {
|
|
155
|
+
const { parseChainIdFromNetwork } = await import('./index.js');
|
|
156
|
+
assert.equal(parseChainIdFromNetwork('eip155:8453'), 8453);
|
|
157
|
+
assert.equal(parseChainIdFromNetwork('eip155:84532'), 84532);
|
|
158
|
+
assert.equal(parseChainIdFromNetwork('solana:mainnet'), 8453);
|
|
159
|
+
assert.equal(parseChainIdFromNetwork(undefined), 8453);
|
|
160
|
+
});
|
|
161
|
+
test('fetchFromAegis returns structured UPSTREAM_ERROR on non-OK HTTP responses instead of throwing on res.json', async () => {
|
|
162
|
+
const { fetchFromAegis } = await import('./index.js');
|
|
163
|
+
const origFetch = globalThis.fetch;
|
|
164
|
+
globalThis.fetch = (async () => new Response(JSON.stringify({ error: 'UPSTREAM_502_ABORTED_BEFORE_CHARGE' }), {
|
|
165
|
+
status: 502,
|
|
166
|
+
headers: { 'Content-Type': 'application/json' },
|
|
167
|
+
}));
|
|
168
|
+
try {
|
|
169
|
+
const out = await fetchFromAegis('/api/v1/token/audit');
|
|
170
|
+
assert.equal(out.status, 'UPSTREAM_ERROR');
|
|
171
|
+
assert.equal(out.statusCode, 502);
|
|
172
|
+
assert.equal(out.charged, false);
|
|
173
|
+
}
|
|
174
|
+
finally {
|
|
175
|
+
globalThis.fetch = origFetch;
|
|
176
|
+
}
|
|
10
177
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aegis-x402-mcp",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
3
|
+
"mcpName": "io.github.Goatincrypto/aegis-x402-mcp",
|
|
4
|
+
"version": "1.0.4",
|
|
5
|
+
"description": "MCP server for AegisAudit x402 token security, honeypot simulation, KYA, and PreFlight clearance",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"main": "dist/index.js",
|
|
7
8
|
"bin": {
|
|
@@ -10,7 +11,8 @@
|
|
|
10
11
|
"files": [
|
|
11
12
|
"dist",
|
|
12
13
|
"README.md",
|
|
13
|
-
"LICENSE"
|
|
14
|
+
"LICENSE",
|
|
15
|
+
"server.json"
|
|
14
16
|
],
|
|
15
17
|
"scripts": {
|
|
16
18
|
"build": "tsc",
|
|
@@ -40,7 +42,7 @@
|
|
|
40
42
|
"author": "Antigravity Autonomous Systems",
|
|
41
43
|
"license": "MIT",
|
|
42
44
|
"dependencies": {
|
|
43
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
45
|
+
"@modelcontextprotocol/sdk": "^1.32.2",
|
|
44
46
|
"viem": "^2.21.0"
|
|
45
47
|
},
|
|
46
48
|
"devDependencies": {
|
package/server.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
+
"name": "io.github.Goatincrypto/aegis-x402-mcp",
|
|
4
|
+
"description": "On-chain token security, honeypot simulation, KYA wallet trust, and x402 PreFlight audits on Base.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"url": "https://github.com/Goatincrypto/aegis-x402-mcp",
|
|
7
|
+
"source": "github"
|
|
8
|
+
},
|
|
9
|
+
"version": "1.0.3",
|
|
10
|
+
"packages": [
|
|
11
|
+
{
|
|
12
|
+
"registryType": "npm",
|
|
13
|
+
"identifier": "aegis-x402-mcp",
|
|
14
|
+
"version": "1.0.3",
|
|
15
|
+
"transport": {
|
|
16
|
+
"type": "stdio"
|
|
17
|
+
},
|
|
18
|
+
"environmentVariables": [
|
|
19
|
+
{
|
|
20
|
+
"name": "AEGIS_CREDIT_TOKEN",
|
|
21
|
+
"description": "Optional prepaid credit token from /pay for zero-wallet Tier-2 MCP access",
|
|
22
|
+
"isRequired": false,
|
|
23
|
+
"format": "string",
|
|
24
|
+
"isSecret": true
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "AEGIS_PRIVATE_KEY",
|
|
28
|
+
"description": "Optional EVM private key for local gasless EIP-3009 x402 USDC settlement on Base",
|
|
29
|
+
"isRequired": false,
|
|
30
|
+
"format": "string",
|
|
31
|
+
"isSecret": true
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"remotes": [
|
|
37
|
+
{
|
|
38
|
+
"type": "streamable-http",
|
|
39
|
+
"url": "https://aegis-audit-x402.project-easy-x.workers.dev/mcp"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|