Olex

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.

Version 0.1.0 13 tools 3 prompts Networks testnet + mainnet

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_balance is the exception, since it must read the chain before it can decrypt anything.

Install

  1. Build
    git clone https://github.com/Ritapossible/Olex.git
    cd olex
    npm install
    npm run build
  2. 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 CLI

    For 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.json in the project mcpServers
    Claude Desktop ~/Library/Application Support/Claude/claude_desktop_config.json on macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows mcpServers
    Cursor ~/.cursor/mcp.json globally, .cursor/mcp.json per project mcpServers
    VS Code .vscode/mcp.json, or MCP: Open User Configuration servers
    Windsurf ~/.codeium/windsurf/mcp_config.json mcpServers
    Codex CLI ~/.codex/config.toml mcp_servers (TOML)
    Gemini CLI ~/.gemini/settings.json mcpServers
    Zed settings.json, via zed: open settings context_servers
    Cline / Roo Code cline_mcp_settings.json / mcp_settings.json mcpServers
  3. 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" }
Adding a view key

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 testnet
45000 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.
A public balance is a floor, not a total

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.

Privacy is decided per parameter

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

ToolArgumentsReturns
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

ToolArgumentsReturns
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

ToolArgumentsReturns
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.

Prefer the environment variable

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.

ToolArgumentsReturns
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.

PromptArgumentsWhat 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.

SurfaceToolsView 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.