Tools allow Claude to interact with external APIs, databases, and services to fetch real-time information and perform actions beyond its built-in knowledge.
Official documentation on Claude Tools
In this tutorial, we’ll explore how to use the tool use feature (also called function calling) with Claude, using the SerpApi Google Maps API as a practical example.
You can use any API, in this example, I’m using an API from SerpApi.
Think of tools as functions that Claude can call when it needs to accomplish specific tasks. Instead of just responding with text, Claude can:
-
Search Google Maps for nearby restaurants
-
Check current weather data
-
Query databases
-
Fetch stock prices
-
And much more!
We have a getting started blog post to start using Claude API with Python
Let’s say we try to get a real-time data like this:
message = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1000,
messages=[
{
"role": "user",
"content": "Top 3 cafes with up to date rating from Google Maps in Jakarta"
}
]
)
Here is the answer:

While it still answers the prompt, it includes a disclaimer that they don’t have access to a real-time data.
Prerequisites
Before we begin, make sure you have:
-
Python 3.7 or higher installed
-
An Anthropic API key (get one here)
-
A SerpApi API key (sign up here)
-
The Anthropic Python SDK installed
pip install anthropic requests python-dotenv
First, let’s define a tool that Claude can use. A tool definition tells Claude:
-
What the tool does
-
What parameters it needs
-
What format those parameters should be in
Here’s how we define a Google Maps search tool:
import os
import json
import requests
from anthropic import Anthropic
from dotenv import load_dotenv
load_dotenv()
client = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
# Define the tool
tools = [
{
"name": "search_google_maps",
"description": "Searches for places on Google Maps based on a query and location. Returns information about businesses, restaurants, attractions, and other points of interest.",
"input_schema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The search query (e.g., 'pizza restaurants', 'hotels', 'gas stations')"
},
"location": {
"type": "string",
"description": "The location to search in (e.g., 'New York, NY', 'London, UK')"
}
},
"required": ["query", "location"]
}
}
]
Next, we need to create the actual Python function that calls the SerpApi:
# SerpApi (or any external API) actual function
def search_google_maps(query, location):
# Find top results from Google Maps using SerpApi
SERPAPI_KEY = os.environ.get("SERPAPI_API_KEY")
params = {
"engine": "google_maps",
"q": query,
"location": location,
"z": "14", #zoom level
"api_key": SERPAPI_KEY
}
try:
response = requests.get("https://serpapi.com/search", params=params)
response.raise_for_status()
data = response.json()
# Extract relevant information
results = []
if "local_results" in data:
for place in data["local_results"][:5]: # Get top 5 results
results.append({
"title": place.get("title", "N/A"),
"rating": place.get("rating", "N/A"),
"address": place.get("address", "N/A"),
"type": place.get("type", "N/A")
})
return json.dumps(results)
except Exception as e:
return json.dumps({"error": str(e)})
Now comes the magic! We create a conversation loop where:
-
We send a message to Claude with the available tools
-
Claude decides if it needs to use a tool
-
We execute the tool and send the results back to Claude
-
Claude provides a final answer to the user
def chat_with_tools(user_message):
messages = [{"role": "user", "content": user_message}]
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=tools,
messages=messages
)
while response.stop_reason == "tool_use":
# Extract tool use from response
tool_use = next(block for block in response.content if block.type == "tool_use")
tool_name = tool_use.name
tool_input = tool_use.input
print(f"\n🔧 Claude is using tool: {tool_name}")
print(f"📥 With parameters: {tool_input}")
# Execute the tool
if tool_name == "search_google_maps":
tool_result = search_google_maps(
query=tool_input["query"],
location=tool_input["location"]
)
print(f"📤 Tool returned: {tool_result[:200]}...")
# Continue the conversation with tool result
messages = [
{"role": "user", "content": user_message},
{"role": "assistant", "content": response.content},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": tool_use.id,
"content": tool_result,
}
],
},
]
# Get Claude's final response
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
tools=tools,
messages=messages
)
# Extract final text response
final_response = next(
(block.text for block in response.content if hasattr(block, "text")),
None,
)
return final_response
Step 4: Putting It All Together
Here’s a complete example you can run:
# Example usage
if __name__ == "__main__":
user_query = "Find me the best Italian restaurants in San Francisco"
print(f"👤 User: {user_query}\n")
response = chat_with_tools(user_query)
print(f"\n🤖 Claude: {response}")
Example Output
👤 User: Find me the best cafe in Jakarta
🔧 Claude is using tool: search_google_maps
📥 With parameters: {'query': 'best cafe', 'location': 'Jakarta, Indonesia'}
📤 Tool returned: [{"title": "Giyanti Coffee Roastery", "rating": 4.6, "address": "Surabaya St No.20, RT.15/RW.5, Menteng, Central Jakarta City, Jakarta 10310, Indonesia", "type": "Cafe"}, {"title": "Kawisari Cafe & Ea...
🤖 Claude: Based on my search for the best cafes in Jakarta, here are some top-rated options:
**Top Recommendations:**
1. **Titik Koma Tanjung Duren** (4.8/5 rating)
- Location: West Jakarta (Jl. Tanjung Duren Utara V No.246)
- Known as a coffee shop with excellent reviews
2. **The Bènsara Cafe** (4.8/5 rating)
- Location: South Jakarta (Jl. Manggarai Utara 1 No.B 9, Manggarai)
- Highly rated cafe with great atmosphere
3. **TOMORO COFFEE - Sabang** (4.8/5 rating)
- Location: Central Jakarta (Jl. H. Agus Salim No.62, Menteng)
- Popular coffee shop in the Sabang area
4. **Giyanti Coffee Roastery** (4.6/5 rating)
- Location: Central Jakarta (Surabaya St No.20, Menteng)
- Coffee roastery with fresh beans and quality brews
5. **Kawisari Cafe & Eatery** (4.5/5 rating)
- Location: Central Jakarta (Jl. Kebon Sirih No.77A, Menteng)
- Cafe and eatery combination
All of these cafes have excellent ratings (4.5+ stars) and are located in prime areas of Jakarta. The top three with 4.8-star ratings would be my strongest recommendations, with Titik Koma Tanjung Duren, The Bènsara Cafe, and TOMORO COFFEE being standout choices.
...
Key Concepts to Remember
-
Tool Definition: You describe what the tool does and what inputs it needs
-
Tool Execution: You write the actual function that performs the action
-
Tool Loop: Claude may need multiple back-and-forth exchanges to complete a task
-
Tool Results: Always return results as strings (often JSON-formatted)
Best Practices
-
Clear descriptions: Make your tool descriptions detailed so Claude knows when to use them
-
Error handling: Always include try-catch blocks in your tool functions
-
Rate limiting: Be mindful of API rate limits when making external calls
-
Security: Never expose API keys in your code - use environment variables
Next Steps
Now that you understand the basics, try:
-
Adding multiple tools (weather, news, database queries)
-
Creating more complex tool chains where Claude uses multiple tools in sequence
-
Building a chatbot that can access your company’s internal APIs