brave-answers-mcp
Provides tools for interacting with the Brave Answers API, enabling synchronous question answering and asynchronous deep research tasks with progress tracking and result retrieval.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@brave-answers-mcp Run a deep research on the economic impact of universal basic income"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
brave-answers-mcp
TypeScript MCP server (stdio) wrapping the Brave Answers API
(POST https://api.search.brave.com/res/v1/chat/completions, header
X-Subscription-Token). The Brave Answers plan is billed separately from the
Brave Search plan — the key is provided as the BRAVE_ANSWERS_KEY env var
(never commit or print it).
Why it exists: no MCP wraps this endpoint (verified 2026-08), and research-mode
calls run ~90–300s — far beyond a blocking agent tool call. This server adds
the missing async submit → status → result semantics: the job lives in the
MCP server process, so it outlives bash timeouts and turn boundaries. The SSE
parser was ported from a working production browser implementation (streaming
pass-through only) and extended with the <answer> tag and display
normalization.
Quick start
npm install
npm run build
export BRAVE_ANSWERS_KEY=...
node dist/index.js # speaks MCP over stdioRegister it in your agent's MCP config (opencode example below).
Related MCP server: Brave Search MCP
Tools
Tool | Mode | Latency | Cost (all measured 2026-08-16) |
| sync single-search, streaming | ~10–30s | $0.051–0.055/call (citations on/off; entities n/a) |
| async research, returns | ~90–312s (wall can exceed budget — see gotchas) | $0.069–0.084 narrow, $0.771 for a 10-query broad run — see cost model |
| poll job | instant | free |
| fetch completed job | instant | free |
answers params: query, country?, language?, enable_citations?
(default true). (enable_entities exists in the API but is silently ignored —
verified via raw SSE probe 2026-08-16: zero <enum_item> frames — so it is not
exposed; the parser branch is kept in case it ships later.)
research_submit params: query, country?, language?,
research_maximum_number_of_iterations? (1–5, default 4),
research_maximum_number_of_seconds? (1–300, default 180; soft target),
research_allow_thinking? (default true),
research_maximum_number_of_queries? (1–50, default 20),
research_maximum_number_of_tokens_per_query? (1024–16384, default 8192),
research_maximum_number_of_results_per_query? (1–60, default 60).
Research mode cannot mix with citations — enforced by omitting that key.
research_status reports live progress (last <progress> frame) while the
job runs; raw SSE is teed for every call.
Request body: model: "brave", exactly one user message, always stream: true
(one tested code path). Timeouts: 60s simple / 600s research. Responses are
routed to an internal brave-pro model.
Cost model (measured 2026-08-16)
<usage> breaks cost into four components:
Component | Rate (derived) | Example run |
Input tokens | ~$0.005 per 1K | 9,210 tokens → $0.046 (dominant) |
Output tokens | ~$0.005 per 1K | 153 tokens → $0.0008 |
Search queries | ~$0.004 each | 1 → $0.004 |
Requests | $0 | 1 → $0.00 |
Research cost is driven by how many queries the engine actually runs (~$0.07/query effective, dominated by snippet tokens), not the iteration caps — those are ceilings, not targets:
Question type | Queries run | Cost | Wall |
Narrow (speculative decoding / MLX) | 1 (of 4-iter cap) | $0.079 | 136s |
Narrow (forced 1 iteration) | 1 | $0.069 | 91s |
Broad (solid-state batteries, 3-iter) | 10 | $0.771 | 312s (240s soft budget) |
So the commonly cited ~$1+/call figure is reasonable for full default runs (20-query cap — historical multi-query runs measured $1–1.45) while early-terminating narrow questions are just cheap. Budget rule of thumb: ~$0.07 × expected queries.
Full <usage> fields: X-Request-Requests, X-Request-Queries,
X-Request-Tokens-In/Out, X-Request-Requests-Cost,
X-Request-Queries-Cost, X-Request-Tokens-In-Cost,
X-Request-Tokens-Out-Cost, X-Request-Total-Cost.
SSE tags parsed: <citation>, <enum_item>, <usage>, <queries>,
<analyzing>, <thinking>, <progress>, <blindspots> plus <answer> —
in research mode the final answer arrives as
<answer>{"answer": "..."}</answer> (a JSON object; also handled if it's a
JSON string). Everything else accumulates as answer content. usage JSON
carries X-Request-Total-Cost / X-Request-Queries / X-Request-Requests.
Display normalization (learned from live runs 2026-08-16): citations are
deduped by URL (Brave emits one frame per inline occurrence — a 10-citation
answer returned 21 frames); repeated <progress> frames for the same
iteration are collapsed, last frame per iteration wins.
Job registry: in-memory Map, 1h TTL after completion. Raw SSE is teed for
every call to $TMPDIR/brave-answers-mcp/<research_id>.sse (research jobs) or
<uuid>.sse (simple calls) for debugging. Note $TMPDIR, not /tmp — hosts
like opencode set a per-user temp dir for child processes. Wiped on reboot.
Build & test
npm install # once
npm run build # tsc → dist/ (re-run after source changes, then restart opencode)
npm run test:parser # offline unit tests for the SSE parser (no API calls)
node dist/smoke.js # end-to-end: tool listing, error path, one LIVE simple call (~$0.05)Node 24, @modelcontextprotocol/sdk 1.30.0, zod 3.25. registerTool takes a
zod shape (not z.object). The SDK's StdioClientTransport gives child
processes a sanitized env by default (getDefaultEnvironment) — pass env:
explicitly in any test client; see registration below for the opencode side.
SDK note (2026-08): 1.30.0 is the last v1-line release. The v2 line
(split @modelcontextprotocol/server + /client packages) shipped with the
2026-07-28 MCP spec; v1 receives bug fixes for six months after the v2
release, so migration is not urgent.
opencode registration
In ~/.config/opencode/opencode.json (global) — replace the path with this
repo's location:
"brave-answers": {
"type": "local",
"command": ["node", "<repo-root>/dist/index.js"],
"environment": { "BRAVE_ANSWERS_KEY": "{env:BRAVE_ANSWERS_KEY}" },
"enabled": true
}environment (not env) is the key that works for local MCPs. The {env:VAR}
interpolation reads from opencode's own environment. If a call returns 401
after restart, the interpolation didn't apply — delete the environment block
and rely on shell-env inheritance instead (opencode launched from the terminal
inherits ~/.zshrc exports). Restart opencode after any config change (not
hot-reloaded).
A search skill for opencode (see references/ notes) documents the
agent-facing workflow: answers for cited one-shot answers,
research_submit → research_status → research_result for deep research.
Artifacts & references
artifacts/sse/— raw SSE streams from the 2026-08-16 test runs (cost evidence, dedup evidence,enable_entitiesprobe). Seeartifacts/README.md.references/official-brave-skills/— pinned copy of the official Brave answers skill (brave/brave-search-skills @62793e0), the source of truth for request parameters and tag formats.
API gotchas (from Brave docs + live testing)
Exactly one user message per request.
enable_researchrequiresstream: true; incompatible withenable_citationsandenable_entities(research has built-in citations).enable_citationsrequires streaming; citations arrive as<citation>frames withnumber/url(+ optionalstart_index/end_index/snippet).Progress frames repeat per iteration (multiple frames, same
number_of_iterations); the cost-relevant fields are in the final<usage>frame — surface it to the user.research_maximum_number_of_secondsis a soft target, not a hard wall-clock cap: a job submitted with a 30s budget ran 91s.Iteration caps are ceilings, not targets: both observed research runs (1-iter-forced and 4-iter-default) executed exactly 1 query / 60 URLs and stopped. Cost follows actual queries/tokens — see the cost model above.
enable_entitiesis silently ignored by the API (no<enum_item>frames even when set; stream routes tobrave-pro) — not exposed in the schema.The
<progress>payload's seconds field has been seen spelledelasped_seconds(upstream typo); the parser handles both.
License
MIT — see LICENSE.
Available Tools
4 toolsanswersA
Brave Answers: AI-synthesized, web-grounded answer with source citations. One blocking call, 10-30s. Billed on the separate Brave Answers plan ($0.05 per call, measured). Use for a direct cited answer without doing your own synthesis. For deep multi-iteration research use research_submit instead.
Inputs: query (required), country, language, enable_citations.
research_resultA
Fetch the result of a completed Brave Answers research job (research_id). If the job is still running, this returns how long it has been running — call again later.
Inputs: research_id (required).
research_statusA
Check the status of a submitted Brave Answers research job (research_id from research_submit). Returns running/completed/failed, elapsed time, and latest progress.
Inputs: research_id (required).
research_submitA
Submit a Brave Answers RESEARCH job: multi-iteration web research (~90-300s). Cost ≈ $0.07 × queries actually run (narrow ≈ $0.07, broad ≈ $0.77, full 20-query runs can exceed $1) — only use when the user explicitly requests deep research. Returns a research_id immediately; the job runs in the background. Poll with research_status and fetch the deliverable with research_result once completed.
Inputs: query (required), country, language, research_allow_thinking, +5 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 4 tools
The tool set cleanly separates a single-shot direct answer from the multi-step research job lifecycle. The research_submit/status/result trio has clear sequential roles with no overlap, and descriptions reinforce when each should be used.
The research_* prefix creates a clear and consistent pattern for the job lifecycle, while 'answers' stands alone as the direct-answer tool. Though not perfectly uniform, the naming is predictable and readable.
With 4 tools, the server is well-scoped for its purpose: one for quick answers, three for asynchronous research jobs. Each tool has a distinct role with no redundancy.
The research lifecycle is fully covered with submit, status, and result. The only minor gap is the lack of explicit cancellation or listing of historical jobs, but these are not essential for the server's stated purpose.
Maintenance
Related MCP Connectors
MCP server for querying Forkast documentation
MCP server for OnceAsk, the AI-native current-address layer for people and agents.
MCP server for querying BrainKB, a knowledge base for neuroscience knowledge graphs.
Related MCP Servers
- -licenseNot gradedqualityBmaintenanceAn MCP server implementation that integrates the Brave Search API, providing both web and local search capabilities.26,972 npm91,897MIT
- AlicenseAqualityDmaintenanceAn MCP Server implementation that integrates the Brave Search API, providing, Web Search, Local Points of Interest Search, Image Search, Video Search, News Search and LLM Context Search capabilities5364 npm131GPL 3.0
- AlicenseAqualityDmaintenanceAn MCP server for integrating with the Brave Search API, and it supports HTTP proxying.216 npm3JavaScriptMIT
- AlicenseAqualityBmaintenanceMCP server for AI-powered research using Gemini. Provides fast grounded web search, deep autonomous research, URL extraction, and session management.9108 PyPI9MIT