Install
$ agentstack add mcp-portkey-wallet-ca-agent-skills ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Portkey CA Agent Skills
> AI Agent toolkit for Portkey Wallet on the aelf blockchain — Email registration, login, transfers, guardian management, and generic contract calls.
[中文文档](./README.zh-CN.md) [](https://github.com/Portkey-Wallet/ca-agent-skills/actions/workflows/test.yml) [](https://Portkey-Wallet.github.io/ca-agent-skills/coverage.json)
Architecture
ca-agent-skills/
├── index.ts # SDK entry — direct import for LangChain / LlamaIndex
├── src/
│ ├── core/ # Pure business logic (no I/O side effects)
│ │ ├── account.ts # checkAccount, getGuardianList, getHolderInfo, getChainInfo
│ │ ├── auth.ts # sendVerificationCode, verifyCode, registerWallet, recoverWallet
│ │ ├── assets.ts # getTokenBalance, getTokenList, getNftCollections, getNftItems, getTokenPrice
│ │ ├── transfer.ts # sameChainTransfer, crossChainTransfer, recoverStuckTransfer
│ │ ├── guardian.ts # addGuardian, removeGuardian
│ │ ├── contract.ts # managerForwardCall, callContractViewMethod
│ │ └── keystore.ts # Encrypted wallet persistence (save, unlock, lock)
│ └── mcp/
│ └── server.ts # MCP adapter — for Claude Desktop, Cursor, GPT, etc.
├── portkey_query_skill.ts # CLI adapter — query commands
├── portkey_auth_skill.ts # CLI adapter — registration & login commands
├── portkey_tx_skill.ts # CLI adapter — transfer & guardian commands
├── cli-helpers.ts # CLI output helpers
├── bin/
│ └── setup.ts # One-command setup for AI platforms
├── lib/
│ ├── config.ts # Network config, env overrides
│ ├── types.ts # TypeScript interfaces & enums
│ ├── aelf-client.ts # aelf-sdk wrapper (wallet, contract, signing)
│ └── http.ts # HTTP client for Portkey backend API
└── __tests__/ # Unit / Integration / E2E tests
Core + Adapters pattern: Three adapters (MCP, CLI, SDK) call the same Core functions — zero duplicated logic.
Features
| # | Category | Capability | MCP Tool | CLI Command | SDK Function | |---|----------|-----------|----------|-------------|--------------| | 1 | Account | Check email registration | portkey_check_account | check-account | checkAccount | | 2 | Account | Get guardian list | portkey_get_guardian_list | guardian-list | getGuardianList | | 3 | Account | Get CA holder info | portkey_get_holder_info | holder-info | getHolderInfo | | 4 | Account | Get chain info | portkey_get_chain_info | chain-info | getChainInfo | | 5 | Auth | Get verifier server | portkey_get_verifier | get-verifier | getVerifierServer | | 6 | Auth | Send verification code | portkey_send_code | send-code | sendVerificationCode | | 7 | Auth | Verify code | portkey_verify_code | verify-code | verifyCode | | 8 | Auth | Register wallet | portkey_register | register | registerWallet | | 9 | Auth | Recover wallet (login) | portkey_recover | recover | recoverWallet | | 10 | Auth | Check status | portkey_check_status | check-status | checkRegisterOrRecoveryStatus | | 11 | Assets | Token balance | portkey_balance | balance | getTokenBalance | | 12 | Assets | Token list | portkey_token_list | token-list | getTokenList | | 13 | Assets | NFT collections | portkey_nft_collections | nft-collections | getNftCollections | | 14 | Assets | NFT items | portkey_nft_items | nft-items | getNftItems | | 15 | Assets | Token price | portkey_token_price | token-price | getTokenPrice | | 16 | Transfer | Same-chain transfer | portkey_transfer | transfer | sameChainTransfer | | 17 | Transfer | Cross-chain transfer | portkey_cross_chain_transfer | cross-chain-transfer | crossChainTransfer | | 18 | Transfer | Transaction result | portkey_tx_result | tx-result | getTransactionResult | | 19 | Transfer | Recover stuck transfer | portkey_recover_stuck_transfer | recover-stuck-transfer | recoverStuckTransfer | | 20 | Guardian | Add guardian | portkey_add_guardian | add-guardian | addGuardian | | 21 | Guardian | Remove guardian | portkey_remove_guardian | remove-guardian | removeGuardian | | 22 | Contract | ManagerForwardCall | portkey_forward_call | forward-call | managerForwardCall | | 23 | Contract | View method call | portkey_view_call | view-call | callContractViewMethod | | 24 | Wallet | Create wallet | portkey_create_wallet | create-wallet | createWallet | | 25 | Wallet | Save keystore | portkey_save_keystore | save-keystore | saveKeystore | | 26 | Wallet | Unlock wallet | portkey_unlock | unlock | unlockWallet | | 27 | Wallet | Lock wallet | portkey_lock | lock | lockWallet | | 28 | Wallet | Wallet status | portkey_wallet_status | wallet-status | getWalletStatus | | 29 | Wallet | Get active wallet context | portkey_get_active_wallet | — | getActiveWallet | | 30 | Wallet | Set active wallet context | portkey_set_active_wallet | — | setActiveWallet | | 31 | Wallet | Manager sync status | portkey_manager_sync_status | manager-sync-status | checkManagerSyncState |
Contract Call Routing
Choose the contract tool by method type, not just by wallet type.
forward-call/managerForwardCallare for state-changing methods only.view-call/callContractViewMethodare forGet*and other read-only methods.- For
Empty-input view methods such asGetConfig, omit--paramsentirely so the tool performs.call()with no arguments. - If a read-only method is routed through
forward-call, the result is aCA.ManagerForwardCallreceipt, not the inner method's decoded view return payload. VirtualTransactionCreatedis expected on successful forwarded writes. It proves that the CA contract created the inner call, but it is not the decoded return value and not a standalone proof of final business success.
Resonance examples:
# Read-only queue status lookup
bun run portkey_query_skill.ts view-call \
--rpc-url https://tdvv-public-node.aelf.io \
--contract-address 28Lot71VrWm1WxrEjuDqaepywi7gYyZwHysUcztjkHGFsPPrZy \
--method-name GetPairQueueStatus \
--params '""'
# State-changing queue join
bun run portkey_tx_skill.ts forward-call \
--login-email "user@example.com" \
--password "your-password" \
--ca-hash "" \
--contract-address 28Lot71VrWm1WxrEjuDqaepywi7gYyZwHysUcztjkHGFsPPrZy \
--method-name JoinPairQueue \
--args '{}' \
--chain-id tDVV
Wallet Persistence (Keystore)
Manager private keys are encrypted and stored locally using aelf-sdk's keystore scheme (scrypt + AES-128-CTR).
Storage location: ~/.portkey/ca/{network}.keystore.json
First-time setup (after registration/recovery)
# AI flow: create_wallet → register → check_status → save_keystore(password)
# The wallet is auto-unlocked after saving.
New conversation
# AI calls portkey_wallet_status to check the active or targeted keystore
# For profile keystores, pass --login-email (or use the active CA profile from a prior save/recover)
# If locked, ask for password → portkey_unlock(password)
# If the password was forgotten, switch to recover-and-save with fresh guardian verification codes
# Write operations in the same process now work automatically
Manual CLI usage
# Save keystore
bun run portkey_auth_skill.ts save-keystore \
--password "your-password" \
--private-key "hex-key" \
--mnemonic "word1 word2 ..." \
--ca-hash "xxx" --ca-address "ELF_xxx_tDVV" \
--origin-chain-id "tDVV"
# Unlock
bun run portkey_auth_skill.ts unlock --password "your-password"
# Or target a specific profile/keystore file
bun run portkey_auth_skill.ts unlock --password "your-password" --login-email "user@example.com"
# If the password was forgotten, re-login / recover and save a new reusable keystore
bun run portkey_auth_skill.ts recover-and-save \
--email "user@example.com" \
--guardians-approved '[...]' \
--chain-id AELF \
--password "new-password"
# Check status
bun run portkey_auth_skill.ts wallet-status
# Lock
bun run portkey_auth_skill.ts lock
How it works
- Save — encrypts the Manager private key + mnemonic with a user-provided password, writes to
~/.portkey/ca/ - Unlock — decrypts the keystore, loads the wallet into memory for the current process
- Lock — clears the private key from memory
- Write operations — automatically use the unlocked wallet for the current process; falls back to
PORTKEY_PRIVATE_KEYenv var if no keystore is unlocked
Recommended CA transfer path
# 1. recover -> save reusable keystore
bun run portkey_auth_skill.ts recover-and-save \
--email "user@example.com" \
--guardians-approved '[...]' \
--chain-id AELF \
--password "your-password"
# 2. poll manager sync on the target chain
bun run portkey_query_skill.ts manager-sync-status \
--ca-hash "" \
--chain-id tDVV \
--manager-address ""
# 3. collect fresh transferApprove proofs
# 4. transfer using the saved keystore directly in the tx command
bun run portkey_tx_skill.ts transfer \
--login-email "user@example.com" \
--password "your-password" \
--ca-hash "" \
--token-contract "" \
--symbol ELF \
--to "" \
--amount 101000000 \
--chain-id tDVV \
--guardians-approved '[...]'
Notes:
- CA write commands can now resolve signer directly from
--login-email+--password, so they no longer depend on a previousunlockfrom another CLI process. - Same-chain and cross-chain transfers now check whether the current manager is already synced to the target chain before sending any transaction.
- Generic
forward-callnow performs the same manager sync precheck before fee preview or transaction send. wallet-statusreturnsrecommendedActionanduserHintwhen a local keystore exists but is still locked.recommendedActionis the machine-routable next step (unlock), whileuserHintcarries the fallback guidance for wrong profile selection or forgotten passwords.- Transfer results include a fee preview when the chain can calculate it, including
chargingAddressand whether the CA appears to be paying the fee.
Cross-skill signing
portkey_save_keystoreandportkey_unlockautomatically update shared active wallet context.- Other write-capable skills can resolve signer by
explicit -> active context -> env(auto mode). - Shared context stores pointers only (no plaintext private key).
Prerequisites
- Bun >= 1.0
- An aelf wallet private key or an unlocked keystore (for write operations only)
Quick Start
1. Install
bun add @portkey/ca-agent-skills
# Or clone locally
git clone https://github.com/AwakenFinance/ca-agent-skills.git
cd ca-agent-skills
bun install
2. Configure
cp .env.example .env
# Edit .env — add your PORTKEY_PRIVATE_KEY (only for write operations)
3. One-Command Setup
# Claude Desktop
bun run bin/setup.ts claude
# Cursor (project-level)
bun run bin/setup.ts cursor
# Cursor (global)
bun run bin/setup.ts cursor --global
# OpenClaw — output config to stdout
bun run bin/setup.ts openclaw
# OpenClaw — merge into existing config
bun run bin/setup.ts openclaw --config-path ./my-openclaw.json
# IronClaw — install trusted skill + stdio MCP server
bun run bin/setup.ts ironclaw
# Check status (Claude, Cursor, OpenClaw, IronClaw)
bun run bin/setup.ts list
# Remove
bun run bin/setup.ts uninstall claude
bun run bin/setup.ts uninstall cursor
bun run bin/setup.ts uninstall openclaw --config-path ./my-openclaw.json
bun run bin/setup.ts uninstall ironclaw
IronClaw
# Install trusted skill + stdio MCP server
bun run bin/setup.ts ironclaw
# Remove IronClaw integration
bun run bin/setup.ts uninstall ironclaw
The IronClaw setup does two things by default:
- Writes a stdio MCP server entry to
~/.ironclaw/mcp-servers.json - Copies this repo's
SKILL.mdto~/.ironclaw/skills/portkey-ca-agent-skills/SKILL.md
Important trust model note:
- Use the trusted skill path above for write-capable CA wallet operations.
- Do not rely on
~/.ironclaw/installed_skills/for this package if you need registration, recovery, transfer, guardian management, or other write actions. - IronClaw attenuates installed skills to read-only tools, which can make the agent appear to "query only" even though the MCP server is available.
The MCP server exposes destructive annotations for CA write operations so IronClaw can request approval before registration, recovery, transfer, guardian, and contract calls. For compatibility, the MCP server currently emits both standard MCP camelCase annotations and IronClaw-compatible snakecase annotations because the current IronClaw source parses snakecase fields for MCP approval hints.
Remote activation contract:
- GitHub repo/tree URLs are discovery sources only, not the final IronClaw install payload.
- Preferred IronClaw activation from npm:
bunx -p @portkey/ca-agent-skills portkey-ca-setup ironclaw - Prefer ClawHub / managed install for OpenClaw when available; otherwise use
bunx -p @portkey/ca-agent-skills portkey-ca-setup openclaw - Local repo checkout remains a development smoke-test path only.
- Migration note:
portkey-setupwas removed in2.0.0; switch npm-based activation toportkey-ca-setup.
Usage
MCP (Claude Desktop / Cursor)
Add to your MCP config (mcp-config.example.json):
{
"mcpServers": {
"ca-agent-skills": {
"command": "bun",
"args": ["run", "/path/to/ca-agent-skills/src/mcp/server.ts"],
"env": {
"PORTKEY_PRIVATE_KEY": "your_private_key_here",
"PORTKEY_NETWORK": "mainnet"
}
}
}
}
OpenClaw
The openclaw.json in the project root defines 13 CLI-based tools for OpenClaw. Use bun run bin/setup.ts openclaw to generate or merge the config.
CLI
# Check if email is registered
bun run portkey_query_skill.ts check-account --email user@example.com
# Get chain info
bun run portkey_query_skill.ts chain-info
# Create wallet
bun run portkey_auth_skill.ts create-wallet
# Resolve the correct flow + chain first
bun run portkey_query_skill.ts prepare-auth-flow --email user@example.com
# Low-level auth tools require explicit chainId from prepare-auth-flow.resolvedChainId
bun run portkey_auth_skill.ts get-verifier --chain-id
bun run portkey_auth_skill.ts send-code --email user@example.com --verifier-id --operation recovery --chain-id
bun run portkey_auth_skill.ts verify-code --email user@example.com --code 123456 --verifier-id --session-id --operation recovery --chain-id
# Token list strategy: aa | auto | eoa (default: auto)
bun run portkey_query_skill.ts token-list --ca-address-infos '[{"chainId":"tDVV","caAddress":"xxx"}]' --strategy auto
# Transfer tokens (requires PORTKEY_PRIVATE_KEY env)
bun run portkey_tx_skill.ts transfer --ca-hash xxx --token-contract xxx --symbol ELF --to xxx --amount 100000000 --chain-id tDVV
Recovery proof validation:
recovernow validates each guardian proof locally before submitting.- Guardian
verificationDocmust come fromverify-codewith--operation recovery; register proofs are rejected.
SDK
import { getConfig, checkAccount, createWallet, getTokenBalance } from '@portkey/ca-agent-skills';
const config = getConfig({ network: 'mainnet' });
// Check account
const account = await checkAccount(config, { email: 'user@example.com' });
// Create wallet
const wallet = createWallet();
// Get balance
const balance = await getTokenBalance(config, {
caAddress: 'xxx',
chainId: 'tDVV',
symbol: 'ELF',
});
Network
| Network | Chain IDs | AA API URL | EOA API URL | |---------|-----------|------------|-------------| | mainnet (default) | AELF,
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Portkey-Wallet
- Source: Portkey-Wallet/ca-agent-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.