Skip to main content
Glama

azeth_create_account

Deploy a smart account with spending limits and trust registry registration for AI agents and services, enabling on-chain identity without requiring ETH for gas.

Instructions

Deploy a new Azeth smart account with guardian guardrails and register it on the ERC-8004 trust registry.

Use this when: An AI agent or service needs its own on-chain identity with spending limits and trust registry presence. One EOA can own multiple smart accounts.

Single atomic transaction: deploys smart account proxy, installs all 4 modules (Guardian, TrustRegistry, PaymentAgreement, Reputation), registers on ERC-8004, and permanently revokes factory access.

Returns: The deployed smart account address, trust registry token ID, and transaction hash.

Gas is automatically sponsored — no ETH required. The SDK uses a gasless relay (EIP-712 signature) so the account can be created without any pre-funding. On testnet, USDC is also auto-funded.

Guardian: By default, the guardian is derived from AZETH_GUARDIAN_KEY env var. If not set, falls back to self-guardian (owner address). For production, always use a separate guardian key. Set AZETH_GUARDIAN_KEY in your .env file.

Example: { "name": "PriceFeedBot", "entityType": "service", "description": "Real-time crypto price data", "capabilities": ["price-feed", "market-data"] }

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
chainNoTarget chain. Defaults to AZETH_CHAIN env var or "baseSepolia". Accepts "base", "baseSepolia", "ethereumSepolia", "ethereum" (and aliases like "base-sepolia", "eth-sepolia", "sepolia", "eth", "mainnet").
nameYesDisplay name for this participant in the trust registry.
entityTypeYesParticipant type: "agent" (AI agent), "service" (API/oracle), or "infrastructure" (bridge/relay).
descriptionYesHuman-readable description of what this participant does.
capabilitiesYesList of capabilities this participant offers (e.g., ["swap", "price-feed", "translation"]).
endpointNoOptional HTTP endpoint (http:// or https://) where this participant can be reached.
maxTxAmountUSDNoMax USD per transaction (default: $100 testnet, $50 mainnet).
dailySpendLimitUSDNoMax USD per day (default: $1000 testnet, $500 mainnet).
guardianNoGuardian address for co-signing operations that exceed spending limits. If omitted, derived from AZETH_GUARDIAN_KEY env var. If neither is set, defaults to the owner address (self-guardian, NOT recommended for production).
emergencyWithdrawToNoAddress where funds are sent during emergency withdrawal. Defaults to the owner EOA address (derived from AZETH_PRIVATE_KEY). Must be a trusted address you control — this is your recovery destination.

Implementation Reference

  • The handler logic for 'azeth_create_account' tool, which handles address validation, guardian/emergency address resolution, guardrail setup, and account creation via the Azeth client.
    async (args) => {
      // Runtime validation for endpoint protocol (replaces .refine() which breaks MCP JSON Schema)
      if (args.endpoint && !args.endpoint.startsWith('http://') && !args.endpoint.startsWith('https://')) {
        return error('INVALID_INPUT', 'Endpoint must use HTTP or HTTPS protocol.');
      }
    
      let client;
      try {
        client = await createClient(args.chain);
    
        // Default guardrails: conservative limits
        const isTestnet = resolveChain(args.chain) === 'baseSepolia';
        const maxTxUSD = args.maxTxAmountUSD ?? (isTestnet ? 100 : 50);
        const dailyUSD = args.dailySpendLimitUSD ?? (isTestnet ? 1000 : 500);
    
        // Resolve guardian address: explicit param > AZETH_GUARDIAN_KEY env > self-guardian (owner)
        let guardianAddress: `0x${string}` = client.address; // fallback: self-guardian
        let guardianSource = 'self (owner EOA)';
    
        if (args.guardian) {
          // Explicit guardian address provided
          if (!validateAddress(args.guardian)) {
            return error('INVALID_INPUT', `Invalid guardian address: "${args.guardian}".`, 'Must be 0x-prefixed followed by 40 hex characters.');
          }
          guardianAddress = args.guardian as `0x${string}`;
          guardianSource = 'explicit parameter';
        } else {
          // Try deriving from AZETH_GUARDIAN_KEY env var
          const guardianKey = process.env['AZETH_GUARDIAN_KEY'];
          if (guardianKey && /^0x[0-9a-fA-F]{64}$/.test(guardianKey.trim())) {
            const { privateKeyToAccount } = await import('viem/accounts');
            const guardianAccount = privateKeyToAccount(guardianKey.trim() as `0x${string}`);
            guardianAddress = guardianAccount.address;
            guardianSource = 'AZETH_GUARDIAN_KEY env var';
          }
        }
    
        // Resolve emergencyWithdrawTo: explicit param > AZETH_EMERGENCY_ADDRESS env > owner EOA
        let emergencyAddress: `0x${string}` = client.address;
        if (args.emergencyWithdrawTo) {
          if (!validateAddress(args.emergencyWithdrawTo)) {
            return error('INVALID_INPUT', `Invalid emergencyWithdrawTo address: "${args.emergencyWithdrawTo}".`, 'Must be 0x-prefixed followed by 40 hex characters.');
          }
          emergencyAddress = args.emergencyWithdrawTo as `0x${string}`;
        } else {
          const envEmergency = process.env['AZETH_EMERGENCY_ADDRESS'];
          if (envEmergency && validateAddress(envEmergency)) {
            emergencyAddress = envEmergency as `0x${string}`;
          }
        }
    
        // Default token whitelist: ETH + USDC + WETH so that payment agreements
        // and other executor-module operations work out of the box.
        const chain = resolveChain(args.chain);
        const defaultTokens: `0x${string}`[] = [
          '0x0000000000000000000000000000000000000000',
          TOKENS[chain].USDC,
          TOKENS[chain].WETH,
        ];
    
        const serverUrl = process.env['AZETH_SERVER_URL'] ?? 'https://api.azeth.ai';
    
        const result = await client.createAccount({
          owner: client.address,
          guardrails: {
            maxTxAmountUSD: BigInt(Math.round(maxTxUSD)) * 10n ** 18n,
            dailySpendLimitUSD: BigInt(Math.round(dailyUSD)) * 10n ** 18n,
            guardianMaxTxAmountUSD: BigInt(Math.round(maxTxUSD * 5)) * 10n ** 18n,
            guardianDailySpendLimitUSD: BigInt(Math.round(dailyUSD * 5)) * 10n ** 18n,
            guardian: guardianAddress,
            emergencyWithdrawTo: emergencyAddress,
          },
          tokens: defaultTokens,
          registry: {
            name: args.name,
            description: args.description,
            entityType: args.entityType,
            capabilities: args.capabilities,
            endpoint: args.endpoint,
          },
        });
    
        const tokenIdStr = result.tokenId.toString();
        const badgeUrl = `${serverUrl}/badge/${tokenIdStr}`;
        const profileUrl = `https://azeth.ai/agent/${result.account}`;
    
        return success(
          {
            account: result.account,
            tokenId: tokenIdStr,
            txHash: result.txHash,
            guardian: guardianAddress,
            guardianSource,
            emergencyWithdrawTo: emergencyAddress,
            badge: badgeUrl,
            profile: profileUrl,
            embedMarkdown: `[![Azeth Trust Badge](${badgeUrl})](${profileUrl})`,
            ...(guardianAddress === client.address ? {
              warning: 'Guardian is set to the owner address (self-guardian). This means guardian co-signatures use the same key as the owner, providing no additional security. For production, set AZETH_GUARDIAN_KEY in your environment or provide a separate guardian address.',
            } : {}),
            ...(wasAutoGenerated() ? {
              keySource: 'auto-generated',
              keyPath: '~/.azeth/key',
              keyWarning: 'This account uses an auto-generated demo key stored at ~/.azeth/key. For production, set AZETH_PRIVATE_KEY in your environment with a key you control.',
            } : {}),
          },
          { txHash: result.txHash },
        );
      } catch (err) {
        if (err instanceof Error && err.message.includes('insufficient funds')) {
          return error(
            'INSUFFICIENT_BALANCE',
            'Account deployment failed: gasless relay unavailable and your EOA has no ETH for direct deployment.',
            'The relay at api.azeth.ai may be down or rate-limited. Try again later, or send a small amount of ETH to your EOA address for direct deployment.',
          );
        }
        return handleError(err);
      } finally {
        try { await client?.destroy(); } catch (e) { process.stderr.write(`[azeth-mcp] destroy error: ${e instanceof Error ? e.message : String(e)}\n`); }
      }
    },
  • Input schema definition for the 'azeth_create_account' tool.
    inputSchema: z.object({
      chain: z.string().optional().describe('Target chain. Defaults to AZETH_CHAIN env var or "baseSepolia". Accepts "base", "baseSepolia", "ethereumSepolia", "ethereum" (and aliases like "base-sepolia", "eth-sepolia", "sepolia", "eth", "mainnet").'),
      name: z.string().min(1).max(256).describe('Display name for this participant in the trust registry.'),
      entityType: z.enum(['agent', 'service', 'infrastructure']).describe('Participant type: "agent" (AI agent), "service" (API/oracle), or "infrastructure" (bridge/relay).'),
      description: z.string().min(1).max(2048).describe('Human-readable description of what this participant does.'),
      capabilities: z.preprocess(
        (val) => typeof val === 'string' ? JSON.parse(val) : val,
        z.array(z.string().max(128)).min(1).max(50),
      ).describe('List of capabilities this participant offers (e.g., ["swap", "price-feed", "translation"]).'),
      endpoint: z.string().url().max(2048)
        .optional()
        .describe('Optional HTTP endpoint (http:// or https://) where this participant can be reached.'),
      maxTxAmountUSD: z.coerce.number().positive().optional()
        .describe('Max USD per transaction (default: $100 testnet, $50 mainnet).'),
      dailySpendLimitUSD: z.coerce.number().positive().optional()
        .describe('Max USD per day (default: $1000 testnet, $500 mainnet).'),
      guardian: z.string().optional().describe(
        'Guardian address for co-signing operations that exceed spending limits. ' +
        'If omitted, derived from AZETH_GUARDIAN_KEY env var. ' +
        'If neither is set, defaults to the owner address (self-guardian, NOT recommended for production).',
      ),
      emergencyWithdrawTo: z.string().optional().describe(
        'Address where funds are sent during emergency withdrawal. ' +
        'Defaults to the owner EOA address (derived from AZETH_PRIVATE_KEY). ' +
        'Must be a trusted address you control — this is your recovery destination.',
      ),
    }),
  • Tool registration for 'azeth_create_account'.
    server.registerTool(
      'azeth_create_account',
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Extensive disclosure: 'Single atomic transaction' explains atomicity; lists 4 installed modules; 'permanently revokes factory access' warns security side-effect; details gasless relay mechanics (EIP-712) and testnet USDC funding; specifies return values (address, token ID, tx hash) despite no output schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well-structured with clear sections (purpose, usage, returns, guardian setup, example). Length is justified by complexity (smart contract deployment with 4 modules). Front-loaded with core action. Minor deduction for density, but no wasted sentences.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Comprehensive for a complex deployment tool: covers prerequisites (env vars AZETH_GUARDIAN_KEY, AZETH_CHAIN), side effects (proxy deployment, module installation, registry registration), gas sponsorship behavior, return values, and security defaults. Sufficient despite no annotations or output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema coverage, baseline is 3. Description adds critical semantic context: explains AZETH_GUARDIAN_KEY env var fallback for guardian param (not in schema), warns against self-guardian in production, and provides concrete JSON example showing expected capability strings and entity types.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with specific verb 'Deploy' targeting 'Azeth smart account' and 'ERC-8004 trust registry'. Clearly distinguishes from siblings like azeth_accounts (likely query) and azeth_deposit (funding) by emphasizing creation with 'guardian guardrails' and multi-module installation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit 'Use this when' clause targeting AI agents/services needing on-chain identity. Notes 'One EOA can own multiple smart accounts' for usage context. Lacks explicit 'when not to use' or direct sibling comparison, but entityType enum and description scope make boundaries clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/azeth-protocol/mcp-azeth'

If you have feedback or need assistance with the MCP directory API, please join our Discord server