Browser MCP Server
by feedmepos
README.md
# Browser MCP Server
An MCP (Model Context Protocol) server that gives AI agents a real, anti-bot-aware browser via [Zyte API](https://www.zyte.com/zyte-api/) — navigate pages, click/type/scroll, take screenshots, and extract structured data, with automatic proxy/IP rotation and ban avoidance.
Built with [NestJS](https://nestjs.com/) and [`@nestjs-mcp/server`](https://www.npmjs.com/package/@nestjs-mcp/server), talking to Zyte's `/extract` endpoint directly over HTTP. Transport is streamable HTTP only, served stateless at a single `/mcp` endpoint.
## Setup
1. Copy `.env.example` to `.env` and fill in:
| Variable | Required | Description |
| --------------------- | -------- | ---------------------------------------------------------------------------------------------------------- |
| `ZYTE_API_KEY` | yes | Your [Zyte API key](https://app.zyte.com/o/zyte-api/api-access) |
| `ZYTE_API_BASE_URL` | no | Override the Zyte API base URL (default `https://api.zyte.com/v1`) |
| `PORT` | no | HTTP port (default `3000`) |
| `BROWSER_TIMEOUT_MS` | no | Per-request timeout for calls to Zyte (default `30000`) |
| `BROWSER_MAX_RETRIES` | no | Retries for rate-limit (429/503) and temporary ban (520) responses, with exponential backoff (default `2`) |
2. Install dependencies and start the server:
```bash
pnpm install
pnpm run start:dev
```
The MCP endpoint is served at `http://localhost:3000/mcp`.
## Tools
| Tool | Returns |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `browser_browse` | Opens a URL, optionally runs actions (click/type/select/scroll/wait), returns a `sessionId`, rendered HTML, and optionally a screenshot |
| `browser_screenshot` | Screenshot of a page, optionally after running actions |
| `browser_extract` | AI-extracted structured JSON matching a JSON Schema you provide |
| `browser_search` | Structured web search results (title/url/snippet) via Zyte's Search API — use to find pages, then open them with `browser_browse` |
`browser_browse`, `browser_screenshot`, and `browser_extract` accept an optional `sessionId` (returned from a previous call) to reuse the same IP address and cookie jar across multiple tool calls — useful for staying logged in or keeping a consistent IP across a multi-step task. Note that, per [Zyte's session docs](https://docs.zyte.com/zyte-api/usage/features.html#sessions), this does **not** persist actual browser/tab state (in-page form input, scroll position, open modals, etc.) between calls — each call loads a fresh page using the same network identity and cookies.
`actions` is a sequence of steps run before the result is captured: `click`, `type`, `select`, `hover`, `keyPress`, `scrollBottom`, `scrollTo`, `waitForSelector`, `waitForTimeout`, `waitForNavigation`, `goto`, `evaluate`. Element-targeting actions take a `selector: { type: "css" | "xpath", value: string }`.
`browser_search` posts to Zyte's separate `/v1/search` endpoint (not `/v1/extract`) and takes a `domain` (a supported search engine, e.g. `"google.com"`), a `query`, and optional `maxResults` (10-100)/`geolocation`/`locale`.
Rate-limit (429/503) and temporary-ban (520) responses from Zyte are retried automatically with exponential backoff, up to `BROWSER_MAX_RETRIES` times, per [Zyte's error handling guidance](https://docs.zyte.com/zyte-api/usage/errors.html). Other error responses (invalid request, permanent ban, account suspended) surface immediately, with Zyte's error `type` included in the message where available.
## Connecting a client
Example remote-MCP client configuration (e.g. Claude Desktop / Claude Code) pointing at a running instance:
```json
{
"mcpServers": {
"browser": {
"url": "http://localhost:3000/mcp"
}
}
}
```
## Testing
```bash
pnpm test # unit tests (service + resolver, global fetch mocked)
pnpm run lint # eslint
pnpm run build # type-check + compile
```
Unit tests mock the global `fetch` used to call Zyte. To verify end-to-end against the live API, run the server with a real `ZYTE_API_KEY` and use `pnpm dlx @modelcontextprotocol/inspector http://localhost:3000/mcp`, or `curl`, to run `initialize` → `tools/list` → `tools/call`.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing