Skip to main content
Glama

get_nep11_transfers

Retrieve NEP-11 non-fungible token transfer records for a given Neo N3 address, with optional time range filters and network selection.

Instructions

Get NEP-11 transfer history for an address.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
addressYesNeo N3 address
fromTimestampMsNoOptional start timestamp in Unix epoch milliseconds
toTimestampMsNoOptional end timestamp in Unix epoch milliseconds
networkNoNetwork to use: "mainnet" or "testnet"

Implementation Reference

  • src/index.ts:388-406 (registration)
    Registration of the 'get_nep11_transfers' tool using the MCP server's registerTool method. Defines the tool name, description, Zod input schema (address required, optional fromTimestampMs, toTimestampMs, network), and a handler lambda that calls callTool().
    registerTool(
      'get_nep11_transfers',
      'Get NEP-11 transfer history for an address.',
      {
        address: z.string().describe('Neo N3 address'),
        fromTimestampMs: z.number().int().nonnegative().optional().describe('Optional start timestamp in Unix epoch milliseconds'),
        toTimestampMs: z.number().int().nonnegative().optional().describe('Optional end timestamp in Unix epoch milliseconds'),
        network: z.string().optional().describe('Network to use: "mainnet" or "testnet"'),
      },
      async (args) => {
        try {
          await this.ensureServicesInitialized();
          const result = await callTool('get_nep11_transfers', args, this.neoServices, this.contractServices);
          return this.formatDelegatedToolResponse(result);
        } catch (error: unknown) {
          return this.createErrorResponse(error);
        }
      }
    );
  • Handler function handleGetNep11Transfers - validates address, parses optional timestamp filters, calls neoService.getNep11Transfers(), and returns success response.
    async function handleGetNep11Transfers(input: Record<string, unknown>, neoService: NeoService): Promise<unknown> {
      try {
        validateAddress(input.address as string);
        const fromTimestampMs = input.fromTimestampMs !== undefined ? validateInteger(input.fromTimestampMs as string | number) : undefined;
        const toTimestampMs = input.toTimestampMs !== undefined ? validateInteger(input.toTimestampMs as string | number) : undefined;
    
        if (fromTimestampMs !== undefined && toTimestampMs !== undefined && fromTimestampMs > toTimestampMs) {
          throw new McpError(ErrorCode.InvalidParams, 'fromTimestampMs must be less than or equal to toTimestampMs.');
        }
    
        const result = await neoService.getNep11Transfers(input.address as string, {
          ...(fromTimestampMs !== undefined ? { fromTimestampMs } : {}),
          ...(toTimestampMs !== undefined ? { toTimestampMs } : {}),
        });
        return createSuccessResponse(result);
      } catch (error) {
        return handleError(error);
      }
    }
  • JSON Schema definition for 'get_nep11_transfers' in the tool setup: describes address (string, required), fromTimestampMs, toTimestampMs, and network fields.
    {
      name: 'get_nep11_transfers',
      description: 'Get NEP-11 transfer history for an address with additive asset and party enrichment when available',
      inputSchema: {
        type: 'object',
        properties: {
          address: {
            type: 'string',
            description: 'Neo N3 address',
          },
          fromTimestampMs: {
            type: 'integer',
            description: 'Optional start of the transfer history window, in Unix epoch milliseconds.',
          },
          toTimestampMs: {
            type: 'integer',
            description: 'Optional end of the transfer history window, in Unix epoch milliseconds.',
          },
          network: {
            type: 'string',
            description: 'Optional: Network to use ("mainnet" or "testnet"). Defaults based on config.',
            enum: [NeoNetwork.MAINNET, NeoNetwork.TESTNET],
          },
        },
        required: ['address'],
      },
  • Service-layer implementation of getNep11Transfers - validates inputs, builds RPC params (with optional timestamp filters), executes the 'getnep11transfers' RPC call, then enriches the response via enrichNep11Transfers().
    async getNep11Transfers(
      address: string,
      options: {
        fromTimestampMs?: number,
        toTimestampMs?: number,
      } = {}
    ) {
      try {
        if (!address || typeof address !== 'string') {
          throw new Error('Invalid address format');
        }
    
        if (options.fromTimestampMs !== undefined && (!Number.isInteger(options.fromTimestampMs) || options.fromTimestampMs < 0)) {
          throw new Error(`Invalid fromTimestampMs: ${options.fromTimestampMs}`);
        }
    
        if (options.toTimestampMs !== undefined && (!Number.isInteger(options.toTimestampMs) || options.toTimestampMs < 0)) {
          throw new Error(`Invalid toTimestampMs: ${options.toTimestampMs}`);
        }
    
        if (options.fromTimestampMs !== undefined && options.toTimestampMs !== undefined && options.fromTimestampMs > options.toTimestampMs) {
          throw new Error('fromTimestampMs must be less than or equal to toTimestampMs');
        }
    
        const params: Array<string | number> = [address];
        if (options.fromTimestampMs !== undefined) {
          params.push(options.fromTimestampMs);
        }
        if (options.toTimestampMs !== undefined) {
          if (options.fromTimestampMs === undefined) {
            params.push(0);
          }
          params.push(options.toTimestampMs);
        }
    
        const transfers = await this.rpcClient.execute(new neonJs.rpc.Query({
          method: 'getnep11transfers',
          params,
        }));
    
        return this.enrichNep11Transfers(transfers as Nep11TransfersResponse, address);
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : 'Unknown error';
        throw new Error(`Failed to get NEP-11 transfers for address ${address}: ${errorMessage}`);
      }
    }
  • Helper enrichNep11Transfers() - enriches sent/received transfer arrays by mapping each entry through buildTransferHistoryEntry(), adding direction, timestampIso, asset, from/to parties and counterparty info.
    private enrichNep11Transfers(transfers: Nep11TransfersResponse, accountAddress: string) {
      if (!transfers || typeof transfers !== 'object') {
        return transfers;
      }
    
      return {
        ...transfers,
        sent: Array.isArray(transfers.sent)
          ? transfers.sent.map((entry: Nep17TransferEntry) => this.buildTransferHistoryEntry(entry, accountAddress, 'sent'))
          : transfers.sent,
        received: Array.isArray(transfers.received)
          ? transfers.received.map((entry: Nep17TransferEntry) => this.buildTransferHistoryEntry(entry, accountAddress, 'received'))
          : transfers.received,
      };
    }
Behavior2/5

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

No annotations exist, so the description must disclose behavioral traits. It only states a read operation ('Get'), but fails to mention pagination, rate limits, response size, or error conditions. This is insufficient for an agent to anticipate side effects or constraints.

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?

The description is a single, concise sentence that front-loads the purpose. It wastes no words, though it could be more informative without sacrificing brevity.

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

Completeness2/5

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

Given the lack of annotations and output schema, the description should elaborate on return format, pagination, and edge cases (e.g., empty history). It only states the basic function, leaving significant gaps for an agent.

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 description coverage is 100%, so each parameter already has a description in the schema. The tool description adds no extra meaning or context for parameters beyond 'transfer history'. Baseline 3 is appropriate as no additional value is provided.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool retrieves NEP-11 transfer history for an address. The verb 'Get' and resource 'NEP-11 transfer history' are specific. However, it does not explicitly differentiate from the sibling tool get_nep17_transfers, although the token standard is distinct in the name.

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

Usage Guidelines2/5

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

No guidance is provided on when to use this tool versus alternatives like get_nep17_transfers or get_nep11_balances. The description lacks context on prerequisites, typical use cases, or exclusions.

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/r3e-network/neo-n3-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server