lan-direct について
lan-directは、フルトンネルVPNを使うコーディングエージェント向けに、ブラウザーMCPサーバーとスキルを提供します。プロキシはホスト名ごとに経路を分け、指定ホストはISP経由、それ以外のブラウザー通信とエージェントはVPNトンネルに残します。
主な機能
- 01ホスト名ごとのブラウザー接続ルーティング
- 02指定ホストをISP経由で接続
- 03未登録の通信をVPNトンネルに維持
- 04Playwright MCPサーバーとエージェントスキルの提供
- 05ホストルールの追加と確認
活用シーン
- 01VPNのIPを拒否するサービスを呼び出すアプリのテスト
- 02同じセッションで国内外のサイトを閲覧
- 03エージェントがVPN利用中にバックエンド通信をISP経由にする
MCP 対応
Playwright MCPサーバーが専用プロキシを起動・管理し、ホストごとにブラウザー接続を振り分けます。MCPクライアントは、指定ホストをISP経由、それ以外をVPNトンネル経由にしてブラウジングできます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
lan-direct
フルトンネル VPN を使っているコーディングエージェント(Claude Code と Codex)向けのスキルとブラウザー MCPです。
エージェントが API にアクセスするためには、VPN をオンにしたままにする必要があります。しかし、テスト対象のアプリが呼び出すサービスは、VPN の国外出口 IP を拒否します。たとえば、国内 API、決済や SMS のゲートウェイ、銀行のエンドポイントなどです。VPN をオフにすることはできません。エージェントとの接続が切れてしまうためです。
lan-direct は、エージェントはトンネルに接続したまま、アプリには ISP 経由の直接経路を提供します。管理者権限も、ルーティングテーブルの編集も、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
次にエージェントを再起動します。これだけです。どのプラットフォームでも同じ 3 行です。
どの方法でインストールした場合も、MCP コマンドには npx -y lan-direct browser のほうがおすすめです。チェックアウト先が移動しても使えますが、クローン内への絶対パスは移動すると使えなくなります。
"--"を引用符で囲む理由。 Windows ではclaudeがclaude.ps1に解決されます。PowerShell のパラメーターバインダーは、スクリプトに渡される前に引用符のない--を取り除きます。そのため CLI は-yを自身のフラグとして読み込み、error: unknown option '-y'で失敗します。引用符で囲めばこれを防げます。また、bash では引用符は処理に影響しないため、同じ行が PowerShell、bash、cmd で使えます。
クローンから
スキルを編集したい場合や、変更を追跡したい場合はこちらがおすすめです。git pull 1 回ですべてを更新できます。一方、npm ではファイルをリンクせずにコピーするため、npm update -g lan-direct && lan-direct install-skill が必要です。
どちらの方法でも、独自のホスト一覧 ~/.lan-direct-hosts は変更されません。
1. エージェントのスキルディレクトリにクローンします。 どちらのエージェントも、ディレクトリをスキャンして 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
エージェントを再起動します。 その後、Claude Code では /lan-direct を使うか、どちらのエージェントでも問題を説明してください。description のフロントマターがトリガーとなり、「VPN をオンにしたままこれをテストして」や「API が VPN の IP を拒否する」のような表現に反応します。
更新するには、git -C <that directory> pull を実行します。再インストールは不要です。
1 つのクローンから両方のエージェントを使う
一度クローンし、もう一方の場所にリンクします。Windows では、シンボリックリンクと違い、管理者権限や Developer Mode がなくてもジャンクションを使えます。
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 1 回で両方を更新できます。
別の場所にインストールする(スキルを編集する場合)
任意の場所にクローンし、スキルディレクトリ内にリンクします。ジャンクションには管理者権限は不要です。シンボリックリンクには、昇格したシェルまたは Developer Mode が必要です。
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 にしてください。どちらのエージェントもディレクトリ名で検出するため、SKILL.md の name: と一致させる必要があります。
ルールは lan-hosts.txt にあり、サフィックス一致で判定されます。
.ir every .ir host
digikala.com also seller.digikala.com, api.digikala.com, ...
一致しないホストはすべてトンネルを経由します。 国内のホストだけを追加してください。海外のホストを追加すると、フィルタリングされる可能性のある ISP 経由で接続されます。
同梱のリストには、.ir 全体に加えて、ほかの TLD を利用しているイランのサービスも含まれています。決済(zarinpal、payping、nextpay)、SMS/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 に、同じ形式で1行に1つずつ追加してください。
# my own
aparat.com
internal.corp
このファイルは git pull の影響を受けず、ブラウザーの起動時に毎回読み込まれるため、再インストールは不要です。ブラウザー以外を再起動する必要もありません。3つのソース、つまり同梱ファイル、独自ファイル、および起動時に渡された --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
同梱内容
2つの要素が一緒にインストールされます。
| 機能 | |
|---|---|
スキル(SKILL.md) | 検出、検証、スタックごとの仕組みの選択、終了処理まで、ワークフロー全体をエージェントに教えます。SKILL.md を検索して自動的に検出されます。 |
ブラウザー MCP(lan-browser.mjs) | 独自のプロキシを起動して管理する Playwright MCP サーバーです。ホストごとに経路を振り分け、1つのブラウザーセッション内で国内サイトは 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 の再設定も不要で、システム全体に影響する設定もありません。ソケットごとの設定なので、明示的にオプトインする仕組みになっています。設定を要求しないプロセスが影響を受けることはありません。この特性により、エージェントはトンネル経由の接続を維持できます。
これは意図的に route add を使いません。静的ルートはシステム全体に適用されるため、その宛先への接続がすべてトンネルから外れ、エージェントも対象になります。また、管理者権限も必要です。
サーバープロセスには --interface フラグがないため、設定方法は2つあります。
| バックエンド | 仕組み |
|---|---|
| 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 は fork されたワーカーにも引き継がれるため、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 を出力します。推測ではなく、2 回プローブして比較します。
バイパスが機能しない場合は処理を続行しないため、誤って成功と判定されることはありません。
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 では、
サービスがシェル環境を引き継がず、libcurl から環境変数が見えません。
2 つのネットワークを同時にブラウジングする
どちらか一方が、もう一方のすべてを網羅しているわけではありません。海外のトンネル経由でイランの ISP に接続した場合の測定結果です。
| VPN 経由 | ISP 経由 | |
|---|---|---|
| youtube、x、facebook、telegram、reddit | 使用可能 | 接続不可 |
| hoosha、neshan、avalai | 接続不可 | 使用可能 |
| github、google、npm | 使用可能 | 使用可能 |
| api.anthropic.com | 使用可能 | 403 |
最後の行が、エージェントをトンネルから決して移動してはならない理由です。移動すると、エージェントは完全に動作しなくなります。
ブラウザー MCP は、1 つのセッションでこの両方を処理します。Chrome には すべて をプロキシに送信するよう指示し、独自のルーティング判断はさせません。プロキシは各 CONNECT からホスト名を読み取り(TLS の前に平文で確認できます)、次のように判断します。
useBind(host) ? net.connect({ host, port, localAddress }) // ISP
: net.connect({ host, port }) // tunnel
「VPN を使う」コードパスはありません。行うのはバインドだけです。これを省略すると OS のルーティングテーブルが適用され、トンネルがそのルートを所有します。LAN はオプトインです。それ以外の場合はトンネルが使われます。
これはセッション単位ではなく、接続単位で適用されます。同じ ページ からの 2 つの fetch 呼び出しでも、物理的に異なるルートを通る場合があります。1 つのタブ内の 1 ページで測定した結果は次のとおりです。
| リクエスト | 外部への経路 |
|---|---|
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件あります。ルーティングの判定条件は、ここで唯一、失敗しても表面化しないロジックなので、特に重点的にテストしています。誤った判定ではエラーもログも出ないまま、トラフィックが誤った物理ネットワークへ送られてしまいます。検出対象の2つの変異について、どちらもテストスイートが失敗することを確認しています。1つは単純なendsWith(そのため、evilhoosha.comがhoosha.comに一致します)、もう1つはループバックのチェック漏れです。
プリロードは、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にオープンプロキシを公開することになります。 lan-direct route <host>を実行すると、統合済みのルールリストに基づいて、ホストがどのネットワーク経由で送信されるかを確認できます。ブラウザーを起動して調べるより高速です。.ps1ファイルは意図的にASCIIのみで記述しています。Windows PowerShell 5.1はBOMなしのUTF-8をANSIとして読み込み、紛れ込んだem dashがあるとパーサーでエラーになります。CIでこれをチェックしています。- フェイクIPのDNS(sing-box、clash)を使用する場合は、
--dns <lanDns>を渡してください。dns.setServers()はdns.lookup()には影響しません。dns.lookup()はトンネルが制御するOSのリゾルバーを経由します。 - 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とLLMゲートウェイのAvalAIを呼び出し、エンドツーエンドでテストしました。どちらも外国のIPアドレスからの接続を拒否します。
| VPN経由 | ISP経由 | |
|---|---|---|
AvalAI /models、/chat/completions | ECONNRESET | 200、実際の応答とトークン使用量 |
| Neshanの逆ジオコーディング | 応答なし | 200、正しい住所 |
| Neshanのルート検索/ジオコーディング | 応答なし | 200 |
Next.js /api/reverse、/api/chat | — | 200、フルスタック経由のライブデータ |
ブラウザーMCPも同じ方法でテストしました。国内のAIプラットフォームとYouTubeを同じセッション内で続けて開き、国内サイト独自のCDNでISPのIPアドレスと国コードIRが報告される一方、YouTubeはトンネル経由でドイツ語ロケールの画面を表示しました。
エージェント自身の接続は、全期間を通してトンネル経由のままでした。
アダプターの検出方法は汎用的です。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とは異なり、送信元アドレスをバインドするだけではルーティングテーブルを上書きできないため、ポリシールーティングを使用するトンネルでは、バインド後もトラフィックがトンネル経由になる場合があります。これは2つのプローブで検出します。そのような場合、lan-detect.shは成功を報告せず、その旨と修正方法を示します。
未検証の項目として、lan-detectの「キルスイッチを検出」する分岐があります。テストマシンでは再現できなかったVPNの状態が必要です。
ライセンス
MIT — LICENSEを参照してください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。