Skip to main content
Glama

read_contract

Read-onlyIdempotent

Query smart contract data by calling read-only functions to retrieve state information, with automatic ABI fetching from block explorers.

Instructions

Call read-only functions on a smart contract. Automatically fetches ABI from block explorer if not provided (requires ETHERSCAN_API_KEY). Falls back to common functions if contract is not verified. Use this to query contract state and data.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
contractAddressYesThe contract address
functionNameYesFunction name (e.g., 'name', 'symbol', 'balanceOf', 'totalSupply', 'owner')
argsNoFunction arguments as strings (e.g., ['0xAddress'] for balanceOf)
abiJsonNoFull contract ABI as JSON string (optional - will auto-fetch verified contract ABI if not provided)
networkNoNetwork name or chain ID. Defaults to Ethereum mainnet.

Implementation Reference

  • The handler function that implements the core logic of the 'read_contract' tool. It parses the ABI if necessary, constructs ReadContractParameters, calls the underlying readContract helper, formats the result using helpers.formatJson, and handles errors appropriately.
        abi,
        functionName,
        args = [],
        network = 'ethereum'
      }) => {
        try {
          // Parse ABI if it's a string
          const parsedAbi = typeof abi === 'string' ? JSON.parse(abi) : abi;
    
          const params = {
            address: contractAddress as Address,
            abi: parsedAbi,
            functionName,
            args
          };
    
          const result = await services.readContract(params, network);
    
          return {
            content: [
              {
                type: 'text',
                text: services.helpers.formatJson(result)
              }
            ]
          };
        } catch (error) {
          return {
            content: [
              {
                type: 'text',
                text: `Error reading contract: ${error instanceof Error ? error.message : String(error)}`
              }
            ],
            isError: true
          };
        }
      }
    );
  • Zod schema defining the input parameters for the 'read_contract' tool, including contractAddress, abi (JSON array), functionName, optional args array, and optional network.
        .string()
        .describe('The address of the smart contract to interact with'),
      abi: z
        .array(z.any())
        .describe(
          'The ABI (Application Binary Interface) of the smart contract function, as a JSON array'
        ),
      functionName: z
        .string()
        .describe(
          "The name of the function to call on the contract (e.g., 'balanceOf')"
        ),
      args: z
        .array(z.any())
        .optional()
        .describe(
          "The arguments to pass to the function, as an array (e.g., ['0x1234...'])"
        ),
      network: z
        .string()
        .optional()
        .describe(
          "Network name (e.g., 'ethereum', 'optimism', 'arbitrum', 'base', 'polygon') or chain ID. Defaults to Ethereum mainnet."
        )
    },
    async ({
      contractAddress,
  • Registration of the 'read_contract' MCP tool using server.tool(), providing name, description, input schema, and handler function.
      "Read data from a smart contract by calling a view/pure function. This doesn't modify blockchain state and doesn't require gas or signing.",
      {
        contractAddress: z
          .string()
          .describe('The address of the smart contract to interact with'),
        abi: z
          .array(z.any())
          .describe(
            'The ABI (Application Binary Interface) of the smart contract function, as a JSON array'
          ),
        functionName: z
          .string()
          .describe(
            "The name of the function to call on the contract (e.g., 'balanceOf')"
          ),
        args: z
          .array(z.any())
          .optional()
          .describe(
            "The arguments to pass to the function, as an array (e.g., ['0x1234...'])"
          ),
        network: z
          .string()
          .optional()
          .describe(
            "Network name (e.g., 'ethereum', 'optimism', 'arbitrum', 'base', 'polygon') or chain ID. Defaults to Ethereum mainnet."
          )
      },
      async ({
        contractAddress,
        abi,
        functionName,
        args = [],
        network = 'ethereum'
      }) => {
        try {
          // Parse ABI if it's a string
          const parsedAbi = typeof abi === 'string' ? JSON.parse(abi) : abi;
    
          const params = {
            address: contractAddress as Address,
            abi: parsedAbi,
            functionName,
            args
          };
    
          const result = await services.readContract(params, network);
    
          return {
            content: [
              {
                type: 'text',
                text: services.helpers.formatJson(result)
              }
            ]
          };
        } catch (error) {
          return {
            content: [
              {
                type: 'text',
                text: `Error reading contract: ${error instanceof Error ? error.message : String(error)}`
              }
            ],
            isError: true
          };
        }
      }
    );
    
    // Write to contract
  • Helper function re-exported from services that performs the actual contract read using viem's publicClient.readContract. Called by the tool handler.
    export async function readContract(
      params: ReadContractParameters,
      network = 'ethereum'
    ) {
      const client = getPublicClient(network);
      return await client.readContract(params);
    }
Behavior4/5

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

Annotations already provide readOnlyHint=true, idempotentHint=true, and destructiveHint=false. The description adds valuable behavioral context beyond annotations: automatic ABI fetching with fallback mechanisms, API key requirement, and network defaults. No contradictions with annotations.

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?

Three sentences with zero waste: first states core purpose, second explains ABI fetching behavior, third provides usage guidance. Front-loaded with essential information, appropriately sized for the tool's complexity.

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?

Given the tool's moderate complexity, rich annotations, and 100% schema coverage, the description is mostly complete. It explains the tool's behavior, usage context, and prerequisites. The main gap is lack of output format details (no output schema), but annotations provide safety context.

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 parameters are well-documented in the schema. The description adds minimal semantic context (e.g., 'falls back to common functions'), but doesn't significantly enhance understanding beyond what the schema provides. Baseline 3 is appropriate.

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 clearly states the tool's purpose with specific verbs ('call read-only functions', 'query contract state and data') and distinguishes it from siblings by emphasizing its read-only nature for smart contracts, unlike write_contract or transfer tools.

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?

Explicitly states when to use this tool ('to query contract state and data') and distinguishes it from alternatives by specifying it's for read-only functions, unlike write_contract which is for write operations. Also mentions prerequisites (ETHERSCAN_API_KEY for auto-fetching).

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/chulanpro5/evm-mcp-server'

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