Skip to main content
Glama
thekk1

playwright-mcp-guarded

by thekk1

playwright-mcp-guarded

一个域受限、不绑定用户的包装器,围绕微软的 playwright-mcp —— 作为 LibreChat 助手(GitHub、Wikipedia、Google、Google Scholar 等)的通用网页抓取/浏览替代品,限定于域名允许列表,通过编辑一个环境变量即可扩展。部署为纯流式 HTTP Docker 服务(不暴露 ports:,无每用户 OAuth),与兄弟项目 time-mcp-http 和 ews-mcp 的多用户模式采用相同结构。

为什么不直接运行 @playwright/mcp

它已经有 --allowed-origins/--blocked-origins 正是为此目的,而本项目并未重新实现该强制机制——它仍然是实际阻止不允许导航的部分。直接运行它缺少两件事:

  1. 其自身文档称 --allowed-origins “不是安全边界”——一个已知的缺口是 Service Worker 和 WebSocket 流量会绕过它所基于的 context.route() 拦截。--block-service-workers(此处也无条件设置)关闭了其中一个缺口;另一个没有对应的标志。

  2. 允许列表从未出现在调用模型可以看到的任何地方——不在 initialize 的 instructions 中,也不在任何工具的 description 中。模型无法预先知道哪些域可访问,因此它只能通过尝试来发现,每次每个被阻止的域都会尝试一次。

Related MCP server: Airlock

工作原理

一个容器,一个进程树,一个配置值(ALLOWED_ORIGINS):

LibreChat --(streamable-http, /mcp)--> guardian (Python, PID 1)
                                          |
                                          | spawns as child process,
                                          | on loopback only
                                          v
                                    @playwright/mcp (Node, --allowed-origins)

guardian/app.py 启动真正的 @playwright/mcp CLI(未修改),作为仅绑定到 localhost 的子进程,作为 MCP 客户端 连接到它,并在容器的公共端口上重新暴露为 MCP 服务器:tools/list 和 initialize 会附加域列表以供可见性,tools/call 原样转发——没有自己的工具逻辑,除了这两处文本编辑外没有改变行为。ALLOWED_ORIGINS 在启动时读取一次,并传递给两者:生成的进程(作为 --allowed-origins,实际强制机制)和两个响应重写(仅可见性)。之后扩展列表只需更改该单个环境变量的一行,而不是两个需要保持同步的配置。

运行

docker build -t playwright-mcp-guarded .
docker run --rm -p 8080:8080 \
  -e ALLOWED_ORIGINS="github.com;raw.githubusercontent.com;wikipedia.org;en.wikipedia.org;google.com;scholar.google.com" \
  playwright-mcp-guarded

ALLOWED_ORIGINS 以分号分隔——与 @playwright/mcp 自身用于 PLAYWRIGHT_MCP_ALLOWED_ORIGINS 的格式相同。空值会阻止所有域(在启动时记录为警告,而不是静默绕过)。

EXTRA_INSTRUCTIONS(可选,自由文本)会原样附加到模型看到的 initialize instructions 中。允许列表只说明哪些域可访问,而不说明如何使用它们背后的内容——例如,自托管搜索引擎的查询语法。这里特意不硬编码:此包装器保持域无关,部署者以他们自己的话提供其特定允许列表所需的任何操作知识:

-e EXTRA_INSTRUCTIONS="Search: http://searxng:8080/search?q=<term> (general), add &categories=science for Google Scholar results."

没有 MCP_API_KEY,MCP 连接本身没有认证门——故意如此,与 ews-mcp/time-mcp-http 的理由相同:任何门的 401 都会使 LibreChat 的非 OAuth MCP 客户端尝试(并卡在)OAuth 上。Docker 网络隔离是边界。任何类型的凭据都不会通过此服务器;它只读取公共页面。

接受的权衡,而非疏忽: 这使强制机制保持在 Playwright 应用层(现在带有 --block-service-workers),而不是独立的网络级边界(例如出口代理)。这是一个刻意的简单性选择——一个可部署单元,一个配置值——而不是声称这是万无一失的。网络级后备可以稍后添加,而无需触及任何此逻辑。

验证

curl -s http://127.0.0.1:8080/readyz   # "ok" once the upstream browser is up

日志应显示上游自身的启动行(Listening on http://localhost:<internal-port>),后跟 playwright-mcp-guarded up, allowed origins=...——第二行是当前实际强制执行的列表,而不仅仅是配置的内容。

测试

pip install -e '.[dev]'
ALLOWED_ORIGINS="github.com;wikipedia.org" pytest

仅单元测试(描述/指令重写、参数传递)——它们不会启动 Chromium 或 Docker。Docker 镜像已手动端到端验证:构建、运行,真实 MCP 客户端连接并列出工具(允许列表在 initialize.instructions 和 browser_navigate 的描述中均可见),成功导航到允许的域(en.wikipedia.org),并在不允许的域(example.com)上得到 net::ERR_BLOCKED_BY_CLIENT——强制和可见性均实时确认,而不仅仅是断言。

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to search the web, fetch news, and retrieve page content via DuckDuckGo or Brave Search, with domain whitelisting and audit logging.
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables LLM agents to safely search and fetch content from a single configured domain, preventing data exfiltration through deterministic enforcement.
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables AI agents to automate browsers through Playwright behind multi-layer safety guards, restricting navigation to allowed domains, defaulting to read-only actions, and recording all behavior in audit logs.
    7
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Enables AI assistants to fetch and process web content securely, including HTML-to-markdown conversion, reader mode, metadata extraction, RSS/sitemap parsing, and robots.txt-aware requests with SSRF protection.
    15
    805 npm
    2
    MIT