Skip to main content
Glama

shardnest

Self-custodial, non-custodial wallet infrastructure — key generation, Shamir secret sharing (2-of-3), signing, and recovery all happen on the user's own machine. The platform never touches key material. Any platform that speaks the signed_request v1 protocol can integrate.

中文版:README.zh-CN.md

Why shardnest

  • Platform keeps zero key material — private keys are generated, split, and signed 100% in the user's local environment. The platform only stores the public address.

  • Recoverable — a 2-of-3 SSS split means losing your device, forgetting your passphrase, or losing one recovery code never means losing your wallet.

  • LLM-safe credential isolation — passphrases and recovery codes never enter an LLM context. CLI generates single-use tokens (5 min TTL, 0600, atomic consume); MCP tools only receive token / local-file-path references.

  • Open protocol — any platform can integrate via signed_request v1 (platform-endorsed signature requests), no lock-in.

Related MCP server: MCP Wallet Signer

Quick start

Requirements: Bun ≥ 1.3.

bun install

# Create a wallet (interactive; passphrase is masked)
SHARDNEST_HOME=$(mktemp -d) bun packages/cli/src/index.ts init

# Commands
bun packages/cli/src/index.ts address                      # show address (no secret)
bun packages/cli/src/index.ts passphrase-token             # local passphrase → single-use token
bun packages/cli/src/index.ts unlock                       # local unlock → signing token
bun packages/cli/src/index.ts sign "<message>"             # EIP-191 personal sign
bun packages/cli/src/index.ts restore                      # recover from 2 recovery codes

Files under ~/.shardnest/ (override with SHARDNEST_HOME):

metadata.json        plaintext { address } — address is not secret
device-share.json    share ①, encrypted with passphrase (scrypt KEK + AES-GCM, 0600)
recovery-codes.txt   share ② (+③ only when email not sent) plaintext recovery codes (0600)
unlock/              token sessions: unlock-*.bin / passphrase-*.bin / consuming-*.bin
mnemonic.txt          (optional) 24-word mnemonic = full private key backup (single point, 0600)

Key management model

  • Creation: CSPRNG private key → SSS 2-of-3 split → share ① encrypted on device (passphrase), recovery codes ②+③ written to local file; optionally share ③ also emailed via SMTP (single share = zero information).

  • Signing: platform issues a signed_request (endorsed with its private key) → MCP verifies endorsement, checks wallet_address, asks the user (approval gate) → consumes a local unlock token → signs in memory → wipes.

  • Recovery: any 2 shares rebuild the same private key. restore cross-checks the derived address against the expected address / previous metadata to reject typo'd recovery codes.

MCP server

SHARDNEST_PLATFORM_ADDRESS=<platform endorsement address> \
SHARDNEST_HOME=~/.shardnest \
bun packages/mcp-server/src/index.ts

Tools: wallet_create · wallet_address · signed_request_sign · wallet_restore · wallet_mnemonic_export · wallet_wipe. Sensitive credentials are never tool arguments — use passphrase_token / recovery_file_path / recovery_codes_file instead.

Email backup (optional): SHARDNEST_SMTP_HOST / PORT / USER / PASS / FROM / TLS.

CLI reference

All commands are interactive (passphrases & recovery codes are masked input).

Command

Purpose

Key prompts / output

init

Create wallet

masked passphrase → email (optional, sends share ③) → generate 24-word mnemonic? (default No) → prints recovery codes, saves files under ~/.shardnest/

address

Show address

none (no secret needed)

passphrase-token

Generate passphrase token for MCP create/restore

masked passphrase → prints token (5 min, single-use, keep out of chats)

unlock

Generate unlock token for MCP signing

masked passphrase + recovery code → prints token

sign <message>

EIP-191 personal sign

masked passphrase + recovery code → {address, signature}

restore

Recover from 2 recovery codes

new masked passphrase → 2 masked recovery codes → expected address (optional, strongly recommended) → email (optional)

restore-mnemonic

Recover from 24-word mnemonic alone

new masked passphrase → 24 words → expected address (optional) → email (optional)

mnemonic-export

Export 24-word mnemonic from any 2 shares

mode a) device share + recovery code, or b) two recovery codes → writes mnemonic.txt

wipe

Best-effort secure erase (3× overwrite then delete; physical erasure not guaranteed on SSD/CoW filesystems)

choose scope: 1) saved files only, 2) everything → file list → confirm phrase PERMANENT DELETE

Mnemonic (optional, default off)

  • Only 24 words are supported: 12 words carry 128 bits < 256-bit private key (capacity constraint).

  • Standard BIP-39/44 semantics: wallet root = 32-byte entropy (protected by 2-of-3 shares); the 24 words are the entropy's standard BIP-39 encoding and derive the account key via m/44'/60'/0'/0/0importable into MetaMask / Ledger / Trust Wallet for the same address. Exportable anytime from any 2 shares.

  • A mnemonic equals the full private key (single point) — leak = funds lost, no threshold protection. Store offline (paper/password manager), then run wipe (scope 1) to remove the local plaintext copy.

  • Generated on init (opt-in) or exported anytime via mnemonic-export (any 2 of 3 shares); recovered via restore-mnemonic.

Email backup (optional)

Env var

Meaning

SHARDNEST_SMTP_HOST

SMTP server (required to enable)

SHARDNEST_SMTP_PORT / TLS

default 465 / true

SHARDNEST_SMTP_USER / PASS / FROM

credentials / sender (default USER)

Recovery code integrity: CRC-256 (keccak256 first 4 bytes, 32-bit) — error-detection miss rate 1/2^32.

Backup distribution after init:

  • Email delivered → local recovery-codes.txt holds only share ② (share ③ lives in the mailbox) — a full local compromise cannot move funds.

  • No email → both shares ②③ stay local with a prominent warning; move one share offline or configure email.

wipe — two scopes

Scope

Deletes

Wallet after

1) saved (default/recommended)

recovery codes + mnemonic (plaintext backups)

still usable (passphrase unlock)

2) all

device share + backups + metadata + token sessions

must rebuild from saved codes/mnemonic

Both scopes overwrite files 3× with random data before unlink (best-effort secure erase — app-layer cannot guarantee physical erasure on SSD, APFS/CoW or snapshot environments; deletion failures are reported, never masked as success) and require the confirm phrase PERMANENT DELETE.

MCP tools

Start the server:

SHARDNEST_PLATFORM_ADDRESS=<platform endorsement address> SHARDNEST_HOME=~/.shardnest \
bun packages/mcp-server/src/index.ts

Sensitive credentials never appear in tool arguments — they travel via local token files / file paths (LLM-isolated).

Tool

Arguments

Notes

wallet_create

passphrase_token, email?, generate_mnemonic?

returns recovery_codes_file / mnemonic_file paths (no plaintext to LLM); rejects when a wallet already exists (WALLET_EXISTS, no token consumed) — rebuild requires wallet_wipe (host approval) or CLI init interactive confirm

wallet_address

current address

wallet_mnemonic_export

approval-gated; writes 24-word mnemonic to local file, returns path only

signed_request_sign

signed_request, unlock_token

double-gated (platform endorsement + user approval); signs domain-separated request context (wallet_address / platform_address / action / intent_hash / nonce / expires_at / user_id)

wallet_restore

recovery_file_path? / mnemonic_file_path?, passphrase_token, expected_address?, email?

file paths must be inside the wallet dir

wallet_wipe

scope? (saved default / all)

approval-gated; returns removed file list

Platform integration (any business platform)

  1. Issue: platform signs a signed_request with its own private key (@wallet-services/protocol issueSignedRequest).

  2. Sign: user's Agent calls MCP signed_request_sign — endorsement verified, wallet_address checked, user confirms, local token consumed, EIP-191 signature returned.

  3. Verify: platform runs @wallet-services/verify-sdk recoverSigner(message, sig) → recovered address must match the bound wallet_address.

See protocol/README.md for the signed_request v1 spec & JSON Schema.

Architecture

core (pure crypto, no IO)          GF(2^8) SSS · keccak address · EIP-55 · scrypt KEK
signer                              WalletVault (sole key holder) · approval gate · token sessions
cli                                 commands · recovery-code CRC · SMTP backup
verify-sdk                          platform-side EIP-191 verification (verify-only, zero keys)
protocol                            signed_request v1 — platform endorsement issue/verify
mcp-server                          shell (credentials never enter LLM; standalone keyless process is roadmap P0-3) wiring the double gates

Cryptographic invariants are documented in AGENTS.md — read it before touching crypto code (GF(2^8) generator must be 3, EIP-191 hashing must stay byte-identical in three places, recovery-code CRC covers index:hex, memory zeroing on all paths).

Testing

cd packages/<pkg> && bun test          # per-package
for p in core signer cli verify-sdk protocol mcp-server; do (cd packages/$p && bun test); done

Documentation

License

MIT

Related MCP Connectors

Related MCP Servers

  • F
    license
    C
    quality
    D
    maintenance
    A suite of MCP servers that allow LLMs to interact with blockchains through MetaMask wallet without exposing private keys, facilitating secure AI-powered blockchain interactions and simplified user onboarding.
    25
    4
    -
  • A
    license
    A
    quality
    A
    maintenance
    MCP server for managing Bitcoin, Liquid Network, and Lightning wallets through AI assistants, with unified seed support, secure encrypted storage, and both CLI and tool interfaces.
    71
    4
    MIT