Your private keys never leave your browser. Every transaction requires explicit user approval in your wallet.
Most blockchain MCPs require you to paste a private key into a config file — giving the AI agent full, unsupervised access to your funds. MCP Wallet Signer takes a different approach: it routes every transaction to your actual browser wallet (MetaMask, Rabby, etc.) via EIP-6963, so you review and approve each action just like any other dapp interaction. No keys in config files, no risk of silent transactions.
Works with any MCP-compatible client via stdio transport.
claude mcp add evm-wallet -- npx -y mcp-wallet-signerAdd to your claude_desktop_config.json:
{
"mcpServers": {
"evm-wallet": {
"command": "npx",
"args": ["-y", "mcp-wallet-signer"]
}
}
}npx -y mcp-wallet-signer
pnpx mcp-wallet-signer
bunx mcp-wallet-signer| Tool | Description | Browser Required |
|---|---|---|
connect_wallet |
Connect wallet, return address | Yes |
send_transaction |
Send ETH/tokens, call contracts | Yes |
sign_message |
Sign arbitrary message (personal_sign) | Yes |
sign_typed_data |
Sign EIP-712 typed data | Yes |
get_balance |
Read ETH balance (via RPC) | No |
- Agent calls an MCP tool (e.g.,
send_transaction) - Server opens browser to a local signing page
- User connects wallet and approves the action
- Result (address, tx hash, signature) returned to agent
Built-in RPC URLs for:
- Ethereum (1)
- Sepolia (11155111)
- Polygon (137)
- Arbitrum One (42161)
- Optimism (10)
- Base (8453)
- Avalanche (43114)
- BNB Smart Chain (56)
Environment variables (optional):
| Variable | Description | Default |
|---|---|---|
EVM_MCP_PORT |
HTTP server port | 3847 |
EVM_MCP_DEFAULT_CHAIN |
Default chain ID | 1 |
Requires Deno v2.0+.
# Install dependencies
deno install
cd web && deno install && cd ..
# Run MCP server in dev mode
deno task dev
# Run web UI dev server (separate terminal)
deno task dev:web
# Run tests
deno task test
# Build web UI
deno task build:web
# Build for npm
deno task build:npm
# Format code
deno task fmt
# Lint code
deno task lintDeveloped with Deno, published to npm via dnt. Source in src/ uses
node: builtins (no Deno-specific APIs) so the npm bundle runs under Node.js.
deno.jsonc # Deno config + npm package metadata (single source of truth for version)
server.json # MCP registry manifest (read by LobeHub etc. from git)
scripts/build-npm.ts # dnt build: reads deno.jsonc, transforms src/ → npm/
├── src/ # Server source (TypeScript, runs under both Deno and Node)
│ ├── index.ts # CLI entry point
│ ├── mcp-server.ts # MCP tool definitions
│ ├── http-server.ts # Lazy-started HTTP server for browser approval UI
│ ├── wallet-signer.ts # Core signing orchestration
│ ├── pending-store.ts # Promise-based request tracking
│ ├── schemas.ts # Zod schemas for MCP tool inputs
│ ├── transport.ts # viem custom transport
│ ├── viem-account.ts # viem local account adapter
│ ├── mod.ts # Library export (npm: "mcp-wallet-signer")
│ ├── wallet-only.ts # Library export (npm: "mcp-wallet-signer/wallet-only")
│ └── version.ts # Reads version from package.json at runtime
├── web/ # Svelte UI (wallet approval pages)
│ └── src/
│ ├── App.svelte
│ └── components/ # ConnectWallet, TransactionSigner, MessageSigner
├── tests/
│ ├── *.test.ts # Unit tests
│ ├── e2e/ # E2E tests (HTTP API)
│ └── e2e-browser/ # E2E tests (Playwright, real browser wallet)
└── npm/ # Generated — dnt output + built web assets
deno task build:npm runs scripts/build-npm.ts which:
- Transforms
src/to ESM JavaScript via dnt →npm/esm/ - Generates
npm/package.jsonfrom metadata indeno.jsonc - Builds the Svelte web UI (
web/→web/dist/) - Copies web assets into
npm/web/
deno task dev # Run MCP server directly with Deno
deno task dev:web # Vite dev server for web UI (separate terminal)
deno task test # Unit + E2E API tests
deno task check # Type check + lint + format checkMIT