@baanish/synthetic-search-mcp
This server lets MCP clients run Synthetic web searches and check their remaining search quota over stdio.
search: run a web search with a singlequerystring and get a small set of results containingurl,title,published, and a truncated page-text snippet.search_quota: check remaining search budget with hourly and subscription limits, requests used, remaining requests, and reset/renewal times.Integrates with local MCP clients such as Claude Code, Codex CLI, Cursor, and VS Code / GitHub Copilot.
Supports both modern stateless MCP clients (2026-07-28 protocol) and legacy 2025-era clients.
Handles rate-limit (429) errors with
Retry-After, repairs malformed JSON control characters, enforces timeouts/response caps, and redacts API-key material from upstream errors.
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., "@@baanish/synthetic-search-mcpsearch for MCP protocol updates"
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.
@baanish/synthetic-search-mcp
A minimal Model Context Protocol server that exposes Synthetic web search over stdio.
It provides two MCP tools:
search: run a web search against Synthetic and return a small set of results withurl,title,published, and a truncated page-text snippet.search_quota: check the remaining hourly search quota (limit, requests, remaining, and reset time) so an agent can stay within budget.
The server is designed for local MCP clients such as Claude Code, Codex CLI, Cursor, and VS Code.
Features
Two focused tools:
searchandsearch_quotaFresh web results from Synthetic's
/v2/searchAPIQuota visibility via Synthetic's
/v2/quotas(search is capped per hour)Clear
429rate-limit errors, includingRetry-Afterwhen providedTruncates extracted page text to about 2000 characters per result
Repairs malformed control characters when
JSON.parsefails, instead of giving upBounded requests: a 30s timeout and a 10 MB response cap prevent hangs
Drops results whose URL is not
http(s):Reads credentials from
SYNTHETIC_API_KEYSpeaks the stateless 2026-07-28 MCP protocol revision while still serving 2025-era clients from the same server factory
Runs over stdio for local MCP integrations
Related MCP server: web-mcp-server
Protocol support
The server speaks both MCP protocol eras from one factory:
2026-07-28 (stateless): a modern client's opening request is served statelessly — no
initializehandshake, noMcp-Session-Id, with the protocol version, client identity, and client capabilities carried in the per-request_metaenvelope. The server implements the spec-requiredserver/discoverRPC, so clients can probe it up front. Protocol state travels on the request itself, so no server-side session state is required: if you wrapcreateServerin an HTTP entry (createMcpHandler), each request can be answered by a fresh instance from the factory behind a plain load balancer.2025-era (legacy): a client that opens with the legacy
initializehandshake is pinned to a 2025-era instance built from the same factory and served exactly as a hand-wired stdio server would be, so existing hosts (Claude Code, Cursor, VS Code, Codex CLI) keep working unchanged.
The stdio entry picks the era once per connection, from how the client opens, and pins one instance from the factory for the connection's lifetime — a property of the one-process-per-client stdio deployment, not of the protocol. No configuration is required.
Requirements
Node.js 20+
A Synthetic API key in
SYNTHETIC_API_KEY
Installation
Use npx:
npx -y @baanish/synthetic-search-mcpOr install globally:
npm install -g @baanish/synthetic-search-mcp
synthetic-search-mcpMCP Client Setup
The server command is:
{
"command": "npx",
"args": ["-y", "@baanish/synthetic-search-mcp"],
"env": {
"SYNTHETIC_API_KEY": "your_api_key_here"
}
}Claude Code
Add a project-level .mcp.json file:
{
"mcpServers": {
"synthetic-search": {
"command": "npx",
"args": ["-y", "@baanish/synthetic-search-mcp"],
"env": {
"SYNTHETIC_API_KEY": "your_api_key_here"
}
}
}
}Codex CLI
Add this to ~/.codex/config.toml:
[mcp_servers.synthetic-search]
command = "npx"
args = ["-y", "@baanish/synthetic-search-mcp"]
env = { SYNTHETIC_API_KEY = "your_api_key_here" }Cursor
Add this to .cursor/mcp.json in your project or the equivalent Cursor MCP settings file:
{
"mcpServers": {
"synthetic-search": {
"command": "npx",
"args": ["-y", "@baanish/synthetic-search-mcp"],
"env": {
"SYNTHETIC_API_KEY": "your_api_key_here"
}
}
}
}VS Code / GitHub Copilot
Add this to .vscode/mcp.json:
{
"servers": {
"synthetic-search": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@baanish/synthetic-search-mcp"],
"env": {
"SYNTHETIC_API_KEY": "your_api_key_here"
}
}
}
}Tool
search
Search the public web through Synthetic.
Input:
{
"query": "latest model context protocol news"
}Output:
[
{
"url": "https://example.com/article",
"title": "Example result",
"text": "Truncated extracted page text...",
"published": "2026-03-12T10:15:00.000Z"
}
]Notes:
Synthetic only supports a single
queryparameter.Result text is truncated to keep MCP context manageable.
publishedmay benullwhen the source does not provide a date.
search_quota
Report the remaining Synthetic search quota. Takes no input.
Output:
{
"hourly": {
"limit": 250,
"requests": 32,
"remaining": 218,
"renewsAt": "2026-06-26T21:00:00.000Z"
},
"subscription": {
"limit": 750,
"requests": 10,
"remaining": 740,
"renewsAt": "2026-07-01T00:00:00.000Z"
}
}Notes:
Search is rate-limited per hour;
hourlyreflects the current window.remainingis derived aslimit - requests(clamped at 0).A window is
nullif Synthetic does not report it.Checking the quota does not count against your search limit.
Development
npm install
npm run buildRun locally:
SYNTHETIC_API_KEY=your_api_key_here npm run devTesting
npm run typecheck # tsc --noEmit over src + tests
npm test # vitest: unit, integration (both MCP protocol eras), and fuzz testsThe suite includes an opt-in live smoke test that calls the real Synthetic API.
It runs only when SYNTHETIC_API_KEY is available (copy .env.example to .env
and add your key) and is skipped automatically otherwise — including in CI.
Security
Credential redaction
Upstream API error bodies are redacted of the active API key and bearer-token-like
material before they are returned over stdio. This prevents a hostile or
misconfigured upstream from reflecting the SYNTHETIC_API_KEY back through MCP
tool output.
Transitive dependency advisories
The runtime MCP dependency is the v2 SDK package @modelcontextprotocol/server,
whose tree is just @modelcontextprotocol/core and zod — it pulls in no HTTP
web-middleware packages. The npm overrides this repo previously carried (for
hono, @hono/node-server, path-to-regexp, fast-uri, ip-address, and
qs, all pulled in transitively by the v1 @modelcontextprotocol/sdk) are
therefore removed, and none of those advisories appear in this repository's
dependency tree anymore.
Remaining local advisory:
esbuild (dev-only, via
tsx): affects the esbuild development server on Windows only; not used at runtime and not published in the npm tarball.
License
MIT
Available Tools
2 toolssearchARead-only
Search the public web with Synthetic. Use this when you need fresh web results with extracted page text for a specific query. Input only supports a single query string, and the response returns a small set of relevant results with URLs, titles, published dates, and truncated text snippets.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | The exact web search query to run. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint and openWorldHint. The description adds useful behavioral details: input constraint (single query string), output characteristics (small set of results with URLs, titles, dates, truncated snippets), and the notion of 'fresh' results. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core action, followed by usage context and output details. Every sentence adds value with no redundant filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter tool with good annotations and no output schema, the description adequately covers input format, output contents, and usage context. It is complete enough for an agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with a clear description of the query parameter. The description's mention of 'single query string' repeats the schema's structure, adding no new semantic information beyond what the schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool searches the public web using Synthetic. It distinguishes itself from the sibling search_quota by focusing on the search functionality itself, not quota management.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use guidance ('Use this when you need fresh web results with extracted page text for a specific query'). Does not explicitly mention when not to use it, but the context is clear and the only sibling (search_quota) is obviously different.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_quotaARead-only
Check how much Synthetic web search quota remains. Search is capped per hour; this returns the hourly search limit, requests used so far, remaining requests, and when the window resets (plus the subscription-period quota). Use it to decide whether you still have search budget before calling search. Checking the quota does not itself count against the limit.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already signals a safe read operation, and the description adds meaningful behavioral context beyond that: the check does not consume the quota and returns a reset time plus subscription-period quota. This is more transparency than a bare read-only declaration would provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences, front-loaded with the core purpose, and every sentence adds value. There is no repetition of schema or annotation content, and the structure flows logically from what the tool returns to when to use it.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by listing the key return fields (hourly limit, requests used, remaining, reset, subscription quota) and the non-counting behavior. For a simple, zero-parameter tool, this is fully sufficient context for an agent to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and an empty schema, so there is nothing to document. The baseline of 4 for a no-parameter tool is appropriate, and the description handles usage entirely without needing parameter detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses the specific verb 'Check' and names the 'Synthetic web search quota' resource, clearly distinguishing this from the sibling `search` tool. It also enumerates the exact data returned (limit, used, remaining, reset), leaving no ambiguity about the tool's function.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use the tool: 'Use it to decide whether you still have search budget before calling `search`.' This directly ties usage to the sibling tool and gives a clear decision-making context. It also notes that checking quota does not count against the limit, which is practical guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v2.0.0- First observed
search - First observed
search_quota
TDQS
Scored across 2 tools
The two tools have completely distinct purposes: one performs web searches, the other checks quota usage. There is no overlap or ambiguity in their roles.
Both tools follow a clean verb_noun pattern: 'search' and 'search_quota' are consistent and clearly derive from the same domain, maintaining a predictable structure.
With only two tools, the server is below the typical 3-15 range. However, for a simple search-focused MCP server, the minimal set is justifiable, though it still feels slightly thin.
The core search functionality is covered, and the quota tool supports operational awareness. A minor gap is the lack of advanced search options like pagination or filters, but the server appears intentionally simple and whole for its stated purpose.
Maintenance
Related MCP Connectors
MCP server for Google search results via SERP API
Docs: https://docs.keenable.ai/mcp-server Keenable is a free, remote MCP server that gives agents access to the web index. Search the web with ranked results and date/site filters, then fetch any indexed page as clean markdown. Works out of the box with no account or API key.
Serper MCP — wraps the Serper Google Search API (serper.dev)
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceA Model Context Protocol server that exposes powerful web search and scraping tools to AI agents and MCP-compatible clients.Apache 2.0
- FlicenseNot gradedqualityDmaintenanceMCP server that exposes web_search and web_fetch tools, allowing LLM applications to search the web via DuckDuckGo and fetch page content as cleaned markdown.-
- FlicenseAqualityDmaintenanceMCP server that provides web search capabilities using the Tavily API.3-
- FlicenseNot gradedqualityCmaintenanceMCP server providing web search, news search, and X/Twitter search capabilities via HTTP or stdio.-