On this page
What adding search to an agent actually takes#
Adding web search to an agent is really one of three jobs. Your code can call a search REST endpoint directly, an official SDK can wrap that call in your language, or the agent can connect to a hosted MCP server that exposes search as a tool it discovers on its own. The API key, the quota and the results are the same in all three — what changes is who owns the loop.
The "5 minutes" in the title is the honest version: from a clean machine to the first real search result takes about five minutes if you already have an LLM provider key. Turning that into production — key management, retries, rate-limit handling, logging — is an afternoon, and this post flags where each piece lives. Every figure below was checked against our own docs and pricing page in November 2026. Disclosure: SearchPipe is built by the team writing this post.
One thing worth deciding before you write any code: pick a backend that will still exist next year. Microsoft's retired-API documentation confirms the public Bing Search and Bing Custom Search APIs were retired on August 11, 2025, and Google's own documentation says existing Programmable Search JSON API customers have until January 1, 2027 to move to an alternative. Migration off a dying endpoint is not how you want to spend a sprint.
Step 1 — Sign up and grab a key#
Create an account, verify your email, and open the API Keys page — a fresh key starts with sp- and works immediately. The free tier is 1,000 credits every month with no payment card, which works out to 2,000 fast searches or 1,000 basic ones; that is comfortably more than a prototype needs. If you later recharge, credits start at $2.50 per 1,000 fast searches, and recharged credits never expire. Full numbers live on the pricing page.
Export the key into your environment — SEARCHPIPE_API_KEY is the name the official SDKs look for — and keep it out of source control. Every endpoint accepts either an Authorization: Bearer header or X-API-Key, so existing HTTP tooling works unchanged.
Step 2 — Your first search: one call, one answer#
The smallest useful request asks a question and requests an answer with five results. This is the same quickstart that ships on the Search API page — copy it, paste your key, run it:
curl -X POST https://searchpipe.tech/v1/search \
-H "Authorization: Bearer sp-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"FastAPI tutorial","max_results":5,"output_type":"answer"}'import httpx
resp = httpx.post(
"https://searchpipe.tech/v1/search",
headers={"Authorization": "Bearer sp-YOUR_KEY"},
json={"query": "FastAPI tutorial", "max_results": 5, "output_type": "answer"},
timeout=60,
)
resp.raise_for_status()
data = resp.json()
print(data["answer"])
for r in data["results"]:
print(r["score"], r["title"], r["url"])const resp = await fetch("https://searchpipe.tech/v1/search", {
method: "POST",
headers: {
"Authorization": "Bearer sp-YOUR_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({ query: "FastAPI tutorial", max_results: 5, output_type: "answer" }),
});
if (!resp.ok) throw new Error(`Search failed (${resp.status}): ${await resp.text()}`);
const data = await resp.json();
console.log(data.answer);
for (const r of data.results) console.log(r.score, r.title, r.url);package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
func main() {
payload, _ := json.Marshal(map[string]any{
"query": "FastAPI tutorial",
"max_results": 5,
"output_type": "answer",
})
req, _ := http.NewRequest("POST", "https://searchpipe.tech/v1/search", bytes.NewReader(payload))
req.Header.Set("Authorization", "Bearer sp-YOUR_KEY")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 60 * time.Second}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}import java.net.URI;
import java.net.http.*;
import java.time.Duration;
public class SearchPipeDemo {
public static void main(String[] args) throws Exception {
String json = """
{"query":"FastAPI tutorial","max_results":5,"output_type":"answer"}
""";
HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_1_1)
.connectTimeout(Duration.ofSeconds(10))
.build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://searchpipe.tech/v1/search"))
.timeout(Duration.ofSeconds(60))
.header("Authorization", "Bearer sp-YOUR_KEY")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<String> resp =
client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());
}
}using System.Net.Http.Json;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "sp-YOUR_KEY");
var payload = new
{
query = "FastAPI tutorial",
max_results = 5,
output_type = "answer",
};
HttpResponseMessage resp = await client.PostAsJsonAsync("https://searchpipe.tech/v1/search", payload);
resp.EnsureSuccessStatusCode();
Console.WriteLine(await resp.Content.ReadAsStringAsync());Three things to notice in the response. results is a ranked list, and each entry carries a url, a title, a relevance score and content — extracted page text, not raw HTML — so whatever reads the answer does not need its own scraper. answer is an optional cited summary generated in the same call. The shape mirrors Tavily's response (url, title, content, score, answer), which is why code written against Tavily tutorials ports with a base-URL change.
Two knobs control the cost. search_depth runs fast at 0.5 credits, basic at 1 and advanced at 2, and max_results accepts 1–20. The full parameter list is on the API reference.
What comes back (trimmed)#
A trimmed response to the call above — two of the five results, with the text shortened — looks like this:
{
"answer": "FastAPI is a modern Python web framework for building APIs with standard type hints; the latest stable line added ...",
"results": [
{
"title": "FastAPI",
"url": "https://fastapi.tiangolo.com/",
"score": 0.92,
"content": "FastAPI is a modern, fast (high-performance) web framework for building APIs with Python 3.8+ based on standard Python type hints. ..."
},
{
"title": "tiangolo/fastapi: FastAPI framework, high performance, ...",
"url": "https://github.com/tiangolo/fastapi",
"score": 0.87,
"content": "The key features are: fast to code, fast to run, based on open standards for APIs: OpenAPI ..."
}
]
}content is the extracted text of the page, which is what saves the agent a fetch: the model reads this field instead of you running a scraping pipeline. score is a 0–1 relevance ranking. And answer condenses the results into one cited summary; drop output_type (or set it to search_results) when you would rather read the raw list yourself.
Step 3 — The five-minute agent loop#
To a language model, your search is just a tool. You describe it with a JSON schema, hand it to the model alongside the user question, and loop: every time the model answers with a tool call, you run the search, append the result, and ask again — until the model answers without calling tools. With the official SDK (pip install searchpipe openai), the whole loop is about forty lines of Python:
import json
import os
from openai import OpenAI
from searchpipe import SearchPipe
client = SearchPipe(api_key=os.environ["SEARCHPIPE_API_KEY"])
llm = OpenAI() # reads OPENAI_API_KEY from the environment
def web_search(query: str, max_results: int = 5) -> str:
"""Search the live web; return the top results as JSON."""
response = client.search(
query, max_results=max_results, search_depth="basic"
)
return json.dumps(
[
{
"title": r.title,
"url": r.url,
"score": r.score,
"content": r.content,
}
for r in response.results
],
ensure_ascii=False,
)
tools = [
{
"type": "function",
"function": {
"name": "web_search",
"description": "Search the live web and return the top results with page text.",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Search query.",
},
"max_results": {"type": "integer", "default": 5},
},
"required": ["query"],
},
},
}
]
messages = [
{"role": "user", "content": "What changed in the latest Python release?"}
]
for _ in range(6): # hard cap: unbounded loops search all afternoon
reply = llm.chat.completions.create(
model="gpt-4o-mini", # any model your provider serves
messages=messages,
tools=tools,
)
message = reply.choices[0].message
messages.append(message)
if not message.tool_calls:
break
for call in message.tool_calls:
result = web_search(**json.loads(call.function.arguments))
messages.append({"role": "tool", "tool_call_id": call.id, "content": result})
print(message.content or "Stopped after 6 tool rounds without a final answer.")
Two things this demo does on purpose. The loop is capped at six rounds — left unbounded, an agent will happily search the web all afternoon — and the final print falls back to a plain notice when the model never stops calling tools. For production, wrap the loop in try/except, set a timeout, and back off exponentially on 429s using the Retry-After header; the rate-limit section below covers the ceiling.
Skip the code: one line of MCP config#
If your agent runs inside an MCP-capable client or automation platform — Claude Desktop, Cursor, Cline, or an n8n flow — you can skip the code entirely. SearchPipe runs a hosted remote MCP server, and the API key travels in the URL, so the entire setup is pasting one link (this is the same snippet from the agents page):
{
"mcpServers": {
"searchpipe": {
"url": "https://searchpipe.tech/mcp/?api_key=sp-YOUR_API_KEY"
}
}
}The client discovers the searchpipe_search tool by itself — no schema to write, no loop to own — and the same key, credit balance and rate-limit window cover both the MCP server and the REST API. There is even a SKILL.md endpoint so an agent can fetch its own setup instructions. Per-client setups and troubleshooting live on the MCP server page.
One security note, because the key is in the URL: a link that contains a real key can leak through logs, proxies, browser history and screenshots. Do not commit a real MCP URL to source control; use your client's secret or environment-variable support where it exists, and rotate the key immediately if the URL ever leaks.
What it costs once the agent works for a living#
An agent task is a loop, not a query: plan, search, read, search again. A single completed task burns five to twenty searches, which is the number that decides your bill. The free tier is 1,000 credits every month, which buys 2,000 fast searches, 1,000 basic ones or 500 advanced ones — a personal agent doing a few tasks a day stays free indefinitely. Recharges run $2.50 per 1,000 fast searches, $5 for basic, $10 for advanced, and unlike monthly-reset plans, recharged credits never expire: a top-up bought in January still works in December. Failed calls are auto-refunded.
Throughput has one ceiling to design around: 100 requests per minute plus a burst of 20, shared across the REST API and MCP under one key. Exceed it and you get a 429 with a Retry-After header — back off and retry. If a production agent genuinely needs more, raising the limit is a support conversation, not a plan upgrade. We broke the per-task economics down in more depth in the agents roundup.
Which path for which agent#
If the agent is a prototype living inside one model vendor, start with that vendor's built-in search tool — zero integration — and graduate to a standalone API when you switch models or outgrow the bundle. If you own the code, the REST API or the SDK is the portable layer; the Tavily-compatible response shape means code from Tavily tutorials ports with a base-URL change (see the Tavily comparison). If your agent runs in an MCP-capable client or an automation platform, the hosted MCP server is the least code by a mile. And if the agent must run for months, weigh how the quota resets over feature lists — monthly resets punish anything that idles; non-expiring credits do not. The full set of options, compared honestly, lives in the agents roundup and the comparison pages, and the free-tier breakdown covers what $0 gets you across six APIs.
One trade-off we repeat everywhere: SearchPipe is the youngest product in this category, and the honest counterweight is publishing things like our public benchmark and these write-ups. Disclosure: SearchPipe is built by the team writing this post. If you want to time the five minutes yourself, signing up takes about a minute and the first 1,000 credits do not ask for a card.
Put the free tier to work
1,000 credits every month, no card required. The same key covers the REST API and a hosted MCP server — top up when you need more; recharged credits never expire.