Explore Internet Computer canisters from your terminal at velocity.
Blast is a small Node.js CLI that discovers a canister’s Candid interface on the fly, lets you inspect methods, call them with JSON, and validate I/O against generated JSON Schemas. It’s distributed as an npm package with a global blast command.
- Discover Candid via canister metadata; compile to an
idlFactorylocally - List methods and their kinds: query, update, or oneway
- Call methods with JSON arguments; normalized JSON output
- Generate JSON Schema for a method’s input/output
- Validate inputs and outputs using Ajv 2020
- Deterministic Ed25519 identity derived from a local secret + numeric id
Audit: https://chatgpt.com/share/68ebd325-f31c-8003-9556-9d7aeab49d6b
- Global (from npm registry):
npm i -g icblast(once published) - Global (from a local checkout):
npm i -g .
This installs a blast executable on your PATH. You can also run it via npx icblast once published.
Add to Codex config
[mcp_servers.blast]
command = "blast"
args = ["mcp"]
blast scan <canister_id> [--host <url>] [--id <0-65535>]
blast call <canister_id> <method> [args_json] [--host <url>] [--id <0-65535>]
blast schema <canister_id> <method> [--host <url>] [--id <0-65535>]
blast validate <canister_id> <method> [args_json] [--host <url>] [--id <0-65535>]
blast principal [--id <0-65535>]
blast mcp # start MCP server on stdio
Examples
- List methods:
./blast scan togwv-zqaaa-aaaal-qr7aa-cai - Call with args:
./blast call r7inp-6aaaa-aaaaa-aaabq-cai config_get - Call with JSON:
./blast call r7... some_method '[{"foo":1}, 2, "bar"]' - Inspect schema:
./blast schema togwv-zqaaa-aaaal-qr7aa-cai icrc55_get_pylon_meta - Validate I/O:
./blast validate togwv-zqaaa-aaaal-qr7aa-cai icrc55_get_pylon_meta '[1,2,3]'
Notes
- JSON arguments must be a JSON array; wrap single args too, e.g.
'[123]'. - Output is normalized for readability: bigints as strings, byte arrays as hex, etc.
- Principals: anywhere a Principal is expected, you can pass a number 0–65535.
0resolves to the current run’s principal (derived from--id),n>0resolves to principal for idn.
- ICRC‑1 accounts (input and output) are strings:
- Pass full ICRC‑1 text (e.g.,
"aaaaa-...-cai-<sub>") or the shorthand"id[-sub]", wheresubis a decimal encoded as a 32‑byte big‑endian subaccount. - Responses also show account records as ICRC‑1 text.
- Pass full ICRC‑1 text (e.g.,
- Identity: derived deterministically from a local secret + an
--idnumber.- On first run, Blast creates a random hex secret in (Linux)
~/.config/blast/secretor (macOS)~/Library/Application Support/blast/secret. - You pass
--id <n>wherenis 0–65535. Blast takes a deterministic slice of the secret based onn, concatenatesn, hashes with SHA‑256, and derives an Ed25519 identity from that hash. Omitted--iddefaults to0.
- On first run, Blast creates a random hex secret in (Linux)
- Host: defaults to
https://icp0.io; override with--host.- Local replica: set
--host http://localhost:8080.
- Local replica: set
Environment override
- Set
SECRET=<string>(min 32 chars) to override the local secret file for identity derivation. Useful for ephemeral or CI contexts. IfSECRETis present and shorter than 32 characters, Blast will error.
- Discovers Candid via canister metadata (
CanisterStatus) only. - Uses an embedded WASM (
didc_wasm_pkg/didc_rust_bg.bin) and JS glue to compile Candid to JS locally, extract anidlFactory, and wrap an actor with light input/output converters. - JSON Schema is synthesized from the Candid types and validated via Ajv 2020.
scanrefreshes and writes a full schema cache per canister.schema/validateread from cache and only fall back to live generation if missing.- Locations:
- Linux:
~/.cache/blast/schemas/<canister>.json - macOS:
~/Library/Caches/blast/schemas/<canister>.json
- Linux:
- Start server:
blast mcp(stdio transport). Tools exposed:principal({ id? })→ text principalscan({ canister, host?, id? })→ text list, refreshes schema cacheschema({ canister, method, host?, id? })→ structuredContent: JSON schemacall({ canister, method, args?, host?, id? })→ structuredContent:{ result: ... }validate({ canister, method, args?, host?, id? })→ structuredContent:{ ok, inputValid, outputValid, errors? }
Tip for local replicas
-
When connecting to a local canister via MCP tools, include
host: 'http://localhost:8080'in the tool arguments. The agent automatically fetches the local root key. -
Example (Node MCP client using SDK):
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
const transport = new StdioClientTransport({ command: 'blast', args: ['mcp'] });
const client = new Client({ name: 'demo', version: '0.0.0' });
await client.connect(transport);
// Example: mainnet
const res = await client.callTool({ name: 'schema', arguments: { canister: 'f54if-eqaaa-aaaaq-aacea-cai', method: 'icrc1_balance_of' } });
console.log(res.structuredContent);
// Example: local replica (DFX)
const resLocal = await client.callTool({
name: 'schema',
arguments: {
canister: 'uxrrr-q7777-77774-qaaaq-cai',
method: 'greet',
host: 'http://localhost:8080',
},
});
console.log(resLocal.structuredContent);
- ESM (Node 18+):
import icblast from 'icblast';
// Identity
const p = await icblast.principal(0);
// Discover + cache
const methods = await icblast.scan('f54if-eqaaa-aaaaq-aacea-cai', { id: 0 });
// Schemas (uses cache; falls back to live)
const sch = await icblast.schema('f54if-eqaaa-aaaaq-aacea-cai', 'icrc1_balance_of', { id: 0 });
// Calls (principal shorthand + ICRC-1 accounts supported)
const bal1 = await icblast.call('f54if-eqaaa-aaaaq-aacea-cai', 'icrc1_balance_of', ['0'], { id: 0 });
const acct = 'togwv-zqaaa-aaaal-qr7aa-cai-oq7ilwi.2e10e7b42023f667a1db51ff9c7c88f08fb9022d6453bf0c5b0696666e41f048';
const bal2 = await icblast.call('f54if-eqaaa-aaaaq-aacea-cai', 'icrc1_balance_of', [acct], { id: 0 });
// Validate I/O
const v = await icblast.validate('f54if-eqaaa-aaaaq-aacea-cai', 'icrc1_balance_of', ['0'], { id: 0 });
- Query balance with shorthand account:
blast call f54if-eqaaa-aaaaq-aacea-cai icrc1_balance_of '["0"]' --id 0
- Query balance with full ICRC‑1 text account:
blast call f54if-eqaaa-aaaaq-aacea-cai icrc1_balance_of '["togwv-zqaaa-aaaal-qr7aa-cai-oq7ilwi.2e10e7b42023f667a1db51ff9c7c88f08fb9022d6453bf0c5b0696666e41f048"]' --id 0
- CI packs the npm tarball on tag pushes matching
v*and attaches it to the GitHub Release.- Tag:
git tag v0.1.0 && git push origin v0.1.0
- Tag:
- Run the CLI locally:
node bin/blast.js ... - Debug conversions:
--debugflag orBLAST_DEBUG=1.
- Minimal actor wrapping; complex types are mapped best-effort.
- Some canisters may not expose Candid metadata; in such cases discovery can fail.