Home/AI & Automation/LLM Agent Tool Use: From Function Calling to MCP
AI & AutomationLLMAgents

LLM Agent Tool Use: From Function Calling to MCP

A complete breakdown of tool use, the core mechanism that lets LLM agents interact with the outside world. We compare OpenAI Function Calling, Anthropic Tool Use, and the Model Context Protocol (MCP) side by side with code.

LLM Agent Tool Use: From Function Calling to MCP
Contents
  1. How Tool Use Works
  2. OpenAI Function Calling
  3. Anthropic Tool Use
  4. Model Context Protocol (MCP)
  5. Tool Design Principles
  6. Parallel Tool Calls
  7. Editor's Note — From the Field
  8. Sources · checked 2026-10-04

Mastering LLM Agent Tool Use: From Function Calling to MCP

What makes an agent an agent is tool use. It is the mechanism that takes LLMs beyond mere text generation and lets them call external APIs, query databases, and execute code.

How Tool Use Works

LLMs only accept text as input and only produce text as output. Tool use bypasses that constraint with the following flow.

CODE
1. User message + tool spec → LLM
2. LLM → "Call this tool with these arguments" (JSON output)
3. Runtime executes the actual function
4. Execution result → passed back to the LLM
5. LLM → generates the final natural-language answer

The key point is that the LLM does not execute functions itself. The runtime does, then hands the results back to the LLM.

OpenAI Function Calling

Python
from openai import OpenAI
import json
import os

client = OpenAI()

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_stock_price",
 "description": " ",
            "parameters": {
                "type": "object",
                "properties": {
                    "symbol": {
                        "type": "string",
 "description": " (: AAPL, TSLA)"
                    },
                    "currency": {
                        "type": "string",
                        "enum": ["USD", "KRW"]
                    }
                },
                "required": ["symbol"]
            }
        }
    }
]

def get_stock_price(symbol, currency="USD"):
    return {"symbol": symbol, "price": 192.5, "currency": currency}

def run_agent(user_message):
    messages = [{"role": "user", "content": user_message}]

    while True:
        response = client.chat.completions.create(
            model=os.environ["OPENAI_MODEL"],  # pick one from platform.openai.com/docs/models
            messages=messages,
            tools=tools,
            tool_choice="auto"
        )
        msg = response.choices[0].message
        messages.append(msg)

        if msg.tool_calls is None:
            return msg.content

        for tc in msg.tool_calls:
            args = json.loads(tc.function.arguments)
            result = get_stock_price(**args)
            messages.append({
                "role": "tool",
                "tool_call_id": tc.id,
                "content": json.dumps(result)
            })

Anthropic Tool Use

Claude's tool use issues calls as tool_use content blocks and returns results as tool_result.

Python
import anthropic, json

client = anthropic.Anthropic()

tools = [{
    "name": "search_docs",
 "description": " ",
    "input_schema": {
        "type": "object",
        "properties": {
            "query": {"type": "string"},
            "max_results": {"type": "integer", "default": 5}
        },
        "required": ["query"]
    }
}]

def search_docs(query, max_results=5):
 return [{"title": "API ", "content": "Bearer method ..."}]

messages = [{"role": "user", "content": " API method ?"}]

while True:
    response = client.messages.create(
        model="claude-sonnet-5-5",
        max_tokens=1024,
        tools=tools,
        messages=messages
    )

    if response.stop_reason == "end_turn":
        text_block = next(b for b in response.content if b.type == "text")
        print(text_block.text)
        break

    messages.append({"role": "assistant", "content": response.content})

    tool_results = []
    for block in response.content:
        if block.type == "tool_use":
            result = search_docs(**block.input)
            tool_results.append({
                "type": "tool_result",
                "tool_use_id": block.id,
                "content": json.dumps(result, ensure_ascii=False)
            })
    messages.append({"role": "user", "content": tool_results})

Model Context Protocol (MCP)

MCP is a tool standardization protocol proposed by Anthropic. It is not tied to any individual LLM SDK; tools are provided independently through a server–client architecture.

Python
# MCP
from mcp.server import Server
import mcp.types as types

server = Server("my-tools-server")

@server.list_tools()
async def handle_list_tools():
    return [
        types.Tool(
            name="query_database",
 description="SQL run Result ",
            inputSchema={
                "type": "object",
                "properties": {
 "sql": {"type": "string", "description": "run SELECT "}
                },
                "required": ["sql"]
            }
        )
    ]

@server.call_tool()
async def handle_call_tool(name, arguments):
    if name == "query_database":
        results = execute_query(arguments["sql"])
        return [types.TextContent(type="text", text=str(results))]

MCP's advantage is reusability. An MCP server you build once can be connected from Claude Desktop, Claude Code, your own agents, and more.

Tool Design Principles

The difference between a good tool and a bad one is in the description.

Bad exampleGood example
"Fetches data""Looks up status, amount, and shipping info for a specific order by order ID. Canceled orders can also be retrieved."
No parameter descriptionsExplicit type, allowed values, and defaults for each parameter

The LLM reads the description to choose a tool. If the description is inaccurate, it will call the wrong tool or pass the wrong arguments.

Parallel Tool Calls

Running multiple tools sequentially is slow. Both the OpenAI and Anthropic APIs support parallel tool calls, where the model calls several tools in one turn. On OpenAI, setting parallel_tool_calls to false limits it to at most one tool per turn (OpenAI, Anthropic).

Python
import asyncio

async def execute_tools_parallel(tool_calls):
    tasks = [dispatch_tool(tc.function.name, json.loads(tc.function.arguments))
             for tc in tool_calls]
    return await asyncio.gather(*tasks)

In the next installment, we cover memory system design—how to let agents maintain conversation context and carry out long-running tasks.

Editor's Note — From the Field

It feels like attaching more tools should make an agent smarter, but in practice, once you go past five or six tools, the LLM frequently misjudges which tool to use and when. What helped most was cutting the number of tools and writing each description so specifically that a human wouldn't get confused either—search_internal_docs (search the internal wiki) rather than search. Tool design is an extension of prompt engineering.

Sources · checked 2026-10-04

Model IDs change, so check the current ID on each provider’s model page before running the code.

✦ ✦ ✦
Sources and verification

Sources and checks vary by article. Only articles with a recorded check date, scope and sources below were checked, and only within that scope. For other articles, verify against the current docs for your version before applying anything, and email us about errors. Editorial policy · email us

This article has no recorded human check (date and scope) yet.

Published · ·Updated ·
Topic-related official docs (auto-linked · not per-claim sources)OpenAI documentation ↗Anthropic documentation ↗

Comments

Be the first to comment.