Skip to main content
Glama

approve_token_spending

Authorize a specific address to spend your ERC20 tokens by defining the token, spender, and amount. Essential for enabling token interactions with DeFi protocols or exchanges.

Instructions

Approve another address (like a DeFi protocol or exchange) to spend your ERC20 tokens. This is often required before interacting with DeFi protocols.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
amountYesThe amount of tokens to approve in token units, not wei (e.g., '1000' to approve spending 1000 tokens). Use a very large number for unlimited approval.
networkNoNetwork name (e.g. 'bsc', 'opbnb', 'ethereum', 'base', etc.) or chain ID. Supports others main popular networks. Defaults to BSC mainnet.bsc
privateKeyNoPrivate key of the token owner account in hex format (with or without 0x prefix). SECURITY: This is used only for transaction signing and is not stored.0x5a2b7e4d9c8f1a3e6b0d2c5f4e3d2a1b0c9f8e7d6a5b4c3d2e1f0a9b8c7d6e5f4
spenderAddressYesThe contract address being approved to spend your tokens (e.g., a DEX or lending protocol)
tokenAddressYesThe contract address of the ERC20 token to approve for spending (e.g., '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' for USDC on Ethereum)

Implementation Reference

  • Registration of the 'approve_token_spending' MCP tool, including input schema definition and handler function that delegates to services.approveERC20
    // Approve ERC20 token spending
    server.tool(
      "approve_token_spending",
      "Approve another address (like a DeFi protocol or exchange) to spend your ERC20 tokens. This is often required before interacting with DeFi protocols.",
      {
        privateKey: privateKeyParam,
        tokenAddress: z
          .string()
          .describe(
            "The contract address of the ERC20 token to approve for spending (e.g., '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' for USDC on Ethereum)"
          ),
        spenderAddress: z
          .string()
          .describe(
            "The contract address being approved to spend your tokens (e.g., a DEX or lending protocol)"
          ),
        amount: z
          .string()
          .describe(
            "The amount of tokens to approve in token units, not wei (e.g., '1000' to approve spending 1000 tokens). Use a very large number for unlimited approval."
          ),
        network: defaultNetworkParam
      },
      async ({ privateKey, tokenAddress, spenderAddress, amount, network }) => {
        try {
          const result = await services.approveERC20(
            tokenAddress,
            spenderAddress,
            amount,
            privateKey,
            network
          )
    
          return mcpToolRes.success({
            success: true,
            txHash: result.txHash,
            tokenAddress,
            spenderAddress,
            amount: result.amount.formatted,
            symbol: result.token.symbol,
            network
          })
        } catch (error) {
          return mcpToolRes.error(error, "approving token spending")
        }
      }
    )
  • The MCP tool handler logic for 'approve_token_spending', which performs the approval by calling the helper function and formats the response.
    async ({ privateKey, tokenAddress, spenderAddress, amount, network }) => {
      try {
        const result = await services.approveERC20(
          tokenAddress,
          spenderAddress,
          amount,
          privateKey,
          network
        )
    
        return mcpToolRes.success({
          success: true,
          txHash: result.txHash,
          tokenAddress,
          spenderAddress,
          amount: result.amount.formatted,
          symbol: result.token.symbol,
          network
        })
      } catch (error) {
        return mcpToolRes.error(error, "approving token spending")
      }
    }
  • Core helper function 'approveERC20' that executes the ERC20 approve transaction using viem's walletClient.writeContract on the 'approve' method. Handles ENS resolution, token decimals, amount parsing, and returns transaction details.
    export async function approveERC20(
      tokenAddressOrEns: string,
      spenderAddressOrEns: string,
      amount: string,
      privateKey: string | `0x${string}`,
      network: string = "ethereum"
    ): Promise<{
      txHash: Hash
      amount: {
        raw: bigint
        formatted: string
      }
      token: {
        symbol: string
        decimals: number
      }
    }> {
      // Resolve ENS names to addresses if needed
      const tokenAddress = (await resolveAddress(
        tokenAddressOrEns,
        network
      )) as Address
      const spenderAddress = (await resolveAddress(
        spenderAddressOrEns,
        network
      )) as Address
    
      // Ensure the private key has 0x prefix
      const formattedKey =
        typeof privateKey === "string" && !privateKey.startsWith("0x")
          ? (`0x${privateKey}` as `0x${string}`)
          : (privateKey as `0x${string}`)
    
      // Get token details
      const publicClient = getPublicClient(network)
      const contract = getContract({
        address: tokenAddress,
        abi: ERC20_ABI,
        client: publicClient
      })
    
      // Get token decimals and symbol
      const decimals = (await contract.read.decimals()) as number
      const symbol = (await contract.read.symbol()) as string
    
      // Parse the amount with the correct number of decimals
      const rawAmount = parseUnits(amount, decimals)
    
      // Create wallet client for sending the transaction
      const walletClient = getWalletClient(formattedKey, network)
    
      // Send the transaction
      const hash = await walletClient.writeContract({
        address: tokenAddress,
        abi: ERC20_ABI,
        functionName: "approve",
        args: [spenderAddress, rawAmount],
        account: walletClient.account!,
        chain: walletClient.chain
      })
    
      return {
        txHash: hash,
        amount: {
          raw: rawAmount,
          formatted: amount
        },
        token: {
          symbol,
          decimals
        }
      }
    }
  • Higher-level registration of the wallet module, which calls registerWalletTools to register the 'approve_token_spending' tool among others.
    export function registerWallet(server: McpServer) {
      registerWalletTools(server)
      registerWaletPrompts(server)
    }
Behavior3/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It explains the purpose and context but doesn't mention important behavioral aspects like transaction costs (gas fees), whether approvals are revocable, security implications of unlimited approvals, or what the tool returns. For a financial transaction tool with zero annotation coverage, this leaves significant gaps.

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 perfectly concise with two sentences that each earn their place. The first sentence states the core purpose, and the second provides important usage context. There's zero wasted language or redundancy.

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

Completeness3/5

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

For a financial transaction tool with 5 parameters, no annotations, and no output schema, the description is adequate but incomplete. It covers the 'what' and 'why' but lacks information about transaction behavior, security considerations, error conditions, or return values. Given the complexity and absence of structured metadata, more completeness would be expected.

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?

The schema has 100% description coverage, so the baseline is 3. The description adds value by explaining the broader context (DeFi protocol interactions) and the purpose of approvals, which helps the agent understand why these parameters matter beyond their technical definitions in the schema.

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 specific action ('Approve another address to spend your ERC20 tokens') and the resource involved (ERC20 tokens). It distinguishes this from sibling tools like 'transfer_erc20' or 'write_contract' by focusing specifically on token spending approvals for DeFi interactions.

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?

The description provides clear context about when to use this tool ('often required before interacting with DeFi protocols'), giving practical guidance. However, it doesn't explicitly mention when NOT to use it or name specific alternatives among the sibling tools, which prevents a perfect score.

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

Related 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/bnb-chain/bnbchain-mcp'

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