Skip to main content
Glama

azeth_balance

Check ETH, USDC, and WETH balances with USD values for your EOA and Azeth smart accounts to view total portfolio value before transactions.

Instructions

Check all balances with USD values for your EOA and all Azeth smart accounts.

Use this when: You need to know how much ETH, USDC, or WETH your accounts hold, or you want a total portfolio value in USD before making a transfer or payment.

Returns: Multi-account breakdown with per-token USD values and grand total. EOA is shown first (index 0), followed by smart accounts in deployment order.

Optionally filter to a single smart account by providing its address.

Note: This is a read-only, single-RPC-call operation and safe to call repeatedly. The owner is determined by the AZETH_PRIVATE_KEY environment variable.

Example: {} or { "smartAccount": "#1" }

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").
smartAccountNoSmart account address, name, or "#N" (account index). If omitted, shows all accounts.

Implementation Reference

  • The azeth_balance handler which checks account balances and USD values, with optional filtering for smart accounts and integration with the trust registry for labels.
    server.registerTool(
      'azeth_balance',
      {
        description: [
          'Check all balances with USD values for your EOA and all Azeth smart accounts.',
          '',
          'Use this when: You need to know how much ETH, USDC, or WETH your accounts hold,',
          'or you want a total portfolio value in USD before making a transfer or payment.',
          '',
          'Returns: Multi-account breakdown with per-token USD values and grand total.',
          'EOA is shown first (index 0), followed by smart accounts in deployment order.',
          '',
          'Optionally filter to a single smart account by providing its address.',
          '',
          'Note: This is a read-only, single-RPC-call operation and safe to call repeatedly.',
          'The owner is determined by the AZETH_PRIVATE_KEY environment variable.',
          '',
          'Example: {} or { "smartAccount": "#1" }',
        ].join('\n'),
        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").'),
          smartAccount: z.string().optional().describe('Smart account address, name, or "#N" (account index). If omitted, shows all accounts.'),
        }),
      },
      async (args) => {
        let client;
        try {
          client = await createClient(args.chain);
    
          // Resolve smartAccount: address, name, "#N", or undefined
          let targetAddress: `0x${string}` | undefined;
          if (args.smartAccount) {
            try {
              targetAddress = await resolveSmartAccount(args.smartAccount, client);
            } catch (resolveErr) {
              return handleError(resolveErr);
            }
          }
    
          const allBalances = await client.getAllBalances();
    
          let accounts = allBalances.accounts;
          if (targetAddress) {
            const target = targetAddress.toLowerCase();
            accounts = accounts.filter((ab) => ab.account.toLowerCase() === target);
          }
    
          // Enrich smart account labels with names from the trust registry.
          // Skip index 0 (EOA). Non-fatal: falls back to default label on any failure.
          const chain = resolveChain(args.chain);
          const trustRegistryAddr = AZETH_CONTRACTS[chain].trustRegistryModule;
          const identityRegistryAddr = ERC8004_REGISTRY[chain];
          for (let i = 0; i < accounts.length; i++) {
            const ab = accounts[i]!;
            // EOA label is always "EOA Wallet" — skip
            if (i === 0 && !targetAddress) continue;
            try {
              const tokenId = await client.publicClient.readContract({
                address: trustRegistryAddr,
                abi: TrustRegistryModuleAbi,
                functionName: 'getTokenId',
                args: [ab.account as `0x${string}`],
              });
              if (tokenId > 0n) {
                const uri = await client.publicClient.readContract({
                  address: identityRegistryAddr,
                  abi: ERC8004_TOKEN_URI_ABI,
                  functionName: 'tokenURI',
                  args: [tokenId],
                });
                const name = parseAgentMetadata(uri).name;
                if (name !== '(unknown)') {
                  // Extract the #N index from the existing label if present
                  const indexMatch = ab.label.match(/#(\d+)/);
                  ab.label = indexMatch ? `${name} (#${indexMatch[1]})` : name;
                }
              }
            } catch {
              // Non-fatal — keep existing label
            }
          }
    
          return success({
            owner: client.address,
            grandTotalUSD: allBalances.grandTotalUSDFormatted,
            accounts: accounts.map((ab) => ({
              account: ab.account,
              label: ab.label,
              totalUSD: ab.totalUSDFormatted,
              balances: ab.balances.map((tb) => ({
                token: tb.symbol,
                balance: tb.balanceFormatted,
                usdValue: tb.usdFormatted,
              })),
            })),
          });
        } catch (err) {
          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`); }
        }
      },
    );
  • Registration of the azeth_balance tool within the registerAccountTools function.
    'azeth_balance',
Behavior5/5

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

No annotations provided, but description comprehensively covers: read-only/safety nature ('read-only, single-RPC-call operation and safe to call repeatedly'), authentication mechanism ('owner is determined by the AZETH_PRIVATE_KEY environment variable'), and return structure ('Multi-account breakdown with per-token USD values... EOA is shown first (index 0)').

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

Conciseness5/5

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

Well-structured with clear sections (action, usage context, returns, optional filtering, implementation notes, examples). Every sentence serves a distinct purpose. Front-loaded with core functionality, followed by when-to-use, then technical implementation details.

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?

Despite no output schema, description fully compensates by detailing the return format (multi-account breakdown, per-token USD values, grand total, ordering of EOA vs smart accounts). Also covers environment variable dependencies (AZETH_PRIVATE_KEY, AZETH_CHAIN) making it complete for a balance query tool.

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 valuable contextual usage guidance: 'Optionally filter to a single smart account by providing its address' explains the filtering behavior, and the examples ('{} or { "smartAccount": "#1" }') demonstrate practical usage patterns beyond raw schema definitions.

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?

Excellent specificity: 'Check all balances with USD values for your EOA and all Azeth smart accounts' provides clear verb (Check), resource (balances), scope (EOA + all smart accounts), and differentiates from siblings like azeth_transfer, azeth_pay, and azeth_deposit by focusing on portfolio reading vs execution.

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?

Strong 'Use this when' section specifies exact scenarios (checking ETH/USDC/WETH holdings, getting portfolio value 'before making a transfer or payment'). Implicitly distinguishes from execution tools by mentioning the 'before' context, though it could explicitly name sibling alternatives like 'instead of azeth_transfer'.

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