@shroud-fi/mcp-server
v0.1.3
Published
Model Context Protocol server for ShroudFi. 9 tools any MCP-aware AI agent host can call — Claude Code, Cursor, Windsurf, Zed.
Downloads
328
Maintainers
Readme
@shroud-fi/mcp-server
Model Context Protocol server exposing the ShroudFi privacy SDK as tools any MCP-aware agent runtime can call — Claude Code, Cursor, Windsurf, Zed AI, custom hosts.
Two transports:
| Transport | Use when | Auth |
|---|---|---|
| stdio | An agent runtime spawns the server as a child process from a local .mcp.json | None — process boundary IS the trust boundary; local key file or env var |
| HTTP | Multiple agents share one server, or the server lives on a different host | EIP-191 challenge-response — every call signs a fresh server-issued nonce |
Tools
| Tool | Args | Purpose |
|---|---|---|
| shroud_register | none | Publish the agent's stealth meta-address into ERC-6538. Idempotent. |
| shroud_send | to, asset, amount | Send to an encoded meta-address (st:base:0x…) — privacy-native shape. |
| shroud_send_to_wallet | recipient, asset, amount | Send to a plain wallet — SDK looks up its meta-address. |
| shroud_receive | fromBlock, toBlock?, finality?, limit? | Scan a block range for incoming stealth payments. |
| shroud_sweep | detection, destination, token?, viaRelayer? | Sweep a detected stealth address (direct or gasless). |
| shroud_balance | address?, token? | Read ETH + optional ERC-20 balance. |
| shroud_status | none | Operator wallet, meta-address, chain, latest block, registration state. |
| shroud_x402_pay | url, method?, body?, headers?, maxPriceUsdcAtomic? | One-shot HTTP 402 client. SDK auto-signs USDC if a 402 lands. |
| shroud_x402_serve | op: 'challenge'\|'verify', … | Server-side x402 primitives — mint 402 challenges or verify payment payloads. |
Environment
| Var | Required | Default | Notes |
|---|---|---|---|
| SHROUDFI_PRIVATE_KEY | one of the two | — | 0x… 32-byte hex. Operator EOA. |
| SHROUDFI_PRIVATE_KEY_FILE | one of the two | — | Path to a file containing the hex private key (one line, trimmed). |
| SHROUDFI_CHAIN | no | base | base, sepolia, 8453, or 84532. |
| SHROUDFI_RPC_URL | no | public default | Alchemy or QuickNode endpoint. |
| SHROUDFI_START_BLOCK | no | 0 | Where shroud_receive defaults its scan cursor. |
| SHROUDFI_MCP_HTTP_PORT | HTTP only | 7070 | Listening port. |
| SHROUDFI_MCP_HTTP_ALLOWED_WALLETS | HTTP recommended | empty (any) | Comma-separated EOA allow-list. Set this in production. |
| SHROUDFI_MASTER_SEED | multi-surface | random per boot | 0x… 32-byte hex. Required when MCP + REST + UI must resolve the same stealth meta-address for the same operator. Skip = different surfaces will disagree on the recipient identity. |
| SHROUDFI_MASTER_SEED_FILE | alt to above | — | Path to a file containing the 0x… seed (one line, trimmed). Use this in production so the seed never ends up in shell history. |
Claude Code — .mcp.json (per-project)
Drop this at the repo root or ~/.config/claude/.mcp.json (global):
{
"mcpServers": {
"shroudfi": {
"command": "node",
"args": ["node_modules/@shroud-fi/mcp-server/dist/esm/bin/stdio.js"],
"env": {
"SHROUDFI_PRIVATE_KEY_FILE": "/absolute/path/to/agent-eoa.key.txt",
"SHROUDFI_CHAIN": "base",
"SHROUDFI_RPC_URL": "https://base-mainnet.g.alchemy.com/v2/<your-key>"
}
}
}
}After install, Claude Code surfaces every shroud_* tool as a callable from within any session inside that repo.
Cursor / Windsurf / Zed AI
Same JSON shape under the editor's own MCP config path:
| Editor | Config path |
|---|---|
| Cursor | Settings → Features → MCP Servers (UI) OR ~/.cursor/mcp.json |
| Windsurf | Settings → MCP Servers OR ~/.codeium/windsurf/mcp_config.json |
| Zed AI | ~/.config/zed/settings.json → assistant.context_servers |
HTTP transport (deployed server)
For shared-infra mode (one server, many agents):
SHROUDFI_PRIVATE_KEY_FILE=/secrets/relayer.key.txt \
SHROUDFI_CHAIN=base \
SHROUDFI_MCP_HTTP_PORT=7070 \
SHROUDFI_MCP_HTTP_ALLOWED_WALLETS=0xAgent1,0xAgent2 \
node node_modules/@shroud-fi/mcp-server/dist/esm/bin/http.jsAuth flow for HTTP clients
// 1. Get a challenge.
const challenge = await fetch('http://localhost:7070/auth/challenge', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ wallet: '0xYourAgentEOA' }),
}).then((r) => r.json());
// 2. Sign the message string (EIP-191 personal_sign).
const signature = await walletClient.signMessage({ message: challenge.message });
// 3. Call any MCP method with the three auth headers.
const response = await fetch('http://localhost:7070/mcp', {
method: 'POST',
headers: {
'content-type': 'application/json',
'x-shroudfi-wallet': '0xYourAgentEOA',
'x-shroudfi-nonce': challenge.nonce,
'x-shroudfi-signature': signature,
},
body: JSON.stringify({
method: 'tools/call',
params: {
name: 'shroud_send_to_wallet',
arguments: {
recipient: '0xRecipientWallet',
asset: { token: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' },
amount: '10000',
},
},
}),
}).then((r) => r.json());Challenges are single-use (consumed on success) and expire after 5 minutes.
Privacy
- Stdio bin writes errors only to stderr — stdout is reserved for the MCP wire protocol.
- HTTP transport returns short tag strings on auth failure (
unauthorized,auth_signature_invalid,auth_challenge_expired); no signature bytes, no key bytes, no amount values are echoed in responses or in error fields. - The MCP tool envelope deliberately does not log tool arguments —
shroud_receivereturns stealth private keys to the caller, and those must never end up in a server log.
License
MIT — same as the rest of the ShroudFi workspace.
