Documentation
Olex
An MCP server that gives AI assistants first-class access to the Aleo privacy blockchain. Read chain state, analyse where a program's private/public boundary actually falls, and decrypt your own records locally with a view key.
Overview
Olex speaks the Model Context Protocol over stdio. Your client launches it as a child process and talks JSON-RPC over stdin and stdout, so there is no port to open and no service to host.
Ask your assistant "what's the latest Aleo block height?" or "does credits.aleo leak the transfer amount?" and it calls the tools below directly instead of you switching to a terminal.
- Read-only by default. The chain tools hold no keys and sign nothing, so an agent cannot move funds with them.
- Privacy analysis needs no keys at all. It is static analysis of deployed Aleo instructions.
- View-key tools run over stdio only. They are never registered on the hosted surface, so the bridge has no code path that could accept a view key. See Surfaces. Two of the three are pure local computation and reach no network at all;
olex_true_balanceis the exception, since it must read the chain before it can decrypt anything.
Install
-
Build
git clone https://github.com/Ritapossible/Olex.git cd olex npm install npm run build -
Register with your client
Claude Code and Codex can write their own config. Everything else is a file you edit by hand.
claude mcp add olex -- node /abs/path/olex/dist/index.js # Claude Code codex mcp add olex -- node /abs/path/olex/dist/index.js # Codex CLIFor the rest, find your client below, then paste the matching block from config shapes. The key column is the part people get wrong - a correct-looking block under the wrong key fails silently, with the server simply absent from the tool list.
Client Config file Key Claude Code claude mcp add, or.mcp.jsonin the projectmcpServersClaude Desktop ~/Library/Application Support/Claude/claude_desktop_config.jsonon macOS,%APPDATA%\Claude\claude_desktop_config.jsonon WindowsmcpServersCursor ~/.cursor/mcp.jsonglobally,.cursor/mcp.jsonper projectmcpServersVS Code .vscode/mcp.json, or MCP: Open User ConfigurationserversWindsurf ~/.codeium/windsurf/mcp_config.jsonmcpServersCodex CLI ~/.codex/config.tomlmcp_servers(TOML)Gemini CLI ~/.gemini/settings.jsonmcpServersZed settings.json, via zed: open settingscontext_serversCline / Roo Code cline_mcp_settings.json/mcp_settings.jsonmcpServers -
Ask
"What's the latest Aleo block height?" "Audit the privacy of credits.aleo." "What did transaction at1fv877... reveal publicly?"
The path must be absolute. A client launches the server from its own
working directory, not yours. On Windows, either escape the separators
(C:\\path\\to\\olex\\dist\\index.js) or use forward
slashes - Node accepts both, but a single backslash in JSON is an
escape character and will not survive parsing.
Config shapes
Three shapes cover every client. They are not interchangeable: the block is identical, the key around it is not.
Most clients
Claude Code, Claude Desktop, Cursor, Windsurf, Gemini CLI, Cline and anything else that follows the reference format.
{
"mcpServers": {
"olex": {
"command": "node",
"args": ["/abs/path/olex/dist/index.js"],
"env": { "OLEX_NETWORK": "testnet" }
}
}
}
VS Code
The top-level key is servers, and each entry carries an
explicit type.
{
"servers": {
"olex": {
"type": "stdio",
"command": "node",
"args": ["/abs/path/olex/dist/index.js"],
"env": { "OLEX_NETWORK": "testnet" }
}
}
}
Zed
Zed calls them context servers and speaks stdio only, which suits Olex exactly.
{
"context_servers": {
"olex": {
"command": "node",
"args": ["/abs/path/olex/dist/index.js"],
"env": { "OLEX_NETWORK": "testnet" }
}
}
}
Codex CLI
TOML rather than JSON, and the key is snake_case.
[mcp_servers.olex]
command = "node"
args = ["/abs/path/olex/dist/index.js"]
env = { OLEX_NETWORK = "testnet" }
To enable the view-key tools, add OLEX_VIEW_KEY to the
same env block. Every client above launches Olex over
stdio on your own machine, so the key never leaves it. Bear in mind
the config file is plain text on disk - if that is not where you
want a view key to live, set the variable in the shell you launch
the client from instead.
Whichever client you use, restart it after editing the file. Most read their MCP config only at startup, and Windsurf needs a full quit rather than just a closed window.
Configuration
Every setting is an environment variable, and every one has a working default.
| Variable | Default | Purpose |
|---|---|---|
OLEX_NETWORK |
testnet |
Set to mainnet to change the default network. Every tool also takes a per-call network argument. |
OLEX_TIMEOUT_MS |
15000 testnet45000 mainnet |
Per-request timeout against the Aleo REST API. Mainnet gets the longer budget because a cold mainnet request can take upwards of 20 seconds. Setting this overrides both defaults. |
OLEX_VIEW_KEY |
unset | An AViewKey1... for the view-key tools. Takes precedence over any view_key argument. |
Testnet is the default everywhere. Pointing an autonomous agent at mainnet should be a deliberate act, not something it drifts into.
Privacy model
Aleo splits state in two, and the split is the thing worth understanding before reading the tool list:
- Public state lives in mappings. Anyone can read it. This is what a block explorer shows.
- Private state lives in encrypted records. Only the account's view key can read them.
olex_get_balance reads the credits.aleo account
mapping, which is public. An address showing 0 credits may
hold a private balance that nobody can see without its view key. Every
balance tool says so in its own output.
No Aleo program is "private" as a whole. A single function can take a
private input and then write it to a mapping, which makes that value
public. Finding those cases is what olex_analyze_privacy is for.
Tool reference
Ten tools need no key material and run on every surface, hosted included.
Arguments in italics are optional. Every tool also accepts
network.
Chain
| Tool | Arguments | Returns |
|---|---|---|
olex_network_status |
none | Latest height, block hash, round, timestamp and proof target. |
olex_get_balance |
address |
Public credits balance from the credits.aleo account mapping. |
olex_get_program |
program_id |
Deployed Aleo instruction source, plus the program's mapping list. |
olex_get_mapping_value |
program_id, mapping_name, key |
One key from any program's on-chain mapping. |
olex_get_block |
height |
A block by height, or the chain tip when height is omitted. |
olex_get_transaction |
transaction_id |
A transaction with its transitions and how many inputs were private. |
Privacy analysis
| Tool | Arguments | Returns |
|---|---|---|
olex_analyze_privacy |
program_id, function_name |
Where the private/public boundary really falls: per-function input and output visibility, mapping writes, and a warning for every private input that reaches public mapping state. |
olex_explain_transaction_privacy |
transaction_id |
Value by value, what a real transaction exposed on-chain and what stayed encrypted, including how many records it produced. |
olex_check_visibility |
type |
What an annotation such as u64.private or credits.aleo/transfer_public.future actually means for an observer. |
Utility
| Tool | Arguments | Returns |
|---|---|---|
olex_convert_credits |
amount, from |
Exact conversion between credits and microcredits using bigint maths, never floats. 1 credit = 1,000,000 microcredits. |
View-key tools
Three tools read your private records. They exist only in the local stdio server, and they are the one thing no block explorer can do for you.
Set OLEX_VIEW_KEY rather than passing view_key
as an argument. An argument is recorded in the conversation transcript;
an environment variable is not. When both are present the environment
variable wins.
A view key grants permanent read access to every record an account has
ever received. Olex never asks for a private key
(APrivateKey1...) and never echoes a view key back, whole
or partial, on success or on failure.
| Tool | Arguments | Returns |
|---|---|---|
olex_view_key_address |
view_key |
Confirms a view key parses and shows which account it unlocks. Start here. |
olex_decrypt_record |
ciphertext, view_key |
Decrypts a record1... ciphertext you own, or tells you plainly that the record belongs to someone else. |
olex_true_balance |
transaction_id, from_block, to_block, view_key |
Public credits plus the private records you own in the scanned scope, and the split between them. |
olex_true_balance needs a scope: either a
transaction_id or a from_block/to_block
range of at most 50 blocks. It refuses an unbounded scan rather than
quietly walking the chain, and the private figure it reports covers only
the range actually scanned.
Prompts
Prompts appear in an MCP client as slash commands. A tool list asks you to know which tool to reach for; a prompt states an intent and lets the model plan the calls.
| Prompt | Arguments | What it does |
|---|---|---|
audit-program-privacy |
program_id, network |
Audits a deployed program and reports what genuinely stays private, what is public despite looking private, and which functions to avoid if an amount must stay hidden. |
explain-transaction-privacy |
transaction_id, network |
Walks a real transaction and explains what an observer learns from it, in plain language. |
true-balance |
transaction_id, from_block, to_block |
Computes a real total balance including private records. Stdio only, since it needs a view key. |
Surfaces
Olex runs on two surfaces, and they do not expose the same tools. The difference is structural rather than a filter.
| Surface | Tools | View keys |
|---|---|---|
| Local stdio | 13 | Available. Keys stay on your machine. |
| Hosted bridge | 10 | Not registered at all. |
The hosted bridge imports the shared server factory, which never imports
the view-key module. So those tools cannot be constructed there even by
mistake, tools/list over HTTP cannot advertise one, and the
WASM cryptography they need never enters the serverless bundle. A separate
allow-list in the bridge is a second, independent barrier rather than the
only one.
The playground runs against
that hosted bridge. It opens a genuine MCP session server-side and
dispatches a real tools/call, so the code it exercises is the
same code your editor gets over stdio - not a browser reimplementation.
Verify
npm run smoke # drives the real server over stdio against live testnet
npm run inspect # opens the official MCP Inspector web UI
npm run smoke spawns the built binary the way a client would
and hits the live network. It is deliberately not a unit test with mocks:
the point is to prove the whole path works, not that the pieces work in
isolation.
npm run inspect prints a localhost URL with an
auth token, which is the closest thing to a live URL an MCP server has.
MCP servers speak JSON-RPC over stdin and stdout; they are launched by the
client, not hosted on a port.