Tool Execution: The _run Method, Error Handling, and Permission Prompts

~15 min read

Every custom tool needs a _run method executed when the agent wants to use it — the book's example fetches live exchange rates and explicitly handles failed requests and invalid currency codes rather than letting them crash the agent.

Once a tool has been selected (the previous subtopic), something actually has to execute it. Every CrewAI tool class needs a _run method, which is what gets executed whenever the agent wants to make use of that tool — this is where the tool's real logic actually lives, as distinct from the schema and description covered in the defining-tools subtopic.

This course's CurrencyConverterTool implements _run by making a real API request to fetch live exchange rates and computing the converted amount — critically, this course is explicit that this implementation also handles errors if the request fails or the currency code is invalid, rather than letting either failure mode propagate up as an unhandled exception. This matters a great deal in agent contexts specifically: an agent that receives a clean error message ('invalid currency code: XYZ') can often recover — asking the user to clarify, or trying a corrected input — in a way it fundamentally can't if the tool just crashes with a raw exception.

There's a second, distinct execution consideration this course raises: since tools can do things like file I/O or network calls, an MCP (or agent framework) implementation often requires that the user explicitly permit a tool call before it runs. This course's concrete example is Claude's client popping up 'The AI wants to use the get_weather tool, allow yes/no?' the first time a tool is invoked, specifically to prevent abuse and ensure the human stays in control of powerful actions. This permission layer is separate from error handling — it's a safety gate BEFORE execution, not recovery AFTER a failure.

Together, these two concerns — graceful error handling inside _run, and (where applicable) a permission gate before execution — are what separate a demo-quality tool from one that's actually safe and reliable to give an agent access to in a real application.

💻 Code example

import requests

class CurrencyConverterTool:
    """_run method: the actual execution logic, with explicit
    error handling for both failure modes the book calls out —
    a failed API request, and an invalid currency code."""

    def _run(self, amount: float, source_currency: str, target_currency: str) -> str:
        try:
            resp = requests.get(
                f"https://v6.exchangerate-api.com/v6/API_KEY/pair/"
                f"{source_currency}/{target_currency}/{amount}",
                timeout=5,
            )
            resp.raise_for_status()
            data = resp.json()

            if data.get("result") != "success":
                # Invalid currency code — return a clear, recoverable
                # message the AGENT can act on, not a raw crash
                return f"Error: invalid currency code — {source_currency} or {target_currency}"

            return f"{amount} {source_currency} = {data['conversion_result']:.2f} {target_currency}"

        except requests.RequestException as e:
            # Failed request — same principle: clean, actionable error
            return f"Error: could not fetch exchange rate ({e})"

# A permission-gated version — the pattern MCP clients use before
# executing tools with side effects (network calls, file I/O)
def execute_with_permission(tool, **kwargs) -> str:
    allowed = input(f"AI wants to use '{tool.__class__.__name__}'. Allow? (y/n): ")
    if allowed.lower() != "y":
        return "Tool execution denied by user"
    return tool._run(**kwargs)

💬 Deep Dive with AI

Key points

  • The _run method is where a tool's actual logic executes, invoked whenever the agent decides to use the tool
  • Explicit error handling (failed requests, invalid input) matters especially for agents — a clean error message lets the agent recover; a raw crash doesn't
  • Since tools can have real side effects (network calls, file I/O), agent frameworks often gate execution behind explicit user permission
  • The book's example: Claude's client asking 'allow yes/no?' the first time a tool is used, keeping the human in control of powerful actions
  • Error handling (recovery after failure) and permission gates (safety before execution) are two distinct, complementary concerns