Communitygithub.com

lan-direct

スキル + ブラウザMCP(Claude Code / Codex向け):アプリとブラウザは実際のISP経由で国内サービスにアクセスし、エージェントはVPNを維持します。ソケット単位のバインディング、ホスト単位のルーティング、管理者権限不要、グローバル設定変更なし。

lan-direct とは?

このスキルは、開発エージェント(Claude CodeやCodex)がVPNに接続したまま、アプリケーションのトラフィックだけを実際のISP経由でルーティングするためのツールです。ルーティングテーブルやシステムプロキシ、VPN設定を全く変更せず、子プロセスへの環境変数スコープ設定とソケット単位のバインドフラグのみを使用するため、エージェント自身の接続に影響を与えません。Windows、Linux、macOSに対応し、Node.jsアプリケーション(Next.jsを含む)向けのプリロードスクリプトや、ブラウザ/Playwright向けの専用MCPサーバーも提供します。また、`lan-hosts` リストに基づいてホスト単位でISPとVPNのルーティングを振り分けるため、一つのブラウザで国内サービスと国外サービスを同時に扱えます。

対応✓Claude Code✓Codex CLI~Cursor
npx skills add farshadmomo/lan-direct

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

lan-direct は何をしますか?

アプリのトラフィックをISP経由でルーティングし、**あなた(エージェント)**はVPNに接続したままにします。

Claude CodeでもCodexでも動作します。その仕組みはソケット単位のバインディングであり、ハーネス(実行環境)には依存しません。

不変条件

ルーティングテーブル、WinINET/システムプロキシ設定、VPNクライアントの設定を決して変更しないこと。許可される操作は次のものだけです:

  • 子プロセスにスコープされた環境変数を設定する、または
  • ツールごとのソースバインディングフラグを渡す。

どちらもソケット単位でオプトイン型であるため、あなた自身の接続には影響しません。これがこのスキルの本質です。もし route add を使おうとしたら、それはこのスキルを破壊していることになります(最後の「逃げ道」セクションを参照)。

VPNの切断を提案しないでください。このスキルはまさにその問題を回避するために存在します。

ワークフロー

1. 検出と確認

powershell -NoProfile -ExecutionPolicy Bypass -File scripts\lan-detect.ps1

LinuxまたはmacOSでは、代わりに以下のカウンターパートを使用します。同じJSON、同じ終了コード契約です:

bash scripts/lan-detect.sh

JSON出力: lanIp, gateway, lanDns, subnet, tunnelActive, vpnAdapter, directEgress, lanEgress, fakeIpDns, bypassWorks。bypassWorks が true の場合のみ終了コード0を返します。これは、推測ではなく2つのライブプローブでバイパスが機能することを証明します。

  • tunnelActive: false -> VPNが起動していません。その旨を伝えて停止してください。バイパスするものはありません。
  • tunnelActive が真で bypassWorks: false -> 以下の「トラブルシューティング」に進んでください。先に進まないでください。トラフィックは静かにVPN上に留まり、誤った合格を報告することになります。

2. メカニズムの選択

Nodeバックエンド(Next.jsを含む)? プロキシをスキップ - 以下の「スタック別レシピ」のNodeレシピに飛んでください。環境変数1つで、プロキシプロセスは不要で、ネイティブ fetch に到達できる唯一の方法です。

それ以外:LANバインドプロキシを起動します。サーバープロセスには --interface フラグがないため、これがISP出口を取得する方法です。

node scripts/lan-proxy.mjs --bind <lanIp> --port 8899          # バックグラウンドで実行
node scripts/lan-proxy.mjs --bind <lanIp> --port 8899 --dns <lanDns>   # fakeIpDns: true の場合

127.0.0.1 のみでリッスンし、トンネリングしたすべてのホストをログに記録するため、アプリが実際に何を呼び出したかを確認できます。

3. バックエンドをプロキシに向けて再起動

HTTP_PROXY=http://127.0.0.1:8899
HTTPS_PROXY=http://127.0.0.1:8899
NO_PROXY=localhost,127.0.0.1,<subnet>

NO_PROXY は重要です。これがないと、バックエンドの自身のローカルサービスへの呼び出しが不必要にプロキシ経由になります(ローカルDB(MySQL、Postgres、Mongo)へのTCP接続はHTTPではなく、どちらにせよ影響を受けません)。

これらはグローバルではなく、バックエンドの起動コマンドに設定してください。以下の「スタック別レシピ」を参照 - HTTP_PROXY だけでは不十分なスタックもあります。

4. 実行と確認

アウトバウンド呼び出しが失敗していたエンドポイントにアクセスします。両方を確認してください:

  • 呼び出しが成功すること、そして
  • プロキシログにダイヤルしたホストが表示されること。

一致するログ行がない合格は、リクエストがプロキシを経由しなかったことを意味します。

5. 後片付け

プロキシを停止し、環境変数なしでバックエンドを再起動します。元に戻すべきものは他にありません。グローバルな状態は変更されていません。

Git Bashから pkill -f lan-proxy を実行しても、Windowsの node.exe は終了しません。以下を使用してください:

Get-CimInstance Win32_Process -Filter "Name='node.exe'" |
  Where-Object { $_.CommandLine -like '*lan-proxy*' } |
  ForEach-Object { Stop-Process -Id $_.ProcessId -Force }

残ったインスタンスは無害ですが、次回の起動時にポート競合で失敗します。

スタック別レシピ

スタックプロキシの指定方法
Python requests / httpx環境変数、そのまま
Go, .NET HttpClient環境変数、そのまま
PHP CLIlibcurl がプロセス環境変数 http_proxy / https_proxy を読み取る
Node(Next.js含む)プロキシは使いません - 以下の lan-bind.mjs プリロードを使用
Apache/XAMPP下のPHP以下を参照 - サービスはシェルを継承しません
curl, wget, npm, ssh, gitプロキシをスキップし、直接バインド(以下の「直接バインディング」を参照)

Node - プリロードを使用し、プロキシは使わない

ネイティブ fetch はNode組み込みのundici上で動作し、Node <= 23では HTTP_PROXY を無視し、https.Agent も受け入れません。Node 22.20で確認済み:plainな環境変数、NODE_USE_ENV_PROXY=1、--use-env-proxy はすべて効果がなく、プロキシログは空のままでトラフィックは静かにVPN経由で外部に出ます。これはNext.js、openai SDK、およびネイティブ fetch を使用するその他すべてに影響します。

プロキシを完全にスキップし、プロセス内のすべてのアウトバウンドソケットをバインドするプリロードを使用してください:

LAN_BIND=<lanIp> node --import "file:///<skill-dir>/scripts/lan-bind.mjs" script.js
LAN_BIND=<lanIp> NODE_OPTIONS="--import file:///<skill-dir>/scripts/lan-bind.mjs" npm run dev

<skill-dir> はこのスキル自身のベースディレクトリで、スラッシュを使用します。通常はClaude Codeでは C:/Users/<you>/.claude/skills/lan-direct、Codexでは C:/Users/<you>/.agents/skills/lan-direct です。--import はWindows上では絶対 file:// URLが必要です。バックスラッシュを含むWindowsパスは失敗します。

NODE_OPTIONS はフォークされたワーカーに伝搬するため、Next.jsやVite開発サーバーをカバーします。

これにより、ネイティブ fetch、openai SDK、axios、node-fetch、got、そしてplainな http/https を一度にカバーします。依存関係もプロキシプロセスも HTTP_PROXY も不要です。ループバック宛先はスキップするため、ローカルDBや開発サーバーはそのまま動作します。

プリロードが利用できない場合のみ:Node >= 24 では NODE_USE_ENV_PROXY=1 と環境変数を尊重し、axios はどのバージョンでも環境変数を尊重します。

Apache / XAMPP下のPHP

httpd.conf の SetEnv/PassEnv は $_SERVER に値を設定するだけです。libcurl はプロセス環境を読み取るため、これらを拾いません。以下のいずれかを使用してください:

  • 既に http_proxy/https_proxy がエクスポートされたシェルからApacheを起動する(例: xampp\apache_start.bat)、または
  • curl_init() の前に putenv('https_proxy=http://127.0.0.1:8899'); を使用する、または
  • curl_setopt($ch, CURLOPT_PROXY, '127.0.0.1:8899'); を直接使用する。

file_get_contents() はこれらのどれも尊重しません。'proxy' => 'tcp://127.0.0.1:8899' を含むストリームコンテキストが必要です。

直接バインディング

ツールが独自のソケットをバインドできる場合、プロキシは不要です:

ツールフラグ
curl--interface <lanIp>
wget--bind-address=<lanIp>
npm--local-address=<lanIp>
ssh-b <lanIp>
Chromium / Playwrightバインドフラグは存在しません - 以下のポート8900のブラウザMCPを使用してください

ブラウザ / Playwright MCP

Chromiumにはソースバインディングフラグがないため、ブラウザがISPに到達するにはプロキシ経由のみとなります。lan-browser.mjs を使用してください:これはPlaywright MCPサーバーで、自身のプロキシを起動して管理するため、ブラウザがプロキシなしで起動することは決してありません。

このスキルに同梱されています。scripts/install.ps1 が登録します:

powershell -NoProfile -ExecutionPolicy Bypass -File <skill-dir>\scripts\install.ps1

ISPを使用するホストは、3つのマージ元から取得されるため、再インストールはほとんど必要ありません。スキルディレクトリ内の lan-hosts.txt(デフォルト同梱、git pull で置き換え)、~/.lan-direct-hosts(ユーザー自身のもの、上書きされない)、および起動時の --lan-hosts a,b です。1行1ルール、# コメント可能、サフィックスマッチング。

ユーザーが別のホストをISP経由でルーティングしたい場合、~/.lan-direct-hosts に行を追加し、ブラウザを再起動するように指示してください。lan-hosts.txt は編集しないでください。次のアップデートで上書きされます。

ユーザーが手動で登録するように依頼した場合、-- がPowerShellのパラメータバインダーを通過する必要があることに注意してください。引数を配列として展開するか、bashから実行してください:

# クローンから
claude mcp add playwright-split --scope user -- \
  node <skill-dir>/scripts/lan-browser.mjs --lan-hosts ".ir"

# npmから - チェックアウトが移動しても持続するため、ユーザーがインストールしている場合はこちらを推奨
claude mcp add playwright-split --scope user -- npx -y lan-direct browser

パッケージがインストールされている場合のその他のCLIサブコマンド:lan-direct detect はプラットフォームに適した検出スクリプトを選択し、lan-direct route <host> はブラウザを起動せずに「このホストはISP経由かトンネル経由か」を回答します。ユーザーがサイトが読み込めないと報告した場合は、こちらを使用してください。間違ったルールとダウンしたサイトは外部からは同じに見えます。

サーバーはLAN IPを検出し、lan-detect がバイパスが壊れていると言った場合は起動を拒否し、既存のプロキシがリッスンしている場合はそれを再利用し、MCPが終了したら起動したものをシャットダウンします。自身のログはstderrに出力します。stdoutはJSON-RPCのためにクリーンなままです。

ポート8900を使用します。上記のバックエンドテストで使用する8899とは意図的に別です。再利用はポートのみで判断されるため、番号を共有すると、すべてをバインドするバックエンドプロキシがブラウザをサイレントにキャプチャし、そのすべてのトラフィックをISP経由でルーティングする可能性があります。

1つのブラウザで混合ブラウジングが可能です。 --lan-hosts によりプロキシがホストごとに決定します。一致するホストはISP経由で出口、それ以外はバインドされずトンネルを使用します。つまり、「hooshaとyoutubeをチェック」でツールを切り替える必要はありません。hooshaはISP経由、youtubeはVPN経由、同じセッションです。プロキシログは各行に決定を表示します:

CONNECT  lan  hoosha.com:443
CONNECT  vpn  youtube.com:443

リストを正確に保ってください:国内ホストがリストにないとトンネル経由になり、空の応答で失敗します。また、外国のホストが誤ってリストに追加されるとISP経由になり、フィルタリングされる可能性があります。サイトが接続断のように見える方法で失敗した場合、サイトがダウンしていると想定する前に、ログがどのルートを選択したかを確認してください。

明示的なリストであり、自動検出ではない理由:トンネルを介してブロックされたホストに接続すると、TCPレベルでは成功し(測定:connect@14ms)、プロキシがすでに 200 Connection Established に応答した後の約860ms後にのみ失敗します。フォールバックすると、TLSハンドシェイクをバッファリングして再生し、国内リクエストごとにその遅延を支払うことになります。

Playwrightはループバックをプロキシ経由でルーティングします。 Chromeは通常localhostをバイパスしますが、プロキシが設定されている場合Playwrightはそれをオーバーライドするため、http://127.0.0.1:3000 は直接アクセスではなく lan-proxy.mjs に到達します。プロキシログで確認済みです。プロキシのループバックガードがローカル開発サーバーに到達可能にするものです。これがないと、それらのリクエストはすべて EADDRNOTAVAIL で失敗します。--proxy-bypass=<-loopback> を追加しないでください。ここでは何も変わらず、状況を混乱させるだけです。

トラブルシューティング

directEgress がトンネル稼働中に lanEgress と等しい。 VPNがキルスイッチまたは厳格ルート(バインドされたソケットをブロックするWFPフィルター)を適用しています。回避策ではなくVPNクライアントで修正してください:厳格ルートを無効にするか、必要なホストの直接/バイパスルーティングルールを追加します。nekoray/sing-box:strict_route をオフにするか、direct アウトバウンドルールを追加します。

Linuxでは、キルスイッチがなくてもこれが発生する可能性があります。ソースアドレスだけではWindowsのようにルーティングテーブルをオーバーライドしないため、ポリシールーティングによりトラフィックがトンネル内に留まります。修正は、LAN IPからのトラフィックを物理ゲートウェイ経由で送信するルール(ip rule add from <lanIp> table <n> とそのテーブルへのデフォルトルート)を追加することです。これにはroot権限が必要で、システム全体の変更となるため、説明してユーザーに決定させてください。このスキルの他のすべては、非特権でプロセススコープのままです。

fakeIpDns: true。 OSリゾルバーが 198.18.x.x プレースホルダーを返しており、これはトンネル内でのみ意味を持ちます。プロキシに --dns <lanDns> を渡して、LAN自身のDNSで解決するようにします。

出口プローブが何も返さない。 プローブホストへの接続がありません。リンクを確認し、再実行してください。

逃げ道

バックエンドを本当にプロキシできない場合(プロキシをサポートしないコンパイル済みバイナリ)、残された唯一のオプションはホスト固有の静的ルートです:

route add <targetIp> mask 255.255.255.255 <gateway> metric 1   # 管理者権限が必要
route delete <targetIp>                                        # 元に戻す、常に

これはグローバルです。 その宛先に対してすべてのプロセスをトンネルから外します - あなた自身が同じホストに接続する場合も含みます。昇格が必要で、削除されるまで存続し、忘れられがちです。使用前に確認し、同じセッション内で削除してください。

関連スキル