@a3stack/data
Data / MCP
MCP server and client with built-in identity verification and payment gating. Expose tools only verified, paying agents can use.
What is MCP?
MCP (Model Context Protocol) is Anthropic's open protocol for AI tool calls. It lets any AI client call functions exposed by any MCP server over HTTP.
@a3stack/data wraps the official MCP SDK and adds:
- Identity layer — expose your ERC-8004 registration as an
agent://identityresource - Payment gating — require x402 payment before serving tool calls
- Auto-resolving client — connect by global ID instead of hardcoded URL
- Auto-payment — client pays x402 automatically, no manual flow
MCP Server
createAgentMcpServer()
typescript
import { createAgentMcpServer } from "@a3stack/data";
import { z } from "zod";
const server = createAgentMcpServer({
name: "MarketDataAgent",
version: "1.0.0",
port: 3000, // default: 3000
// Identity: expose your ERC-8004 registration as agent://identity resource
identity: {
chainId: 8453, // Base
agentId: 42, // your registered agent ID
},
// Payment gating: require USDC per tool call
payment: {
payTo: "0xYourWallet...",
amount: "1000", // 0.001 USDC
asset: USDC_BASE,
network: "eip155:8453",
description: "MarketDataAgent: 0.001 USDC per call",
freeTools: ["ping"], // these tools are always free
},
});typescript
import { z } from "zod";
// Register tools (MCP API passthrough)
server.tool(
"get-price",
"Get the current price of a cryptocurrency",
{ symbol: z.string().describe("Token symbol, e.g. ETH, BTC") },
async ({ symbol }) => ({
content: [{ type: "text", text: JSON.stringify({ symbol, price: 2800 }) }],
})
);
server.tool(
"analyze-token",
"Get detailed analysis for a token",
{
symbol: z.string(),
depth: z.enum(["basic", "detailed"]).default("basic"),
},
async ({ symbol, depth }) => ({
content: [{ type: "text", text: `Analysis for ${symbol} (${depth})` }],
})
);
// Start server
const { url } = await server.listen();
console.log(`Serving at ${url}`);
// → http://localhost:3000/mcpserver.listen()
Returns { url, app, transport }. The server runs athttp://localhost:{port}/mcp by default.
Free tools
Some tools can bypass the payment gate (e.g. health checks, ping):
typescript
// Free tools are always served without payment check
const server = createAgentMcpServer({
name: "MyAgent",
payment: {
payTo: "0x...",
amount: "10000",
freeTools: ["ping", "health", "info"], // these bypass payment gate
},
});
// "ping" is automatically registered as a free tool
// It returns: { status: "ok", requiresPayment: true, freeTools: [...] }Identity resource
typescript
// When identity config is set, the server auto-exposes:
// Resource: agent://identity
//
// Clients can read it with:
const identity = await client.getAgentIdentity();
// Returns the full AgentRegistration from ERC-8004
// The resource URI is: "agent://identity"
// content-type: application/jsonMCP Client
createAgentMcpClient()
Connect by global ID (recommended — auto-resolves, auto-pays):
typescript
import { createAgentMcpClient } from "@a3stack/data";
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount(process.env.PRIVATE_KEY);
// Connect by ERC-8004 global ID (recommended)
// Auto-resolves endpoint, verifies identity, auto-pays x402
const client = await createAgentMcpClient({
agentId: "eip155:8453:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432#2376",
payer: {
account,
maxAmount: "100000", // max 0.10 USDC auto-pay per session
},
});Connect by URL directly:
typescript
// Connect by direct URL (no identity check, no auto-payment)
const client = await createAgentMcpClient({
url: "https://mcp.someagent.ai/mcp",
});Client methods
typescript
// List available tools
const tools = await client.listTools();
tools.forEach(t => console.log(`- ${t.name}: ${t.description}`));
// Call a tool (auto-pays if required)
const result = await client.callTool("get-price", { symbol: "ETH" });
const data = JSON.parse(result.content[0].text);
console.log(data.price); // 2800
// Read the agent's identity resource
const identity = await client.getAgentIdentity();
console.log(identity?.name); // "MarketDataAgent"
console.log(identity?.services); // [{ name: "MCP", ... }]
// Close when done
await client.close();probeAgent()
Discover what an agent offers before connecting. No wallet needed — read-only.
typescript
import { probeAgent } from "@a3stack/core";
// Discover an agent without connecting (no wallet needed)
const info = await probeAgent("eip155:8453:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432#2376");
console.log(info.verified); // true — on-chain verified
console.log(info.owner); // "0x1be93C..."
console.log(info.endpoints.mcp); // "https://mcp.arcabot.ai/mcp"
console.log(info.endpoints.a2a); // null (not configured)
console.log(info.acceptsPayment); // true
console.log(info.services); // [{ name: "MCP", endpoint: "...", version: "..." }]
console.log(info.registrations); // cross-chain IDsServer config reference
| Option | Type | Description |
|---|---|---|
name | string | MCP server name |
version | string | Server version |
port | number | HTTP port (default: 3000) |
identity.chainId | number | Chain for ERC-8004 lookup |
identity.agentId | number | Your registered agent token ID |
payment.payTo | string | Wallet receiving USDC |
payment.amount | string | USDC amount in base units |
payment.network | string | CAIP-2 network (default: eip155:8453) |
payment.freeTools | string[] | Tool names exempt from payment |
Client config reference
| Option | Type | Description |
|---|---|---|
agentId | string | ERC-8004 global ID (auto-resolves URL) |
url | string | Direct MCP endpoint URL |
payer.account | Account | viem Account for signing payments |
payer.maxAmount | string | Max USDC to auto-pay per session |