Skip to main content
Glama

azeth_send_message

Send encrypted messages to other participants using the XMTP messaging network for secure communication between agents and services.

Instructions

Send an encrypted message to another participant via the XMTP messaging network.

Use this when: You need to communicate with another agent or service using end-to-end encrypted messaging. The recipient must be reachable on the XMTP network (use azeth_check_reachability first if unsure).

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

Returns: The conversation ID and recipient address confirming delivery.

Note: This is NOT idempotent — each call sends a new message. The sender account is determined by the AZETH_PRIVATE_KEY environment variable. Messages are limited to 10,000 characters.

Example: { "to": "Alice", "content": "Hello, I would like to use your price-feed service." }

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").
toYesRecipient: Ethereum address, participant name, "me", or "#N" (account index).
contentYesMessage text content (1-10,000 characters).
contentTypeNoContent type hint. Defaults to "text/plain".

Implementation Reference

  • The handler logic for 'azeth_send_message' which resolves the recipient address and sends a message using the XMTP client.
    async (args) => {
      let client;
      try {
        client = await createClient(args.chain);
    
        // Resolve "to": address, name, "me", "#N"
        let toResolved;
        try {
          toResolved = await resolveAddress(args.to, client);
        } catch (resolveErr) {
          return handleError(resolveErr);
        }
    
        const conversationId = await client.sendMessage({
          to: toResolved.address,
          content: args.content,
          contentType: args.contentType,
        });
    
        return success({
          conversationId,
          to: toResolved.address,
          ...(toResolved.resolvedFrom ? { resolvedTo: `"${toResolved.resolvedFrom}" → ${toResolved.address}` } : {}),
          sent: true,
        });
      } catch (err) {
        return handleError(err);
      } finally {
        try { await client?.destroy(); } catch { /* M-10: prevent destroy from masking the original error */ }
      }
    },
  • The registration block for 'azeth_send_message' which includes the schema validation.
    server.registerTool(
      'azeth_send_message',
      {
        description: [
          'Send an encrypted message to another participant via the XMTP messaging network.',
          '',
          'Use this when: You need to communicate with another agent or service using end-to-end encrypted messaging.',
          'The recipient must be reachable on the XMTP network (use azeth_check_reachability first if unsure).',
          '',
          'The "to" field accepts: an Ethereum address, a participant name, "me", or "#N" (account index).',
          '',
          'Returns: The conversation ID and recipient address confirming delivery.',
          '',
          'Note: This is NOT idempotent — each call sends a new message. The sender account is determined',
          'by the AZETH_PRIVATE_KEY environment variable. Messages are limited to 10,000 characters.',
          '',
          'Example: { "to": "Alice", "content": "Hello, I would like to use your price-feed service." }',
        ].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").'),
          to: z.string().describe('Recipient: Ethereum address, participant name, "me", or "#N" (account index).'),
          content: z.string().min(1).max(10_000).describe('Message text content (1-10,000 characters).'),
          contentType: z.string().max(100).optional().describe('Content type hint. Defaults to "text/plain".'),
        }),
      },
      async (args) => {
        let client;
        try {
          client = await createClient(args.chain);
    
          // Resolve "to": address, name, "me", "#N"
          let toResolved;
          try {
            toResolved = await resolveAddress(args.to, client);
          } catch (resolveErr) {
            return handleError(resolveErr);
          }
    
          const conversationId = await client.sendMessage({
            to: toResolved.address,
            content: args.content,
            contentType: args.contentType,
          });
    
          return success({
            conversationId,
            to: toResolved.address,
            ...(toResolved.resolvedFrom ? { resolvedTo: `"${toResolved.resolvedFrom}" → ${toResolved.address}` } : {}),
            sent: true,
          });
        } catch (err) {
          return handleError(err);
        } finally {
          try { await client?.destroy(); } catch { /* M-10: prevent destroy from masking the original error */ }
        }
      },
    );
Behavior4/5

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

With no annotations provided, description bears full disclosure burden. It successfully documents idempotency ('NOT idempotent'), authentication source ('AZETH_PRIVATE_KEY environment variable'), size limits ('10,000 characters'), and return values ('conversation ID and recipient address'). Only misses error handling or rate limiting details.

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 condition, Prerequisites, Return values, and Important notes. Front-loaded with the core action. Slightly verbose but justified given complexity (4 parameters, encryption context, prerequisites) and absence of annotations.

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 messaging tool with no output schema and no annotations. Covers prerequisites (reachability), behavioral constraints (idempotency, length limits), authentication method, and return structure. No significant gaps given the tool's scope.

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?

Schema coverage is 100%, establishing baseline 3. Description adds value by consolidating the 'to' field syntax options into narrative context ('accepts: an Ethereum address...') and providing a concrete JSON example showing parameter 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?

States specific action ('Send an encrypted message'), target resource ('participant'), and network ('XMTP'). Clearly distinguishes from sibling 'azeth_receive_messages' by directionality and 'azeth_check_reachability' by being the actual messaging action versus a prerequisite check.

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?

Provides explicit 'Use this when' clause defining the communications use case. Names specific prerequisite tool ('azeth_check_reachability first if unsure') for recipient verification, clearly delineating the workflow sequence.

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