Skip to content
Skip to content

MCP Integration

Balchemy exposes its full capability layer through the Model Context Protocol (MCP). Both human-operated clients (Claude Desktop, OpenAI, etc.) and external AI agents can call the same execution core, subject to scope and policy rules.

MCP is the protocol surface only — it does not create a separate business-logic layer. Every tool call flows through the same policy, audit, and trading engine that the rest of the platform uses.


Quick start — Claude Desktop in 30 seconds

Add this to your claude_desktop_config.json:

{
  "mcpServers": {
    "balchemy": {
      "transport": "http",
      "url": "https://api.balchemy.ai/mcp/<your-publicId>",
      "headers": {
        "Authorization": "Bearer <your-mcp-api-key>"
      }
    }
  }
}

Replace <your-publicId> and <your-mcp-api-key> with values from your bot's MCP settings in Studio. Restart Claude Desktop and the ask_bot and trade_command tools will appear in the tool list.


Endpoints

ALL  https://api.balchemy.ai/mcp/:publicId
GET  https://api.balchemy.ai/mcp/:publicId/events/sse

The main endpoint accepts any HTTP method — POST is standard for JSON-RPC calls. The SSE endpoint provides a streaming event channel for real-time responses.

The mcp prefix is intentionally outside the /api namespace. This keeps the MCP surface clean and separately addressable.


Two MCP modes

Balchemy supports two distinct principal models over the same endpoint infrastructure.

Mode 1 — Studio bot MCP (human operator)

Use this when a real person connects Balchemy tools from Claude Desktop, the OpenAI Plugins interface, or another MCP-compatible client.

The operator:

  • owns or manages a Studio bot
  • creates an MCP API key in the bot cockpit (Studio > Bot > MCP)
  • connects that key from their client application
  • all requests execute in that bot's principal context

Authentication is via a long-lived MCP API key scoped to the bot. The key is revealed once at creation time and stored as a hash — if you lose it, rotate it.

Mode 2 — External agent MCP (Hub/ERC-8004)

Use this when an external AI agent discovers Balchemy through ERC-8004 identity onboarding.

The external agent:

  • onboards through /api/public/erc8004/onboarding/siwe or /identity
  • receives a publicId and identity access token
  • calls tools via POST /mcp/<publicId> using the identity token as the bearer token
  • executes in its own isolated principal context with its own custodial wallet

See ERC-8004 Agent Identity for the full onboarding flow.


Authentication

Studio bot — MCP API key

POST /mcp/<publicId>
Authorization: Bearer <mcp-api-key>
Content-Type: application/json

Keys are managed through the bot MCP interface:

MethodPathDescription
GET/api/nest/bots/:botId/mcpGet MCP config and key list
POST/api/nest/bots/:botId/mcp/keysCreate a new MCP API key
DELETE/api/nest/bots/:botId/mcp/keys/:keyIdRevoke a key
POST/api/nest/bots/:botId/mcp/step-upIssue a step-up token
GET/api/nest/bots/:botId/mcp/logsFetch audit logs

External agent — identity access token

POST /mcp/<publicId>
Authorization: Bearer <identity-access-token>
Content-Type: application/json

Identity access tokens are issued by AgentIdentityIssuerService using ES256 (ECDSA P-256). TTLs are scope-capped: read tokens last up to 3600 s, trade tokens up to 300 s, manage tokens up to 60 s.

You can also pass the token via the X-Balchemy-Mcp-Key or X-Mcp-Token headers as alternatives to Authorization.


Scope model

All MCP keys and identity tokens carry a scope that limits which tools they can call.

ScopeAccessSafety profile
readMarket data, portfolio, research, logs, status, read-only configread_only
tradeAll read access plus trading commands, approvals, mutable workflowstrade_guarded
manageControl-plane actions: key rotation, scope updates, withdraw ownershipmanage_step_up

Scope hierarchy for external agents

External agents that onboard automatically receive read + trade by default. The manage scope is not granted at onboarding time. A developer must claim the agent's control plane (via Hub), then issue a step-up token before manage actions are permitted.


Step-up for manage actions

Manage-scoped operations require an additional step-up header:

X-Balchemy-Step-Up: <step-up-token>

Studio bot:

POST /api/nest/bots/:botId/mcp/step-up
Authorization: Bearer <session-token>

External agent:

POST /api/nest/agents/:agentId/control/mcp/step-up
Authorization: Bearer <identity-access-token>
X-Balchemy-Step-Up: <existing-step-up-or-manage-token>

If the X-Balchemy-Step-Up header is missing or expired, manage requests return 403 Forbidden.


Tool model

The platform has 106 registered tools in a single ToolRegistry singleton. Both MCP and LLM function calling consume tools from the same registry — there is no separate MCP tool universe.

Default tool set (7 tools)

When MCP_EXPOSE_GRANULAR_TOOLS is false (the default), only high-level agent-facing tools are visible over MCP:

ToolScopeDescription
ask_bottradeSend a natural-language message to the bot and receive a reply
trade_commandtradeExecute a natural-language trading command through the trading engine
agent_executetradeHigh-level execution for external agents — runs intent through the core pipeline
agent_researchreadResearch a token or market query; returns a structured research envelope with delta tracking
agent_portfolioreadPortfolio and position snapshot with delta-from-last-call tracking
agent_statusreadAuth, scope, and runtime health status for the calling agent
agent_configtradeGet or update trading defaults and risk policy (get / update_trade_defaults / update_risk_policy)

This default keeps the tool list concise and low-noise for agents that only need high-level orchestration.

Full tool set (106 tools, MCP_EXPOSE_GRANULAR_TOOLS=true)

Set the environment variable on the backend to expose all registered tools over MCP:

MCP_EXPOSE_GRANULAR_TOOLS=true

Tool categories and approximate counts:

CategoryApprox. countExample tools
ai7ask_bot, agent_execute, agent_research, agent_portfolio, agent_status, agent_config, trade_command
trading-core8+trading_positions, trading_orders, trading_swap_solana, trading_swap_evm, trading_dca
trading-strategies6+Strategy CRUD, strategy execution
trading-config5+Trading defaults, risk policy, approval config
wallet14trading_wallet_list, trading_wallet_default, trading_wallet_connect, trading_wallet_verification_message, approvals, default order profiles
evm6+EVM-specific positions, balances, approvals
evm-dex6DEX pool data, liquidity, pool search
evm-pretrade4+Pre-trade approval checks, allowance queries
market14Token info, price, OHLCV, trending, top movers, market cap
security3Contract security scan, rugpull check, holder analysis
solana8+Solana-specific token data, Jupiter routing, Solana balances
indexer5On-chain indexer queries for transactions, holders
social1X/Twitter sentiment and post search
launchpad9Pump.fun / launchpad token creation, bonding curve data
verification3+Identity verification helpers
simulation2Trade simulation, slippage estimation

Scope still applies regardless of MCP_EXPOSE_GRANULAR_TOOLS. A read-scoped key cannot call trade-guarded tools even if all tools are listed.


Request/response examples

Standard tool call (JSON-RPC 2.0)

POST /mcp/<publicId>
Authorization: Bearer <mcp-api-key>
Content-Type: application/json
 
{
  "jsonrpc": "2.0",
  "id": "req-001",
  "method": "tools/call",
  "params": {
    "name": "ask_bot",
    "arguments": {
      "message": "What is my current SOL balance and any open positions?",
      "chat_id": "session-abc123"
    }
  }
}

Response:

{
  "jsonrpc": "2.0",
  "id": "req-001",
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"reply\":\"Your SOL balance is 4.82 SOL...\",\"structured\":{\"compacted_count\":0},\"trace_id\":\"...\",\"session_cursor\":\"2026-03-19T10:00:00.000Z\",\"capabilities_hash\":\"...\",\"metadata\":{\"tool\":\"ask_bot\",\"raw_mode\":false,\"ts\":\"...\"}}"
      }
    ]
  }
}

The text field always contains a JSON string with the reply (human-readable), structured (machine-readable), and metadata (trace/session) keys. Parse it with JSON.parse.

External agent — research call

POST /mcp/<publicId>
Authorization: Bearer <identity-access-token>
Content-Type: application/json
 
{
  "jsonrpc": "2.0",
  "id": "req-002",
  "method": "tools/call",
  "params": {
    "name": "agent_research",
    "arguments": {
      "query": "BONK token recent activity",
      "chain": "solana",
      "includeOnchain": true,
      "includeHolders": false
    }
  }
}

List available tools

POST /mcp/<publicId>
Authorization: Bearer <mcp-api-key>
Content-Type: application/json
 
{
  "jsonrpc": "2.0",
  "id": "req-003",
  "method": "tools/list"
}

Response includes the tool names, descriptions, and JSON Schema input schemas for all scope-permitted tools.

SSE streaming

GET /mcp/<publicId>/events/sse
Authorization: Bearer <mcp-api-key>
Accept: text/event-stream

The SSE channel delivers real-time events as the tool execution progresses. Each event follows the standard data: <json> format.


Tool parameters reference

ask_bot

ParameterTypeRequiredDescription
messagestringYesNatural-language message to send to the bot
chat_idstringNoConversation session ID for context continuity; defaults to mcp-<botId>
metadataobjectNoArbitrary key-value metadata passed to the message context

trade_command

ParameterTypeRequiredDescription
messagestringYesNatural-language trading command
chat_idstringNoConversation session ID
last_mentioned_castringNoContract address most recently mentioned in conversation context
recent_messagesstring[]NoRecent conversation messages for context window

agent_research

ParameterTypeRequiredDescription
querystringYesResearch query (token symbol, address, or topic)
chainstringNoTarget chain: solana, base, or ethereum
includeXbooleanNoInclude X/Twitter posts
includeOnchainbooleanNoInclude on-chain activity data
includeDevWalletsbooleanNoInclude developer wallet analysis
includeHoldersbooleanNoInclude holder distribution data
maxPostsnumberNoMaximum number of social posts to include

agent_config

ParameterTypeRequiredDescription
operationstringYesOne of: get, update_trade_defaults, update_risk_policy
defaultsobjectConditionalRequired for update_trade_defaults — trading default overrides
policyobjectConditionalRequired for update_risk_policy — risk policy updates

Error codes

CodeMeaningCommon cause
401 UnauthorizedMissing or invalid bearer tokenKey revoked, expired identity token
403 ForbiddenScope insufficient or step-up missingtrade tool called with read key; manage action without step-up
404 Not FoundpublicId not foundWrong public ID or agent not yet provisioned
429 Too Many RequestsRate limit exceededToo many calls in the configured window
400 Bad RequestInvalid JSON-RPC request bodyMalformed JSON or missing required fields
JSON-RPC -32601Method not foundCalling an unknown method value
JSON-RPC -32603Internal errorTool execution error; see message field
JSON-RPC INVALID_PARAMSBad tool argumentsMissing required tool argument
JSON-RPC INVALID_REQUESTMissing principal contextBot user context could not be resolved

Rate limits

MCP rate limiting is configurable server-side via environment variables:

VariableDefaultDescription
MCP_RATE_LIMIT_ENABLEDfalseEnable/disable rate limiting
MCP_RATE_LIMIT_MAX(unset)Maximum requests per window
MCP_RATE_LIMIT_WINDOW(unset)Window duration in milliseconds

When rate limiting is enabled and a caller exceeds the limit, the server returns 429 Too Many Requests. The response body is a standard JSON-RPC error envelope.

In production deployments Balchemy also enforces Redis-backed per-user rate limits at the application layer independently of MCP-specific limits.


Audit and safety

Every MCP tool call is:

  1. Scope-checked against the key or token scope before the tool executes
  2. Policy-evaluated by the tool's safetyProfile (read_only / trade_guarded / manage_step_up)
  3. Origin-filtered against MCP_ALLOWED_ORIGINS if set
  4. Audit-logged to McpAuditLog — toolName, scope, authType, keyId, ip, duration, success/failure
  5. Argument-redacted in the log — wallet addresses, order IDs, and token mints are masked to xxxx...xxxx
  6. Session-trackedBot.mcpConfig.lastUsedAt and per-key lastUsedAt are updated on each call

Audit logs are accessible at GET /api/nest/bots/:botId/mcp/logs.


Control-plane routes (external agents)

After an agent's control plane is claimed in Hub, these management routes become available:

POST /api/nest/agents/:agentId/control/claim
POST /api/nest/agents/:agentId/control/mcp/step-up
PUT  /api/nest/agents/:agentId/control/scopes
POST /api/nest/agents/:agentId/control/mcp/keys/rotate
PUT  /api/nest/agents/:agentId/control/withdraw

All control-plane routes require a manage-scoped token plus a valid X-Balchemy-Step-Up header.


Connection lost. Retrying...