Skip to main content

Agents

An LLM agent that reads or writes Aleo state needs its capabilities described as tools: a name, a description the model reads to decide when to call it, a JSON Schema for its arguments, and a handler that actually runs when the model calls it. @provablehq/veil-core ships that description for its own read and write actions under a /agent subpath, and an MCP server binding under /mcp. @provablehq/shield-swap-sdk ships the same two subpaths for DEX actions, in a shape designed to sit alongside the core tools rather than replace them.

The tool shape​

An AgentTool pairs a schema with the handler that executes it:

type AgentToolSchema = {
name: string
description: string
inputSchema: { type: 'object'; properties: Record<string, unknown>; required?: string[] }
}

type AgentToolHandler = (params: Record<string, unknown>) => Promise<unknown>

type AgentTool = { schema: AgentToolSchema; handler: AgentToolHandler }

This maps directly onto MCP's tool declaration and onto the tool/function shapes LangChain, the Vercel AI SDK, and the Claude and OpenAI APIs each use, so one set of schemas and handlers serves any of them — only the adapter that registers the tools and routes calls to handler changes.

Core tools​

createAgentTools builds the full set of AgentTools for the base Aleo actions, gated by which clients are passed in: a PublicClient enables the read-only tools, a WalletClient enables the tools that sign and spend.

import { createPublicClient, http } from '@provablehq/veil-core'
import { createAgentTools } from '@provablehq/veil-core/agent'

const client = createPublicClient({
transport: http('https://edge.provable.com/api/v2', { network: 'mainnet' }),
})

const tools = createAgentTools({ client })
ToolNeedsDescription
aleo_get_block_numberclientCurrent chain height
aleo_get_balanceclientPublic credits balance for an address
aleo_read_mappingclientRead a value from a program's public mapping
aleo_get_programclientFetch a deployed program's source
aleo_get_blockclientFetch a block by height or hash
aleo_get_transactionclientFetch a transaction by id
aleo_describe_programclientParse a program's functions, mappings, and closures
aleo_executewalletClientExecute a program function
aleo_transferwalletClientTransfer credits to an address
aleo_deploywalletClientDeploy a program

aleoAgentToolSchemas(config?) returns the schemas alone, filtered the same way, for a caller that wants to register tool descriptions with a model without wiring up execution yet. Every write tool signs, proves, and broadcasts when called — an agent with a walletClient configured pays fees on every aleo_execute, aleo_transfer, or aleo_deploy call the model makes.

Serving tools over MCP​

createMcpServer adapts createAgentTools's output into an MCP server — a tool list plus a dispatcher. It is not a running process; the caller still wires the returned tools and handleToolCall into an MCP SDK server over whichever transport it uses (stdio, HTTP):

import { createMcpServer } from '@provablehq/veil-core/mcp'

const server = createMcpServer({ client })

const result = await server.handleToolCall('aleo_get_block_number', {})
// { height: '3082441' }

toMcpServer(tools) is the package-agnostic version underneath — it takes any AgentTool[], not core's specifically, which is how a caller combines tool sets from more than one package.

Shield Swap tools​

@provablehq/shield-swap-sdk exposes the same two subpaths for its DEX actions. createShieldSwapAgentTools returns AgentTool[] in the identical shape core's createAgentTools returns, gated by which backing is configured: a client extended with shieldSwapActions enables on-chain reads and private-balance lookups, an api client enables the off-chain DEX API reads (pool listing, routing, token registry), and both together enable the tools that combine them. Money-moving writes — swap, mint, add or remove liquidity — are opt-in via includeWrites, since a model calling them can move funds. The write tools target the local-signer path: they auto-select records and auto-fetch the dynamic-dispatch program sources, so the agent supplies only amounts and token programs. walletClient below is the same wallet client used throughout the rest of the docs:

import { shieldSwapActions } from '@provablehq/shield-swap-sdk'
import { createShieldSwapAgentTools } from '@provablehq/shield-swap-sdk/agent'

const swapClient = walletClient.extend(
shieldSwapActions({ api: {} }),
)

const tools = createShieldSwapAgentTools({
client: swapClient,
api: swapClient.api,
includeWrites: true,
})

createShieldSwapMcpServer({ client, api }) from @provablehq/shield-swap-sdk/mcp is the equivalent MCP binding, serving only the shield_swap_* tool set.

Most DEX API endpoints are bearer-gated. When both client and api are configured, the tool set includes the auth flow: shield_swap_authenticate signs the API's challenge with the client account and unlocks the gated API tools for the session, and shield_swap_create_api_token / shield_swap_list_api_tokens / shield_swap_revoke_api_token manage long-lived ss_… tokens an agent can persist and pass back as api: { apiToken } on later runs. An agent that hits an auth error on an API tool calls shield_swap_authenticate and retries.

Access is the second gate: a first-time account also needs a referral code (the invite codes Shield Swap distributes), or gated endpoints return 403 redeem an invite code to unlock access. shield_swap_get_access_status reports the gate and shield_swap_redeem_access_code redeems a code the operator supplies — one-time per account, unlocked immediately.

Combining tool sets​

Because createAgentTools and createShieldSwapAgentTools both return AgentTool[], serving Aleo and DEX tools from one MCP server is a matter of concatenating the two arrays before calling core's toMcpServer. Reusing client from Core tools above and swapClient from Shield Swap tools:

import { createAgentTools } from '@provablehq/veil-core/agent'
import { toMcpServer } from '@provablehq/veil-core/mcp'

const coreTools = createAgentTools({ client, walletClient })
const swapTools = createShieldSwapAgentTools({ client: swapClient, api: swapClient.api })

const server = toMcpServer([...coreTools, ...swapTools])

const pools = await server.handleToolCall('shield_swap_list_pools', { limit: 5 })
const height = await server.handleToolCall('aleo_get_block_number', {})

The same AgentTool[] array registers directly with LangChain, the Vercel AI SDK, or a hand-rolled Claude or OpenAI tool-use loop — toMcpServer is only needed for the MCP transport specifically.