MCP Server
The VeilNet MCP server (@veilnet/mcp-server) lets any Model Context Protocol client — Claude Code, Claude Desktop, Cursor, Continue, Cline, OpenClaw, Zed, or any custom SDK build — create and run encrypted on-chain agent strategies without leaking the strategy parameters to VeilNet or to the LLM provider.
- Seven tools:
agent_create,agent_list,agent_get,agent_update,agent_delete,agent_run,wallet_status - Encryption: AES-256-GCM with AAD-bound metadata (
{kind, version}) — VeilNet servers only ever see ciphertext - Master key: 32 bytes generated in your browser at
https://app.veilnet.to(Agent tab), wrapped with your passphrase via PBKDF2-SHA256 (600,000 iterations), stored as an opaque envelope by VeilNet - Transport: stdio (works in every major MCP client today). HTTP+SSE deferred to a later release.
- Package:
@veilnet/mcp-serveron npm
How it works
┌─────────────────────────────────────────────────────────────┐
│ Your machine │
│ │
│ MCP Client (Claude Code / Cursor / etc.) │
│ │ │
│ │ stdio (JSON-RPC) │
│ ▼ │
│ @veilnet/mcp-server │
│ • reads ~/.veilnet/session.json + master.key on boot │
│ • encrypts params locally → AES-256-GCM │
│ • decrypts agent payloads locally on agent_get/agent_run │
└─────────────────────────────────────────────────────────────┘
│
│ HTTPS Authorization: Bearer <JWT>
▼
┌─────────────────────────────────────────────────────────────┐
│ api.veilnet.to │
│ /agents CRUD (auth + rate-limited) │
│ /agents/keys/envelope GET/POST wrapped key │
│ │
│ Stores: ciphertext, iv, kind, timestamps — that's it. │
└─────────────────────────────────────────────────────────────┘
│
▼
MongoDB — server is blind to your strategy parametersPrivacy invariant: strategy parameters are encrypted on your machine with a master key VeilNet does not have. The backend stores only ciphertext + IV + the agent kind + lifecycle timestamps. The LLM provider only sees tool calls and any plaintext you put in the chat — never your master key, never your JWT.
Prerequisites
- Node.js ≥ 22. Native WebCrypto is required for the master-key file loader.
- A funded VeilNet shielded-USDC balance. Get one at
https://app.veilnet.to(Deposit tab). - Two files at
~/.veilnet/— see Initial setup below.
Initial setup — one-time
- Open
https://app.veilnet.to, connect your EVM wallet (MetaMask, Rabby, etc.), and sign the SIWE login message. - Click the Agent tab in the dApp.
- Enter a passphrase (≥ 8 characters). If you lose this passphrase, you lose access to your encrypted agents on any new device.
- Click Generate & download. Two files download:
session.json— short-lived JWT + your wallet address + API base URL (valid for 7 days)master.key— your 32-byte AES master key, base64-encoded inside JSON
- Move both files into
~/.veilnet/.
mkdir -p ~/.veilnet
mv ~/Downloads/session.json ~/.veilnet/session.json
mv ~/Downloads/master.key ~/.veilnet/master.key
chmod 600 ~/.veilnet/session.json ~/.veilnet/master.keymkdir %USERPROFILE%\.veilnet 2>nul
move /Y "%USERPROFILE%\Downloads\session.json" "%USERPROFILE%\.veilnet\session.json"
move /Y "%USERPROFILE%\Downloads\master.key" "%USERPROFILE%\.veilnet\master.key"New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.veilnet" | Out-Null
Move-Item "$env:USERPROFILE\Downloads\session.json" "$env:USERPROFILE\.veilnet\session.json" -Force
Move-Item "$env:USERPROFILE\Downloads\master.key" "$env:USERPROFILE\.veilnet\master.key" -ForceFile permissions
On POSIX systems, tighten both files with chmod 600. v0.1 of the MCP server prints a warning if it sees world-readable files; v0.2 will hard-fail. Windows uses ACLs — the file is already only readable by your user account by default.
JWT expiry
session.json is valid for 7 days. When it expires the tools start returning VEILNET_REAUTH_REQUIRED — reopen the Agent tab in the dApp and re-download just session.json. Your master.key does not change unless you click Reset on the dApp (which invalidates all existing encrypted agents).
Install in your MCP client
The server is the same binary for every client; only the wiring changes. Pick the one(s) you use.
Claude Code
# Registers the server globally for your user
claude mcp add veilnet --scope user -- npx -y @veilnet/mcp-serverVerify with claude mcp list — you should see veilnet: ✓ Connected.
Claude Desktop
Edit claude_desktop_config.json:
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
| Linux | ~/.config/Claude/claude_desktop_config.json |
{
"mcpServers": {
"veilnet": {
"command": "npx",
"args": ["-y", "@veilnet/mcp-server"]
}
}
}If npx isn't on Claude Desktop's PATH (common on macOS when Node was installed via nvm or fnm), use the absolute node path and binary path instead:
{
"mcpServers": {
"veilnet": {
"command": "/usr/local/bin/node",
"args": ["/path/to/global/node_modules/@veilnet/mcp-server/bin/veilnet-mcp.js"]
}
}
}Restart Claude Desktop. The 🔌 icon at the bottom of any chat shows registered MCP servers.
Cursor
- Global (every workspace):
~/.cursor/mcp.json - Per-project (overrides global for that repo):
.cursor/mcp.jsonin the repo root
{
"mcpServers": {
"veilnet": {
"command": "npx",
"args": ["-y", "@veilnet/mcp-server"]
}
}
}Toggle the server on under Settings → Cursor Settings → MCP.
Continue (VS Code / JetBrains)
Continue uses standalone YAML blocks per server. Create .continue/mcpServers/veilnet.yaml in your home or project root:
name: VeilNet MCP
version: 0.1.0
schema: v1
mcpServers:
- name: veilnet
type: stdio
command: npx
args:
- "-y"
- "@veilnet/mcp-server"TIP
MCP tools are only usable in Continue's agent mode — not chat or edit. Switch with the mode selector at the bottom of the input box.
Cline (VS Code extension)
Easiest path: in the Cline panel, click the MCP Servers icon → Configure tab → Configure MCP Servers. The JSON file that opens is the one you want.
To edit by hand:
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json |
| Windows | %APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json |
| Linux | ~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json |
{
"mcpServers": {
"veilnet": {
"command": "npx",
"args": ["-y", "@veilnet/mcp-server"]
}
}
}OpenClaw
Edit ~/.openclaw/mcp.json (or use the in-app Settings → MCP Servers panel — the file it opens is the same one):
{
"mcpServers": {
"veilnet": {
"command": "npx",
"args": ["-y", "@veilnet/mcp-server"]
}
}
}Restart OpenClaw. The server appears in the MCP indicator at the bottom of any chat.
Zed
Open settings.json (cmd/ctrl + ,) and add a context_servers entry:
{
"context_servers": {
"veilnet": {
"command": {
"path": "npx",
"args": ["-y", "@veilnet/mcp-server"]
}
}
}
}Zed picks up new context servers without a restart. Open the assistant panel and look for veilnet under available tools.
Any other MCP-spec client (custom SDK build)
If your client speaks the MCP stdio transport, point it at the same binary.
TypeScript:
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "npx",
args: ["-y", "@veilnet/mcp-server"],
});
const client = new Client({ name: "my-app", version: "1.0.0" }, { capabilities: {} });
await client.connect(transport);
const tools = await client.listTools(); // 7 veilnet toolsPython:
from mcp.client.stdio import stdio_client, StdioServerParameters
params = StdioServerParameters(command="npx", args=["-y", "@veilnet/mcp-server"])
async with stdio_client(params) as (read, write):
# use read/write to drive the seven veilnet tools
...Tool names, shapes, and error codes are identical across every client.
Optional — install the Claude Code skill
A skill at skills/veilnet-agent/SKILL.md teaches Claude how to map natural-language strategy descriptions ("weekly $50 USDC into ETH") to the right tool call without you writing JSON.
mkdir -p ~/.claude/skills/veilnet-agent
curl -fsSL https://raw.githubusercontent.com/syncodemayo/VeilNet/main/skills/veilnet-agent/SKILL.md \
-o ~/.claude/skills/veilnet-agent/SKILL.mdNew-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.claude\skills\veilnet-agent" | Out-Null
Invoke-WebRequest `
-Uri "https://raw.githubusercontent.com/syncodemayo/VeilNet/main/skills/veilnet-agent/SKILL.md" `
-OutFile "$env:USERPROFILE\.claude\skills\veilnet-agent\SKILL.md"Restart Claude Code. The skill auto-activates whenever you mention agents, DCA, rebalance, or yield.
Private repo
The repo is currently private; the curl/PowerShell links above are placeholders until the skill is published publicly. In the meantime, copy the file manually from the package — node_modules/@veilnet/mcp-server/skills/veilnet-agent/SKILL.md (if shipped) or from the VeilNet team.
Tools reference
Tool names and shapes are the same in every MCP client.
| Tool | Shape (Zod) | Notes |
|---|---|---|
wallet_status | {} | Confirms session + backend reachability. Returns {address, exp, backend: "ok" | "unreachable"}. |
agent_create | { kind: "dca" | "rebalance" | "yield", params: object } | Encrypts params locally with AAD {kind, version}. |
agent_list | {} | Returns metadata only — never params. |
agent_get | { id: string } | Decrypts params locally; returned to the agent process only. |
agent_update | { id: string, status?: "active" | "paused", params?: object } | At least one of status or params is required. Re-encrypts with the existing kind. |
agent_delete | { id: string } | Soft delete. |
agent_run | { id: string } | Bumps lastRunAt and returns decrypted params. |
Agent kinds
Pass the param object as a plain JSON value — the MCP server stringifies and encrypts it.
dca — dollar-cost averaging
{
"fromAsset": "USDC", // source ticker
"toAsset": "ETH", // destination ticker
"amountPerRun": "50", // human string (NOT raw units)
"cadence": "weekly", // hourly | daily | weekly | monthly
"maxSlippageBps": 50, // 50 = 0.5%; default 50
"expiresAt": "2026-12-31T00:00:00Z" // optional ISO timestamp
}rebalance — keep a basket at target weights
{
"targetWeights": { "ETH": 5000, "USDC": 3000, "WBTC": 2000 }, // bps; must sum to 10000
"tolerance": 200, // bps drift before rebalancing; default 200 (2%)
"cadence": "daily" // hourly | daily | weekly
}yield — auto-route to highest-APR pool
{
"asset": "USDC",
"protocol": "aave-v3", // aave-v3 | compound-v3 | morpho
"minAprBps": 300, // 300 = 3%; default 300
"maxAllocation": "1000" // human string cap
}Sensible defaults (your AI agent will pick these automatically)
| Field | Default |
|---|---|
maxSlippageBps | 50 (0.5%) |
cadence (DCA) | weekly |
cadence (rebalance) | daily |
tolerance (rebalance) | 200 bps |
minAprBps (yield) | 300 |
Natural-language usage
Once installed, you don't need to write JSON. Just describe what you want:
| You say | Your AI calls |
|---|---|
| "Set up a weekly $50 USDC into ETH DCA" | agent_create({kind:"dca", params:{fromAsset:"USDC", toAsset:"ETH", amountPerRun:"50", cadence:"weekly", maxSlippageBps:50}}) |
| "Rebalance my wallet to 50% ETH, 30% USDC, 20% WBTC daily" | agent_create({kind:"rebalance", params:{targetWeights:{ETH:5000, USDC:3000, WBTC:2000}, tolerance:200, cadence:"daily"}}) |
| "Yield-farm 1000 USDC into Aave with 3% minimum" | agent_create({kind:"yield", params:{asset:"USDC", protocol:"aave-v3", minAprBps:300, maxAllocation:"1000"}}) |
| "What agents do I have?" | agent_list() |
| "Pause my DCA" | agent_list() → find kind:"dca", status:"active" → agent_update({id, status:"paused"}) |
| "Run my rebalance now" | agent_run({id}) |
| "Delete the yield bot" | agent_delete({id}) |
Quick smoke test
To prove the connection without modifying anything:
- Ask your AI: "What's my VeilNet wallet status?" → triggers
wallet_status→ should reportaddress: 0x…andbackend: "ok". - Ask: "List my agents." → triggers
agent_list→ empty array is fine on first run.
If wallet_status returns VEILNET_REAUTH_REQUIRED, re-download session.json from the Agent tab.
Troubleshooting
| Error code | Meaning | Fix |
|---|---|---|
VEILNET_SESSION_MISSING | ~/.veilnet/session.json not found | Run the Agent-tab setup. |
VEILNET_SESSION_MALFORMED | Bad JSON or missing required fields | Re-download session.json. |
VEILNET_REAUTH_REQUIRED | JWT expired (server returned 401) | Re-download session.json from the Agent tab. |
VEILNET_MASTER_KEY_MISSING | ~/.veilnet/master.key not found | Re-download master.key. |
VEILNET_MASTER_KEY_MALFORMED | Wrong shape (must be base64 of exactly 32 bytes inside the JSON) | Re-download master.key. |
VEILNET_DECRYPT_FAILED | Master key doesn't match this agent's ciphertext | Confirm you're using the master.key for the same wallet that created the agent. |
VEILNET_API_RATE_LIMITED | Hit the per-user rate limit | Wait the seconds in the Retry-After header / error message. |
VEILNET_API_NOT_FOUND | Agent id doesn't exist (or was soft-deleted) | agent_list to see current ids. |
Common gotchas
- Two browser downloads were blocked. Chrome auto-blocks the second of two near-simultaneous downloads. If only
session.jsoncame through, scroll to the bottom of the success panel in the Agent tab and click the second download button formaster.keyexplicitly. npxnot found in Claude Desktop. Use the absolutenode+ binary path layout shown in the Claude Desktop snippet above.world-readablewarnings on stderr. Runchmod 600 ~/.veilnet/*on macOS / Linux. v0.1 only warns; v0.2 will refuse to start.- Tool calls return
VEILNET_REAUTH_REQUIREDon every call. Your JWT has expired. The 7-day clock starts from each Generate.
Threat model
VeilNet servers can see:
- Ciphertext, IV, the
kindstring ("dca"/"rebalance"/"yield"), lifecycle timestamps.
VeilNet servers cannot see:
- Strategy parameters (amounts, tickers, weights, slippage, etc.).
- Your master key — the wrapped envelope at
/agents/keys/envelopeis decryptable only with your passphrase.
The LLM provider (Anthropic, OpenAI, etc.) sees:
- The names of the tools your AI calls.
- Any plain text you type into the chat.
- Decrypted
paramsreturned byagent_get/agent_run— the MCP server passes these back as tool results. Don't dump strategy plaintext into the chat scrollback if you want to keep it private from the provider.
Network observers (between you and api.veilnet.to) see:
- TLS-encrypted traffic. The wire shape (ciphertext + IV + iterations) is opaque even inside the TLS stream.
An attacker who steals only your wallet:
- Can re-authenticate to VeilNet, but cannot decrypt your existing agents without
master.key.
An attacker who steals master.key + a valid JWT:
- Can decrypt all your agents. Keep
master.keyoffline-backed-up (a hardware vault, password manager, or air-gapped USB). To rotate, click Reset on the Agent tab — this replaces the envelope and invalidates the old key (and any agents encrypted with it).
FAQ
What does VeilNet actually store?
{ address, agentId, kind, ciphertext, iv, version, status, createdAt, updatedAt }. Plus your wrapped envelope at /agents/keys/envelope. That's it. No plaintext params ever touch the disk.
Can I use the same setup on multiple machines?
Yes. Copy ~/.veilnet/session.json and ~/.veilnet/master.key to the second machine (over a secure channel — encrypted USB, SSH, etc.). Both machines share the same JWT, so the 7-day expiry is shared too.
For a clean per-device setup, the Agent tab will (in a future release) offer per-device envelope wrapping. For now, the simple file copy is the supported path.
What happens if I lose my passphrase?
You can still authenticate (SIWE doesn't need the passphrase), but you cannot decrypt your existing agents on a new device. On the current device, your master.key file is intact and still works.
To recover, you must agent_delete every existing agent, click Reset on the Agent tab, choose a new passphrase, and re-create your strategies.
What models / providers does this work with?
Any model your MCP client supports. The MCP server is provider-agnostic — Claude (3.5 Sonnet, Opus 4.x, Haiku), GPT-4o, GPT-4.1, Gemini 1.5/2.0, Llama, local Ollama models, etc.
Does the MCP server run on remote / serverless?
Not in v0.1 — stdio only. HTTP+SSE transport is on the roadmap. For now, the server runs as a local subprocess of your MCP client.
Is this open source?
The packages (@veilnet/agent-crypto, @veilnet/mcp-server) and the dApp are open source. The protocol contracts are audited and on-chain. See the npm page and https://github.com/syncodemayo/VeilNet (private during beta — request access via support@veilnet.to).
Where can I report bugs?
Email support@veilnet.to or open an issue on the GitHub repo if you have access. Include the error code (VEILNET_*) and which MCP client / OS / Node version you're on. Never paste the contents of master.key or session.json into a bug report.
Versioning
- v0.1 — stdio only, 7 tools, AAD-bound encryption, single envelope per user, soft-delete agents.
- v0.2 (planned) — hard-fail on world-readable files, JWT auto-refresh, per-device envelope wrapping, HTTP+SSE transport, OS-keychain integration (macOS Keychain / Windows Credential Manager / libsecret).
License
MIT.
