# IC Phantom agent guide

Use this guide with the official Internet Computer MCP connector. Read [`/llms.txt`](/llms.txt) first; it contains the mandatory identity, approval, and retry rules. The exact interface is [`/canister-api.did`](/canister-api.did).

## 1. Enable the official connector

Use the production MCP endpoint `https://mcp.internetcomputer.org/mcp`. The page at [mcp.beta.id.ai](https://mcp.beta.id.ai/) explains setup; `https://mcp.beta.id.ai/mcp-beta` is only for testing with beta Internet Identity.

The user must:

1. Enable **AI access** in [Internet Identity settings](https://id.ai/manage/settings).
2. Add the official production endpoint as a trusted connector.
3. Add that endpoint to the MCP-capable AI app and authenticate it with Internet Identity.
4. Grant **Actions and questions** for wallet discovery, live balances, minting, or transfers. IC Phantom uses authenticated update calls for those operations. Questions-only mode can still use query-only identity, validation, and pending-intent methods.

This flow provides a time-limited delegation for the user's app-specific II principal. It never exposes the user's private identity key.

## 2. Prove the app identity boundary

1. Resolve `https://hbxmr-wyaaa-aaaap-an3ia-cai.icp.net/` with `resolve_app`.
2. Reuse the exact canonical `derivation_origin` returned by resolution.
3. Call `list_app_accounts`. If more than one account exists, ask the user to select one and use that selection consistently.
4. Call `get_app_principal` for the selected account.
5. Resolve backend canister `f4kcz-fqaaa-aaaap-an3hq-cai`, and load its Candid/API docs if needed with `get_canister_candid` and `get_canister_api_doc`.
6. Call query `whoami()` on the backend.
7. Call update `get_account_manifest_ii()` once.
8. Require: connector app principal = `whoami` = `manifest.identity_principal`.

Stop on any mismatch. A principal is scoped to the app derivation origin and selected II account; the same human signing two different origins does not imply the same wallet.

## 3. Use the canonical account manifest

`get_account_manifest_ii()` is the only account-discovery call agents need. It returns:

- `identity_principal`, `authentication_method`, and `wallet_source`
- the optional `linked_phantom_pubkey`
- one fingerprint for the full account set
- canonical ICP, SOL, DOGE, BTC, and ckBTC addresses with per-address fingerprints
- ckBTC owner and 32-byte subaccount values

Cache the manifest for the session. Do not independently derive addresses or repeat discovery before every operation.

The recommended state is `wallet_source = internet_identity`: the II browser UI and ICP MCP already control the same II-derived accounts. No Phantom connection or link is required.

If `wallet_source = linked_phantom`, report that the optional advanced link is active before showing balances or preparing a transfer. It changes ICP/SOL/DOGE derivation; BTC and ckBTC remain owned by the II principal. Linking does not move or reconcile funds.

## 4. Distinguish BTC from ckBTC

These are two addresses and two network actions:

| Goal | Use | Then |
| --- | --- | --- |
| Deposit native BTC | `manifest.btc.address` on Bitcoin mainnet | After the transaction appears, call `mint_ckbtc_from_btc_ii()` once with explicit approval; report pending sats/confirmations or refresh ckBTC when minted |
| Deposit existing ckBTC | `manifest.ckbtc.address` on the ckBTC ICRC-1 ledger | Refresh `get_ckbtc_balance_ii()` |
| Send ckBTC on IC | Principal or canonical ICRC account | Verify, obtain explicit approval, then call the official ledger as the II principal |
| Withdraw to native BTC | Verified Bitcoin mainnet address | Verify, approve the official minter, then call it as the II principal; minimum 50,000 sats |

There is no standalone native BTC balance API. `mint_ckbtc_from_btc_ii()` is also the on-demand deposit-status check: a response beginning `Pending BTC detected` includes pending sats and confirmation progress; a response beginning `Minted` means the ready deposit was converted and should be followed by `get_ckbtc_balance_ii()`. Never poll the method or automatically retry it.

For II, `ckbtc_owner` is the app principal and the all-zero `ckbtc_subaccount_hex` denotes the default/null subaccount. Phantom mode still requires its exact backend owner and non-default subaccount. Never send ckBTC to the BTC address or native BTC to the ICRC account.

The official ckBTC ledger is `mxzaz-hqaaa-aaaar-qaada-cai`; the minter is `mqygn-kiaaa-aaaar-qaadq-cai`. The ledger transfer fee is currently 10 sats. BTC withdrawal requires at least 50,000 sats and incurs approval plus Bitcoin network fees.

## 5. Verify every recipient

Call query `verify_recipient(asset, address)` before preparing a send. Supported assets are `ICP`, `SOL`, `DOGE`, `CKBTC`, and `BTC`.

Proceed only when `valid = true`, and use the returned `normalized_address`. Show the exact network, address type, full normalized address, and fingerprint. Validation checks syntax/network/checksum where available; `ownership = not-proven` is intentional. For new or high-risk destinations, ask the user to compare the full address or fingerprint through a separate trusted channel.

## 6. Prepare, review, and confirm backend-managed rails

ICP, SOL, and DOGE value movement uses one generic backend protocol:

1. Convert the human amount to an exact `nat64` integer.
2. Call `prepare_transfer_ii(asset, normalized_destination, amount)`.
3. Show every returned field without shortening the destination or omitting fees, expiry, safety notice, or confirmation code.
4. Ask the user to approve that exact intent and repeat the confirmation code in a later response.
5. Call `confirm_transfer_ii(intent_id, confirmation_code)` exactly once before expiry.
6. If declined, call `cancel_transfer_ii()`.

Do not call the retired backend direct methods `transfer_ii`, `transfer_sol_ii`, `transfer_doge_ii`, `transfer_ckbtc_ii`, or `withdraw_ckbtc_to_btc_ii`. They remain in Candid only for upgrade compatibility and return a retirement message.

For ckBTC sends and BTC withdrawals, use `verify_recipient` plus explicit review, then submit to the official ckBTC ledger/minter with the selected II identity. The default source subaccount is null. A withdrawal requires a ledger `icrc2_approve` followed by minter `retrieve_btc_with_approval`; obtain approval for each update and treat uncertain outcomes as unknown.

`prepare_transfer_ii` moves no funds. The intent is caller-bound, one-at-a-time, valid for 10 minutes, and consumed before the confirmation handler performs its first downstream await.

## 7. Handle unknown outcomes safely

A timeout is an unknown outcome, not a failure. Do not prepare or confirm another send immediately. Inspect `get_pending_transfer_ii()`, `get_nonce_ii()`, the relevant balance, and any ledger block or chain transaction evidence. Tell the user which facts are known and which remain uncertain. Retry only after proving the original operation did not execute.

Several endpoints return status text. Treat text beginning with `Transfer failed`, `Send failed`, `Withdraw failed`, or `Mint failed`, and text describing a retired method or error, as failure.

## 8. Units and rail behavior

- ICP: e8s, 8 decimals. Destination is a 64-hex ICP account identifier.
- SOL: lamports, 9 decimals. Destination is a Solana mainnet base58 public key.
- DOGE: koinu/base units, 8 decimals. Only confirmed DOGE is spendable; quote current miner fees first.
- CKBTC: satoshis, 8 decimals. Destination is a principal or canonical ICRC account.
- BTC: satoshis, 8 decimals. Destination is a Bitcoin mainnet address; this explicitly converts ckBTC to BTC through the minter.

This app is not a general cross-chain swap engine. ICP, SOL, DOGE, and ckBTC remain on their own rails. Only the official BTC ↔ ckBTC minter flow converts between native BTC and ckBTC.

## 9. Keep cycle use conservative

Use one manifest call per authenticated session, refresh balances only on request, and poll no faster than 10 seconds. Prefer the local `verify_recipient` query before a fee-bearing call. SOL/DOGE reads, key derivation, BTC address discovery, and minter operations can consume cycles. Never mint speculatively and never automatically retry value-moving calls.

## 10. Optional Phantom linking (advanced)

Ignore Phantom methods during normal ICP MCP operation. A human can open the UI's collapsed advanced section when they intentionally want II/MCP ICP, SOL, and DOGE derivation to follow a Phantom public key. BTC/ckBTC stay on the II principal. Linking requires a canister- and II-principal-bound Phantom signature; unlinking requires the authenticated II caller. Neither action moves funds, so the human must record both manifests and reconcile affected balances first.
