内容
<div align="center">
<!-- Optional: drop your own logo here, e.g. assets/logo.png at ~120px wide -->
<!-- <img src="assets/logo.png" alt="Abstraxn" width="120" /> -->
<h1>@abstraxn/agent-kit</h1>
<p>
<a href="https://www.npmjs.com/package/@abstraxn/agent-kit"><img src="https://img.shields.io/npm/v/@abstraxn/agent-kit.svg" alt="npm version" /></a>
<a href="https://www.npmjs.com/package/@abstraxn/agent-kit"><img src="https://img.shields.io/npm/dm/@abstraxn/agent-kit.svg" alt="npm downloads" /></a>
<a href="https://github.com/Abstraxn-Labs/agent-kit/actions/workflows/ci.yml"><img src="https://github.com/Abstraxn-Labs/agent-kit/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
<img src="https://img.shields.io/badge/TypeScript-ready-3178C6.svg" alt="TypeScript" />
<a href="LICENSE"><img src="https://img.shields.io/npm/l/@abstraxn/agent-kit.svg" alt="License: MIT" /></a>
</p>
<p><strong>Backend SDK for creating and managing Web3 AI agents with auto-provisioned Abstraxn server wallets.</strong></p>
<p>
<a href="https://docs.abstraxn.com/guides/ai/agent-kit-overview">Docs</a> ·
<a href="https://github.com/Abstraxn-Labs/abstraxn-agent-examples">Examples</a> ·
<a href="https://dashboard.abstraxn.com">Dashboard</a> ·
<a href="https://github.com/Abstraxn-Labs/agent-kit/issues">Report a bug</a>
</p>
</div>
## Features
- **Auto-provisioned server wallets** — create an agent and its wallet in one call, or bring your own EVM/Solana address.
- **Spend policies** — cap agent budgets per period, with hard-block or advisory enforcement.
- **Interaction policies** — server-side guardrails on contracts, methods, recipients, and amounts that agents cannot bypass.
- **Autonomous transactions** — queue, claim, sign, and broadcast on-chain intents from MCP clients.
- **ERC-8004 on-chain identity** — register agent identity with a server or bring-your-own signer.
- **MCP-native & x402-aware** — works with Cursor, Claude Desktop, and CLI; budgets paid MCP tools.
## Installation
```bash
npm install @abstraxn/agent-kit
```
## Prerequisites
- **Node.js** >= 18
- **API Key** from the [Abstraxn Dashboard](https://dashboard.abstraxn.com)
> Looking for runnable end-to-end apps? See the **[abstraxn-agent-examples](https://github.com/Abstraxn-Labs/abstraxn-agent-examples)** repo — six agents you can clone and run in five minutes.
<details>
<summary>Table of Contents</summary>
- [Basic Integration](#basic-integration)
- [1. Initialize the SDK](#1-initialize-the-sdk)
- [2. Create an Agent (with auto-provisioned wallet)](#2-create-an-agent-with-auto-provisioned-wallet)
- [2b. Create an Agent (external / bring-your-own wallet)](#2b-create-an-agent-external--bring-your-own-wallet)
- [3. List Agents](#3-list-agents)
- [4. Get Agent by ID](#4-get-agent-by-id)
- [5. Update Agent](#5-update-agent)
- [6. Set Spend Policy](#6-set-spend-policy)
- [7. Interaction Policies (off-chain guardrails)](#7-interaction-policies-off-chain-guardrails)
- [8. Autonomous Transactions (delegated MCP execution)](#8-autonomous-transactions-delegated-mcp-execution)
- [9. Delete Agent](#9-delete-agent)
- [10. Register ERC-8004 On-Chain Identity](#10-register-erc-8004-on-chain-identity)
- [Signing Transactions with the Wallet](#signing-transactions-with-the-wallet)
- [Full Integration Example](#full-integration-example)
- [Configuration](#configuration)
- [Error Handling](#error-handling)
- [Security Notes](#security-notes)
- [Examples](#examples)
- [Contributing](#contributing)
- [License](#license)
</details>
---
## Basic Integration
### 1. Initialize the SDK
```typescript
import { AgentKitClient } from '@abstraxn/agent-kit';
const agentKit = new AgentKitClient({
apiKey: process.env.ABSTRAXN_API_KEY!,
wallet: 'server', // default — auto-provision Abstraxn server wallet
});
```
### 2. Create an Agent (with auto-provisioned wallet)
This is the primary flow. The SDK will:
- Generate a P-256 access key pair
- Create a server wallet via Abstraxn
- Retrieve the wallet's EVM address
- Register the agent in the backend
```typescript
const { agent, wallet } = await agentKit.createAgent({
name: 'Trading Assistant',
description: 'AI agent that executes trades within spend policy',
userIdentity: 'user-123@example.com',
userName: 'John Doe', // optional
userEmail: 'john@example.com', // optional
metadata: { role: 'trader' }, // optional
});
// ─── Agent Details ───
console.log('Agent ID:', agent.id);
console.log('Agent API Key:', agent.apiKey);
console.log('Is Active:', agent.isActive);
// ─── Wallet Details ───
console.log('EVM Address:', wallet.evmAddress);
console.log('Organization ID:', wallet.organizationId);
// ⚠️ IMPORTANT: Store these securely in your backend database.
// The accessKey is the ONLY way to sign transactions for this wallet.
// It CANNOT be retrieved again.
console.log('Access Key:', wallet.accessKey);
await saveToDatabase({
agentId: agent.id,
accessKey: wallet.accessKey!, // secret — encrypt at rest (server wallet only)
evmAddress: wallet.evmAddress,
organizationId: wallet.organizationId,
});
```
### 2b. Create an Agent (external / bring-your-own wallet)
Use your own EVM or Solana address — no server wallet or `accessKey` is created:
```typescript
const agentKit = new AgentKitClient({
apiKey: process.env.ABSTRAXN_API_KEY!,
wallet: 'external',
});
const { agent, wallet } = await agentKit.createAgent({
name: 'Trading Assistant',
description: 'Uses the user MetaMask wallet',
userIdentity: 'user-123@example.com',
evmAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', // required (or solanaAddress)
});
console.log(wallet.type); // 'external'
console.log(wallet.evmAddress); // saved on the agent record
// wallet.accessKey is undefined — sign txs with your own wallet stack
```
You can also override per call without changing client config:
```typescript
const { agent, wallet } = await agentKit.createAgent({
wallet: 'external',
evmAddress: '0x...',
name: '...',
description: '...',
userIdentity: '...',
});
```
`createAgentDirect()` is equivalent to external mode (POST `/agents` with addresses only).
### 3. List Agents
```typescript
const { items, total } = await agentKit.listAgents({
offset: 0,
limit: 20,
});
console.log(`Total agents: ${total}`);
items.forEach((agent) => {
console.log(`${agent.name} — ${agent.evmAddress} — active: ${agent.isActive}`);
});
```
### 4. Get Agent by ID
```typescript
const agent = await agentKit.getAgent('agent-uuid-here');
console.log(agent.name, agent.evmAddress);
```
### 5. Update Agent
```typescript
const updated = await agentKit.updateAgent('agent-uuid-here', {
name: 'Updated Agent Name',
description: 'Updated description',
isActive: false,
});
```
### 6. Set Spend Policy
```typescript
// Enable a daily budget of $5
const agent = await agentKit.updateSpendPolicy('agent-uuid-here', {
enabled: true,
budgetUsd: '5.00',
period: 'daily',
hardBlock: true, // false = advisory only
});
// Disable spend policy
await agentKit.updateSpendPolicy('agent-uuid-here', {
enabled: false,
});
```
Spend policy controls **paid MCP tool** budgets (x402). For on-chain interaction guardrails (contracts, recipients, amounts), use **interaction policies** below.
### 7. Interaction Policies (off-chain guardrails)
Configure per-agent rules enforced **before every MCP tool call**. All enabled policies must pass (AND). Enforcement is server-side — agents cannot bypass it.
**Rule types (per-chain):**
| Rule | Purpose |
|------|---------|
| `contractWhitelist` | Allow only listed contract/mint addresses |
| `methodWhitelist` | Allow only matching calldata patterns (`*` = hex wildcard) |
| `recipientBlacklist` | Block transfers to listed addresses |
| `nativeAmountLimits` | Min/max for native token amounts |
| `tokenAmountLimits` | Min/max per token symbol or contract |
```typescript
// Create a policy
const policy = await agentKit.createInteractionPolicy('agent-uuid-here', {
name: 'transfer-guardrails',
enabled: true,
hardBlock: true,
rules: {
recipientBlacklist: [{
chain: 'ethereum',
addresses: ['0xBadAddress000000000000000000000000000001'],
}],
nativeAmountLimits: [{
chain: 'ethereum',
max: '0.5',
}],
contractWhitelist: [{
chain: 'ethereum',
addresses: ['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'], // USDC
}],
methodWhitelist: [{
chain: 'ethereum',
contract: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
// Full calldata pattern — length must match; * = any hex digit
calldataPatterns: ['0xa9059cbb' + '*'.repeat(128)],
}],
tokenAmountLimits: [{
chain: 'ethereum',
token: 'USDC',
max: '1000',
}],
},
});
// List all policies for an agent
const { items, total } = await agentKit.listInteractionPolicies('agent-uuid-here');
// Get, update, or delete
const one = await agentKit.getInteractionPolicy('agent-uuid-here', policy.id);
await agentKit.updateInteractionPolicy('agent-uuid-here', policy.id, {
enabled: false,
});
await agentKit.deleteInteractionPolicy('agent-uuid-here', policy.id);
```
**Agent app integration:** expose policy CRUD from your backend (not the browser) using your dashboard API key. Map your user → `agent.id`, then call the SDK methods above. See your agent app's policy UI → backend → SDK flow.
**Auth:** policies can be managed with your **dashboard API key** (all agents under your app) or the agent's own **Kong API key** (`agent.apiKey` from `createAgent`) for that agent only.
**MCP violation:** when a tool call breaks a policy, MCP returns JSON-RPC **`-32404`** with `data.interactionPolicy.violations[]`.
### 8. Autonomous Transactions (delegated MCP execution)
When **autonomous transactions** are enabled for an agent, external MCP clients (Cursor, Claude Desktop, CLI) can **queue** on-chain intents instead of receiving only unsigned payloads. Your integrator backend (which holds the agent `accessKey`) claims, signs, broadcasts, and reports status back to Agent Kit.
**Two execution paths:**
| Context | MCP header | MCP response (autonomous ON) | Who signs |
|---------|------------|------------------------------|-----------|
| **In-app chat** | `managed` | `unsigned_transaction_ready` | Your app backend (immediate) |
| **External MCP** | `delegated` (default) | `transaction_pending` | Your integrator backend |
When autonomous is **OFF** and the caller is external, MCP returns **`unsigned_transaction_ready` only** (no queue).
#### Enable per agent
```typescript
const config = await agentKit.getAutonomousTx('agent-uuid-here');
console.log(config.enabled); // false by default
await agentKit.updateAutonomousTx('agent-uuid-here', {
enabled: true,
maxPendingAgeSeconds: 300, // optional — pending tx expiry
maxConcurrentPending: 10, // optional — queue cap per agent
});
```
Combine with strict **interaction policies** (section 7). Enabling autonomous increases risk if policies are loose.
#### MCP execution context
Use `createMcpClient()` with the agent's Kong API key (`agent.apiKey`). In-app chat should send `managed`; external tools default to `delegated`.
```typescript
const mcp = agentKit.createMcpClient(agent.apiKey);
// External client (Cursor / CLI) — may queue when autonomous ON
const result = await mcp.callTool('transfer', {
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
amount: '1',
token: 'POL',
chain: 'polygon',
}, {
executionContext: 'delegated', // default
idempotencyKey: 'cursor-transfer-001', // optional — dedupe retries
});
// In-app chat — sign immediately on your backend
await mcp.callTool('transfer', args, {
executionContext: 'managed',
});
```
When autonomous is enabled and context is `delegated`, on-chain tools may return `transaction_pending` with `pendingTransactionId` instead of `unsigned_transaction_ready` only.
#### Integrator execution loop
1. **Subscribe to webhooks** (per dashboard API key):
```typescript
await agentKit.createWebhookSubscription({
url: 'https://api.yourapp.com/kit-webhooks/transactions',
secret: process.env.KIT_WEBHOOK_SECRET!,
events: ['transaction.created', 'transaction.updated', 'transaction.expired'],
});
// List or remove subscriptions
const subs = await agentKit.listWebhookSubscriptions();
await agentKit.deleteWebhookSubscription(subs[0].id);
```
Webhooks are HMAC-signed (`X-Agent-Kit-Signature`, `X-Agent-Kit-Timestamp`). Verify the signature before processing.
2. **On `transaction.created`** — claim, sign with stored `accessKey`, broadcast, update status:
```typescript
const pending = await agentKit.claimPendingTransaction(agentId, pendingId);
// Sign pending.mcpResult with your wallet stack (ServerSigner, viem, etc.)
const txHash = '0x…';
await agentKit.updatePendingTransaction(agentId, pendingId, {
status: 'submitted',
txHash,
});
await agentKit.updatePendingTransaction(agentId, pendingId, {
status: 'confirmed',
txHash,
});
```
3. **Poll as fallback** if webhooks are unavailable:
```typescript
const { items } = await agentKit.listPendingTransactions(agentId, {
status: 'pending',
limit: 20,
});
const one = await agentKit.getPendingTransaction(agentId, pendingId);
await agentKit.cancelPendingTransaction(agentId, pendingId); // optional
```
**Auth:** autonomous config, pending txs, and webhooks use your **dashboard API key** (integrator). MCP tool calls use the agent's **Kong API key** (`agent.apiKey`).
See also: [Autonomous transactions guide](https://docs.abstraxn.com/guides/ai/autonomous-transactions) (Abstraxn docs).
### 9. Delete Agent
```typescript
await agentKit.deleteAgent('agent-uuid-here');
```
### 10. Register ERC-8004 On-Chain Identity
#### Server wallet
After creating an agent and funding its server wallet with native gas on the target chain:
```typescript
const identity = await agentKit.registerAgentIdentity({
agentId: agent.id,
userIdentity: 'user-123@example.com',
accessKey: wallet.accessKey,
organizationId: wallet.organizationId,
evmAddress: wallet.evmAddress,
chainId: 11155111, // Sepolia — backend must have IdentityRegistry configured for this chain
});
console.log(identity.registration.agentIdentity);
// eip155:11155111:0x8004A818BFB912233c491871b3d84c89A494BD9e:42
const stored = await agentKit.getAgentIdentity(agent.id, 11155111);
```
#### External wallet (bring-your-own signer)
Registry is a **3-step** flow: prepare (backend) → sign (your wallet) → confirm (backend).
```typescript
import { createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { sepolia } from 'viem/chains';
// 1. Create agent with your address (no server wallet)
const { agent } = await agentKit.createAgent({
wallet: 'external',
evmAddress: process.env.DEV_EVM_ADDRESS!,
name: 'My Agent',
description: '...',
userIdentity: 'user@example.com',
});
// 2. Register — you provide the signer
const identity = await agentKit.registerAgentIdentityExternal({
agentId: agent.id,
evmAddress: process.env.DEV_EVM_ADDRESS!,
chainId: 11155111,
signTransaction: async ({ prepare, fromAddress }) => {
const account = privateKeyToAccount(process.env.DEV_PRIVATE_KEY as `0x${string}`);
const walletClient = createWalletClient({
account,
chain: sepolia,
transport: http(prepare.rpcUrl),
});
const hash = await walletClient.sendTransaction({
account: fromAddress,
chain: sepolia,
to: prepare.registerCall.to as `0x${string}`,
data: prepare.registerCall.data,
value: BigInt(prepare.registerCall.value || '0'),
});
return hash;
},
});
```
**Manual steps** (same APIs, full control):
```typescript
const prepare = await agentKit.prepareAgentIdentity(agent.id, { chainId: 11155111 });
// sign prepare.registerCall with MetaMask / viem / ethers…
const confirmed = await agentKit.confirmAgentIdentity(agent.id, {
chainId: 11155111,
txHash: '0x…',
});
```
Requirements for external registry:
- Agent `evmAddress` must match the account that signs (and holds gas on that `chainId`).
- Backend must have IdentityRegistry configured for the `chainId`.
- `registerAgentIdentity()` (server) needs `accessKey` + `organizationId`; external flow does not.
Registration file (public): `GET {AGENT_KIT_PUBLIC_URL}/agents/{agentId}/registration`
---
## Signing Transactions with the Wallet
After creating an agent, use the stored `accessKey` to sign transactions via the `ServerSignerClient`:
```typescript
const signer = agentKit.getServerSigner();
// Authenticate using the stored access key
const session = await signer.authenticate({
userIdentity: 'user-123@example.com',
accessKey: storedAccessKey, // retrieved from your database
});
// Create a viem public client for EVM operations
const publicClient = signer.createPublicClient({
rpcUrl: 'https://rpc-amoy.polygon.technology',
chainId: 80002,
organizationId: storedOrganizationId,
fromAddress: storedEvmAddress as `0x${string}`,
});
// Send a transaction
const prepared = await publicClient.prepareTransaction({
to: '0x1111111111111111111111111111111111111111' as `0x${string}`,
value: 1_000_000_000_000_000n, // 0.001 ETH
});
const txHash = await publicClient.signAndSendPreparedTransaction(
prepared.unsignedTransaction,
);
const receipt = await publicClient.waitForTransactionReceipt(txHash);
console.log('Transaction confirmed:', receipt.transactionHash);
// Sign a message
const signature = await publicClient.signMessage({
message: 'Hello from my agent',
});
```
---
## Full Integration Example
A complete backend service that creates an agent and later uses it to send a transaction:
```typescript
import { AgentKitClient } from '@abstraxn/agent-kit';
const agentKit = new AgentKitClient({
apiKey: process.env.ABSTRAXN_API_KEY!,
});
// ── Step 1: Create agent + wallet (run once, store results) ──
async function onboardAgent(userEmail: string) {
const { agent, wallet } = await agentKit.createAgent({
name: `Agent for ${userEmail}`,
description: 'Autonomous trading agent',
userIdentity: userEmail,
userEmail,
});
// Store in your database
return {
agentId: agent.id,
apiKey: agent.apiKey,
accessKey: wallet.accessKey, // ⚠️ encrypt at rest
evmAddress: wallet.evmAddress,
organizationId: wallet.organizationId,
};
}
// ── Step 2: Use the agent to sign & send transactions ──
async function executeAgentTrade(agentRecord: {
accessKey: string;
evmAddress: string;
organizationId: string;
userIdentity: string;
}) {
const signer = agentKit.getServerSigner();
await signer.authenticate({
userIdentity: agentRecord.userIdentity,
accessKey: agentRecord.accessKey,
});
const client = signer.createPublicClient({
rpcUrl: process.env.RPC_URL!,
chainId: Number(process.env.CHAIN_ID!),
organizationId: agentRecord.organizationId,
fromAddress: agentRecord.evmAddress as `0x${string}`,
});
const prepared = await client.prepareTransaction({
to: '0xRecipientAddress...' as `0x${string}`,
value: 500_000_000_000_000n,
});
const txHash = await client.signAndSendPreparedTransaction(
prepared.unsignedTransaction,
);
const receipt = await client.waitForTransactionReceipt(txHash);
return receipt;
}
// ── Step 3: Manage agents ──
async function manageAgents() {
// List all agents
const { items } = await agentKit.listAgents();
// Set spend limits
for (const agent of items) {
await agentKit.updateSpendPolicy(agent.id, {
enabled: true,
budgetUsd: '10.00',
period: 'daily',
hardBlock: true,
});
// Set interaction guardrails (optional)
await agentKit.createInteractionPolicy(agent.id, {
name: 'default-guardrails',
rules: {
nativeAmountLimits: [{ chain: 'ethereum', max: '1.0' }],
},
});
}
// Deactivate an agent
await agentKit.updateAgent(items[0].id, { isActive: false });
}
```
---
## Configuration
| Option | Required | Default | Description |
| ------------ | -------- | -------------------------------- | ---------------------------------------- |
| `apiKey` | Yes | — | API key from the Abstraxn dashboard |
| `baseUrl` | No | `https://agent-kit.abstraxn.com` | Agent Kit service base URL |
| `retryCount` | No | `1` | Number of retries for transient failures |
| `fetch` | No | Global `fetch` | Custom fetch implementation |
## Error Handling
All errors extend `AgentKitError` with `code` and `statusCode` properties:
```typescript
import {
AgentKitError,
ValidationError, // 400 — invalid input
BadRequestError, // 400 — server rejected request
UnauthorizedError, // 401 — invalid or missing API key
ForbiddenError, // 403 — insufficient permissions
NotFoundError, // 404 — agent not found
ConflictError, // 409 — duplicate resource
NetworkError, // network connectivity issue
} from '@abstraxn/agent-kit';
try {
await agentKit.createAgent({ ... });
} catch (error) {
if (error instanceof UnauthorizedError) {
console.error('Invalid API key — check your dashboard');
} else if (error instanceof NotFoundError) {
console.error('Agent not found');
} else if (error instanceof AgentKitError) {
console.error(`[${error.code}] ${error.message}`);
}
}
```
## Security Notes
- Store `accessKey` in a secure secrets manager or encrypted database column.
- Never expose `accessKey` in frontend code or logs.
- The `mcpToken` (from `bindAgent`) is a one-time value — store it securely on first receipt.
- Rotate API keys via the Abstraxn dashboard if compromised.
- Found a vulnerability? See [SECURITY.md](SECURITY.md) for how to report it privately.
## Examples
Runnable end-to-end apps live in the **[abstraxn-agent-examples](https://github.com/Abstraxn-Labs/abstraxn-agent-examples)** repo — six agents (web crawling, trading, tx monitoring, fraud/policy guardrails, x402-paid market data) you can clone and run in five minutes.
Local package examples live in [`examples/`](examples/):
```bash
ABSTRAXN_API_KEY=... npm run example:register-identity
```
## Contributing
Contributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md) for dev setup, commit conventions, and the release process. See [CHANGELOG.md](CHANGELOG.md) for release history.
## Support
- **Bugs / feature requests**: [open a GitHub issue](https://github.com/Abstraxn-Labs/agent-kit/issues).
- **Security vulnerabilities**: see [SECURITY.md](SECURITY.md) — please don't file a public issue.
- **Dashboard / API keys**: [dashboard.abstraxn.com](https://dashboard.abstraxn.com).
- **Docs**: [docs.abstraxn.com](https://docs.abstraxn.com/guides/ai/agent-kit-overview).
---
<div align="center">
<sub>If Agent Kit is useful, please <a href="https://github.com/Abstraxn-Labs/agent-kit">star the repo</a> — it helps other builders find it.</sub>
</div>
## License
[MIT](LICENSE)
连接信息
猜你喜欢
暂无推荐服务器