Abstraxn ships two sample projects you can clone or mirror: Together they show the full path from dashboard credentials to a user-facing agent with chat, portfolio, and on-chain actions. Folder names in your monorepo may differ; the patterns below apply to any backend and frontend you build.

What you are building

Prerequisites

  1. Dashboard setup — application API key and MCP URL.
  2. SDK quickstart — understand createAgent and accessKey.
  3. Postgres (or adapt persistence) for the sample service.

Part 1 — Sample backend API (NestJS)

Install and configure

Create agent — SDK + server wallet

When the UI calls POST /agents, AgentsService.create:
  1. Calls agentKitClient.createAgent({ name, description, userIdentity: userId }).
  2. Receives agent (Kit id, per-agent apiKey) and wallet (evmAddress, organizationId, accessKey).
  3. Encrypts wallet.accessKey with ENCRYPTION_KEY and saves to Postgres.
  4. Never returns accessKey in API responses.
This matches SDK quickstart. After creation, the agent appears in dashboard All agents with EVM/Solana addresses. Your production checklist:
  • Map userIdentity to your stable user id (the sample uses userId).
  • Fund the agent EVM address with native gas before transfers or x402.
  • Store agentId (Kit UUID) for MCP agent_id in tool arguments.

REST surface (your API, JWT)

Swagger is available when enabled in your Nest build.

MCP + LLM chat loop

McpClientService (on module init when MCP_SERVER_URL is set):
  1. initialize + notifications/initialized
  2. tools/list → cache tool schemas
  3. Expose tools to the LLM as OpenAI functions
ChatService.sendMessageStreaming:
  1. Loads session messages.
  2. Calls LLM with tool definitions.
  3. On tool call → McpClientService.callTool(name, args, paymentPayload?).
  4. For application key, include agent_id: session.agentId in args (Kit UUID from DB).
  5. Streams assistant text to the client over SSE.
Relevant files:
  • src/chat/mcp-client.service.ts
  • src/chat/chat.service.ts
  • src/chat/llm.service.ts

Transfer auto-sign (unsigned MCP → broadcast)

When the LLM calls MCP transfer, the tool returns an unsigned transaction. The sample app:
  1. Detects transfer metadata in the stream (transfer_confirmation_ui / pending transfer flow).
  2. Asks the user to confirm in the UI.
  3. AgentSigningService loads decrypted accessKey, authenticates server signer, signs and sends via viem.
See src/agents/agent-signing.service.ts and src/agents/pending-transfer.service.ts.

x402 in chat (paid_fetch, get_token_price)

When MCP returns payment required (-32402 or paymentRequired):
  1. AgentSigningService.createX402PaymentPayloadForAgent builds paymentPayload using the agent’s access key.
  2. Chat layer retries tools/call with top-level paymentPayload.
See x402 payments and src/chat/mcp-x402.util.ts.

Part 2 — Sample web app (Next.js)

Install and configure

Set backend URL in lib/constants.ts:

Auth

  • Email OTP or Google OAuth → auth-store JWT.
  • lib/api.ts adds Authorization: Bearer on every request to your API only.

Agents UI

Creating an agent in the UI → POST /agents on your backend → SDK createAgent → dashboard All agents updates on refresh.

Chat (BFF)

The browser never calls Agent Kit or the LLM directly.
  1. UI posts to Next.js app/api/chat/route.ts with Bearer JWT.
  2. Route proxies to POST /chat/sessions/:sessionId/messages on the backend with SSE.
  3. lib/chat/create-chat-session.ts creates sessions via your API.

Category specialist agents

The sample web app supports predefined specialist agents via serviceAgent on chat requests (or the category picker in the UI). Each specialist filters MCP tools and injects focused system prompts. Example: open chat as Portfolio & Price with ?serviceAgent=portfolio.

Portfolio and ERC-8004 identity

  • components/portfolio/ — balances from /agents/assets
  • RegisterIdentityModal — user picks a supported chainId; your API posts { "chainId": … } to /agents/:id/register-identity (full list)
  • RegisterIdentityFundRequiredModal — prompts to fund the agent EVM wallet when gas is insufficient
  • AgentIdentityDetails — global id, on-chain agent id, registry, owner, explorer links
  • useAgentIdentity / lib/fetch-agent-identity.ts — load identity from your backend (proxies Agent Kit)
Your API must decrypt accessKey and call @abstraxn/agent-kit registerAgentIdentity (or Kit REST prepare/confirm). The browser never signs registration transactions directly. Full standard and dashboard parity: ERC-8004 agent identity.

Transaction history

  • hooks/use-agent-transactions.ts — on-chain transfer history helpers

Part 3 — Map dashboard UI to your code


Security model

Application API key, MCP token, ENCRYPTION_KEY, and LLM keys live only in backend env. The web app holds the user JWT only.
Losing accessKey means you cannot sign transfers or x402 for that agent. Encrypt the DB column; never expose in GET /agents/:id.
Always proxy tool execution through your backend so keys and paymentPayload signing stay server-side.

Customize for production