Skip to main content
Glama

write_contract

Destructive

Execute state-changing smart contract functions like minting, swapping, or staking by automatically fetching contract ABIs and handling transaction execution with wallet integration.

Instructions

Execute state-changing functions on a smart contract. Automatically fetches ABI from block explorer if not provided (requires ETHERSCAN_API_KEY). Use this to call any write function on verified contracts. Requires wallet to be configured (via private key or mnemonic).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
contractAddressYesThe contract address
functionNameYesFunction name to call (e.g., 'mint', 'swap', 'stake', 'approve')
argsNoFunction arguments as strings (e.g., ['0xAddress', '1000000'])
valueNoETH value to send with transaction in ether (e.g., '0.1' for payable functions)
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 for the 'write_contract' tool. It processes inputs, parses ABI if necessary, constructs contract parameters, calls the underlying writeContract service, and returns a formatted response with the transaction hash or error details.
      contractAddress,
      abi,
      functionName,
      args,
      privateKey,
      network = 'ethereum'
    }) => {
      try {
        // Parse ABI if it's a string
        const parsedAbi = typeof abi === 'string' ? JSON.parse(abi) : abi;
    
        const contractParams: Record<string, any> = {
          address: contractAddress as Address,
          abi: parsedAbi,
          functionName,
          args
        };
    
        const txHash = await services.writeContract(
          privateKey as Hex,
          contractParams,
          network
        );
    
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify(
                {
                  network,
                  transactionHash: txHash,
                  message: 'Contract write transaction sent successfully'
                },
                null,
                2
              )
            }
          ]
        };
      } catch (error) {
        return {
          content: [
            {
              type: 'text',
              text: `Error writing to contract: ${error instanceof Error ? error.message : String(error)}`
            }
          ],
          isError: true
        };
      }
    }
  • Zod schema defining the input parameters for the write_contract tool: contractAddress, abi, functionName, args, privateKey, and optional network.
      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., 'transfer')"
        ),
      args: z
        .array(z.any())
        .describe(
          "The arguments to pass to the function, as an array (e.g., ['0x1234...', '1000000000000000000'])"
        ),
      privateKey: z
        .string()
        .describe(
          'Private key of the sending account in hex format (with or without 0x prefix). SECURITY: This is used only for transaction signing and is not stored.'
        ),
      network: z
        .string()
        .optional()
        .describe(
          "Network name (e.g., 'ethereum', 'optimism', 'arbitrum', 'base', 'polygon') or chain ID. Defaults to Ethereum mainnet."
        )
    },
  • The server.tool call that registers the 'write_contract' tool with the MCP server, providing name, description, input schema, and handler function.
      'write_contract',
      'Write data to a smart contract by calling a state-changing function. This modifies blockchain state and requires gas payment and transaction 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., 'transfer')"
          ),
        args: z
          .array(z.any())
          .describe(
            "The arguments to pass to the function, as an array (e.g., ['0x1234...', '1000000000000000000'])"
          ),
        privateKey: z
          .string()
          .describe(
            'Private key of the sending account in hex format (with or without 0x prefix). SECURITY: This is used only for transaction signing and is not stored.'
          ),
        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,
        privateKey,
        network = 'ethereum'
      }) => {
        try {
          // Parse ABI if it's a string
          const parsedAbi = typeof abi === 'string' ? JSON.parse(abi) : abi;
    
          const contractParams: Record<string, any> = {
            address: contractAddress as Address,
            abi: parsedAbi,
            functionName,
            args
          };
    
          const txHash = await services.writeContract(
            privateKey as Hex,
            contractParams,
            network
          );
    
          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify(
                  {
                    network,
                    transactionHash: txHash,
                    message: 'Contract write transaction sent successfully'
                  },
                  null,
                  2
                )
              }
            ]
          };
        } catch (error) {
          return {
            content: [
              {
                type: 'text',
                text: `Error writing to contract: ${error instanceof Error ? error.message : String(error)}`
              }
            ],
            isError: true
          };
        }
      }
    );
  • Supporting helper function that creates a wallet client from the provided private key and network, then invokes viem's writeContract method to execute the contract interaction.
    export async function writeContract(
      privateKey: Hex,
      params: Record<string, any>,
      network = 'ethereum'
    ): Promise<Hash> {
      const client = getWalletClient(privateKey, network);
      return await client.writeContract(params as any);
    }
Behavior4/5

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

The description adds valuable behavioral context beyond annotations: it discloses the automatic ABI fetching capability (with ETHERSCAN_API_KEY requirement), wallet configuration requirements, and the focus on verified contracts. While annotations already indicate destructiveHint=true and readOnlyHint=false, the description provides practical implementation details that help the agent understand execution requirements.

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?

The description is efficiently structured in three sentences: first states core functionality, second explains ABI auto-fetching, third specifies prerequisites. Each sentence adds distinct value with zero redundancy. The information is front-loaded with the primary purpose stated immediately.

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?

For a complex destructive tool with no output schema, the description provides good context about requirements (wallet, API key), behavior (ABI auto-fetching), and scope (verified contracts, write functions). It could be more complete by mentioning transaction confirmation or gas handling, but covers the essential operational context given the annotations already indicate destructive nature.

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?

With 100% schema description coverage, the input schema already documents all 6 parameters thoroughly. The description mentions ABI auto-fetching (related to 'abiJson') and wallet requirements (implied for all operations), but doesn't add significant parameter-specific semantics beyond what the schema provides. This meets the baseline expectation when schema coverage is complete.

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 ('Execute state-changing functions', 'call any write function') and resources ('on a smart contract'). It distinguishes from sibling tools like 'read_contract' by emphasizing write operations and from 'approve_token_spending' by being a general-purpose contract interaction tool.

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?

The description provides explicit usage guidance: 'Use this to call any write function on verified contracts' establishes the primary use case. It also mentions prerequisites ('Requires wallet to be configured') and when not to use alternatives (implied by distinguishing from read operations). The sibling tool list shows clear alternatives like 'read_contract' for non-state-changing calls.

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