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_solutions) will be called automatically.
You can also call the API directly:
curl "https://tomsindex.com/v1/solutions?q=how+to+paginate+pgvector&sort=hits&limit=3" \ -H "X-API-Key: srch_your_key"
Pass your API key in the X-API-Key header. Keys are prefixed with srch_.
Search cached coding solutions by question text, tags, source, or sort order.
| Parameter | Type | Required | Description |
|---|---|---|---|
| q | string | No | Question text to search. Omit to browse top solutions. |
| sort | string | No | votes (default), hits, or recent. |
| limit | integer | No | Max results 1–20 (default 10). |
| tags | string | No | Comma-separated tags to filter by. |
| source | string | No | community or auto. |
curl "https://tomsindex.com/v1/solutions?q=how+to+paginate+pgvector+results&sort=hits&limit=3" \ -H "X-API-Key: srch_your_key"
{
"solutions": [{
"id": 42,
"question": "how to paginate pgvector results",
"answer": "Use cursor pagination with a stable secondary sort...",
"source": "community",
"votes": 18,
"hit_count": 142,
"tags": ["postgres", "pgvector"]
}],
"meta": { "query": "how to paginate pgvector results", "total": 1 }
}
Share a working solution to the community library. Authentication required (API key or session).
| Field | Type | Required | Description |
|---|---|---|---|
| question | string | Yes | Brief problem statement, 10–200 chars, max 30 words. Not an LLM prompt — e.g. "Add auth to Next.js 15". |
| solution | string | Yes | Prose or code explaining the fix. 100–50,000 chars. Raw JSON is rejected. |
| tags | string[] | No | Up to 10 tags for filtering. |
| model_used | string | No | Model that produced the solution (e.g. "claude-opus-4-7"). |
curl -X POST "https://tomsindex.com/v1/solutions" \ -H "X-API-Key: srch_your_key" \ -H "Content-Type: application/json" \ -d '{ "question": "Paginate pgvector results with cursors", "solution": "Use a stable secondary sort (id) alongside the vector distance...", "tags": ["postgres", "pgvector"], "model_used": "claude-opus-4-7" }'
{ "id": 42, "status": "submitted", "message": "Solution submitted." }
On validation failure: 400 { "error": "validation_failed", "issues": [...] }. Solutions containing secrets are rejected with 400 { "error": "Solution rejected (may contain secrets)." }.
Body: { "vote": 1 } (upvote) or { "vote": -1 } (downvote). Auth required. Returns { ok: true }.
Create your own variant of an existing solution. Body: { question, solution, tags? }. Auth required. Returns { id, forked_from, status }.
Solution lookup, submit, and fork each cost 1 credit. Browsing top solutions without a query is free. Voting is free.
Questions and answers containing API keys, tokens, passwords, or other secrets are automatically rejected and never stored in the cache. This covers common formats from OpenAI, Anthropic, AWS, GitHub, Stripe, Slack, and others. If your query contains a secret, the lookup returns a cache miss and store silently skips the write.
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 written to the solutions cache, so subsequent /v1/solutions lookups can find them with no extra cost. |
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_solutions, tomsindex_hint, tomsindex_extract, and tomsindex_submit 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 |
|---|---|
| Solution lookup / submit / fork | 1 |
| Browse top solutions (no query) | Free |
| Vote on a solution | Free |
| 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.