Skip to main content
Glama

azeth_get_registry_entry

Look up participant details in the trust registry using token ID or smart account address to verify registration, capabilities, and reputation scores.

Instructions

Look up a specific participant on the trust registry by token ID or smart account address.

Use this when: You know a specific agent/service address or token ID and want to see their registration details, capabilities, and reputation.

Provide EITHER tokenId OR address (at least one required). If address is provided, it is resolved to a token ID via on-chain lookup.

Returns: Full registry entry including name, description, entity type, capabilities, endpoint, and weighted reputation score.

This is read-only and safe to call at any time.

Example: { "address": "0x1234..." } or { "tokenId": "5" }

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").
tokenIdNoERC-8004 token ID of the participant to look up.
addressNoSmart account address of the participant. Resolved to tokenId on-chain.

Implementation Reference

  • The handler for the azeth_get_registry_entry tool, which resolves an address or tokenId to a registry entry, potentially falling back from a server API to on-chain metadata resolution.
    // azeth_get_registry_entry
    // ──────────────────────────────────────────────
    server.registerTool(
      'azeth_get_registry_entry',
      {
        description: [
          'Look up a specific participant on the trust registry by token ID or smart account address.',
          '',
          'Use this when: You know a specific agent/service address or token ID and want',
          'to see their registration details, capabilities, and reputation.',
          '',
          'Provide EITHER tokenId OR address (at least one required).',
          'If address is provided, it is resolved to a token ID via on-chain lookup.',
          '',
          'Returns: Full registry entry including name, description, entity type,',
          'capabilities, endpoint, and weighted reputation score.',
          '',
          'This is read-only and safe to call at any time.',
          '',
          'Example: { "address": "0x1234..." } or { "tokenId": "5" }',
        ].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").'),
          tokenId: z.string().regex(/^\d+$/).optional().describe('ERC-8004 token ID of the participant to look up.'),
          address: z.string().optional().describe('Smart account address of the participant. Resolved to tokenId on-chain.'),
        }),
      },
      async (args) => {
        try {
          if (!args.tokenId && !args.address) {
            return error('INVALID_INPUT', 'Provide at least one of "tokenId" or "address".');
          }
    
          const chainName = resolveChain(args.chain);
          const serverUrl = process.env['AZETH_SERVER_URL'] ?? 'https://api.azeth.ai';
    
          // Create a public client for on-chain reads
          const { createPublicClient, http } = await import('viem');
          const viemChain = resolveViemChain(chainName);
          const rpcUrl = process.env[RPC_ENV_KEYS[chainName]] ?? SUPPORTED_CHAINS[chainName].rpcDefault;
          const publicClient = createPublicClient({ chain: viemChain, transport: http(rpcUrl) });
    
          // Resolve tokenId from address if needed
          let tokenId: bigint;
          let resolvedAddress = args.address as `0x${string}` | undefined;
    
          if (args.tokenId) {
            tokenId = BigInt(args.tokenId);
          } else {
            // Validate address format
            if (!validateAddress(args.address!)) {
              return error('INVALID_INPUT', `Invalid address: "${args.address}". Expected 0x + 40 hex characters.`);
            }
            const addr = args.address!.trim() as `0x${string}`;
            resolvedAddress = addr;
    
            const trustRegAddr = AZETH_CONTRACTS[chainName].trustRegistryModule as `0x${string}`;
            try {
              tokenId = await publicClient.readContract({
                address: trustRegAddr,
                abi: TrustRegistryModuleAbi,
                functionName: 'getTokenId',
                args: [addr],
              }) as bigint;
            } catch {
              return error('ACCOUNT_NOT_FOUND', `Could not resolve token ID for address ${addr}. The address may not be registered.`);
            }
    
            if (tokenId === 0n) {
              return error('ACCOUNT_NOT_FOUND', `Address ${addr} is not registered on the trust registry.`);
            }
          }
    
          // Try server API first
          let entry: { tokenId: string | number; owner: string; name: string; description: string; entityType: string; capabilities: string[]; endpoint?: string; pricing?: string; catalog?: CatalogEntry[]; active: boolean } | null = null;
          let source: 'server' | 'on-chain' = 'server';
    
          try {
            const serverEntry = await getRegistryEntry(serverUrl, tokenId);
            if (serverEntry) {
              entry = serverEntry as unknown as typeof entry;
            }
          } catch {
            // Server unavailable — fall back to on-chain
          }
    
          // On-chain fallback via tokenURI
          if (!entry) {
            source = 'on-chain';
            try {
              const registryAddr = ERC8004_REGISTRY[chainName] as `0x${string}`;
              const uri = await publicClient.readContract({
                address: registryAddr,
                abi: ERC8004_TOKEN_URI_ABI,
                functionName: 'tokenURI',
                args: [tokenId],
              }) as string;
    
              const meta = parseRegistryDataURI(uri);
              if (meta) {
                // If no address was provided (lookup by tokenId), resolve owner via ownerOf
                let ownerAddress = resolvedAddress ?? '';
                if (!ownerAddress) {
                  try {
                    ownerAddress = await publicClient.readContract({
                      address: registryAddr,
                      abi: ERC721_OWNER_OF_ABI,
                      functionName: 'ownerOf',
                      args: [tokenId],
                    }) as `0x${string}`;
                  } catch { /* owner resolution failed — leave empty */ }
                }
                entry = {
                  tokenId: tokenId.toString(),
                  owner: ownerAddress,
                  name: meta.name,
                  description: meta.description,
                  entityType: meta.entityType,
                  capabilities: meta.capabilities,
                  endpoint: meta.endpoint,
                  pricing: meta.pricing,
                  catalog: meta.catalog,
                  active: true,
                };
              }
            } catch {
              return error('ACCOUNT_NOT_FOUND', `Token ID ${tokenId} not found on the trust registry.`);
            }
          }
    
          if (!entry) {
            return error('ACCOUNT_NOT_FOUND', `No registry entry found for token ID ${tokenId}.`);
          }
    
          // Overlay per-key metadata updates (from setMetadata) onto the base entry.
          // This ensures fields updated via azeth_update_service are reflected in reads.
          const registryAddr = ERC8004_REGISTRY[chainName] as `0x${string}`;
          await overlayMetadataUpdates(publicClient as any, registryAddr, tokenId, entry as Record<string, unknown>);
    
          // Optional reputation enrichment
          let reputation: { weightedValue: string; weightedValueFormatted: string; totalWeight: string; totalWeightFormatted: string; opinionCount: string } = { weightedValue: '0', weightedValueFormatted: '0', totalWeight: '0', totalWeightFormatted: '0', opinionCount: '0' };
          try {
            const repModuleAddr = AZETH_CONTRACTS[chainName].reputationModule;
            if (repModuleAddr) {
              const rep = await publicClient.readContract({
                address: repModuleAddr,
                abi: ReputationModuleAbi,
                functionName: 'getWeightedReputationAll',
                args: [tokenId],
              }) as readonly [bigint, bigint, bigint];
              const [wv, tw, oc] = rep;
              // Format weighted value using same heuristic as reputation.ts
              const absValue = wv < 0n ? -wv : wv;
              const isHighPrecision = absValue > 10n ** 15n;
              const weightedValueFormatted = isHighPrecision
                ? formatTokenAmount(wv, 18, 4)
                : wv.toString();
              // Format totalWeight as USD with adaptive precision
              const totalWeightFormatted = formatTokenAmount(tw, 12, 2);
              reputation = {
                weightedValue: wv.toString(),
                weightedValueFormatted,
                totalWeight: tw.toString(),
                totalWeightFormatted,
                opinionCount: oc.toString(),
              };
            }
          } catch { /* reputation not available — default zeros used */ }
    
          return success({
            tokenId: tokenId.toString(),
            address: entry.owner || resolvedAddress || null,
            name: entry.name,
            description: entry.description,
            entityType: entry.entityType,
            capabilities: entry.capabilities,
            endpoint: entry.endpoint ?? null,
            pricing: entry.pricing ?? null,
            catalog: entry.catalog ?? null,
            active: entry.active,
            reputation,
            source,
          });
        } catch (err) {
          return handleError(err);
        }
      },
    );
  • Registration of the azeth_get_registry_entry tool within the registry tools module.
    /** Register trust registry MCP tools: azeth_publish_service, azeth_discover_services, azeth_get_registry_entry, azeth_update_service */
    export function registerRegistryTools(server: McpServer): void {
Behavior4/5

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

Good: No annotations provided, so description carries full burden. Discloses 'read-only and safe', on-chain resolution behavior for addresses, and detailed return structure (name, capabilities, reputation score). Missing error behavior or rate limit disclosures.

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?

Excellent: Well-structured with clear logical sections (Purpose, Usage, Input guidance, Returns, Safety, Example). Front-loaded with core purpose. No redundant text; every sentence adds unique value beyond the schema.

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

Completeness4/5

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

Strong for complexity level: No output schema exists, but description compensates by documenting all return fields. Covers all 3 parameters with chain aliases noted. Would benefit from error case documentation (e.g., 'not found' handling).

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?

Strong: Schema coverage is 100%, but description adds critical semantic constraints beyond schema—the XOR requirement ('Provide EITHER...') and address resolution logic. Includes concrete JSON examples that clarify expected formats.

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: States specific verb 'Look up' + resource 'participant on the trust registry' + exact identifiers 'token ID or smart account address'. Clearly distinguishes from sibling discovery tools by emphasizing 'specific participant' lookup vs broad discovery.

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: Contains explicit 'Use this when' clause defining the specific scenario (known address/token ID seeking details). States parameter constraint 'EITHER...OR (at least one required)'. Lacks explicit 'when not to use' or named alternative siblings (e.g., vs discover_services).

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