internull-mcp
v0.3.1
Published
MCP server for AI agents to interact with the InterNull privacy protocol: deposit, claim keys, withdraw across chains via 3-of-5 distributed threshold cryptography
Maintainers
Readme
InterNull MCP Server
A Model Context Protocol (MCP) server that enables AI agents to interact with the InterNull Protocol, a privacy-preserving, cross-chain payment system built on distributed threshold cryptography.
What is This?
This MCP server gives any AI agent the ability to:
- Deposit funds into the InterNull treasury on any supported chain
- Claim one-time-use private keys via 3-of-5 distributed key generation
- Withdraw funds on any supported chain (including cross-chain)
- Relay gas-free withdrawals via the built-in relayer
- Manage wallets with encrypted local storage
The agent never sees the full private key during key generation. Each of the 5 DKG nodes only holds a share. The agent reconstructs the key locally using Lagrange interpolation over secp256k1.
Architecture
AI Agent (Claude, Cursor, Windsurf, custom agents)
|
| MCP Protocol (stdio)
|
InterNull MCP Server
|
|--- DKG Node 1 (theblackbox.network/node1)
|--- DKG Node 2 (theblackbox.network/node2)
|--- DKG Node 3 (theblackbox.network/node3) ← 3-of-5 threshold
|--- DKG Node 4 (theblackbox.network/node4)
|--- DKG Node 5 (theblackbox.network/node5)
|
|--- EVM Chains (Sepolia, Base Sepolia, BNB Testnet, Polygon Amoy, Hyperliquid)
|--- Solana (Devnet)The DKG node endpoints still resolve at theblackbox.network; that host is the canonical production mirror for the InterNull backend.
Supported Chains & Denominations
50 registered merkle roots across 7 chains, 4 tokens, and 14 chain+token combinations:
| Chain | Token | Denominations | |-------|-------|---------------| | Sepolia | ETH | 0.001, 0.01, 0.05, 0.1, 0.5, 1 | | Sepolia | USDC | 1, 2, 5, 10 | | Sepolia | LINK | 0.5, 1, 2 | | Base Sepolia | ETH | 0.001, 0.01, 0.05, 0.1 | | Base Sepolia | USDC | 1, 2, 5 | | BNB Testnet | TBNB | 0.01, 0.05, 0.1, 0.5 | | BNB Testnet | USDC | 1, 2, 5 | | BNB Testnet | LINK | 0.5, 1, 2 | | Polygon Amoy | POL | 1, 2 | | Polygon Amoy | USDC | 1, 2, 5 | | Hyperliquid Testnet | HYPE | 0.01, 0.1, 0.5 | | Hyperliquid Testnet | USDC | 1, 2, 5 | | Solana Devnet | SOL | 0.1, 0.5, 1 | | Solana Devnet | USDC | 1, 2, 5 |
Use the
get_available_denominationstool to query live denominations. New ones are added regularly.
Quick Start
1. Install
git clone https://github.com/InterNullOrg/internull-mcp.git
cd internull-mcp
npm install
npm run buildRepo:
github.com/InterNullOrg/internull-mcp. npm:internull-mcp.
2. Configure Your MCP Client
Add the server to your AI agent's MCP configuration.
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"internull": {
"command": "node",
"args": ["/absolute/path/to/internull-mcp/dist/index.js"],
"env": {
"DKG_NODE_1": "https://theblackbox.network/node1",
"DKG_NODE_2": "https://theblackbox.network/node2",
"DKG_NODE_3": "https://theblackbox.network/node3",
"DKG_NODE_4": "https://theblackbox.network/node4",
"DKG_NODE_5": "https://theblackbox.network/node5"
}
}
}
}Add to project .mcp.json or ~/.claude/settings.json:
{
"mcpServers": {
"internull": {
"command": "node",
"args": ["/absolute/path/to/internull-mcp/dist/index.js"],
"env": {
"DKG_NODE_1": "https://theblackbox.network/node1",
"DKG_NODE_2": "https://theblackbox.network/node2",
"DKG_NODE_3": "https://theblackbox.network/node3",
"DKG_NODE_4": "https://theblackbox.network/node4",
"DKG_NODE_5": "https://theblackbox.network/node5"
}
}
}
}Add to .cursor/mcp.json in your project root:
{
"mcpServers": {
"internull": {
"command": "node",
"args": ["/absolute/path/to/internull-mcp/dist/index.js"],
"env": {
"DKG_NODE_1": "https://theblackbox.network/node1",
"DKG_NODE_2": "https://theblackbox.network/node2",
"DKG_NODE_3": "https://theblackbox.network/node3",
"DKG_NODE_4": "https://theblackbox.network/node4",
"DKG_NODE_5": "https://theblackbox.network/node5"
}
}
}
}Use tsx instead of node for development:
{
"mcpServers": {
"internull": {
"command": "npx",
"args": ["tsx", "/absolute/path/to/internull-mcp/src/index.ts"],
"env": {
"DKG_NODE_1": "https://theblackbox.network/node1",
"DKG_NODE_2": "https://theblackbox.network/node2",
"DKG_NODE_3": "https://theblackbox.network/node3",
"DKG_NODE_4": "https://theblackbox.network/node4",
"DKG_NODE_5": "https://theblackbox.network/node5"
}
}
}
}3. Talk to Your Agent
Once configured, the agent automatically discovers all 18 tools. Example prompts:
"Create a wallet and deposit 0.1 ETH on Sepolia"
"Claim 10 keys of 0.001 ETH on Base Sepolia from my deposit"
"Withdraw key #3 to my wallet on Base Sepolia"
"Check the health of the DKG network"
"Move 0.05 ETH from Sepolia to Base Sepolia privately"Migrating from blackbox-mcp v0.2.x
Version 0.3.0 renames the published npm package from blackbox-mcp to internull-mcp. To migrate:
- Uninstall the old package (if installed globally):
npm uninstall -g blackbox-mcp. - Install the new one:
npm install -g internull-mcp(or usenpx internull-mcpin your MCP config). - Update the
command/argsin your MCP config to point atinternull-mcpinstead ofblackbox-mcp. Rename themcpServerskey from"blackbox"to"internull"if you want a cleaner identifier (it is an arbitrary label; any name works). - Your existing wallets are preserved. The server looks in
~/.internull-mcp/wallets/first and falls back to~/.blackbox-mcp/wallets/if only the legacy directory exists. No manual copy is required. If you want to move them explicitly, runmv ~/.blackbox-mcp ~/.internull-mcp.
Available Tools (18)
Wallet Management
| Tool | Description |
|------|-------------|
| create_wallet | Create a new EVM or Solana wallet with encrypted storage |
| import_wallet | Import an existing wallet from a private key |
| list_wallets | List all stored wallets |
| get_balance | Get native and token balances on any chain |
Protocol Discovery
| Tool | Description |
|------|-------------|
| get_supported_chains | List all supported chains with RPC URLs and treasury addresses |
| get_chain_tokens | Get tokens and denominations for a specific chain |
| get_available_denominations | Get registered denominations (merkle roots) for a chain |
| get_token_mappings | Get cross-chain token mapping rules |
| check_health | Check DKG network health |
| get_leaderboard | Get top depositors leaderboard |
Core Operations
| Tool | Description |
|------|-------------|
| deposit | Deposit funds into the treasury (handles ERC20 approval automatically) |
| claim_keys | Request keyshares from DKG nodes and reconstruct private keys via Lagrange interpolation |
| withdraw_onchain | Execute on-chain withdrawal using a one-time key |
| deposit_and_claim | Combined deposit + claim in one step |
Relay & Swap
| Tool | Description |
|------|-------------|
| relay_withdraw | Gas-free withdrawal via the relayer service |
| check_relay_status | Check relay job status |
| get_relay_info | Get relay service info and fees |
| get_swap_quote | Get cross-chain swap quote |
Agent Guide Resource
The server exposes an internull://agent-guide resource containing detailed instructions for agents: denomination rules, security model, error handling, and step-by-step workflows. MCP-compatible agents read this automatically.
Environment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| MCP_TRANSPORT | Transport mode: stdio or http | stdio |
| PORT | HTTP server port (when MCP_TRANSPORT=http) | 3001 |
| CORS_ORIGIN | Allowed CORS origin (when MCP_TRANSPORT=http) | * |
| DKG_NODE_1 through DKG_NODE_5 | Individual DKG node URLs | https://theblackbox.network/node1..5 |
| DKG_NODE_URLS | Comma-separated node URLs (alternative) | — |
| DKG_THRESHOLD | Minimum shares needed for reconstruction | 3 |
| WALLET_STORE_PATH | Path to encrypted wallet storage | ~/.internull-mcp/wallets (falls back to ~/.blackbox-mcp/wallets if legacy dir exists and new dir is empty) |
Deployment
The server supports two transport modes:
| Mode | Use Case | How |
|------|----------|-----|
| stdio (default) | Local MCP clients (Claude Desktop, Cursor, Claude Code) | node dist/index.js |
| http | Hosted server for web agents, remote access | MCP_TRANSPORT=http node dist/index.js |
Deploy on EC2 (Docker)
# On your EC2 instance
git clone https://github.com/InterNullOrg/internull-mcp.git
cd internull-mcp
docker compose up -dThe server will be available at http://<your-ec2-ip>:3001/mcp with a health check at /health.
To use a custom port or restrict CORS:
PORT=8080 CORS_ORIGIN=https://yourdomain.com docker compose up -dDeploy on EC2 (without Docker)
git clone https://github.com/InterNullOrg/internull-mcp.git
cd internull-mcp
npm install
npm run build
# Run with systemd, pm2, or directly:
MCP_TRANSPORT=http PORT=3001 \
DKG_NODE_1=https://theblackbox.network/node1 \
DKG_NODE_2=https://theblackbox.network/node2 \
DKG_NODE_3=https://theblackbox.network/node3 \
DKG_NODE_4=https://theblackbox.network/node4 \
DKG_NODE_5=https://theblackbox.network/node5 \
node dist/index.jsWith pm2 for process management:
npm install -g pm2
MCP_TRANSPORT=http PORT=3001 pm2 start dist/index.js --name internull-mcp
pm2 save
pm2 startup # auto-start on rebootDeploy behind Nginx (HTTPS)
server {
listen 443 ssl;
server_name mcp.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/mcp.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mcp.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 300s;
}
}HTTP API Endpoints
| Endpoint | Method | Description |
|----------|--------|-------------|
| /mcp | POST | MCP Streamable HTTP endpoint (all tool calls go here) |
| /mcp | GET | SSE stream for server-initiated messages |
| /mcp | DELETE | Close session |
| /health | GET | Health check. Returns {"status":"ok","sessions":N} |
Connecting Web Agents to Hosted Server
Web-based agents connect via the Streamable HTTP transport:
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
const transport = new StreamableHTTPClientTransport(
new URL('https://mcp.yourdomain.com/mcp')
);
const client = new Client({ name: 'my-web-agent', version: '1.0.0' });
await client.connect(transport);
// Now call any of the 18 tools
const result = await client.callTool('check_health', {});NPM Install (for local agents)
# Install globally
npm install -g internull-mcp
# Then use in MCP config:
# "command": "internull-mcp"Or use npx without installing:
{
"mcpServers": {
"internull": {
"command": "npx",
"args": ["internull-mcp"],
"env": {
"DKG_NODE_1": "https://theblackbox.network/node1",
"DKG_NODE_2": "https://theblackbox.network/node2",
"DKG_NODE_3": "https://theblackbox.network/node3",
"DKG_NODE_4": "https://theblackbox.network/node4",
"DKG_NODE_5": "https://theblackbox.network/node5"
}
}
}
}How It Works
Deposit
- Agent calls
depositwith chain, amount, and token - MCP server submits a deposit transaction to the on-chain treasury contract
- Treasury locks the funds
Key Claim (Distributed Key Generation)
- Agent calls
claim_keyswith the deposit tx hash and withdrawal requests - MCP server signs a proof message with the agent's wallet
- Each of the 5 DKG nodes independently:
- Verifies the deposit on-chain
- Verifies the signature
- Returns its keyshare (a partial secret)
- MCP server reconstructs the full private key locally using Lagrange interpolation over secp256k1
- Each key is a one-time-use ECDSA key tied to a specific merkle root and key index
No single node ever knows the full private key. Any 3-of-5 shares are sufficient.
Withdrawal
- Agent calls
withdraw_onchain(orrelay_withdrawfor gas-free) - MCP server signs the withdrawal message with the reconstructed one-time key
- The treasury contract verifies:
- ECDSA signature validity
- Merkle proof (key belongs to a registered batch)
- Nullifier (key hasn't been used before)
- Funds are released to the recipient
- The key is permanently marked as spent
Cross-Chain
Deposits on chain A can generate withdrawal keys for chain B. Requirements:
- A valid token mapping exists between the chains (admin-configured)
- The denomination is registered on the target chain
- The deposit amount covers the total requested value
Security Model
| Property | Implementation | |----------|---------------| | No single point of failure | 3-of-5 threshold. Any 3 nodes reconstruct, no pair can. | | One-time keys | On-chain nullifier prevents reuse | | Wallet encryption | AES-256-GCM with PBKDF2 (100k iterations) | | Request authentication | ECDSA/Ed25519 signature on every keyshare request | | Deposit verification | Each node independently verifies deposits on-chain | | Idempotent claims | Re-requesting same deposit returns identical keys | | UTXO model | Deposit fully allocated on first claim; different configs rejected | | Timestamp validation | Requests must be within 5 minutes |
Agentic Usage Patterns
Privacy Payment Agent
1. create_wallet → agent wallet
2. (user funds wallet with ETH)
3. deposit → 0.001 ETH on Sepolia
4. claim_keys → 1 key for base_sepolia
5. withdraw_onchain → sends to recipient on Base Sepolia
(deposit chain != withdrawal chain = unlinkable)Batch Payment Agent
1. deposit → 0.1 ETH on Sepolia
2. claim_keys → 100 keys of 0.001 ETH across multiple chains
3. withdraw_onchain → execute each withdrawal to different recipients
(each withdrawal is independent and unlinkable)Gas-Free Agent
1. claim_keys → get keys from a previous deposit
2. get_relay_info → check if relay is enabled + get fees
3. relay_withdraw → relayer pays gas on target chain
4. check_relay_status → poll until confirmedTesting
The repository includes test suites that were used to validate the protocol:
# End-to-end: deposit → claim → withdraw
npx tsx test-e2e.ts
# Edge cases: invalid denominations, double-spend, wrong signer, expired timestamps
npx tsx test-edge-cases.ts
# 100-key stress test: all C(5,3)=10 share combinations per key
npx tsx test-100-keys.ts
# Cross-chain 50+50 split with timing measurements
npx tsx test-100-keys-v2.ts
# Idempotency: re-claim returns identical keys
npx tsx test-idempotency-splits.tsTest Results (Verified)
- 200 keys generated across test runs. All reconstructed successfully.
- 2000 share combinations tested (10 per key). All passed.
- All key_indexes and addresses are unique per batch.
- Re-claims return identical keys (verified 3 times independently).
- Backend rejects different claim configs for same deposit (UTXO model).
- Key retrieval: ~52s for 100 keys (P2P mini-VSS exchange).
- Local reconstruction: ~5ms per key (Lagrange interpolation).
Project Structure
internull-mcp/
├── src/
│ ├── index.ts # MCP server: 18 tools + agent guide resource (stdio + HTTP)
│ ├── api.ts # InterNull API client (DKG node communication)
│ ├── config.ts # Environment configuration loader
│ ├── crypto.ts # Lagrange interpolation, ECDSA signatures, key reconstruction
│ └── wallet.ts # Encrypted wallet manager (AES-256-GCM + PBKDF2)
├── Dockerfile # Docker image for EC2/cloud deployment
├── docker-compose.yml # One-command deployment
├── package.json
├── tsconfig.json
└── test-*.ts # Test suitesLicense
MIT
