Skip to main content
Glama
Byski

mcp-searchapi

by Byski
README.md
# mcp-searchapi

An [MCP](https://modelcontextprotocol.io) server for [SearchApi.io](https://www.searchapi.io). Eight search engines exposed as discrete tools, returning trimmed structured results instead of raw SERP payloads.

```bash
npx -y mcp-searchapi
```

## Why this exists

Two SearchApi MCP packages were already on npm when this was written. Both are single-version releases from mid-2025 that have not been updated since, neither has a test suite, and one of them targets SearchAPI**.site**, a different product. So this is not a third copy of the same thing:

**One tool per engine, not one `search` tool with a mode flag.** A model picks `google_jobs` correctly far more often than it picks `search(engine="google_jobs")`. Every parameter carries a description written as guidance, because those descriptions are the prompt the model actually reads.

**Trimmed structured output.** SearchApi returns results under a different key per engine (`organic_results`, `local_results`, `shopping_results`, `videos`, `jobs`), each with a different field set, and the payloads are large. Measured against live responses on 7 August 2026:

| Tool | Raw payload | Returned at `limit: 10` | Saved |
|---|---:|---:|---:|
| `google_search` | 171,668 B | 2,507 B | 98.5% |
| `google_shopping` | 117,262 B | 4,391 B | 96.3% |
| `google_maps` | 71,607 B | 3,172 B | 95.6% |
| `youtube_search` | 56,836 B | 3,587 B | 93.7% |
| `google_jobs` | 86,433 B | 7,772 B | 91.0% |
| `google_news` | 38,176 B | 4,221 B | 88.9% |
| `amazon_search` | 47,732 B | 7,718 B | 83.8% |
| `google_scholar` | 19,066 B | 5,813 B | 69.5% |

The percentage matters less than the ceiling: whatever the engine sends back, a page of results stays under 8KB. Handing a model 171KB of ad blocks, favicons and pagination tokens spends its context window on things it will never use.

Every result normalises to a common core (`position`, `title`, `url`, `snippet`) plus the extras that matter for that engine: price and rating for shopping, coordinates and opening state for maps, company and posting date for jobs, channel and view count for YouTube, citation counts for Scholar.

## Setup

Get a key at [searchapi.io](https://www.searchapi.io). The free tier is 100 searches a month.

### Claude Desktop

`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS, `%APPDATA%\Claude\claude_desktop_config.json` on Windows:

```json
{
  "mcpServers": {
    "searchapi": {
      "command": "npx",
      "args": ["-y", "mcp-searchapi"],
      "env": { "SEARCHAPI_API_KEY": "your-key" }
    }
  }
}
```

### Cursor

`~/.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "searchapi": {
      "command": "npx",
      "args": ["-y", "mcp-searchapi"],
      "env": { "SEARCHAPI_API_KEY": "your-key" }
    }
  }
}
```

### VS Code

`.vscode/mcp.json`:

```json
{
  "servers": {
    "searchapi": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "mcp-searchapi"],
      "env": { "SEARCHAPI_API_KEY": "your-key" }
    }
  }
}
```

### Hosted

```bash
SEARCHAPI_API_KEY=your-key npx -y mcp-searchapi --http --port 3000
```

Serves streamable HTTP at `/mcp` and a health check at `/health`. Stateless, so it scales horizontally without sticky sessions.

## Tools

| Tool | Engine | Use it for | Extra fields |
|---|---|---|---|
| `google_search` | Google | General questions, fact-checking, finding sources | `source`, `domain` |
| `google_news` | Google News | Recent events, "what's happening with X" | `source`, `date` |
| `google_shopping` | Google Shopping | Price comparison, product availability | `price`, `rating`, `reviews`, `seller`, `delivery` |
| `google_jobs` | Google Jobs | Vacancies, hiring, job market | `company`, `location`, `postedAt`, `scheduleType` |
| `google_scholar` | Google Scholar | Papers, citations, academic sources | `publication`, `authors`, `citedBy` |
| `google_maps` | Google Maps | Places, local business, "near me" | `address`, `rating`, `openState`, `latitude`, `longitude` |
| `youtube_search` | YouTube | Videos, tutorials, talks | `channel`, `views`, `length`, `publishedTime` |
| `amazon_search` | Amazon | Amazon product lookups | `asin`, `price`, `rating`, `isSponsored` |

### Parameters

`query` is required everywhere. `limit` (default 10, max 50) caps what comes back to the model. The rest are offered only on the engines that accept them:

| Parameter | Meaning | Available on |
|---|---|---|
| `location` | Geo-target as `City,Country` | search, news, shopping, jobs, maps |
| `gl` | Two-letter country code | search, news, shopping, maps, youtube, amazon |
| `hl` | Two-letter language code | all except amazon |
| `num` | Results to request from the engine | search, news, shopping, scholar |
| `page` | Page number, from 1 | all except youtube |

`google_jobs` deliberately does not offer `gl`: the API rejects country codes on that engine (`gl=ie` returns HTTP 400 `Unsupported value`). Use `location` instead. Advertising a parameter the API will reject is worse than not having it, because the model has no way to discover the constraint.

### Example

```
google_jobs(query: "backend engineer", location: "Dublin,Ireland", limit: 3)
```

```json
{
  "engine": "google_jobs",
  "query": "backend engineer",
  "totalResults": 10,
  "results": [
    {
      "position": 1,
      "title": "Backend Engineer",
      "url": "https://...",
      "company": "Example Ltd",
      "location": "Dublin, Ireland",
      "via": "LinkedIn",
      "postedAt": "2 days ago",
      "scheduleType": "Full-time",
      "snippet": "..."
    }
  ]
}
```

`totalResults` reports what the engine returned, not what was kept, so the model can tell there is more available behind a higher `limit`.

## Errors

Failures come back as tool errors with something actionable, not a bare status code:

| Condition | Message |
|---|---|
| Missing key | Server exits at startup rather than failing on the first call |
| 401 | Names `SEARCHAPI_API_KEY` and links where to get one |
| 429 | Says quota or rate limit, and notes the free tier is 100/month |
| 400 | Passes through the API's own message, for example the `gl` rejection above |
| Timeout | Reports the elapsed limit; defaults to 30s |
| No results | Not an error. Returns an empty `results` array with a `notice` |

## Development

```bash
npm install
npm test           # 77 tests, no network
npm run typecheck
npm run build

SEARCHAPI_API_KEY=... node scripts/smoke.mjs   # end-to-end, costs 1 search
```

Tests run against real captured API responses in `test/fixtures/`, one per engine plus an empty-result case, so they exercise the shapes the API actually returns rather than the shapes it was assumed to return. Nothing in `npm test` touches the network.

Adding an engine is a data change: append an entry to `ENGINES` in `src/engines.ts` with its result key, supported parameters and a normaliser. The server registers tools from that registry.

## Licence

MIT

TDQS

A4.2/5.0

Scored across 8 tools

Disambiguation5/5

Each tool targets a distinct search vertical (general web, news, shopping, jobs, academic, maps, videos, Amazon). The descriptions clearly specify when to use each, leaving no ambiguity between them.

Naming Consistency4/5

Most tools follow a 'google_<service>' pattern, but youtube_search and amazon_search use a '<service>_search' pattern, creating a minor inconsistency. The overall style is still readable and predictable.

Tool Count5/5

With 8 tools, the server is well-scoped for a search aggregation service. Each tool covers a major search category without unnecessary redundancy.

Completeness5/5

The tool surface covers a broad range of search needs: general web, news, shopping, jobs, academic, maps, videos, and e-commerce. For a search-focused server, this is a comprehensive set with no obvious missing core capabilities.

Maintenance

ActivitySlowing
ResponsivenessNo issues