Skip to main content
Glama

azeth_receive_messages

Read encrypted XMTP messages from other agents or services. Check specific conversations or get an inbox overview of latest messages.

Instructions

Read incoming encrypted messages from the XMTP messaging network.

Use this when: You want to check for messages from other agents or services. This is the "inbox" view — it lets you read what others have sent you.

Two modes:

  1. With "from": Read messages from a specific sender (up to "limit" messages)

  2. Without "from": Read the latest message from each conversation (inbox overview)

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

Returns: Array of messages with sender address, content, timestamp, and conversation ID.

Note: XMTP messages are end-to-end encrypted. The account reading messages is determined by the AZETH_PRIVATE_KEY environment variable. First call may be slow due to XMTP initialization.

Example: { "from": "Alice", "limit": 10 } or { } (all conversations)

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").
fromNoRead messages from a specific sender. Accepts: address, name, "me", "#N". Omit for inbox overview.
limitNoMaximum messages to return. Defaults to 20. Max 100.

Implementation Reference

  • The handler implementation for azeth_receive_messages. It supports two modes: retrieving messages from a specific sender or providing an inbox overview with the latest message per conversation.
      async (args) => {
        let client;
        try {
          client = await createClient(args.chain);
          const limit = args.limit ?? 20;
    
          if (args.from) {
            // Mode 1: Messages from specific sender
            let fromResolved;
            try {
              fromResolved = await resolveAddress(args.from, client);
            } catch (resolveErr) {
              return handleError(resolveErr);
            }
    
            const messages = await client.getMessages(fromResolved.address, limit);
    
            return success({
              from: fromResolved.address,
              ...(fromResolved.resolvedFrom ? { resolvedFrom: `"${fromResolved.resolvedFrom}" → ${fromResolved.address}` } : {}),
              messageCount: messages.length,
              messages: messages.map(msg => ({
                sender: msg.sender,
                content: msg.content,
                timestamp: new Date(msg.timestamp).toISOString(),
                conversationId: msg.conversationId,
              })),
            });
          } else {
            // Mode 2: Inbox overview — latest message per conversation
            const conversations = await client.getConversations();
    
            // For each conversation, get the latest message
            const inbox = [];
            for (const conv of conversations.slice(0, limit)) {
              try {
                const messages = await client.getMessages(conv.peerAddress, 1);
                inbox.push({
                  conversationId: conv.id,
                  peerAddress: conv.peerAddress,
                  createdAt: new Date(conv.createdAt).toISOString(),
                  latestMessage: messages.length > 0 ? {
                    content: messages[0]!.content,
                    sender: messages[0]!.sender,
                    timestamp: new Date(messages[0]!.timestamp).toISOString(),
                  } : null,
                });
              } catch {
                // Skip conversations that fail to load
                inbox.push({
                  conversationId: conv.id,
                  peerAddress: conv.peerAddress,
                  createdAt: new Date(conv.createdAt).toISOString(),
                  latestMessage: null,
                });
              }
            }
    
            return success({
              conversationCount: conversations.length,
              showing: inbox.length,
              inbox,
            });
          }
        } catch (err) {
          return handleError(err);
        } finally {
          try { await client?.destroy(); } catch { /* M-10: prevent destroy from masking the original error */ }
        }
      },
    );
  • The input schema validation for azeth_receive_messages using Zod.
      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").'),
        from: z.string().optional().describe('Read messages from a specific sender. Accepts: address, name, "me", "#N". Omit for inbox overview.'),
        limit: z.coerce.number().int().min(1).max(100).optional().describe('Maximum messages to return. Defaults to 20. Max 100.'),
      }),
    },
  • Registration of the azeth_receive_messages tool within the MCP server.
    server.registerTool(
      'azeth_receive_messages',
Behavior4/5

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

No annotations provided, so description carries full disclosure burden. It successfully documents: end-to-end encryption nature, account determination via AZETH_PRIVATE_KEY environment variable, initialization latency on first call, and dual behavioral modes. Missing rate limits or caching details, but covers critical runtime characteristics well.

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 trigger, behavioral modes, return values, implementation notes, and examples. Front-loaded with essential information. Slightly verbose but information-dense; the mode differentiation and return structure documentation justify the length given no output schema exists.

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?

Excellent compensation for missing annotations and output schema. Describes return structure (array with sender, content, timestamp, conversation ID), encryption characteristics, environment variable dependencies, and performance characteristics. Covers all 3 parameters conceptually and provides concrete usage examples. Complete for a message retrieval 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?

Schema has 100% coverage (baseline 3). Description adds value by explaining the interaction model between parameters—the 'Two modes' section clarifies that omitting 'from' triggers inbox overview behavior while including it enables specific sender filtering with limit application. Examples demonstrate valid parameter combinations.

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?

Description opens with specific verb 'Read' and resource 'incoming encrypted messages from the XMTP messaging network.' It clearly distinguishes from sibling azeth_send_message by describing this as the 'inbox view' for reading what others sent you, versus sending.

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?

Provides explicit 'Use this when' guidance for checking messages from other agents. Documents two distinct usage modes (with/without 'from' parameter) that clarify behavioral alternatives. Lacks explicit 'when not to use' or comparison to azeth_list_conversations, but the 'inbox' framing provides clear contextual boundaries.

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