Price lookup with a cross-check¶
Answer "what is the Bitcoin price?" from live data, and check a web search result against a structured API in code.
Requires tool calls
The deployment must allow api.coingecko.com and mcp.exa.ai
(GET /health → allow_hosts). Both services work without an API key.
Full request body
{
"system": "You are a financial assistant. Answer only from the data provided.",
"context": "User message: \"Bro, what's the bitcoin price right now in dollars?\"",
"schema": {
"coin": {
"enum": [
"bitcoin",
"ethereum",
"solana"
],
"instruction": "Crypto coin the user is asking about."
},
"search_result": {
"type": "call",
"http": {
"method": "POST",
"url": "https://mcp.exa.ai/mcp",
"headers": {
"Accept": "application/json, text/event-stream"
},
"body": {
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "web_search_exa",
"arguments": {
"query": "{coin} price today in USD",
"numResults": 3
}
}
},
"timeout": 30,
"response": {
"select": "result.content[0].text"
}
},
"args": {
"coin": "$coin"
},
"expose": true,
"on_error": "review"
},
"api_price": {
"type": "call",
"http": {
"method": "GET",
"url": "https://api.coingecko.com/api/v3/simple/price",
"query": {
"ids": "{coin}",
"vs_currencies": "usd"
},
"timeout": 10,
"response": {
"select": "{coin}.usd"
}
},
"args": {
"coin": "$coin"
},
"expose": true,
"on_error": "reject",
"on": [
{
"when": {
"eq": null
},
"do": "reject"
}
]
},
"search_price": {
"type": "number",
"nullable": true,
"depends_on": [
"search_result"
],
"instruction": "Price in USD according to search_result (number only, no digit separators). null if not found.",
"on": [
{
"when": {
"gt_expr": "api_price * 1.05"
},
"do": "review"
},
{
"when": {
"lt_expr": "api_price * 0.95"
},
"do": "review"
}
]
},
"answer": {
"type": "string",
"free_form": true,
"depends_on": [
"api_price"
],
"instruction": "Answer the user's question in 1 sentence in English using api_price. Copy the price digits EXACTLY as in Known values (do not change or group the digits).",
"on_reject": "Sorry, the price data is currently unavailable (the API failed or the coin is unknown). Please try again shortly."
}
},
"max_new_tokens": 80
}
What happens¶
- The model picks
coinfrom an enum (a clean argument for the URLs). - Two calls run in parallel: a web search through Exa's public MCP endpoint, and CoinGecko's price API.
- The model reads
search_pricefrom the search text only. It does not depend onapi_price, so the API price is not in its prompt and cannot be copied. - Code compares the two (
gt_expr/lt_expr, ±5%) and flags a mismatch. answeruses the API price. If the price API fails, the request is rejected with an honest message instead of an invented price.
Lessons from testing¶
- A search result still showed a stale price (about $64,575 while the API said about $84,500). The model read it correctly with confidence ~1.0: confidence cannot catch a wrong source, a cross-check can.
- When the price API was rate-limited and the call only used
on_error: review, the answer invented a price. Useon_error: rejectfor data an answer depends on. - Asked to format 1514071277 with separators, the model wrote "Rp15.140.712.77". Ask it to copy digits as they are and format numbers in your own code.
The simpler version without search (CoinGecko only) is playground preset 24. Guide: Tool calls.