@hinkal/mcp
v0.0.5
Published
Model Context Protocol server for Hinkal: private deposits, withdrawals, sends, transfers, swaps, bridges and x402 API payments on EVM chains, Solana, and Tron from any MCP client.
Readme
@hinkal/mcp
Private crypto from any MCP client (Claude Desktop, Claude Code, Cursor, ...) powered by Hinkal. Shield tokens into a private balance, unshield, swap and bridge inside the private balance with no public trace of the trade, pay other Hinkal users with no on-chain trace, or send to any address with no link back to you - on every Hinkal-supported chain. Ask your assistant to list chains for the current list.
Also pays x402 paid APIs: your assistant checks the price of a 402-gated URL, and after you approve it pays and fetches the content - privately by default, so the seller cannot link the payment to your wallet.
Nothing to sign, no wallet to connect: a wallet is created automatically on first use and held server-side by Hinkal. Your machine keeps only an access key.
Install
Recommended - install globally (fast startup, explicit updates), then register the hinkal-mcp command with your client:
npm i -g @hinkal/mcpClaude Code:
claude mcp add hinkal -- hinkal-mcpClaude Desktop - add to claude_desktop_config.json:
{
"mcpServers": {
"hinkal": { "command": "hinkal-mcp" }
}
}Alternative - no install, run through npx (note: npx caches versions - see Updating):
claude mcp add hinkal -- npx -y @hinkal/mcp{
"mcpServers": {
"hinkal": { "command": "npx", "args": ["-y", "@hinkal/mcp"] }
}
}Any other MCP client: use hinkal-mcp (or npx -y @hinkal/mcp) as a stdio server command. Requires Node.js 18+. No configuration needed.
First use
- Ask your assistant for your wallet addresses. The wallet starts empty.
- Send the tokens you want to shield plus the chain's native gas token to the address for your chain.
- Back up the wallet: ask to export the wallet key and store the output somewhere safe. It is the only recovery - Hinkal cannot restore a lost key.
- Go: "deposit 10 USDC", "show my balances", "send 5 USDC privately to 0x...".
Tools
Your assistant picks the right one - just say what you want. What each does:
Balances
| Tool | What it does |
| --------------------- | --------------------------------------------------------------------------- |
| get_all_balances | Public and private (shielded) balances on every supported chain in one call |
| get_balances | Private (shielded) balances on one chain |
| get_public_balances | Regular on-chain balances of any wallet (defaults to yours) |
| get_stuck_balances | Funds from private sends whose payout leg never completed |
Moving funds (shielded)
| Tool | What it does |
| --- | --- |
| deposit | Shield your own funds: public balance -> your private balance. Gas only, no Hinkal fee |
| withdraw | Unshield: private balance -> any public address. Fee on top |
| deposit_for_other | Shield into another Hinkal user's private balance (gift/fund them privately) |
| private_transfer | Pay another Hinkal user shielded-to-shielded - no on-chain trace of sender, recipient, or amount |
| private_send | Pay one or more public addresses with no on-chain link back to you; payouts complete asynchronously |
| private_swap | Swap one token for another inside your private balance - no public trace of the trade. Pass a destination chain to bridge privately instead (EVM to EVM, same token). Fee comes out of the output |
| check_private_send_status | Poll a private_send payout by its scheduleId until it completes |
| recover_stuck_funds | Withdraw the stuck UTXOs of one token (from get_stuck_balances) to a public address |
| recover_temporary_wallet_funds | Recover funds stranded by an interrupted private swap or bridge. Destination is automatic; omit the chain to scan every EVM bridge chain |
Paid APIs (x402)
| Tool | What it does |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| initiate_x402_request | Call a possibly paid URL without paying. Free content comes back directly; a paywall comes back as a decoded price quote (token, amount, chain, recipient) |
| complete_x402_request | Pay a quoted URL and return its content, only when the price is within your approved maxAmount. Default pays privately: the amount is unshielded to a fresh temporary wallet that signs the payment, unlinkable to your wallet (Hinkal fee on top). source: "public" pays from the public balance instead - cheaper, no privacy |
| recover_x402_temp_wallets | Sweep funds stranded on temporary payment wallets back to your wallet after a failed private payment. The temporary wallet needs no gas; your main wallet submits the transfer |
Account
| Tool | What it does |
| ---------------------- | --------------------------------------------------------------------------------- |
| get_wallet_status | Is the wallet set up, and its addresses if known |
| get_wallet_addresses | Your public EVM/Tron/Solana addresses - fund these before depositing |
| export_wallet_key | Reveal the wallet's private access key for backup. Sensitive: full wallet control |
Plain public wallet actions (visible on-chain, no privacy)
| Tool | What it does |
| --- | --- |
| wallet_send | Normal token transfer from your wallet |
| wallet_swap | Normal public swap from your wallet via an aggregator. Pass a destination chain to bridge instead; routes touching Solana or Tron settle asynchronously |
| wallet_approve | Set an ERC-20/TRC-20 allowance for a spender contract |
| wallet_execute | Arbitrary contract call (EVM calldata or Tron selector) |
| wallet_sign_message / wallet_sign_typed_data | Sign a message / EIP-712 data; nothing is broadcast |
| wallet_solana_execute | Sign and broadcast a prepared Solana transaction |
| tron_freeze / tron_unfreeze | Stake/unstake TRX for energy or bandwidth (cheap Tron transactions) |
| tron_delegate_resource | Lend staked energy/bandwidth to another Tron address |
Info
| Tool | What it does |
| ---------------------------------------------------- | ---------------------------------------------------------------------------------- |
| list_chains / list_tokens | Browse supported chains and tokens (rarely needed - tools accept symbols directly) |
| ping | Check the Hinkal API is up |
| get_contract_addresses | Deployed Hinkal contract addresses per chain |
| get_enclave_public_key / get_enclave_attestation | Verify the API runs in a genuine secure enclave |
Configuration (optional)
Everything works with zero configuration. Override via a CLI flag on the server command (e.g. hinkal-mcp --dir ~/wallets) or an environment variable; the flag wins when both are set:
| Flag | Env variable | What it's for |
| ------------ | ---------------------------- | ---------------------------------------------------------------------------------------- |
| --dir | HINKAL_DIR | Data directory for the keystore; defaults to ~/.hinkal (%APPDATA%\hinkal on Windows) |
| --keystore | SIGNER_KEYSTORE_PASSPHRASE | Passphrase that encrypts the keystore at rest; must then be provided on every launch |
Backup and restore
Your wallet identity is one file: mcp-identity.json in the data directory. It survives updates and reinstalls; it does not survive deleting the file or losing the machine.
Private x402 payments also write x402-temp-wallets.jsonl next to it: the keys of the temporary payment wallets. Normally they hold nothing after a payment completes, but if a payment fails after funding, the money sits on that temporary wallet and this file is the way back to it - keep it.
Unlike mcp-identity.json, these keys are not encrypted - the passphrase does not cover them. The file is kept owner-only (chmod 600) on every write, so anyone who can read your home directory can spend whatever is still sitting on those wallets. Run recover_x402_temp_wallets after a failed payment so it holds nothing worth stealing.
Restore on any machine by recreating that file from your export_wallet_key backup (then chmod 600):
{ "stampSeed": "<stampPrivateKey>", "organizationId": "<organizationId>", "userId": "<userId>" }Your wallet and shielded balances are back on the next tool call.
Testing x402 against a live resource
The unit suite covers the x402 logic with the network stubbed out. Real payments - unshielding,
signing, settlement, and recovery - are exercised by an integration spec that is skipped unless
X402_TEST_URL is set:
X402_TEST_URL=https://x402.payai.network/api/base/paid-content \
X402_TEST_MAX_AMOUNT=0.02 \
X402_TEST_CHAIN_ID=8453 \
HINKAL_DIR=/tmp/x402-integration \
SIGNER_KEYSTORE_PASSPHRASE=<passphrase> \
npx jest --config apps/mcp-server/jest.config.ts --runTestsByPath \
apps/mcp-server/src/tests/x402Payment.integration.spec.tsThe URL above is PayAI's echo merchant: 0.01 USDC per call on Base mainnet, and it refunds each payment, so a full run costs only gas plus the Hinkal fee on the private payment. It is a third-party service - confirm it still refunds before pointing it at a wallet you care about.
It spends real funds: the wallet behind HINKAL_DIR needs a shielded balance of the token the
resource charges in, plus native gas on that chain for the recovery sweep. The last case deliberately
strands a payment after the unshield and then proves recover_x402_temp_wallets brings the money
back, so run it on a wallet you are willing to move funds from.
Updating
npm i -g @hinkal/mcp@latestRestart your client afterwards. If you use npx instead of a global install, also clear its cache (rm -rf ~/.npm/_npx) - npx pins cached versions and prefers global installs. Updates never touch your wallet.
