JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 76
  • Score
    100M100P100Q95207F
  • License MIT

Balchemy external AI agent onboarding + MCP SDK — ERC-8004 onboarding, Solana/EVM trading, 100 tools via MCP

Package Exports

  • @balchemyai/agent-sdk

Readme

@balchemyai/agent-sdk

TypeScript SDK for Balchemy external AI agents. Handles onboarding (SIWE wallet-based or walletless Identity flow), MCP tool access, token lifecycle management, and real-time SSE event streaming.

Installation

npm install @balchemyai/agent-sdk

Auth Paths

Path 1 — SIWE (wallet-based)

Use this when your agent controls a Solana or EVM wallet and can sign messages.

import { BalchemyAgentSdk } from "@balchemyai/agent-sdk";

const sdk = new BalchemyAgentSdk({
  apiBaseUrl: "https://api.balchemy.ai/api",
});

// 1. Request a nonce and SIWS message
const { message, nonce } = await sdk.requestSiweNonce({
  address: "YOUR_WALLET_ADDRESS",
  chainId: 8453,
  domain: "youragent.example.com",
  uri: "https://youragent.example.com",
  statement: "Sign in to Balchemy",
});

// 2. Sign `message` with your wallet (off-chain, using your signing library)
const signature = await wallet.signMessage(message);

// 3. Onboard
const response = await sdk.onboardWithSiwe({
  message,
  signature,
  agentId: "your-agent-unique-id",
  scope: "trade", // "read" | "trade"
});

const mcp = sdk.connectMcp({
  endpoint: response.mcp.endpoint,
  apiKey: response.mcp.apiKey ?? "",
});

Path 2 — Identity / Walletless

Use this when your agent has an HMAC-signed identity token (for balchemy native) or ES256 JWT (for external providers) from a provider registered with Balchemy.

import { BalchemyAgentSdk } from "@balchemyai/agent-sdk";

const sdk = new BalchemyAgentSdk({
  apiBaseUrl: "https://api.balchemy.ai/api",
});

const response = await sdk.onboardWithIdentity({
  provider: "your-registered-provider-id",
  identityToken: "YOUR_PROVIDER_JWT",
  agentId: "your-agent-unique-id",
  chainId: 8453,
  scope: "trade",
});

const mcp = sdk.connectMcp({
  endpoint: response.mcp.endpoint,
  apiKey: response.mcp.apiKey ?? "",
});

Using the MCP Client

// List available tools
const { tools } = await mcp.listTools();

// Natural language query
const reply = await mcp.askBot({ message: "What is the price of SOL?" });

// Execute an agent instruction
const result = await mcp.agentExecute({
  instruction: "Find a low-risk setup on Base with 50 USDC",
});

// EVM quote (read-only, no wallet interaction)
const quote = await mcp.evmQuote({
  chainId: 8453,
  sellToken: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base
  buyToken:  "0x4200000000000000000000000000000000000006", // WETH on Base
  sellAmount: "50000000", // 50 USDC (6 decimals)
});

// EVM swap (submit: false = pending order, submit: true = on-chain execution)
const swap = await mcp.evmSwap({
  chainId: 8453,
  sellToken: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  buyToken:  "0x4200000000000000000000000000000000000006",
  sellAmount: "50000000",
  submit: true,
});

Tool Exposure and Scope

By default the MCP endpoint exposes a curated agent-facing tool set for chat, execution, setup, behavior rules, portfolio/status, and subscriptions.

The broader internal catalog is only exposed when the platform flag MCP_EXPOSE_GRANULAR_TOOLS=true is enabled on the bot. Contact the Balchemy team if your integration needs granular tool access beyond the default agent-facing surface.

Tool scopes:

Scope Access
"read" Read-only tools — market data, portfolio views, research
"trade" All read tools + trade execution tools

Pass scope during onboarding to receive an MCP key with the appropriate permissions.

Error Handling

All SDK methods throw AgentSdkError on failure.

import { AgentSdkError } from "@balchemyai/agent-sdk";
import type { AgentSdkErrorCode } from "@balchemyai/agent-sdk";

try {
  const result = await mcp.agentExecute({ instruction: "..." });
} catch (err: unknown) {
  if (err instanceof AgentSdkError) {
    const code: AgentSdkErrorCode = err.code;
    // "auth_error" | "policy_error" | "rate_limit" | "provider_auth_error"
    // | "network_error" | "execution_error" | "invalid_response"
    console.error(`[${code}] ${err.message}`, err.details);
  }
}

Tool Response Helpers

import { getToolText, parseToolJson, isToolError } from "@balchemyai/agent-sdk";

const response = await mcp.agentPortfolio();

if (isToolError(response)) {
  console.error("Tool returned an error:", getToolText(response));
} else {
  const data = parseToolJson(response); // T | null
  console.log(data);
}

Token Management

import { TokenStore } from "@balchemyai/agent-sdk";

const store = new TokenStore({
  // Called when the stored token nears expiry — return a fresh OnboardingResponse
  refreshFn: async () => {
    return sdk.onboardWithIdentity({ ... });
  },
});

await store.set(response);
const token = await store.get(); // auto-refreshes if expiry < threshold

Identity Access Token

The OnboardingResponse includes an identityAccess field when the platform issues a short-lived access token alongside the MCP key.

import type { IdentityAccess } from "@balchemyai/agent-sdk";

const access: IdentityAccess | undefined = response.identityAccess;
if (access) {
  console.log(access.scope);     // "read" | "trade"
  console.log(access.expiresAt); // ISO timestamp
}

SSE Event Streaming

import { SseEventStream } from "@balchemyai/agent-sdk";
import type { SseEvent } from "@balchemyai/agent-sdk";

const stream = new SseEventStream(
  `${response.mcp.endpoint}/events/sse`,
  response.mcp.apiKey ?? "",
  { reconnectDelayMs: 2000, maxReconnects: 0 }
);

// Async iterator
for await (const event of stream) {
  const e: SseEvent = event;
  console.log(e.event, e.data);
}

// Or callback-based
const unsubscribe = stream.subscribe(
  (event) => console.log(event),
  (err)   => console.error(err)
);
// later: unsubscribe();

Identity Token Revocation

// Revoke a token by JTI
await sdk.revokeIdentityToken({ jti: "the-token-jti", ttlSeconds: 86400 });

// Check revocation status
const { revoked } = await sdk.getIdentityTokenRevokeStatus({ jti: "the-token-jti" });

Platform Endpoints Reference

Endpoint Path Auth
MCP server POST /api/mcp/{publicId} Authorization: Bearer <mcp-api-key>
SIWE nonce POST /api/nest/auth/evm/nonce Public
SIWE onboarding POST /api/public/erc8004/onboarding/siwe Public
Walletless onboarding POST /api/public/erc8004/onboarding/identity Public
Token revoke POST /api/public/erc8004/onboarding/tokens/revoke Public
JWKS GET /.well-known/jwks.json Public
MCP discovery GET /.well-known/mcp.json Public
Agent directory GET /api/nest/agents/verified/page Public

Note: the JWKS endpoint is served at /.well-known/jwks.json (root-relative, not under /api).

Platform Operator Setup

To enable agent onboarding, the following environment variables must be configured on the backend:

Variable Required Description
AGENT_WALLETLESS_ONBOARDING_ENABLED For walletless path Set to true to enable the identity/walletless onboarding endpoint. Default: false.
SIWE_DOMAIN_ALLOWLIST For SIWE path Comma-separated list of allowed domains for SIWE message verification (e.g. youragent.example.com,localhost).
ERC8004_IDENTITY_PROVIDERS For walletless path Comma-separated list of allowed identity provider IDs (e.g. github-actions,openclaw).
AGENT_IDENTITY_ISSUER_PRIVATE_KEY_PEM For identity tokens ES256 private key (PEM or base64) for signing agent identity access tokens. Required if issuing short-lived identity tokens.
API_URL Always Base API URL used to build MCP endpoint URLs in onboarding responses (e.g. https://api.balchemy.ai/api).

Getting Started (Quickstart)

  1. Install the SDK:

    npm install @balchemyai/agent-sdk
  2. Create an MCP API key for your bot via the Hub UI: Hub > Your Bot > API Keys > Create Key.

  3. Choose an auth path:

    • SIWE (wallet-based): Your agent must control an EVM wallet and can sign messages.
    • Walletless (identity token): Your agent has an HMAC-signed identity token (balchemy native) or ES256 JWT (external provider) from a registered provider. The platform operator must set AGENT_WALLETLESS_ONBOARDING_ENABLED=true.
  4. Run the relevant code example in the Auth Paths section above.

  5. Use the returned mcp.endpoint and mcp.apiKey to make MCP tool calls.

  6. The MCP key is scoped — "read" for read-only tools, "trade" for trade execution tools. Choose at onboarding time via the scope parameter.

Notes

  • agent_seed_request is disabled on the platform. The requestSeed() method exists for backward compatibility but always throws a deterministic AgentSdkError with code "execution_error".
  • apiBaseUrl must include the /api path segment and must not have a trailing slash.
  • The JWKS endpoint is at /.well-known/jwks.json (root-relative). Do not prefix with /api.
  • If walletless onboarding returns HTTP 403 with code: "FEATURE_DISABLED", the platform operator needs to set AGENT_WALLETLESS_ONBOARDING_ENABLED=true.

Docs