尧图精选

排查 Playwright MCP「Browser is already in use」错误:配置目录锁的成因与修复,以及 invisible_playwright_mcp 的规避设计

🕒 发布时间:2026/10/1 9:31:32 📁 来源:尧图网络
人工智能AI Agent浏览器控制GUI 自动化MCP 服务【免费下载链接】invisible_playwright_mcpPlaywright MCP server undetected by anti-bots and captchas: AI agent browses the web on anti-detect stealth Firefox, Python, undetected browser automation, scraping, computer use.项目地址https://gitcode.com/GitHub_Trending/jo/invisible_playwright_mcp点击查看免费下载导读本文围绕 Playwright MCP 常见的 Browser is already in use 报错讲清它的本质——这是浏览器配置目录profile directory上的锁而不是「有另一个浏览器正在运行」的陈述随后给出四种典型触发路径与对应修复手段--isolated、独立--user-data-dir、重启服务、删除锁前的存活检查。最后结合当前开源仓库 invisible_playwright_mcp 的源码说明它的「一进程只服务一个身份」设计如何从根本上绕开同类的池内冲突以及为什么持久化配置目录这一层它依然遵守浏览器的单实例约束。一、先读懂报错这是锁不是「浏览器在运行」当你在 MCP 客户端里看到类似下面的信息时Browser is already in use for /path/to/mcp-chrome, use --isolated to run multiple instances of the same browser它宣告的对象是配置文件目录上的锁lock而不是某个正在运行的浏览器进程。持久化配置目录在同一时刻只能被一个浏览器实例打开而 Playwright MCP 默认使用一个固定配置目录。任何「取走了锁却没有归还」的东西——哪怕该进程已经不存在——都会让这个报错继续出现。Microsoft 官方文档直接陈述了这一约束一个持久化配置只能同时被一个浏览器实例使用因此共享同一工作区workspace的并发 MCP 客户端必然互相冲突。理解这一点是后续所有排查的前提进程列表为空、页面关闭、甚至整个客户端退出都不能保证锁被释放。二、走到这个报错的四种途径按发生频率与迷惑程度排序第二个客户端。同一个 server 被注册在两处——比如编辑器里一个、终端助手一个且两者都活着——两个进程都要同一个配置目录。这是该报错本来要表达的场景在编辑器环境里最常见GitHub Copilot 中的浏览器 MCP server 一文解释了为什么编辑器场景特别容易踩中。上一次运行是被杀死的。会话不是以「干净关闭」结束锁文件的生命周期长于进程。此时没有任何东西在运行报错照样出现。这是最常见的、也是最令人困惑的一种你的进程列表是空的报错却还在。关闭操作没有重置服务端自身状态。上游 server 被反复报告的缺陷browser_close之后内部「in use」标志并不总是被清除于是即使浏览器已经没了下一次 navigate 仍会报同样的错。重启 MCP server 可以清掉它。一次安装半启动了浏览器。browser_install可能留下一个「占用着配置目录却不可用」的实例导致服务端对状态的认知与真实状态不一致。三、四种修复按你的目标选择3.1 想要并发客户端用--isolated配置目录改为会话内存态、不共享任何东西两个客户端就不再争抢。代价是每次启动都是未登录状态——对探索型任务来说这通常恰好是你想要的。--isolated是 server 侧的启动参数需要在注册 MCP 命令时传入。3.2 想保留持久化给每个客户端各自的配置目录这是 Playwright MCP best practices 中「值得主动做出的四个决定」之一--user-data-dir path为每个客户端传不同的路径。你保留持久化同时消除碰撞。注意这是 server 的命令行选项如果你的客户端只允许注册一个不带参数的命令那么在不能手工编辑配置块的情况下你可能根本够不到这个选项。3.3 没有进程在跑重启 server在编辑器或聊天客户端里重启意味着重载 MCP 连接而不是只关掉标签页。这一动作清除上文中第三种情况的内存态标志如果真正重启后报错仍在说明锁在磁盘上——接下来要检查的正是配置目录本身。3.4 删除任何东西之前先确认浏览器真的还活着陈旧锁与「活着的第二个客户端」在报错文本上完全一样但需要完全相反的修复。删除一个正在被运行的浏览器持有的锁会损坏配置目录。稳妥的检查方式是查看进程列表确认对应浏览器进程的存活状态而不是直接删除锁文件。四、为什么在 invisible_playwright_mcp 这里不会以同样方式发生当前仓库 invisible_playwright_mcp 的服务端走了完全相反的设计路线这段历史值得展开因为它正是同一个取舍从两端各看一次直到 0.39.0一个会话可以容纳最多八个浏览器名字由你随意发明直到 0.41.0每个工具还携带一个会话标识符单个进程在背后同时调度多个会话现在两者都已不存在一个 server 在其整个生命周期内只服务一个身份旁边只有一个不共享任何东西的辅助浏览器browser_open只在这两者之间选择而不是往一个池子里添加。以上版本节点与设计变迁来自 本文关联文档 的原始叙述对应的当前实现可以在仓库源码中逐一印证src/invisible_playwright_mcp/mcp/server.py 的模块注释开宗明义「THERE IS NO SESSION CONCEPT HERE, AND THAT IS DELIBERATE」——该进程只服务一件工作两个固定角色main与support。工具枚举、命名、触达第二个浏览器的方式被彻底移除browser参数是Literal[main, support]模型无法发明第三个名字。src/invisible_playwright_mcp/mcp/work.py 用MAX_BROWSERS_PER_SESSION 2把数量写死并注释说明了从「八个浏览器 八个身份」收缩到「一个身份 一个辅助」的理由身份活在浏览器上seed、指纹、profile一个会话持有八个浏览器就等于持有八个身份而上层的对话与存档却只针对一个会话「这是谁的」就有了两个答案。决定「这个进程服务哪件工作」的唯一来源是环境变量INVISIBLE_MCP_SESSION_ID在 server.py 中读取一次、永远如此绝不会变成工具参数、不会出现在 schema 里、模型既读不到也传不了未设置时落到storage.DEFAULT_SESSION_ID default见 src/invisible_playwright_mcp/storage.py。4.1 没有池子就没有池内碰撞由于没有「浏览器池」可供碰撞上面的冲突场景在这里无法以同样方式发生。你付出的代价是不能通过注册一个 server 来同时跑多个身份——答案变成了再注册一个 server。两种形态不存在抽象的优劣Microsoft 的做法是把选择放进一个 flag本项目的做法是把选择放进「你注册了几个 server」。4.2 持久化配置目录同类约束仍然存在但「同类的坑」在持久化配置这一层依然会找上门因为这条约束属于浏览器而不是 server——这也是为什么 已登录会话必须被刻意处理。一个目录、一个活浏览器。如果你把两个会话指向同一个profile_dir第二个会话一样会度过糟糕的一天。本项目的对应参数是--profile-dirbrowser_open工具参数为profile底层启动 kwargs 名为profile_diruvx invisible-playwright-mcp ui --profile-dir /path/to/your-profilesrc/invisible_playwright_mcp/cli.py 中声明为「Persistent profile dir; logins survive across runs」并在 README 中解释为「A directory to keep the profile in, so logins and cookies survive restarts」。src/invisible_playwright_mcp/mcp/plan.py 的_resolve_profile是唯一读取STEALTHFOX_PROFILE_DIR的地方并把相对路径解析为绝对路径——因为相对路径会相对 server 进程的工作目录解析调用方既看不见也不控制它同一个字符串在不同启动目录下是不同目录昨天的登录会静默消失。src/invisible_playwright_mcp/mcp/session.py 的_attach明确区分两条启动路径无profile_dir时是「临时模式」Browser new_context()设置profile_dir时直接进入持久化 BrowserContext没有.new_context()。测试 tests/mcp_server/test_real_launch.py 专门覆盖了持久化模式这一条路径。src/invisible_playwright_mcp/mcp/work.py 中WHO_A_BROWSER_IS (seed, proxy, profile_dir)明确一个浏览器「是谁」由这三个字段决定也只有它们会被写进会话存档而「用什么引擎、是否显示窗口」属于本次启动的属性由plan.launched_here每次现场决定绝不从文件读回——避免一次有头模式的运行替所有后续进程做决定。也就是说本项目绕开的是「池内多浏览器互相抢目录」这一层因为没有池保留的是「同一持久化目录同一时刻只能有一个活浏览器」这一层因为这是浏览器本身的不变式。两点合起来就是这篇文章标题里那个「规避设计」的准确边界。五、常见问题速答为什么明明没东西在运行却提示浏览器在使用中因为锁在配置目录上可以比取走它的进程活得更久也因为 server 自己维护了一个标志位硬杀进程不会清除它。--isolated会丢掉我的登录吗会。这正是 isolated 的含义。如果需要在没有共享配置目录的情况下获得特定的登录态请使用--storage-state。能不能同时跑两个 MCP 浏览器客户端能用--isolated或给每个客户端一个互不相同的--user-data-dir。不能在同一个共享持久化配置上同时跑。这是 bug 吗一半是。配置目录锁是浏览器自身的约束行为正确而browser_close后标志位未重置这一点上游已作为缺陷跟踪。六、相关阅读与源码入口Playwright MCP best practices值得主动做出的配置取舍Playwright MCP vs the CLI两种驱动方式的对比the MCP server本项目的会话模型说明src/invisible_playwright_mcp/mcp/server.py两个固定浏览器main/support与「无会话概念」的实现src/invisible_playwright_mcp/mcp/work.pyopen/acting/close生命周期与MAX_BROWSERS_PER_SESSIONsrc/invisible_playwright_mcp/mcp/plan.pyplan_session与profile_dir/STEALTHFOX_PROFILE_DIR的唯一解析点tests/mcp_server/test_one_plan_for_one_session.py单个会话单一计划的行为验证tests/mcp_server/test_real_launch.py持久化配置目录profile_dir真实启动路径的测试。结论遇到 Browser is already in use先把它读成「配置目录被锁」而不是「浏览器在跑」按「并发 →--isolated要持久化 → 每人一个目录没进程 → 重启服务要删锁 → 先验活」四步走。invisible_playwright_mcp 用「一进程一身份 固定双浏览器」的结构在池内根除了同类冲突但持久化目录的单实例约束是浏览器的地盘两个会话指向同一个profile_dir时你依然需要上述第一条的纪律。赞分享人工智能AI Agent浏览器控制GUI 自动化MCP 服务【免费下载链接】invisible_playwright_mcpPlaywright MCP server undetected by anti-bots and captchas: AI agent browses the web on anti-detect stealth Firefox, Python, undetected browser automation, scraping, computer use.项目地址https://gitcode.com/GitHub_Trending/jo/invisible_playwright_mcp点击查看免费下载相关推荐抖音无水印批量下载怎么实现Douzy 从 Cookie 登录到归档管理的完整教程抖音无水印批量下载怎么实现Douzy 从 Cookie 登录到归档管理的完整教程 Douzydouyin downloader是一个 Python 写的抖网页爬虫CLIn8n-workflows 的 ai-stack 启动报“Port 5678 is already in use”怎么排查n8n workflows 的 ai stack 启动报“Port 5678 is already in use”怎么排查 在 n8n workflows 仓工作流自动化文档Meshery Design 验证机制实战以 Design With Validation Errors 目录设计为例排查与修复配置错误Meshery Design 验证机制实战以 Design With Validation Errors 目录设计为例排查与修复配置错误 本篇技术指南以云原生微服务运维DevOps上一篇Undercover CI/CD集成指南在GitHub Actions、CircleCI和Semaphore中自动检测未测试代码下一篇React Scroll 源码解析深入理解滚动动画实现原理创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →