Skip to content

Instantly share code, notes, and snippets.

@quantumproxies
Created August 21, 2026 12:42
Show Gist options
  • Select an option

  • Save quantumproxies/572de9b2f727dc61370c2303a6b52338 to your computer and use it in GitHub Desktop.

Select an option

Save quantumproxies/572de9b2f727dc61370c2303a6b52338 to your computer and use it in GitHub Desktop.
Give Claude live web access with two tool definitions — QuanticData + the Claude API https://quanticdata.io/blog/how-to-use-claude-api/
"""A Claude tool loop with real web access, in one file.
pip install anthropic requests
export ANTHROPIC_API_KEY=sk-ant-... QD_API_KEY=qd_live_...
python3 qd_claude_tools.py "What changed in the EU AI Act timeline this month?"
Two tools is enough: search to FIND, scrape to READ. A search costs $0.0005 and a page
$0.0002, so a six-source turn is about a thousandth of what the model tokens cost.
https://quanticdata.io/web-data-api-for-ai/ · https://quanticdata.io/blog/how-to-use-claude-api/
Prefer no plumbing at all? https://github.com/quantumproxies/quanticdata-mcp-server
"""
import json
import os
import sys
import requests
from anthropic import Anthropic
MODEL = os.environ.get("ANTHROPIC_MODEL", "claude-sonnet-5")
BASE = "https://api.quanticdata.io/v1"
QD = {"Authorization": f"Bearer {os.environ['QD_API_KEY']}"}
TOOLS = [
{
"name": "search",
"description": ("Search the live web and get organic results with title, link and "
"snippet. Finds pages; does not return their content."),
"input_schema": {
"type": "object",
"properties": {"query": {"type": "string"},
"country": {"type": "string", "description": "ISO code, e.g. us"}},
"required": ["query"],
},
},
{
"name": "scrape",
"description": ("Read one URL as clean Markdown, boilerplate removed. Pass `query` to "
"get only the passages relevant to a question."),
"input_schema": {
"type": "object",
"properties": {"url": {"type": "string"}, "query": {"type": "string"}},
"required": ["url"],
},
},
]
def run_tool(name, args):
if name == "search":
p = requests.post(f"{BASE}/serp", headers=QD, timeout=120,
json={"query": args["query"], "country": args.get("country"),
"num": 10}).json().get("payload", {})
return json.dumps([{k: r.get(k) for k in ("position", "title", "link", "snippet")}
for r in (p.get("organic") or [])])
body = {"url": args["url"], "format": "markdown", "contentMode": "article",
"max_tokens": 1500}
if args.get("query"):
body |= {"query": args["query"], "highlights": True}
p = requests.post(f"{BASE}/scrape", headers=QD, json=body, timeout=180).json().get("payload", {})
highlights = p.get("highlights")
text = "\n\n".join(h.get("text", "") for h in highlights) if highlights else p.get("markdown", "")
return f"source: {args['url']}\n\n{text}"
client = Anthropic()
messages = [{"role": "user", "content": " ".join(sys.argv[1:]) or "What is an MCP server?"}]
system = ("You have live web access. Search to find sources, scrape to read them, and cite the "
"URL for every factual claim. If the tools did not answer, say so rather than guessing.")
for _ in range(8):
response = client.messages.create(model=MODEL, max_tokens=4096, system=system,
tools=TOOLS, messages=messages)
messages.append({"role": "assistant", "content": response.content})
for block in response.content:
if block.type == "text" and block.text.strip():
print(block.text)
calls = [b for b in response.content if b.type == "tool_use"]
if not calls:
break
messages.append({"role": "user", "content": [
{"type": "tool_result", "tool_use_id": c.id, "content": run_tool(c.name, c.input)}
for c in calls
]})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment