Windows 部署 Playwright MCP 供 linux Codex 远程操作 Chrome:403 Forbidden 与 0 Tools 问题排查

一、背景

在 Linux 环境下使用 Codex 进行项目开发时,经常需要通过浏览器完成前端页面验证、UI 交互测试、页面截图等任务。

如果 Linux 服务器没有图形界面,直接部署 Chrome 会增加环境维护成本。

一种更轻量的方案是:

  • Linux:运行 Codex,作为 MCP Client。

  • Windows:运行 Playwright MCP Server。

  • Chrome:安装在 Windows 上,由 Playwright MCP 控制。

  • 网络:Linux 通过局域网访问 Windows 的 MCP HTTP 服务。

架构如下:

bash 复制代码
Linux
  └── Codex
       └── MCP Client
            │
            │ HTTP / MCP
            ▼
Windows
  └── Playwright MCP Server
       └── Google Chrome

本次部署过程中,先后遇到了 PowerShell 脚本执行限制、Windows 防火墙权限问题,以及最关键的 MCP 403 Forbidden 和 Codex failed (0 tools) 问题。

下面记录完整的排查与解决过程。

二、环境说明

项目 环境
MCP Client Linux + Codex
MCP Server Windows
浏览器 Google Chrome
MCP 实现 @playwright/mcp
传输方式 Streamable HTTP
MCP 端口 8931
Windows IP 192.0.2.10(示例)
Linux IP 192.0.2.20(示例)

实际部署时将示例 IP 替换为真实局域网 IP。

三、Windows 安装并启动 Playwright MCP

3.1 安装 Node.js

首先在 Windows 安装 Node.js,并确认 npm 和 npx 可用:

bash 复制代码
node -v
npm -v
npx.cmd -v

Playwright MCP 官方项目:

github.com/microsoft/p...

3.2 PowerShell 禁止执行 npx.ps1

直接执行:

bash 复制代码
npx -y @playwright/mcp@latest

出现错误:

bash 复制代码
无法加载文件 C:\Program Files\nodejs\npx.ps1,
因为在此系统上禁止运行脚本。

PSSecurityException
FullyQualifiedErrorId : UnauthorizedAccess

原因分析

PowerShell 的 Execution Policy 禁止运行 .ps1 脚本,而 npx 命令匹配到了 npx.ps1。

这并不是 Node.js 安装失败。

解决方案

直接调用 npx.cmd:

bash 复制代码
npx.cmd -y @playwright/mcp@latest

该方式不需要修改 PowerShell 执行策略。

不建议为了运行 npx 而直接关闭系统级脚本执行限制。

3.3 启动 Playwright MCP HTTP 服务

bash 复制代码
npx.cmd -y @playwright/mcp@latest `
  --browser chrome `
  --host 0.0.0.0 `
  --port 8931

参数说明:

参数 作用
--browser chrome 使用 Google Chrome
--host 0.0.0.0 监听所有网络接口
--port 8931 MCP HTTP 服务端口
--allowed-hosts 限制允许访问服务的 HTTP Host

注意:--host 和 --allowed-hosts 是两个不同的概念。

前者决定服务监听在哪个网络地址上,后者用于 HTTP Host 校验。

四、Windows 防火墙配置

4.1 检查网络类型

执行:

bash 复制代码
Get-NetConnectionProfile

发现:

bash 复制代码
NetworkCategory : Public

Windows 当前使用 Public 网络配置文件。

如果防火墙规则只指定 Private,则不会匹配当前 Public 网络。

4.2 添加防火墙规则时拒绝访问

执行:

bash 复制代码
New-NetFirewallRule `
  -DisplayName "Playwright MCP" `
  -Direction Inbound `
  -Protocol TCP `
  -LocalPort 8931 `
  -RemoteAddress 192.0.2.20 `
  -Action Allow `
  -Profile Public

出现:

bash 复制代码
New-NetFirewallRule : 拒绝访问

原因

当前 PowerShell 没有管理员权限。

解决方案

以管理员身份启动 PowerShell:

bash 复制代码
Start-Process powershell -Verb RunAs

然后重新执行防火墙规则创建命令。

这里使用 -RemoteAddress 限制来源 IP,而不是向整个局域网开放 MCP 服务。

4.3 验证端口连通性

在 Linux 执行:

bash 复制代码
nc -vz 192.0.2.10 8931

返回:

bash 复制代码
Connection to 192.0.2.10 8931 port [tcp/*] succeeded!

说明 TCP 连接已经成功。

但需要注意:

TCP 端口可连接,不代表 MCP 协议初始化成功。

五、Codex 显示 failed (0 tools)

在 Linux 的 Codex 配置文件:

bash 复制代码
~/.codex/config.toml

添加:

bash 复制代码
[mcp_servers.playwright]
url = "http://192.0.2.10:8931/mcp"
startup_timeout_sec = 60
tool_timeout_sec = 120

启动 Codex 后发现:

bash 复制代码
playwright: failed (0 tools)

说明 Codex 没有成功发现 Playwright MCP 提供的工具。

由于前面的 nc 已经成功,问题不一定出在网络连通性上,需要进一步检查 HTTP 层。

六、定位 403 Forbidden

6.1 使用 curl 测试 MCP 地址

Linux 执行:

bash 复制代码
curl -i --max-time 10 \
  http://192.0.2.10:8931/mcp

返回:

bash 复制代码
HTTP/1.1 403 Forbidden
Content-Length: 63

Access is only allowed at 192.0.2.10, localhost, 127.0.0.1

这个响应非常关键。

它说明:

  1. TCP 连接正常。

  2. HTTP 请求已经到达 MCP 服务。

  3. 服务端拒绝了请求。

  4. 拒绝原因与 HTTP Host 白名单有关。

此时继续修改 Windows 防火墙已经没有意义。

6.2 分析 HTTP Host

请求地址:

bash 复制代码
http://192.0.2.10:8931/mcp

实际 HTTP Host 通常为:

bash 复制代码
Host: 192.0.2.10:8931

而服务端允许的 Host 为:

bash 复制代码
192.0.2.10
localhost
127.0.0.1

由此怀疑:当前 MCP 服务的 Host 校验未能正确匹配带端口的 Host。

6.3 手动修改 Host 验证

Linux 执行:

bash 复制代码
curl -i --noproxy '*' \
  -H 'Host: 192.0.2.10' \
  http://192.0.2.10:8931/mcp

返回:

bash 复制代码
HTTP/1.1 400 Bad Request
Content-Length: 15

Invalid request

这是整个排障过程中最关键的验证。

对比两次请求:

请求 HTTP 状态
默认 Host,包含端口 403 Forbidden
手动指定不带端口的 Host 400 Bad Request

两次请求访问同一个 IP、同一个端口、同一个路径,仅修改了 HTTP Host。

结果从 403 变为 400,说明请求通过了此前的 Host 校验,并进入后续请求处理流程。

因此可以确认:之前的 403 与 Host 白名单匹配有关。

但普通 GET 返回 400 并不代表 MCP 初始化成功,还需要使用符合 MCP 协议的请求验证。

七、解决方案

7.1 调整 allowed-hosts

首先尝试在 Windows 上将包含端口的地址加入白名单:

bash 复制代码
npx.cmd -y @playwright/mcp@latest `
  --browser chrome `
  --host 0.0.0.0 `
  --port 8931 `
  --allowed-hosts "192.0.2.10:8931,192.0.2.10,localhost,127.0.0.1"

需要注意,不同 Playwright MCP 版本可能对带端口的 Host 有不同处理行为,必须通过实际测试确认。

重新执行:

bash 复制代码
curl -i --noproxy '*' \
  http://192.0.2.10:8931/mcp

如果不再出现 Host 校验导致的 403,说明问题已得到进一步解决。

7.2 验证 MCP 初始化

使用 JSON-RPC initialize 请求:

bash 复制代码
curl -i --noproxy '*' \
  --max-time 15 \
  -X POST \
  http://192.0.2.10:8931/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-03-26",
      "capabilities": {},
      "clientInfo": {
        "name": "curl-test",
        "version": "1.0"
      }
    }
  }'

正常情况下,服务端应返回 MCP 初始化结果,其中包含协议版本、服务端能力以及服务端信息。

7.3 重新验证 Codex

重新启动 Codex:

bash 复制代码
codex

在交互界面执行:

bash 复制代码
/mcp

确认 Playwright MCP 状态正常,并且能够发现浏览器操作工具。

可以通过以下任务验证:

bash 复制代码
使用 Playwright MCP 打开 https://example.com,
获取页面结构并截图。

如果 Windows Chrome 正常打开页面,且 Codex 能读取页面内容,则说明端到端调用成功。

本次实际问题最终已解决,但没有保留最终生效配置的完整输出。因此本文能够确认的是 Host 校验故障及其定位过程,不将某个未单独验证的配置变更描述为唯一有效修复。

八、更安全的部署方式:SSH 隧道

对于长期运行的环境,不建议直接向整个局域网开放具有浏览器控制能力的 MCP 服务。

更推荐:

bash 复制代码
Linux Codex
    |
    | localhost:8931
    |
SSH Tunnel
    |
    | Windows localhost:8931
    |
Playwright MCP
    |
Google Chrome

Windows 只监听本机:

bash 复制代码
npx.cmd -y @playwright/mcp@latest `
  --browser chrome `
  --host 127.0.0.1 `
  --port 8931

Linux 建立 SSH 隧道:

bash 复制代码
ssh -N \
  -L 8931:127.0.0.1:8931 \
  windowsuser@192.0.2.10

前提是 Windows 已启用 OpenSSH Server,并允许 Linux 通过 SSH 访问。

Codex 配置:

bash 复制代码
[mcp_servers.playwright]
url = "http://127.0.0.1:8931/mcp"
startup_timeout_sec = 60
tool_timeout_sec = 120

这种方式的优势:

  • 不需要向局域网开放 MCP HTTP 端口。

  • 通信通过 SSH 加密。

  • MCP 可以只监听 Windows 本地回环地址。

  • 降低其他局域网设备直接调用浏览器工具的风险。

九、故障排查总结

故障现象 原因或排查方向 解决方法
npx.ps1 禁止执行 PowerShell Execution Policy 使用 npx.cmd
New-NetFirewallRule 拒绝访问 管理员权限不足 提升 PowerShell 权限
Linux 无法连接 8931 监听地址、防火墙或网络问题 检查监听和入站规则
nc 成功但 Codex 0 tools MCP HTTP 或协议初始化失败 检查 HTTP 响应
HTTP 403 Forbidden Host 白名单校验拒绝 检查 allowed-hosts
修改 Host 后返回 400 已通过此前的 Host 校验 继续测试 MCP initialize
MCP 初始化成功但工具不可用 客户端配置或工具发现问题 检查 Codex 配置和日志

十、总结

本次问题的核心并不是 Windows 防火墙,也不是 Linux 无法连接 Windows。

实际排查链路为:

bash 复制代码
PowerShell 执行策略
        ↓
npx.cmd 启动 MCP
        ↓
Windows 防火墙放通
        ↓
Linux nc 连接成功
        ↓
Codex failed (0 tools)
        ↓
curl 返回 403 Forbidden
        ↓
发现 HTTP Host 白名单校验问题
        ↓
修改 Host 后返回 400
        ↓
调整 MCP 访问配置
        ↓
Codex 与 Playwright MCP 恢复正常

这次故障最值得总结的一点是:

MCP 的网络可达性与 MCP 协议可用性是两个不同层次的问题。

nc 只能证明 TCP 连接成功,无法证明 MCP 初始化、工具发现以及工具调用正常。

遇到 failed (0 tools) 时,应按以下顺序排查:

  1. TCP 端口是否可达。

  2. HTTP 请求是否被服务端接受。

  3. MCP initialize 是否成功。

  4. MCP tools/list 是否返回工具。

  5. Codex 是否成功加载并调用工具。

通过分层验证,可以避免反复修改防火墙、重装 Node.js 或盲目调整 Codex 配置。

相关推荐
用户394995084635 小时前
Python 的哈希契约:为什么 list 不能当字典的键
后端
leo在掘金5 小时前
744B模型,32GB内存跑起来
后端·架构
dpharness5 小时前
我亲手跑了一遍存量统计,兜底类居然排到第二
后端
智迁5 小时前
MySQL 到 Kingbase 实时同步:从 Docker 部署到增删改验证
前端·后端
Ramble_Naylor5 小时前
Rust深度解读:异步流(Async Streams)与生成器的处理艺术
开发语言·后端·rust
用户360055579005 小时前
Kestrel_VLLM - 30 · MTP 头适配:十五个张量与一个不存在的 oracle
后端
泡海椒5 小时前
jquick-pdf 漏斗图怎么用:Java 生成带客户转化漏斗的 PDF 信用评级报告
后端
极限实验室5 小时前
Easysearch 布尔查询子句重排序(二)|ConjunctionDISI 按 cost 排序源码解析
后端·搜索引擎·性能优化
废柴程序员_熊熊5 小时前
用 Docker 搭 n8n 私有服务器:2 个容器、382 MB 内存,附可导入的测试工程
后端