shieldapi-mcp 1.0.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 +92 -0
- package/dist/index.js +79 -0
- package/package.json +37 -0
- package/src/index.ts +147 -0
- package/tsconfig.json +13 -0
package/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# ShieldAPI MCP Server
|
|
2
|
+
|
|
3
|
+
Security intelligence tools for AI agents — check URLs, domains, IPs, emails, and passwords for threats. Pay-per-request with USDC micropayments via [x402](https://www.x402.org/), or use free demo mode.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx shieldapi-mcp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
That's it. Without a wallet configured, it runs in **demo mode** (free sample data).
|
|
12
|
+
|
|
13
|
+
## Setup for Claude Desktop
|
|
14
|
+
|
|
15
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"mcpServers": {
|
|
20
|
+
"shieldapi": {
|
|
21
|
+
"command": "npx",
|
|
22
|
+
"args": ["-y", "shieldapi-mcp"],
|
|
23
|
+
"env": {
|
|
24
|
+
"SHIELDAPI_WALLET_PRIVATE_KEY": "0x..."
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Setup for Cursor
|
|
32
|
+
|
|
33
|
+
Add to `.cursor/mcp.json`:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"mcpServers": {
|
|
38
|
+
"shieldapi": {
|
|
39
|
+
"command": "npx",
|
|
40
|
+
"args": ["-y", "shieldapi-mcp"],
|
|
41
|
+
"env": {
|
|
42
|
+
"SHIELDAPI_WALLET_PRIVATE_KEY": "0x..."
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Tools
|
|
50
|
+
|
|
51
|
+
| Tool | Description | Price |
|
|
52
|
+
|------|-------------|-------|
|
|
53
|
+
| `check_url` | Check URL for malware, phishing (URLhaus + heuristics) | $0.003 |
|
|
54
|
+
| `check_password` | Check SHA-1 hash against HIBP breach database | $0.001 |
|
|
55
|
+
| `check_password_range` | HIBP k-Anonymity prefix lookup | $0.001 |
|
|
56
|
+
| `check_domain` | Domain reputation (DNS, blacklists, SPF/DMARC, SSL) | $0.003 |
|
|
57
|
+
| `check_ip` | IP reputation (blacklists, Tor exit, reverse DNS) | $0.002 |
|
|
58
|
+
| `check_email` | Email breach lookup via HIBP | $0.005 |
|
|
59
|
+
| `full_scan` | All checks combined on a single target | $0.01 |
|
|
60
|
+
|
|
61
|
+
## Environment Variables
|
|
62
|
+
|
|
63
|
+
| Variable | Default | Description |
|
|
64
|
+
|----------|---------|-------------|
|
|
65
|
+
| `SHIELDAPI_URL` | `https://shield.vainplex.dev` | API base URL |
|
|
66
|
+
| `SHIELDAPI_WALLET_PRIVATE_KEY` | *(none)* | EVM private key for USDC payments. If not set, uses free demo mode. |
|
|
67
|
+
| `SHIELDAPI_NETWORK` | `base` | Network for payments (Base mainnet) |
|
|
68
|
+
|
|
69
|
+
## Demo Mode
|
|
70
|
+
|
|
71
|
+
Without `SHIELDAPI_WALLET_PRIVATE_KEY`, all tools return sample data for free. Great for testing your agent integration before configuring payments.
|
|
72
|
+
|
|
73
|
+
## How Payments Work
|
|
74
|
+
|
|
75
|
+
ShieldAPI uses [x402](https://www.x402.org/) — an open standard for HTTP-native micropayments:
|
|
76
|
+
|
|
77
|
+
1. Your agent calls a tool (e.g. `check_url`)
|
|
78
|
+
2. ShieldAPI responds with HTTP 402 + payment details
|
|
79
|
+
3. The MCP server automatically pays with USDC on Base
|
|
80
|
+
4. ShieldAPI returns the security data
|
|
81
|
+
|
|
82
|
+
You need USDC on Base in your wallet. Typical cost: $0.001–$0.01 per request.
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
MIT
|
|
87
|
+
|
|
88
|
+
## Links
|
|
89
|
+
|
|
90
|
+
- **API**: https://shield.vainplex.dev
|
|
91
|
+
- **Docs**: https://shield.vainplex.dev/api/health
|
|
92
|
+
- **Source**: https://github.com/alberthild/shieldapi-mcp
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ShieldAPI MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Exposes ShieldAPI security intelligence as native MCP tools.
|
|
6
|
+
* Handles x402 USDC micropayments automatically, with demo fallback.
|
|
7
|
+
*/
|
|
8
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
9
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
const { SHIELDAPI_URL = 'https://shield.vainplex.dev', SHIELDAPI_WALLET_PRIVATE_KEY, SHIELDAPI_NETWORK = 'base', } = process.env;
|
|
12
|
+
const demoMode = !SHIELDAPI_WALLET_PRIVATE_KEY;
|
|
13
|
+
// --- x402 payment setup (lazy, only if wallet configured) ---
|
|
14
|
+
let paymentFetch = fetch;
|
|
15
|
+
async function initPaymentFetch() {
|
|
16
|
+
if (demoMode)
|
|
17
|
+
return;
|
|
18
|
+
const { wrapFetchWithPayment, x402Client } = await import('@x402/fetch');
|
|
19
|
+
const { ExactEvmScheme, toClientEvmSigner } = await import('@x402/evm');
|
|
20
|
+
const { createWalletClient, http, publicActions } = await import('viem');
|
|
21
|
+
const { privateKeyToAccount } = await import('viem/accounts');
|
|
22
|
+
const { base } = await import('viem/chains');
|
|
23
|
+
const account = privateKeyToAccount(SHIELDAPI_WALLET_PRIVATE_KEY);
|
|
24
|
+
const walletClient = createWalletClient({
|
|
25
|
+
account,
|
|
26
|
+
chain: base,
|
|
27
|
+
transport: http(),
|
|
28
|
+
}).extend(publicActions);
|
|
29
|
+
// Type assertion needed: viem walletClient.extend(publicActions) is structurally compatible
|
|
30
|
+
// but TypeScript can't prove it due to complex generic types in viem + @x402/evm
|
|
31
|
+
const signer = toClientEvmSigner(walletClient);
|
|
32
|
+
const client = new x402Client().register(`eip155:${base.id}`, new ExactEvmScheme(signer));
|
|
33
|
+
paymentFetch = wrapFetchWithPayment(fetch, client);
|
|
34
|
+
}
|
|
35
|
+
// --- API caller ---
|
|
36
|
+
async function callShieldApi(endpoint, params) {
|
|
37
|
+
const url = new URL(`${SHIELDAPI_URL}/api/${endpoint}`);
|
|
38
|
+
for (const [key, value] of Object.entries(params)) {
|
|
39
|
+
url.searchParams.set(key, value);
|
|
40
|
+
}
|
|
41
|
+
if (demoMode) {
|
|
42
|
+
url.searchParams.set('demo', 'true');
|
|
43
|
+
}
|
|
44
|
+
const response = await paymentFetch(url.toString());
|
|
45
|
+
if (!response.ok) {
|
|
46
|
+
const body = await response.text();
|
|
47
|
+
throw new Error(`ShieldAPI ${endpoint} failed (${response.status}): ${body}`);
|
|
48
|
+
}
|
|
49
|
+
return response.json();
|
|
50
|
+
}
|
|
51
|
+
function formatResult(data) {
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// --- MCP Server ---
|
|
57
|
+
const server = new McpServer({
|
|
58
|
+
name: 'ShieldAPI',
|
|
59
|
+
version: '1.0.0',
|
|
60
|
+
});
|
|
61
|
+
// Tools
|
|
62
|
+
server.tool('check_url', 'Check a URL for malware, phishing, and other threats. Uses URLhaus + heuristic analysis.', { url: z.string().describe('The URL to check (e.g. https://example.com)') }, async ({ url }) => formatResult(await callShieldApi('check-url', { url })));
|
|
63
|
+
server.tool('check_password', 'Check if a password hash (SHA-1) has been exposed in known data breaches via HIBP.', { hash: z.string().describe('SHA-1 hash of the password (40 hex chars)') }, async ({ hash }) => formatResult(await callShieldApi('check-password', { hash })));
|
|
64
|
+
server.tool('check_password_range', 'Look up a SHA-1 hash prefix in the HIBP k-Anonymity database.', { prefix: z.string().describe('First 5 characters of the SHA-1 password hash') }, async ({ prefix }) => formatResult(await callShieldApi('check-password-range', { prefix })));
|
|
65
|
+
server.tool('check_domain', 'Check domain reputation: DNS records, blacklists (Spamhaus, SpamCop, SORBS), SPF/DMARC, SSL.', { domain: z.string().describe('Domain name to check (e.g. example.com)') }, async ({ domain }) => formatResult(await callShieldApi('check-domain', { domain })));
|
|
66
|
+
server.tool('check_ip', 'Check IP reputation: blacklists, Tor exit node detection, reverse DNS.', { ip: z.string().describe('IPv4 address to check (e.g. 8.8.8.8)') }, async ({ ip }) => formatResult(await callShieldApi('check-ip', { ip })));
|
|
67
|
+
server.tool('check_email', 'Check if an email address has been exposed in known data breaches via HIBP.', { email: z.string().describe('Email address to check') }, async ({ email }) => formatResult(await callShieldApi('check-email', { email })));
|
|
68
|
+
server.tool('full_scan', 'Run all security checks on a target (URL, domain, IP, or email). Most comprehensive scan.', { target: z.string().describe('Target to scan — URL, domain, IP address, or email') }, async ({ target }) => formatResult(await callShieldApi('full-scan', { target })));
|
|
69
|
+
// --- Start ---
|
|
70
|
+
async function main() {
|
|
71
|
+
await initPaymentFetch();
|
|
72
|
+
const transport = new StdioServerTransport();
|
|
73
|
+
await server.connect(transport);
|
|
74
|
+
console.error(`ShieldAPI MCP server running (${demoMode ? 'DEMO mode' : 'PAID mode'})`);
|
|
75
|
+
}
|
|
76
|
+
main().catch((err) => {
|
|
77
|
+
console.error('Fatal:', err);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "shieldapi-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for ShieldAPI",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"shieldapi-mcp": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"start": "node dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"mcp",
|
|
15
|
+
"shieldapi",
|
|
16
|
+
"x402"
|
|
17
|
+
],
|
|
18
|
+
"author": "Vainplex (https://vainplex.dev)",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/alberthild/shieldapi-mcp"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@modelcontextprotocol/sdk": "1.27.1",
|
|
26
|
+
"@x402/core": "2.5.0",
|
|
27
|
+
"@x402/evm": "2.5.0",
|
|
28
|
+
"@x402/fetch": "2.5.0",
|
|
29
|
+
"viem": "^2.17.4",
|
|
30
|
+
"zod": "^3.23.8"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^20.11.24",
|
|
34
|
+
"typescript": "^5.3.3"
|
|
35
|
+
},
|
|
36
|
+
"type": "module"
|
|
37
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ShieldAPI MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Exposes ShieldAPI security intelligence as native MCP tools.
|
|
6
|
+
* Handles x402 USDC micropayments automatically, with demo fallback.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
10
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
|
|
13
|
+
const {
|
|
14
|
+
SHIELDAPI_URL = 'https://shield.vainplex.dev',
|
|
15
|
+
SHIELDAPI_WALLET_PRIVATE_KEY,
|
|
16
|
+
SHIELDAPI_NETWORK = 'base',
|
|
17
|
+
} = process.env;
|
|
18
|
+
|
|
19
|
+
const demoMode = !SHIELDAPI_WALLET_PRIVATE_KEY;
|
|
20
|
+
|
|
21
|
+
// --- x402 payment setup (lazy, only if wallet configured) ---
|
|
22
|
+
|
|
23
|
+
let paymentFetch: typeof fetch = fetch;
|
|
24
|
+
|
|
25
|
+
async function initPaymentFetch(): Promise<void> {
|
|
26
|
+
if (demoMode) return;
|
|
27
|
+
|
|
28
|
+
const { wrapFetchWithPayment, x402Client } = await import('@x402/fetch');
|
|
29
|
+
const { ExactEvmScheme, toClientEvmSigner } = await import('@x402/evm');
|
|
30
|
+
const { createWalletClient, http, publicActions } = await import('viem');
|
|
31
|
+
const { privateKeyToAccount } = await import('viem/accounts');
|
|
32
|
+
const { base } = await import('viem/chains');
|
|
33
|
+
|
|
34
|
+
const account = privateKeyToAccount(SHIELDAPI_WALLET_PRIVATE_KEY as `0x${string}`);
|
|
35
|
+
const walletClient = createWalletClient({
|
|
36
|
+
account,
|
|
37
|
+
chain: base,
|
|
38
|
+
transport: http(),
|
|
39
|
+
}).extend(publicActions);
|
|
40
|
+
|
|
41
|
+
// Type assertion needed: viem walletClient.extend(publicActions) is structurally compatible
|
|
42
|
+
// but TypeScript can't prove it due to complex generic types in viem + @x402/evm
|
|
43
|
+
const signer = toClientEvmSigner(walletClient as unknown as Parameters<typeof toClientEvmSigner>[0]);
|
|
44
|
+
const client = new x402Client().register(
|
|
45
|
+
`eip155:${base.id}`,
|
|
46
|
+
new ExactEvmScheme(signer)
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
paymentFetch = wrapFetchWithPayment(fetch, client);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// --- API caller ---
|
|
53
|
+
|
|
54
|
+
async function callShieldApi(endpoint: string, params: Record<string, string>): Promise<unknown> {
|
|
55
|
+
const url = new URL(`${SHIELDAPI_URL}/api/${endpoint}`);
|
|
56
|
+
for (const [key, value] of Object.entries(params)) {
|
|
57
|
+
url.searchParams.set(key, value);
|
|
58
|
+
}
|
|
59
|
+
if (demoMode) {
|
|
60
|
+
url.searchParams.set('demo', 'true');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const response = await paymentFetch(url.toString());
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
const body = await response.text();
|
|
66
|
+
throw new Error(`ShieldAPI ${endpoint} failed (${response.status}): ${body}`);
|
|
67
|
+
}
|
|
68
|
+
return response.json();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function formatResult(data: unknown): { content: Array<{ type: 'text'; text: string }> } {
|
|
72
|
+
return {
|
|
73
|
+
content: [{ type: 'text' as const, text: JSON.stringify(data, null, 2) }],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// --- MCP Server ---
|
|
78
|
+
|
|
79
|
+
const server = new McpServer({
|
|
80
|
+
name: 'ShieldAPI',
|
|
81
|
+
version: '1.0.0',
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Tools
|
|
85
|
+
|
|
86
|
+
server.tool(
|
|
87
|
+
'check_url',
|
|
88
|
+
'Check a URL for malware, phishing, and other threats. Uses URLhaus + heuristic analysis.',
|
|
89
|
+
{ url: z.string().describe('The URL to check (e.g. https://example.com)') },
|
|
90
|
+
async ({ url }) => formatResult(await callShieldApi('check-url', { url }))
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
server.tool(
|
|
94
|
+
'check_password',
|
|
95
|
+
'Check if a password hash (SHA-1) has been exposed in known data breaches via HIBP.',
|
|
96
|
+
{ hash: z.string().describe('SHA-1 hash of the password (40 hex chars)') },
|
|
97
|
+
async ({ hash }) => formatResult(await callShieldApi('check-password', { hash }))
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
server.tool(
|
|
101
|
+
'check_password_range',
|
|
102
|
+
'Look up a SHA-1 hash prefix in the HIBP k-Anonymity database.',
|
|
103
|
+
{ prefix: z.string().describe('First 5 characters of the SHA-1 password hash') },
|
|
104
|
+
async ({ prefix }) => formatResult(await callShieldApi('check-password-range', { prefix }))
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
server.tool(
|
|
108
|
+
'check_domain',
|
|
109
|
+
'Check domain reputation: DNS records, blacklists (Spamhaus, SpamCop, SORBS), SPF/DMARC, SSL.',
|
|
110
|
+
{ domain: z.string().describe('Domain name to check (e.g. example.com)') },
|
|
111
|
+
async ({ domain }) => formatResult(await callShieldApi('check-domain', { domain }))
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
server.tool(
|
|
115
|
+
'check_ip',
|
|
116
|
+
'Check IP reputation: blacklists, Tor exit node detection, reverse DNS.',
|
|
117
|
+
{ ip: z.string().describe('IPv4 address to check (e.g. 8.8.8.8)') },
|
|
118
|
+
async ({ ip }) => formatResult(await callShieldApi('check-ip', { ip }))
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
server.tool(
|
|
122
|
+
'check_email',
|
|
123
|
+
'Check if an email address has been exposed in known data breaches via HIBP.',
|
|
124
|
+
{ email: z.string().describe('Email address to check') },
|
|
125
|
+
async ({ email }) => formatResult(await callShieldApi('check-email', { email }))
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
server.tool(
|
|
129
|
+
'full_scan',
|
|
130
|
+
'Run all security checks on a target (URL, domain, IP, or email). Most comprehensive scan.',
|
|
131
|
+
{ target: z.string().describe('Target to scan — URL, domain, IP address, or email') },
|
|
132
|
+
async ({ target }) => formatResult(await callShieldApi('full-scan', { target }))
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// --- Start ---
|
|
136
|
+
|
|
137
|
+
async function main(): Promise<void> {
|
|
138
|
+
await initPaymentFetch();
|
|
139
|
+
const transport = new StdioServerTransport();
|
|
140
|
+
await server.connect(transport);
|
|
141
|
+
console.error(`ShieldAPI MCP server running (${demoMode ? 'DEMO mode' : 'PAID mode'})`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
main().catch((err) => {
|
|
145
|
+
console.error('Fatal:', err);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"strict": true,
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"forceConsistentCasingInFileNames": true,
|
|
9
|
+
"outDir": "./dist",
|
|
10
|
+
"rootDir": "./src"
|
|
11
|
+
},
|
|
12
|
+
"include": ["src/**/*"]
|
|
13
|
+
}
|