PR

LAN越しにClaude認証を共有する ── claudeway開発記 (1)

Diary

LAN越しにClaude認証を共有する

出発点

ある認証済みアカウントでClaude Codeを使っている。認証済みアカウントはトークン制限が緩く、実用的な長さのやり取りが可能だ。

ただし、このアカウントにログインできるのはホストPC上のClaude CLIだけ。機密上の理由から、別のPC(クライアントPC)でこのアカウントに直接ログインすることはできない。

一方で、2台のPCは同じLANにつながっている。ホストPCではClaude CLIがOAuth認証済みの状態で動く。クライアントPCにはVSCodeがあり、そこからClaude Codeを使いたい。

仕様書の「背景・目的」には、こう書いた。

  • 認証済みアカウントのClaudeはトークン制限が緩い
  • 認証済みアカウントをクライアントPCで直接ログインすることは機密上NG
  • ホストPCを踏み台にして、認証・API呼び出しをホストPC上で完結させる

要するに、認証情報を動かせないなら、リクエストのほうを動かす。クライアントPCからプロンプトをホストPCに送り、ホストPC上でClaude CLIを叩き、結果を返す。認証情報はホストPCから一歩も出ない。

発想自体はシンプルだが、実現するには「VSCodeのAIアシスタント連携がどういうプロトコルで動いているのか」を理解する必要があった。

MCPとは何か

VSCode 1.115.0以降には、MCP(Model Context Protocol)クライアントが組み込まれている。MCPは、AIアシスタントと外部ツールをつなぐためのオープンプロトコルだ。

MCPの通信は JSON-RPC 2.0 をベースにしており、以下のようなメソッドで構成される。

  1. initialize ── ハンドシェイク。クライアントとサーバーが互いのcapabilities(対応機能)を交換する
  2. tools/list ── サーバーが提供するツールの一覧をクライアントが取得する
  3. tools/call ── クライアントがツールを実行する。引数を渡して結果を受け取る

トランスポート方式はいくつかあるが、VSCodeのMCPクライアントは「Streamable HTTP」をサポートしている。これは、単一のHTTPエンドポイント(POST /mcp)にJSON-RPCリクエストを送り、レスポンスをJSONまたはSSE(Server-Sent Events)で返すという方式だ。

これを知った時点で、構想が具体化した。

ホストPCにMCPサーバーを立てる。ask_claude というツールを1つだけ公開する。クライアントPCのVSCodeはそのMCPサーバーにLAN経由で接続し、ツールを呼ぶ。ホストPC側ではClaude CLIをサブプロセスとして起動し、出力をSSEでストリーミング返却する。

クライアントPC(VSCode MCP Client)
    │
    │ HTTP POST(JSON-RPC 2.0)/ SSE(同一LAN)
    │ 例: http://192.168.x.x:8080/mcp
    ▼
ホストPC:MCPプロキシサーバー(Node.js)
    │
    │ 子プロセス(spawn)
    ▼
claude --print "..." --output-format stream-json
    ↑
  認証済みアカウントでOAuth認証済み

MCPプロトコルに準拠することで、VSCode側は「リモートにあるMCPサーバーに接続している」としか認識しない。特別なクライアント実装は不要で、VSCodeの標準的なMCP接続設定(.vscode/mcp.json)にURLを書くだけで済む。

設計方針を決める

プロキシサーバーを claudeway と名付けた。名前の意図としては Claude + gateway ── Claude AIへの通り道だ。

実装に入る前に、いくつかの設計方針を決めた。

外部依存ゼロ

Node.jsの標準ライブラリだけで実装する。使うモジュールは httpchild_process の2つ。

Express や Fastify といったフレームワークは使わない。MCPサーバーが受け付けるエンドポイントは POST /mcpGET /mcpGET /health の3つだけであり、ルーティングの複雑さはほぼない。LAN内で動く個人ツールに依存ツリーを持ち込むメリットはなく、むしろ node src/server.js 一発で起動できることのほうが価値がある。

実際、最終的な package.jsondependencies フィールドは存在しない。テストも node:testnode:assert で書いており、devDependencies もゼロだ。

単機能

公開するMCPツールは ask_claude の1つだけ。プロンプト文字列を受け取り、Claudeの回答テキストを返す。

仕様書のツール定義はこうなっている。

{
  "name": "ask_claude",
  "description": "ホストPCのClaude CLIを通じてプロンプトを実行し、結果を返す",
  "inputSchema": {
    "type": "object",
    "properties": {
      "prompt": {
        "type": "string",
        "description": "Claudeに送信するプロンプト",
        "maxLength": 100000
      }
    },
    "required": ["prompt"]
  }
}

ファイル操作、コード実行、コンテキスト管理といった機能はスコープ外。プロキシが扱うのはテキストの入出力だけだ。機能を絞ることはセキュリティの簡素化にも直結する。

LAN前提の割り切り

認証機構は持たない。HTTPS化もしない。IPホワイトリストも実装しない。「同じLANに接続している=信頼できる」という前提で設計した。

README にも仕様書にも「LAN内専用、インターネットには絶対に公開しない」と明記している。この割り切りがあるからこそ、実装をシンプルに保てる。セキュリティ上の考慮は「信頼境界をLANの内側に限定する」ことで対処する設計だ。

ストリーミング対応

Claude CLIには --output-format stream-json というオプションがある。これを指定すると、回答がNDJSON(1行1JSONオブジェクト)形式でストリーミング出力される。

このストリーミング出力をそのままSSE経由でクライアントに流せば、VSCode上でClaudeの回答がリアルタイムに表示される。回答全文の生成を待ってから一括返却するよりも、ユーザー体験は格段に良い。

ただし、実際に --output-format stream-json を試してみると、--verbose フラグも同時に指定しないとエラーになることがわかった(CLI バージョン 2.1.100での検証結果)。このような「ドキュメントに書かれていない挙動」は、事前に検証しておかないと実装時にハマる。CLIの出力スキーマの検証結果は docs/verify-cli-results.md に記録した。

同時リクエスト制限

tools/call(=Claude CLI呼び出し)は同時に1件だけ受け付ける。2件目以降は即座にJSON-RPCエラー(-32000 Server busy)を返す。

個人利用のプロキシであり、マルチユーザー対応は不要だ。Claude CLIの同時実行を避けることで、リソース管理の複雑さを排除した。

技術スタック

最終的な構成を一覧にするとこうなる。

レイヤー 技術 補足
ランタイム Node.js v18+ engines フィールドで明示
HTTP サーバー node:http 標準ライブラリ
プロセス管理 node:child_process(spawn) shell: false でコマンドインジェクション防止
プロトコル JSON-RPC 2.0 over Streamable HTTP MCP仕様 2025-11-25 準拠
ストリーミング Server-Sent Events (SSE) keepalive 30秒間隔
CLI連携 claude --print --output-format stream-json --verbose --verbose は必須
テスト node:test + node:assert 標準ライブラリ。39テスト
外部依存 なし dependencies / devDependencies ともにゼロ

開発の進め方

このプロジェクトは、Claude Code自身をペアプログラマーとして使いながら開発した。仕様策定、コードレビュー、テスト設計といった工程を、Claude Codeのエージェント機能を活用して進めた。

開発はすべて2026年4月11日の1日で行っている。最初のコミットが14:04(JST)、v1.0.0のリリース準備が完了したのが翌日の0:07。約10時間で仕様策定から実装・テスト・LAN実機検証・公開準備まで完了した。コミット数は29。

大まかな流れはこうだった。

  1. 仕様策定 ── MCPプロトコルの要件、CLI連携の方式、エラーハンドリング方針をまとめた仕様書を作成
  2. 実装 ── 仕様に基づいて src/server.js を実装(最終的に約800行)
  3. レビュー・バグ修正 ── レビューで2件のバグを発見・修正(SSEハンドリング関連)
  4. テスト追加 ── 39のテストケースを作成。MCPプロトコル準拠、入力バリデーション、エラーパス、エッジケースをカバー
  5. 仕様・実装・テストの三点突合 ── 仕様書と実装とテストの間に12件のギャップを発見し、すべて解消
  6. 実機検証 ── ローカルおよびLAN越しの実機で動作確認(VSCode 1.115.0、Windows 11 Pro)
  7. 公開準備 ── 用語の中立化、IPアドレスの匿名化、英語READMEの追加、MITライセンスの付与

次回は、MCPプロトコルの実装で具体的にどう躓き、どう解決したかについて書く。


claudeway は GitHub で公開しています(MIT License)。

コメント

タイトルとURLをコピーしました