Metadata-Version: 2.4
Name: pydoll-browser-mcp
Version: 0.2.0
Summary: MCP server for browser automation powered by pydoll (Chrome/Edge over CDP) with multi-context, multi-tab and per-context proxy support.
Author: pydoll-browser-mcp contributors
License: MIT
Keywords: mcp,pydoll,browser,automation,cdp,proxy,chrome,model-context-protocol
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: System :: Networking
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pydoll-python>=2.26.0
Requires-Dist: mcp>=2.0.0
Requires-Dist: pydantic>=2
Requires-Dist: httpx>=0.27
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pytest-asyncio>=0.24; extra == "dev"
Dynamic: license-file

# pydoll-browser-mcp

An MCP server for browser automation built on [pydoll](https://github.com/autoscrape-labs/pydoll)
(real Chrome/Edge over CDP) with:

- multi-context and multi-tab control,
- **per-context proxies** (isolated cookies/storage per identity),
- a large tool surface covering navigation, elements, network, storage, devtools,
  stealth, HTTP-via-browser and a raw `cdp_send` escape hatch.

> Note: the PyPI distribution is `pydoll-browser-mcp` (the older `pydoll-mcp` name belongs to an
> unrelated project). The Python import package is `pydoll_mcp`.

## Install / run (no project files needed)

Once published, run it straight from PyPI with [`uv`](https://docs.astral.sh/uv/):

```bash
uvx pydoll-browser-mcp
```

or with [`pipx`](https://pipx.pypa.io/):

```bash
pipx run pydoll-browser-mcp
```

Both download the server + dependencies into an isolated environment and run it over stdio, so
nothing is added to the user's project directory. To install it permanently:

```bash
uv tool install pydoll-browser-mcp     # or: pipx install pydoll-browser-mcp
```

### Development install (this repo)

```bash
python -m venv .venv
.venv\Scripts\python -m pip install -e .
.venv\Scripts\python -m pydoll_mcp.server
```

## opencode config

Published (isolated, no project files):

```jsonc
{
  "mcp": {
    "pydoll": {
      "type": "local",
      "command": ["uvx", "pydoll-browser-mcp"],
      "enabled": true
    }
  }
}
```

Local checkout / venv:

```jsonc
{
  "mcp": {
    "pydoll": {
      "type": "local",
      "command": ["C:\\path\\to\\pydoll-mcp\\.venv\\Scripts\\python.exe", "-m", "pydoll_mcp.server"],
      "environment": { "PYDOLL_MCP_PROFILE": "full", "PYDOLL_MCP_HEADLESS": "true" },
      "enabled": true
    }
  }
}
```

## Profiles

`PYDOLL_MCP_PROFILE` selects the default tool set: `core`, `balanced` (default) or `full`.
`balanced` = core + network + storage + meta. `full` also enables input, stealth, devtools, http.

## Configuration (environment)

| Variable | Default | Purpose |
| --- | --- | --- |
| `PYDOLL_MCP_BROWSER` | `chrome` | `chrome` or `edge` |
| `PYDOLL_MCP_HEADLESS` | `true` | headless new mode |
| `PYDOLL_MCP_PROFILE` | `balanced` | tool profile |
| `PYDOLL_MCP_EXECUTABLE_PATH` | | explicit browser binary |
| `PYDOLL_MCP_USER_DATA_DIR` | | persistent profile dir |
| `PYDOLL_MCP_OUTPUT_DIR` | `~/.pydoll-mcp/output` | screenshots/PDFs/downloads |
| `PYDOLL_MCP_SCRIPT_TIMEOUT` | `30` | seconds a script may run before the tab call is aborted (0 = unlimited) |
| `PYDOLL_MCP_MAX_RESULT_BYTES` | `2000000` | max size of a tool result before it is truncated (0 = unlimited) |
| `PYDOLL_MCP_MAX_TABS` | `25` | max tabs per browser (0 = unlimited) |
| `PYDOLL_MCP_MAX_CONTEXTS` | `10` | max contexts per browser (0 = unlimited) |
| `PYDOLL_MCP_ALLOW_JS` | `true` | enable `tab_execute_script` |
| `PYDOLL_MCP_ALLOW_CDP` | `true` | enable `cdp_send` |
| `PYDOLL_MCP_ALLOW_FILE_ACCESS` | `true` | allow file inputs/PDF output |
| `PYDOLL_MCP_ALLOW_UNRESTRICTED_FILE_ACCESS` | `false` | disable the file jail |
| `PYDOLL_MCP_FILE_ROOTS` | output dir + cwd | comma-separated allowed roots |

## Proxies

`context_create(proxy_server="host:port:user:password")` gives that context its own egress IP.
`context_create(proxy_server="http://user:pass@host:port")` and `socks5://host:port` also work.
Use `proxy_test(proxy_server=...)` to verify the egress IP before a run. Note: Chrome does not
support authenticated SOCKS5; use an unauthenticated local forwarder for that case.

## Session persistence

Use `context_storage_state_export` / `context_storage_state_import` to move cookies + localStorage
between runs or machines. (Chrome profile-dir persistence is unreliable because pydoll force-stops
the process after `Browser.close`.)

## Resilience

Each tab is locked independently, so a hung script or renderer on one tab no longer blocks other
tabs or browsers. Scripts are aborted after `PYDOLL_MCP_SCRIPT_TIMEOUT` seconds (Chrome terminates
them first when it can) and oversized results are truncated. `tab_info` reports `alive` plus an
`unresponsive_reason` when a tab stops responding, `browser_status` lists `dead_tabs` whose CDP
connection dropped, and closing a stuck tab (`tab_close`) always works.

## Development

```bash
python -m venv .venv
.venv\Scripts\python -m pip install -e ".[dev]"
```

Test harnesses (require Chrome; some hit the network / use proxies):

```bash
.venv\Scripts\python tests\live_check.py    # every tool category, local fixture
.venv\Scripts\python tests\deep_check.py    # 155 checks, asserts 100% tool coverage
.venv\Scripts\python tests\ultra_check.py   # multi-browser, isolated contexts, persistence, stress
.venv\Scripts\python tests\stdio_check.py   # real MCP stdio handshake
.venv\Scripts\python tests\proxy_check.py   # per-context proxy egress
```

## Publishing

```bash
python -m pip install build twine
python -m build
twine check dist/*
twine upload dist/*          # prompts for a PyPI API token (username: __token__)
```
