Skip to main content
Glama

azeth_discover_agent_capabilities

Discover services, pricing, and usage instructions from other agents by sending a capabilities request over XMTP before making service requests or payments.

Instructions

Discover what services an agent offers by sending them a capabilities request over XMTP.

Use this when: You want to find out what services another agent provides, their pricing, and how to use them — before making a service request or payment.

Sends a JSON capabilities request to the target agent and waits for their response. The target agent must be online and have a MessageRouter configured to respond.

The "agentAddress" field accepts: an Ethereum address, a participant name, "me", or "#N" (account index).

Returns: The agent's capabilities including services, pricing, and usage instructions. If no response within the timeout, returns an error indicating the agent may be offline.

Example: { "agentAddress": "0x1234567890abcdef1234567890abcdef12345678" }

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").
agentAddressYesTarget agent: Ethereum address, participant name, "me", or "#N" (account index).
timeoutMsNoTimeout in milliseconds to wait for response. Defaults to 15000 (15 seconds). Max 60000.

Implementation Reference

  • The handler logic for 'azeth_discover_agent_capabilities' which sends a capability request via XMTP and polls for a response.
      async (args) => {
        let client;
        try {
          client = await createClient(args.chain);
          const timeoutMs = args.timeoutMs ?? 15_000;
    
          // Resolve target address
          let resolved;
          try {
            resolved = await resolveAddress(args.agentAddress, client);
          } catch (resolveErr) {
            return handleError(resolveErr);
          }
    
          // Send capabilities request
          const capabilitiesRequest = JSON.stringify({ type: 'capabilities' });
          await client.sendMessage({
            to: resolved.address,
            content: capabilitiesRequest,
          });
    
          // Poll for response within timeout
          const startTime = Date.now();
          const pollIntervalMs = 2_000;
    
          while (Date.now() - startTime < timeoutMs) {
            // Wait before polling
            await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
    
            const messages = await client.getMessages(resolved.address, 5);
            if (messages.length > 0) {
              // Look for a capabilities response among recent messages
              for (const msg of messages) {
                // Skip messages older than our request
                if (msg.timestamp < startTime) continue;
    
                try {
                  const parsed: unknown = JSON.parse(msg.content);
                  if (
                    typeof parsed === 'object' &&
                    parsed !== null &&
                    'type' in parsed &&
                    (parsed as { type: string }).type === 'capabilities'
                  ) {
                    return success({
                      agentAddress: resolved.address,
                      ...(resolved.resolvedFrom ? { resolvedFrom: `"${resolved.resolvedFrom}" → ${resolved.address}` } : {}),
                      capabilities: parsed,
                    });
                  }
                } catch {
                  // Not valid JSON — skip
                }
              }
            }
          }
    
          // Timeout — no response received
          return error(
            'NETWORK_ERROR',
            `No capabilities response received from ${resolved.address} within ${timeoutMs}ms. ` +
            'The agent may be offline or does not have a MessageRouter configured.',
          );
        } catch (err) {
          return handleError(err);
        } finally {
          try { await client?.destroy(); } catch { /* M-10: prevent destroy from masking the original error */ }
        }
      },
    );
  • Zod schema defining the input for 'azeth_discover_agent_capabilities'.
    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").'),
      agentAddress: z.string().describe('Target agent: Ethereum address, participant name, "me", or "#N" (account index).'),
      timeoutMs: z.coerce.number().int().min(1000).max(60_000).optional().describe('Timeout in milliseconds to wait for response. Defaults to 15000 (15 seconds). Max 60000.'),
    }),
  • Registration of the 'azeth_discover_agent_capabilities' tool within the MCP server.
    server.registerTool(
      'azeth_discover_agent_capabilities',
      {
        description: [
          'Discover what services an agent offers by sending them a capabilities request over XMTP.',
          '',
          'Use this when: You want to find out what services another agent provides, their pricing,',
          'and how to use them — before making a service request or payment.',
          '',
          'Sends a JSON capabilities request to the target agent and waits for their response.',
          'The target agent must be online and have a MessageRouter configured to respond.',
          '',
          'The "agentAddress" field accepts: an Ethereum address, a participant name, "me", or "#N" (account index).',
          '',
          'Returns: The agent\'s capabilities including services, pricing, and usage instructions.',
          'If no response within the timeout, returns an error indicating the agent may be offline.',
          '',
          'Example: { "agentAddress": "0x1234567890abcdef1234567890abcdef12345678" }',
        ].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").'),
          agentAddress: z.string().describe('Target agent: Ethereum address, participant name, "me", or "#N" (account index).'),
          timeoutMs: z.coerce.number().int().min(1000).max(60_000).optional().describe('Timeout in milliseconds to wait for response. Defaults to 15000 (15 seconds). Max 60000.'),
        }),
      },
Behavior4/5

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

With no annotations provided, the description carries full disclosure burden. It effectively covers prerequisites ('target agent must be online and have a MessageRouter'), protocol details ('Sends a JSON capabilities request'), synchronous behavior ('waits for their response'), and failure modes ('If no response within the timeout').

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: purpose (sentence 1), usage guidelines (sentence 2), behavioral details (sentences 3-4), parameter notes (sentence 5), return values (sentence 6), and example (sentence 7). Every sentence earns its place with zero redundancy.

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?

For a 3-parameter tool with no annotations or output schema, the description is comprehensive. It explains return values ('capabilities including services, pricing, and usage instructions'), timeout behavior, and prerequisites that would otherwise be unknown.

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

Parameters3/5

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

Schema coverage is 100%, establishing a baseline of 3. The description duplicates the agentAddress format documentation from the schema and includes a helpful JSON example, but does not add significant semantic value beyond the well-documented schema.

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?

The description leads with a specific action ('Discover what services an agent offers') and mechanism ('sending them a capabilities request over XMTP'), distinguishing it from sibling tool 'azeth_discover_services' (which likely queries the registry) by emphasizing direct agent-to-agent communication.

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

Usage Guidelines5/5

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

Explicit 'Use this when' pattern clearly defines the context (finding services/pricing) and positions the tool relative to alternatives ('before making a service request or payment'), implying when to use payment/agreement tools instead.

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