关于 lan-direct
lan-direct 为使用全隧道 VPN 的编码 Agent 提供浏览器 MCP 服务和技能。其代理按主机名分流:指定主机经 ISP 连接,其他浏览器流量及 Agent 保持在 VPN 隧道中。
主要功能
- 01按主机名路由浏览器连接
- 02让指定主机经 ISP 连接
- 03未匹配流量保留在 VPN 隧道
- 04提供 Playwright MCP 服务和 Agent 技能
- 05添加并检查主机路由规则
适用场景
- 01测试会拒绝 VPN IP 的服务所调用的应用
- 02在同一浏览器会话访问境内外网站
- 03Agent 使用 VPN 时让后端请求经 ISP 连接
MCP 相关
Playwright MCP 服务会启动并管理自己的代理,按主机名路由浏览器连接。MCP 客户端可借此浏览网页:指定主机经 ISP 连接,其他主机仍走 VPN 隧道。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
lan-direct
为全隧道 VPN 环境下的编码 Agent 提供的技能和浏览器 MCP——适用于 Claude Code 和 Codex。
你必须保持 VPN 开启,因为 Agent 需要通过它访问自己的 API。但你正在测试的应用会调用拒绝 VPN 外部出口 IP 的服务:国内 API、支付或短信网关、银行接口。关闭 VPN 不可行——那会切断 Agent 的连接。
lan-direct 为应用提供 ISP 直连路径,同时让Agent 保持在隧道中。无需管理员权限,不用编辑路由表,也不必重新配置 VPN。工作原理。
安装
需要 Node ≥ 20.6,以及 Windows 上的 PowerShell,或 Linux/macOS 上的 bash 和 curl。无需管理员权限,无需符号链接,也不用重命名。
从 npm 安装
npm install -g lan-direct
lan-direct install-skill # or --codex
claude mcp add playwright-split --scope user "--" npx -y lan-direct browser
然后重启 Agent。就这么简单——所有平台都使用相同的三行命令。
无论你采用哪种安装方式,npx -y lan-direct browser 都是更好的 MCP 命令:它不受检出目录移动的影响,而指向克隆目录的绝对路径则会受影响。
为什么要给
"--"加引号。 在 Windows 上,claude会解析为claude.ps1,PowerShell 的参数绑定器会在脚本看到裸--之前将其剥离。随后 CLI 会把-y当作自己的标志读取,并报错error: unknown option '-y'。加引号可以避免这个问题,而且在 bash 中引号不起作用——因此同一行命令可用于 PowerShell、bash 和 cmd。
从克隆安装
如果你想编辑或跟踪技能,建议使用这种方式——只需执行一次 git pull 就能更新所有内容;使用 npm 时则需要执行 npm update -g lan-direct && lan-direct install-skill,因为 install-skill 会复制文件,而不是创建链接。
无论采用哪种方式,都不会触碰你自己的主机列表 ~/.lan-direct-hosts。
1. 克隆到 Agent 的技能目录。 两个 Agent 都会扫描目录中的 SKILL.md 来发现技能,只是扫描的目录不同。
# Windows - Claude Code
git clone https://github.com/farshadmomo/lan-direct.git "$HOME\.claude\skills\lan-direct"
# Windows - Codex
New-Item -ItemType Directory -Force -Path "$HOME\.agents\skills" | Out-Null
git clone https://github.com/farshadmomo/lan-direct.git "$HOME\.agents\skills\lan-direct"
# Linux / macOS - Claude Code
git clone https://github.com/farshadmomo/lan-direct.git ~/.claude/skills/lan-direct
# Linux / macOS - Codex
mkdir -p ~/.agents/skills
git clone https://github.com/farshadmomo/lan-direct.git ~/.agents/skills/lan-direct
2. 注册浏览器 MCP:
powershell -NoProfile -ExecutionPolicy Bypass `
-File "$HOME\.claude\skills\lan-direct\scripts\install.ps1"
安装程序会验证绕过是否确实有效,将服务注册到此检出目录,并打印适用于 Codex 的 ~/.codex/config.toml 等效配置块。可以安全地重复运行——它会替换现有条目,而不是重复添加。
在 Linux/macOS 上没有安装脚本;请直接注册:
claude mcp add playwright-split --scope user "--" \
node ~/.claude/skills/lan-direct/scripts/lan-browser.mjs --port 8900
重启 Agent。 然后在 Claude Code 中使用 /lan-direct;或者在任一 Agent 中直接描述问题——description frontmatter 是触发条件,会对“在 VPN 开启时测试这个”或“API 拒绝 VPN IP”等说法作出响应。
更新方法:git -C <that directory> pull。无需重新安装。
从单个克隆同时使用两个 Agent
克隆一次,然后为第二个位置创建链接。在 Windows 上,目录联接无需管理员权限或开发者模式即可使用,不像符号链接:
git clone https://github.com/farshadmomo/lan-direct.git "$HOME\.claude\skills\lan-direct"
New-Item -ItemType Directory -Force -Path "$HOME\.agents\skills" | Out-Null
cmd /c mklink /J "$env:USERPROFILE\.agents\skills\lan-direct" "$env:USERPROFILE\.claude\skills\lan-direct"
macOS/Linux:
git clone https://github.com/farshadmomo/lan-direct.git ~/.claude/skills/lan-direct
mkdir -p ~/.agents/skills
ln -s ~/.claude/skills/lan-direct ~/.agents/skills/lan-direct
执行一次 git pull 即可同时更新两处。
安装到其他位置(用于编辑技能)
将仓库克隆到任意位置,然后创建链接。目录联接无需管理员权限;符号链接则需要提升权限的 shell 或开发者模式:
git clone https://github.com/farshadmomo/lan-direct.git "D:\projects\lan-direct"
cmd /c mklink /J "$env:USERPROFILE\.claude\skills\lan-direct" "D:\projects\lan-direct"
无论采用哪种安装方式,技能文件夹内的目录必须命名为 lan-direct——两个 Agent 都根据目录名称发现技能,而且该名称必须与 SKILL.md 中的 name: 匹配。
规则位于 lan-hosts.txt 中,采用后缀匹配:
.ir every .ir host
digikala.com also seller.digikala.com, api.digikala.com, ...
未匹配的主机都会走隧道。 只列出国内主机——添加国外主机会让流量经由可能会过滤内容的 ISP 发出。
随附列表涵盖所有 .ir 域名,以及使用其他顶级域名的伊朗服务:
支付(zarinpal、payping、nextpay)、短信/OTP(kavenegar、melipayamak、farazsms、ippanel)、
托管(parspack、hostiran、mizbanfa)、地图(neshan)、电商(digikala、torob、basalam)、
教育和招聘(quera、faradars、maktabkhooneh、7learn、irantalent)、AI(hoosha、gapgpt),
以及这些网站嵌入的分析域名(najva、yektanet)。所有域名都经过验证:通过隧道均无法访问,通过 ISP 则可以正常响应。
添加你自己的规则
将它们放入 ~/.lan-direct-hosts,每行一条,格式相同:
# my own
aparat.com
internal.corp
git pull 永远不会改动此文件,并且每次浏览器启动时都会读取——无需重新安装,也无需重启浏览器以外的任何东西。三个来源的规则会合并:随附文件、你的文件,以及启动时传入的任何 --lan-hosts a,b。
规则配置错误时,表现会像网站宕机一样,因此代理会打印每个连接所选的路由。在责怪网站之前先检查一下——也可以直接查询,无需启动任何东西:
$ lan-direct route hoosha.com youtube.com api.anthropic.com
24 rules in effect
hoosha.com lan ISP (bound)
youtube.com vpn tunnel
api.anthropic.com vpn tunnel
包含内容
分为两部分,安装时会一并安装:
| 功能 | |
|---|---|
技能(SKILL.md) | 教会 Agent 完整的工作流程——检测、验证、按技术栈选择机制、清理。通过扫描 SKILL.md 自动发现。 |
浏览器 MCP(lan-browser.mjs) | 一个 Playwright MCP 服务,会启动并管理自己的代理,且按主机路由:国内网站通过 ISP 访问,其他所有网站通过隧道访问,均在同一个浏览器会话中完成。 |
MCP 是浏览功能得以正常工作的关键——Chromium 没有源地址绑定标志,因此浏览器只能通过代理访问 ISP。没有它,技能可以涵盖后端和 CLI,但无法处理网页。
工作原理
按套接字绑定源地址。显式绑定到物理网络适配器 IP 的套接字会使用该适配器的默认路由,而不是隧道:
$ curl -s https://api.ipify.org # 203.0.113.7 (VPN exit)
$ curl -s --interface 192.168.1.20 https://api.ipify.org # 198.51.100.42 (real ISP)
无需管理员权限,无需编辑路由表,无需重新配置 VPN,也不会影响全局。由于这是按套接字生效的,因此默认就是选择性启用——不请求此功能的进程不会受到影响。这一特性确保 Agent 始终使用隧道。
这里特意不使用 route add。静态路由是全局的:它会让所有进程(包括 Agent)访问该目标时绕过隧道,而且需要管理员权限。
服务进程没有 --interface 标志,因此有两种方式可以为它指定接口:
| 你的后端 | 机制 |
|---|---|
| Node / Next.js | lan-bind.mjs——一个 --import 预加载模块,会绑定进程中的每个套接字 |
| 其他所有情况 | lan-proxy.mjs——一个本地代理,其出站套接字会被绑定,并由 HTTP_PROXY 驱动 |
Node 陷阱
如果你的后端使用 Node,HTTP_PROXY 不会生效,而且会静默失败。
原生 fetch 使用 Node 内置的 undici;在 Node ≤ 23 中,它会忽略代理环境变量,也不接受 https.Agent。已在 Node 22.20 上验证:普通环境变量、NODE_USE_ENV_PROXY=1 和 --use-env-proxy 都不起作用——代理日志为空,但流量却经由 VPN 发出。这会影响 Next.js、openai SDK 以及其他使用原生 fetch 的程序。
lan-bind.mjs 会在预加载模块中修补 net/tls,从而覆盖捆绑的 undici。这样即可同时涵盖原生 fetch、openai SDK、axios、node-fetch、got 以及普通的 http/https——无需依赖项、无需代理进程,也无需 HTTP_PROXY。NODE_OPTIONS 会传递给派生的工作进程,因此也适用于 Next.js 和 Vite 开发服务器。
它会特意跳过回环目标:源地址为 LAN IP 的套接字无法访问 127.0.0.1,因此如果没有这一保护,任何使用本地 Redis/Postgres/Mongo 的应用都会因 EADDRNOTAVAIL 而崩溃。
手动使用
以下路径中的 $skill 均指安装位置:
$skill = "$HOME\.claude\skills\lan-direct" # Claude Code
$skill = "$HOME\.agents\skills\lan-direct" # Codex
1. 检测并验证。 仅当绕过确实有效时才会以退出码 0 结束。
powershell -NoProfile -ExecutionPolicy Bypass -File "$skill\scripts\lan-detect.ps1"
bash ~/.claude/skills/lan-direct/scripts/lan-detect.sh # Linux / macOS
输出 lanIp、gateway、lanDns、subnet、tunnelActive、vpnAdapter、directEgress、
lanEgress、fakeIpDns、bypassWorks。它会探测两次并进行比较,而不是想当然地假设绕过有效——
如果绕过未生效,则拒绝继续,因此绝不会误报通过。
2a. Node 后端。 原样复制粘贴;只需填写 lanIp:
$env:LAN_BIND = "<lanIp>"
$env:NODE_OPTIONS = "--import file:///$($skill -replace '\\','/')/scripts/lan-bind.mjs"
npm run dev
在 Git Bash 中执行相同操作,路径需写完整:
LAN_BIND=<lanIp> \
NODE_OPTIONS="--import file:///C:/Users/YOU/.claude/skills/lan-direct/scripts/lan-bind.mjs" \
npm run dev
在 Windows 上,--import 需要带正斜杠的绝对 file:// URL——直接使用 Windows
路径会失败。
2b. 其他情况。 启动代理:
node "$skill\scripts\lan-proxy.mjs" --bind <lanIp> --self-test # run with the tunnel UP
node "$skill\scripts\lan-proxy.mjs" --bind <lanIp> --port 8899
然后使用 HTTP_PROXY=http://127.0.0.1:8899、
HTTPS_PROXY=http://127.0.0.1:8899、NO_PROXY=localhost,127.0.0.1,<subnet> 启动后端。
对于 HTTP_PROXY 仍不够用的技术栈,请参阅 SKILL.md——尤其是 Apache 下的 PHP,
因为服务不会继承你的 shell 环境,libcurl 也看不到这些变量。
同时浏览两个网络
两种路径互不包含对方的能力。在使用外国隧道的伊朗 ISP 上进行测量:
| 经 VPN | 经 ISP | |
|---|---|---|
| youtube、x、facebook、telegram、reddit | 可用 | 无法访问 |
| hoosha、neshan、avalai | 无法访问 | 可用 |
| github、google、npm | 可用 | 可用 |
| api.anthropic.com | 可用 | 403 |
最后一行就是为什么绝不能让 Agent 离开隧道——一旦这么做,Agent 就会完全停止工作。
浏览器 MCP 会在一个会话中处理这种混合情况。Chrome 被设定为将所有流量发送到代理,
自身不做路由决策;代理会从每个 CONNECT 中读取主机名(TLS 握手前以明文传输),然后作出决定:
useBind(host) ? net.connect({ host, port, localAddress }) // ISP
: net.connect({ host, port }) // tunnel
代码中没有“使用 VPN”的路径。唯一执行的操作是绑定——跳过它,操作系统路由表就会生效,而隧道拥有该路由表。LAN 路由需主动启用;否则默认使用隧道。
路由按连接决定,而非按会话决定。同一页面中的两次 fetch 调用可以经过不同的物理路由——以下是在同一标签页的同一页面中测得的结果:
| 请求 | 出口 |
|---|---|
api.hoosha.com(已列出) | ISP |
api.ipify.org(未列出) | VPN |
每条代理日志都会注明所选路由:
CONNECT lan hoosha.com:443
CONNECT vpn youtube.com:443
浏览器代理运行在 8900 端口,特意与上文后端测试使用的 8899 端口区分开。MCP 会复用已在其端口上运行的服务,因此如果共用端口,一个绑定所有流量的后端代理可能会在不知情的情况下接管浏览器,并将其所有流量经 ISP 发送——这会导致隧道原本要访问的站点无法使用。
内容
| 文件 | 用途 |
|---|---|
SKILL.md | 技能说明:工作流、各技术栈的操作方法、故障排除 |
lan-hosts.txt | 经 ISP 路由的主机名。你的主机名应添加到 ~/.lan-direct-hosts |
scripts/install.ps1 | 将浏览器 MCP 注册到此工作副本。可安全重复运行 |
scripts/lan-detect.ps1 | 查找物理适配器并验证绕过是否有效。输出 JSON |
scripts/lan-detect.sh | Linux 和 macOS 版,输出相同 JSON,退出码约定也相同 |
scripts/lan-bind.mjs | Node 预加载脚本——绑定整个进程。适用于 Node/Next.js |
scripts/lan-proxy.mjs | 无依赖的 HTTP/CONNECT 代理,支持可选的按主机路由 |
scripts/lan-browser.mjs | MCP 服务——Playwright 加上由它启动并管理的代理 |
scripts/lan-route.mjs | 可导入并经过测试的路由规则。也作为库导出 |
bin/lan-direct.mjs | CLI:detect、proxy、browser、route、install-skill |
test/ | npm test——测试路由、规则解析、代理和预加载脚本 |
需要 Node ≥ 20.6 和 curl(Windows 10+ 内置,其他系统通常已提供)。无依赖。
开发
npm test # node:test, no install step - there are no dependencies
共 34 项测试。路由判定逻辑受到最多关注,因为这里的逻辑只有它出错时不会显现——错误匹配会将流量发送到错误的物理网络,既没有报错,也不会产生日志。它旨在捕获的两种变更都已验证会导致测试套件失败:简单使用 endsWith(因此 evilhoosha.com 会匹配 hoosha.com),以及缺少环回地址检查。
预加载脚本在真实的子进程中测试,并设置了 LAN_BIND 为 192.0.2.1——该地址不属于这台机器,因此绑定套接字会立即失败。这证明补丁确实生效,而不是悄无声息地什么也没做。
CI 无法覆盖的内容:lan-proxy.mjs --self-test,它需要已启用的隧道和物理网络适配器。请在 VPN 已连接时手动运行。变更记录见 CHANGELOG.md。
如果你使用的是旧运行时,有一个容易踩坑的地方:Node 20.6.0 无法运行测试套件——所有断言都会通过,但之后测试运行器一直不会退出。这是该版本测试运行器的错误,不是 lan-direct 的问题;lan-direct 在该版本上运行正常。任何当前版本的 20.x 或 22 都可以。
说明
- 代理仅监听
127.0.0.1。如果绑定到更广泛的地址,就会向局域网开放一个代理。 lan-direct route <host>会根据合并后的规则列表显示某个主机的流量将通过哪个网络发出。比启动浏览器查看快得多。.ps1文件刻意只使用 ASCII 字符:Windows PowerShell 5.1 会将无 BOM 的 UTF-8 作为 ANSI 读取,而一个多余的长破折号就会导致解析器出错。CI 会对此进行检查。- 使用 fake-IP DNS(sing-box、clash)时,请传入
--dns <lanDns>。dns.setServers()不会影响dns.lookup(),后者会经由隧道控制的操作系统解析器进行解析。 - 在 Git Bash 中运行
pkill -f lan-proxy不会终止 Windows 上的node.exe。请使用SKILL.md中的 PowerShell 清理步骤。
验证环境
在 Windows 11、Node 22.20、Intel Wi-Fi 上,使用 nekoray / sing-box TUN 验证;在一个真实的 Next.js 16 应用中端到端测试,该应用会调用 Neshan(伊朗地图服务)和 AvalAI(大模型网关),二者都会直接拒绝来自国外 IP 的请求:
| 经由 VPN | 经由 ISP | |
|---|---|---|
AvalAI /models、/chat/completions | ECONNRESET | 200,返回真实补全结果和 token 用量 |
| Neshan 反向地理编码 | 无响应 | 200,返回正确地址 |
| Neshan 路由 / 地理编码 | 无响应 | 200 |
Next.js /api/reverse、/api/chat | — | 200,全栈返回实时数据 |
浏览器 MCP 也以同样方式进行了测试:在一个会话中先后打开一个国内 AI 平台和 YouTube;国内网站自身的 CDN 报告了 ISP 地址和国家代码 IR,同时 YouTube 则通过隧道呈现其德语区域版本的页面框架。
Agent 自身的连接始终走隧道。
适配器发现方式是通用的——Windows 上使用 Get-NetAdapter -Physical,Linux 上使用 sysfs device 符号链接,macOS 上使用 networksetup——因此 WireGuard、OpenVPN、WARP 等类似工具应该也能使用。但 lan-detect 会通过实测验证,而不是想当然;无法验证时会以非零状态码退出。
平台状态。 Windows 是经过端到端测试的平台。lan-detect.sh 已在 Linux(Ubuntu 24.04)上运行,并正确返回接口、网关、DNS、路由和退出码——但测试机器没有自己的隧道,因此 已验证绕过 分支尚未得到验证。macOS 的实现依据 networksetup/ipconfig/netstat 的文档行为编写,尚未实际运行过。两者都会拒绝猜测,因此失败时会明确报错,而不会悄悄让流量经过 VPN。欢迎提交测试报告。
Linux 有一个特别需要注意的地方:绑定源地址本身并不能像在 Windows 上那样覆盖路由表,因此使用策略路由的隧道可能会继续承载该流量,即使流量已经绑定了源地址。这正是两项探测要检测的情况——如果发生,lan-detect.sh 会明确指出并给出修复方法,而不会报告成功。
尚未验证的还有:lan-detect 的“检测到 kill-switch”分支,因为测试机器无法将 VPN 设置为所需状态。
许可证
MIT——详见 LICENSE。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。