Pick your editor and run the install command:
| Tool | Command |
|---|---|
| Claude Code | npx tomsindex |
| Codex CLI | npx tomsindex |
| Cursor | Settings → MCP → Add Server → command: npx tomsindex |
The installer will prompt you for an API key. Generate one here if you don’t have one yet.
Ask your AI assistant any coding question — TomsIndex tools (tomsindex_search, tomsindex_hint, tomsindex_extract) will be called automatically.
You can also call the API directly:
curl "https://tomsindex.com/v1/search?q=how+to+paginate+pgvector" \ -H "X-API-Key: srch_your_key"
Pass your API key in the X-API-Key header. Keys are prefixed with srch_.
Get ranked web results for a query. Hybrid BM25 + vector ranking across 10M+ indexed pages. Pass a location for “near me” queries; the response includes news, places, and shopping verticals when the query calls for them.
| Parameter | Type | Required | Description |
|---|---|---|---|
| q | string | Yes | Search query |
| limit | integer | No | Max results 1–20 (default 5). Each batch of 5 results costs 1 credit. |
| offset | integer | No | Pagination offset (default 0). Use with limit to page through results. |
| near | string | No | Free-text location (e.g. "San Francisco"). Alias: location. |
| lat | float | No | Latitude for location-based queries. Use with lng. |
| lng | float | No | Longitude for location-based queries. Use with lat. |
| include_answer | boolean | No | Generate or look up an LLM answer summarising the top results. Authenticated callers only — generation costs LLM tokens. Cache lookup runs first; generated answers are cached, so repeat queries cost nothing extra. |
curl "https://tomsindex.com/v1/search?q=what+to+do+in+boston&near=Boston&include_answer=true" \ -H "X-API-Key: srch_your_key"
{
"query": "what to do in boston",
"answer": "Boston offers a mix of history, food, and culture …",
"results": [{
"id": "sd:b122ef44",
"title": "Things to Do in Boston | Attractions, Tours …",
"url": "https://www.meetboston.com/things-to-do/",
"content": "Step into history on the Freedom Trail, grab a lobster roll …",
"score": 0.92
}],
"local_results": [{ "name": "Freedom Trail", "address": "Boston, MA" }],
"response_time": 0.14,
"usage": { "credits": 1 }
}
| Field | Description |
|---|---|
query | The normalised query that was run |
answer | LLM summary string. Only present when include_answer=true and results were available. |
results | Array of ranked results: id, title, url, content, score (0–1) |
news_results | News vertical results (present when query has news intent) |
local_results | Places results (present when query has local intent) |
shopping_results | Shopping results (present when query has shopping intent) |
response_time | Seconds taken to serve the request |
usage.credits | Credits consumed by this request |
Each batch of 5 results costs 1 credit. Default (5 results) = 1 credit, 10 results = 2 credits, 15 = 3, 20 = 4. If you don't have enough credits, the API returns 429 before running the search.
Unauthenticated requests get a free preview of 2 results. Log in or provide an API key for full results.
Get a coding hint and relevant library docs for any task. Hints give your model edge-case warnings, checklists, or reasoning guidance that improve its output. If your task mentions a library (React, Prisma, Next.js, etc.), you also get up-to-date documentation snippets from 100+ indexed packages. Hints are only served when they’d help — if your task is simple or your model is already strong enough, you still get the docs.
| Field | Type | Required | Description |
|---|---|---|---|
| q | string | Yes | The question or task |
| context | string | No | Your code context (source snippets, file paths, errors). Makes hints specific to your situation. Not cached — keeps hints reusable. Max 16KB. |
| current_model | string | No | The model calling this API (e.g. claude-haiku-4-5). Helps us decide whether a hint would help or not. |
| mode | string | No | hint (default) or solve. Solve mode calls a frontier model to answer the task directly and returns a solution field. |
| session_id | string | No | Session ID from /v1/session/context. Lets hints reference your files and recent errors. |
curl -X POST "https://tomsindex.com/v1/hint" \ -H "X-API-Key: srch_your_key" \ -H "Content-Type: application/json" \ -d '{ "q": "add cursor pagination to a REST API", "current_model": "claude-haiku-4-5" }'
{
"hint": "Warning: AI models frequently score poorly on this question because they miss critical edge cases.\n\nHandle: empty result set, cursor pointing to deleted row, concurrent inserts changing page boundaries...",
"recommended_follow_up": [
{ "label": "Edge cases", "q": "What edge cases break cursor pagination?" }
],
"session_id": "abc123",
"hint_type": "counterexample",
"prompt_transform": "counterexample",
"docs": [
{ "library": "prisma", "content": "## Cursor-based pagination\nUse cursor with skip: 1 to paginate...", "source": "context-pkg" }
],
"docs_used": ["prisma"]
}
Sometimes a hint isn’t needed — your task is straightforward or your model is strong enough. You still get docs if libraries were detected.
{
"hint": null,
"recommended_follow_up": [],
"session_id": null,
"skipped": true,
"skip_reason": "model_tier_4_skip",
"docs": [
{ "library": "next.js@15", "content": "## Middleware\nMiddleware runs before cached content and routes are matched...", "source": "llms.txt" }
],
"docs_used": ["next.js@15"]
}
| skip_reason | What it means |
|---|---|
atomic_trivial_skip | Task is simple enough that your model can handle it without a hint. |
model_tier_4_skip | Your model is already strong enough (e.g. Opus, GPT-5). Hints aren’t needed. |
score_N_below_threshold | Task difficulty is N/10 — below the level where hints add value. |
The type of hint is automatically chosen based on your task:
| hint_type | Best for | What you get |
|---|---|---|
counterexample | Coding | Edge cases your model is likely to miss |
negative | Reasoning, logic | Common wrong approaches to avoid |
cot | Math, writing | Step-by-step reasoning guidance |
checklist | STEM, science | Verification checklist for correctness |
opus-hint | Very hard tasks | Tailored checklist from a frontier model |
{
"hint": null,
"solution": "function paginateCursor(query, cursor, limit) {\n ...",
"recommended_follow_up": [],
"session_id": "abc123"
}
Mention a library in your task and you get current documentation back in the docs array. Covers 100+ libraries including React, Next.js, Prisma, Express, Django, Tailwind, and more. The docs_used array shows which libraries matched.
Each hint call costs 1 credit. Skipped hints (nothing returned) are free. Solve mode costs 1 credit. Library docs are included with hints at no extra cost.
Send your working directory, recent conversation, open files, and errors so that future /v1/hint calls can reference your actual project. Attach a session_id and pass the same ID to /v1/hint.
| Field | Type | Required | Description |
|---|---|---|---|
| session_id | string | Yes | Session identifier (same one you pass to /v1/hint) |
| cwd | string | No | Working directory path |
| recent_messages | string[] | No | Last 3–5 user messages from the conversation |
| files_mentioned | string[] | No | File paths discussed or edited in the session |
| errors | string[] | No | Recent error messages or stack traces |
| stack | string | No | Tech stack (e.g. "node express postgres") |
curl -X POST "https://tomsindex.com/v1/session/context" \ -H "X-API-Key: srch_your_key" \ -H "Content-Type: application/json" \ -d '{ "session_id": "sess_abc123", "cwd": "/Users/me/myproject", "files_mentioned": ["src/auth.js", "src/db.js"], "errors": ["TypeError: Cannot read property id of undefined"], "stack": "node express postgres" }'
{ "ok": true, "session_id": "sess_abc123" }
Context is stored in memory for 1 hour. When /v1/hint is called with the same session_id, the stored context is injected into the LLM synthesis step — making hints reference your actual files and errors instead of giving generic advice. Context is not embedded or cached — it only affects the current session's hint quality.
Free. Session context updates are not billed.
Crawl any URL and get back clean markdown, metadata, links, and media. Powered by a headless browser — handles JavaScript-rendered pages, SPAs, and dynamic content.
| Field | Type | Required | Description |
|---|---|---|---|
| url | string | Yes | The URL to extract content from. https:// is added if missing. You may also pass urls as an array (first URL is used). |
| extract_depth | string | No | "basic" (default) or "advanced". Advanced waits for JavaScript and scans the full page; default timeout bumps to 30s. |
| format | string | No | "markdown" (default) or "text" (strips markdown formatting). |
| css_selector | string | No | Extract only content matching this CSS selector (e.g. "article", ".main-content"). |
| query | string | No | If provided, the page is chunked and the most relevant chunks are returned in raw_content. |
| chunks_per_source | number | No | Max chunks returned when query is set. 1–5, default 3. |
| include_images | boolean | No | Include extracted images in media. Default false. |
| stealth | boolean | No | Run Crawl4AI in stealth mode — uses an undetected browser, simulates a real user, and patches navigator fingerprinting to bypass basic bot detection (Cloudflare, PerimeterX, etc.). Slower than the default. Default false. |
| timeout | number | No | Max seconds to wait. 1–60. Default 15 (basic) or 30 (advanced). |
curl -X POST "https://tomsindex.com/v1/extract" \ -H "X-API-Key: srch_your_key" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com", "css_selector": "article", "stealth": true }'
{
"results": [{
"url": "https://example.com",
"markdown": "# Example Domain\n\nThis domain is for use in illustrative examples...",
"raw_content": "# Example Domain\n\n...",
"metadata": {
"title": "Example Domain",
"description": "",
"language": null,
"statusCode": 200,
"url": "https://example.com"
},
"links": [{ "href": "https://www.iana.org/domains/example", "text": "More information...", "type": "external" }]
}],
"failed_results": [],
"response_time": 2.134
}
When extraction fails, results is empty and failed_results contains { url, error }.
import requests def extract(url, css_selector=None, stealth=False): r = requests.post( "https://tomsindex.com/v1/extract", headers={"X-API-Key": "srch_..."}, json={ "url": url, "css_selector": css_selector, "stealth": stealth, }, ) data = r.json() return data["results"][0]["markdown"]
const res = await fetch("https://tomsindex.com/v1/extract", { method: "POST", headers: { "X-API-Key": "srch_...", "Content-Type": "application/json", }, body: JSON.stringify({ url: "https://example.com", stealth: true }), }); const { results } = await res.json(); const { markdown, metadata } = results[0];
Each extract call costs 1 credit. Recently crawled pages are served from cache at no extra cost.
OpenAI-compatible web_search tool endpoint — drop into LiteLLM, LangChain, OpenRouter, or raw OpenAI function calling. Returns a simplified response (no verticals or meta) optimized for tool-use contexts.
| Field | Type | Required | Description |
|---|---|---|---|
| query | string | Yes | Search query (alias: q) |
| limit | integer | No | Max results 1–20 (default 5) |
| feedback | array | No | Piggyback relevance feedback from previous results. Each item: { "result_id": "...", "vote": 1 } where vote is 1 (relevant) or -1 (not relevant). Improves future ranking. |
{
"results": [{
"result_id": "a1b2c3",
"title": "AWS Lambda Pricing",
"url": "https://aws.amazon.com/lambda/pricing/",
"snippet": "Pay per request and compute time …"
}]
}
{
"type": "function",
"function": {
"name": "web_search",
"description": "Search the web using TomsIndex",
"parameters": {
"type": "object",
"properties": { "query": { "type": "string" } },
"required": ["query"]
}
}
}
import requests def web_search(query, limit=5): r = requests.post( "https://tomsindex.com/v1/tools/web_search", headers={"X-API-Key": "srch_..."}, json={"query": query, "limit": limit}, ) return r.json()["results"]
Same as /v1/search — 1 credit per 5 results.
TomsIndex ships as an MCP server exposing tomsindex_search, tomsindex_hint, and tomsindex_extract tools. Session context is automatically sent via the UserPromptSubmit hook — no manual setup needed.
npx tomsindex
{
"mcpServers": {
"tomsindex": {
"command": "npx",
"args": ["tomsindex"],
"env": { "TOMSINDEX_API_KEY": "srch_..." }
}
}
}
All errors return JSON: { "error": "<message>" }.
| Status | Meaning |
|---|---|
| 400 | Missing or malformed parameters |
| 401 | Missing or invalid API key |
| 429 | Credit limit or rate limit hit — back off and honor Retry-After |
| 500 | Server error — retry with exponential backoff |
All actions use the same credit pool.
| Action | Credits |
|---|---|
| Search (per 5 results) | 1 |
| Extract a page | 1 |
| Hint (with or without docs) | 1 |
| Answer generate (cache miss) | 1 |
| Hint skipped (nothing returned) | Free |
| Plan | Credits / mo | Overage |
|---|---|---|
| Free | 1,000 | — |
| Pro ($9/mo) | 10,000 | $0.005 / credit |
Pro includes a configurable spending cap (default $10/mo). The API returns 429 when the cap is reached. Increase it in your dashboard.
Unauthenticated requests see a preview of 2 results.