Claude doesn’t know what TSLA closed at. Ask it anyway and it will hand you a confident number that is wrong, because the price isn’t in its training data and never will be.
Tool use fixes this. You give Claude a function it can call, and when a question needs a real price, it calls your function instead of guessing.
Alpha Vantage recently shipped an official MCP server for this. It works well, but it means wiring up an MCP client, a transport, and a connection first. If you want the full MCP setup, that route is there. If you want 20 lines that work right now, keep reading.
We will use Marketstack for the data. Its free tier gives you 100 requests a month, enough to prototype an agent.
Table of Contents
Step 1: Define a stock price tool for Claude
This is the contract. It tells Claude that there is a function called get_stock_price, what it does, and that it takes one string argument. Claude reads the description to decide when to call it, so write the description like you mean it.
TOOLS = [{
"name": "get_stock_price",
"description": "Get the latest end-of-day price for a stock ticker: open, high, low, close, and volume.",
"input_schema": {
"type": "object",
"properties": {
"symbol": {"type": "string", "description": "Stock ticker, e.g. TSLA or AAPL"}
},
"required": ["symbol"],
},
}]
That input_schema is plain JSON Schema. Claude fills in symbol based on the user’s question and never invents fields you didn’t define. The description is the part worth getting right: a vague one makes Claude call the tool at the wrong times or skip it when it should fire, so name the exact data it returns.
Step 2: Fetch live prices from the Marketstack API
When Claude calls the tool, your code receives the symbol and has to actually get the data. Here is the whole function. It hits the Marketstack /eod/latest endpoint and returns the first result as a JSON string.
def get_stock_price(symbol):
r = requests.get("https://api.marketstack.com/v2/eod/latest",
params={"access_key": MARKETSTACK_KEY, "symbols": symbol})
return json.dumps(r.json()["data"][0])
A successful response from that endpoint looks like this (trimmed; a full v2 record also returns adjusted prices, split_factor, dividend, and description):Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.
{
"open": 358.40,
"high": 364.10,
"low": 355.21,
"close": 362.89,
"volume": 78213400,
"symbol": "TSLA",
"exchange": "XNAS",
"exchangeCode": "NASDAQ",
"name": "Tesla Inc",
"date": "2026-05-28T00:00:00+0000"
}
Everything Claude needs is in close, plus open, high, low, and volume for context. The date field tells you exactly when the data is from, which matters because the free tier returns the latest close, not an intraday tick. If you need minute-by-minute prices, that lives on a paid plan.
Step 3: The complete stock data agent script
Install the two dependencies first, set your keys as environment variables, and that is the entire setup.
pip install anthropic requests
Drop in your two keys and run it. This is the whole thing, including the tool-call loop that sends Claude’s request to Marketstack and feeds the result back.
import json, os, requests, anthropic
MARKETSTACK_KEY = os.environ["MARKETSTACK_API_KEY"]
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY from your environment
TOOLS = [{
"name": "get_stock_price",
"description": "Get the latest end-of-day price for a stock ticker: open, high, low, close, and volume.",
"input_schema": {
"type": "object",
"properties": {"symbol": {"type": "string", "description": "Stock ticker, e.g. TSLA"}},
"required": ["symbol"],
},
}]
def get_stock_price(symbol):
r = requests.get("https://api.marketstack.com/v2/eod/latest",
params={"access_key": MARKETSTACK_KEY, "symbols": symbol})
return json.dumps(r.json()["data"][0])
def ask(question):
messages = [{"role": "user", "content": question}]
while True:
resp = client.messages.create(model="claude-sonnet-4-6", max_tokens=1024,
tools=TOOLS, messages=messages)
if resp.stop_reason != "tool_use":
return resp.content[0].text
messages.append({"role": "assistant", "content": resp.content})
results = [{"type": "tool_result", "tool_use_id": block.id,
"content": get_stock_price(block.input["symbol"])}
for block in resp.content if block.type == "tool_use"]
messages.append({"role": "user", "content": results})
print(ask("What's TSLA trading at?"))
How the tool-call loop works (Claude + Marketstack)
Here is what happens when you run it with “What’s TSLA trading at?”:
- You send the question. Claude reads it, sees the get_stock_price tool, and decides the question needs real data. It stops with stop_reason “tool_use” and a call for {“symbol”: “TSLA”}.
- The loop catches that, runs get_stock_price(“TSLA”), and hits Marketstack. Back comes the JSON above with a close of 362.89.
- That JSON goes back to Claude as a tool_result. Now Claude has the number, so it stops calling tools and writes a plain answer.
The printed result reads something like:
Tesla (TSLA) last closed at $362.89 on the Nasdaq, up from an open of $358.40, with about 78.2 million shares traded.
Get Your Free
Stock Data API Key!
Marketstack
Join thousands of developers using Marketstack for real-time market data!
Get Your Free API Key!No Credit Card Required*
100 Requests Free!
Real number, real source, zero hallucination. The while loop matters here because it handles the back-and-forth automatically, so if a question needs two lookups, the same code covers it. It also handles the opposite case cleanly: ask Claude something that needs no price, like “what is a stock split?”, and it answers straight away without ever touching Marketstack, so you only spend a request when you actually need one.
Extend the agent: historical data, multiple tickers, and more
Add a date_from and date_to to the same endpoint for historical charts, pass comma-separated symbols like TSLA,AAPL to compare several at once, or add a second tool for company fundamentals and let Claude pick between them. The full endpoint list is in the Marketstack documentation, and for more on building data-backed agents see APILayer’s guide on making your API agent-ready and the stock data API guide. For deeper context on the mechanics, Anthropic’s tool use documentation covers the full request and response shape.
Frequently asked questions
Why does an AI model give wrong stock prices?
Live prices are not in the model’s training data, so when you ask without tools it guesses and still sounds confident. Tool use fixes this: the model calls a function backed by a live API like Marketstack and answers from the real response.
How do I give an AI agent live stock data?
Define a tool the model can call, back it with a stock API, and return the JSON to the model. With Marketstack and Claude tool use it takes about 20 lines of Python: a tool schema, a fetch wrapper around /v2/eod/latest, and a short tool-call loop.
Is Marketstack free to use?
Marketstack has a free tier with 100 requests a month and end-of-day data going back one year. Intraday (minute-by-minute) prices are on the paid plans.
What is the difference between end-of-day and intraday data?
End-of-day data is one record per trading day: the close, plus open, high, low, and volume. Intraday data updates through the day at minute or tick level. The Marketstack free tier returns end-of-day; intraday requires a paid plan.
Which Marketstack endpoint returns the latest price?
Send a GET request to https://api.marketstack.com/v2/eod/latest with your access_key and a symbols parameter (for example symbols=TSLA). It returns the most recent end-of-day record for each ticker.
Does this pattern work with models other than Claude?
Yes. Any model that supports tool or function calling can use the same approach. The tool schema and the request loop differ slightly between providers, but the idea is identical: the model calls your function, you return real data, and it answers from that.
Marketstack’s free tier gives you 100 requests a month, more than enough to prototype your agent. Grab your API key at marketstack.com and drop it into the script above. Your Claude agent will stop guessing stock prices in about 90 seconds.