Hermes Agent Wiki 非公式・日本語wiki

SSH / リモートホスト越しの OAuth

目次

Hermes のプロバイダーのうち、Spotifyリモートの MCP サーバー(Linear、Sentry、Atlassian、Asana、Figma など)は、*ループバックへ戻ってくる* 方式の OAuth を使います。認証サーバーがブラウザを http://127.0.0.1:<port>/callback へ転送し、Hermes が立ち上げた小さな HTTP の待ち受けが認可コードを受け取るしくみです。

Hermes とブラウザが同じマシンにあるなら、これは問題なく動きます。壊れるのは両者が別のマシンにあるときです。手元のノート PC のブラウザはそのノート PC の 127.0.0.1 を見に行きますが、待ち受けているのはリモートのサーバーの 127.0.0.1 だからです。

解決策は、SSH のローカル転送を 1 行足すことです。対話的な端末で MCP サーバーを使う場合は、代わりに転送先の URL を貼り戻すやり方でも済むことが多く、そのときはトンネルが要りません。

xAI Grok OAuth(xai-oauth)は OAuth のデバイスコード方式を使っており、ループバックへのコールバックは使いません。表示された確認用 URL をどれかのブラウザで開けば、Hermes が承認されるまで問い合わせ続けます。SSH のトンネルは不要です。xAI Grok OAuth を参照してください。

要点だけ

# On your local machine (laptop), in a separate terminal:
ssh -N -L 43827:127.0.0.1:43827 user@remote-host

# In your existing SSH session on the remote machine:
hermes auth spotify --no-browser
# → Hermes prints an authorize URL. Open it in a browser on your laptop.
# → Your browser redirects to 127.0.0.1:43827/callback, the tunnel forwards
#   the request to the remote listener, login completes.

Hermes は実際に使ったポートを Waiting for callback on ... の行に表示します。そこから写してください。Spotify の既定は 43827 番です。

トンネルが必要なプロバイダー

プロバイダー ループバックのポート トンネルは必要か
Spotify 43827(既定) 必要。Hermes がリモートにある場合
MCP サーバー(auth: oauth サーバーごとに自動で選ばれます 必要。Hermes がリモートにある場合(または転送先 URL を貼り戻す)
xai-oauth(Grok SuperGrok) 該当なし 不要。デバイスコード方式
anthropic(Claude Pro/Max) 該当なし 不要。コードを貼る方式
openai-codex(ChatGPT Plus/Pro) 該当なし 不要。デバイスコード方式
minimaxnous-portal 該当なし 不要。デバイスコード方式

この表にないプロバイダーなら、トンネルは要りません。

MCP サーバー

リモートの MCP サーバー(Linear、Sentry、Atlassian、Asana、Figma など)も、同じループバック転送の方式を使います。Hermes はサーバーごとに空いているポートを自動で選び、OAuth が始まったところで認可用の URL を表示します。表示されるのは、mcp_servers: に新しいサーバーが増えたときの起動時か、hermes mcp login <server> を実行したときです。

リモートのホストから完了させる方法は 2 つあります。

方法 1 — 転送先の URL を貼り戻す(準備不要で、どこでも使えます)。 対話的な端末では、ローカルの待ち受けを動かすのと並行して、Hermes が転送先 URL の貼り付けを促します。ブラウザで承認すると http://127.0.0.1:<port>/callback への転送で接続エラーの画面になりますが、これは想定どおりです。ブラウザのアドレス欄にある URL 全体を写して、Hermes のプロンプトに貼り付けてください。

  MCP OAuth: authorization required.
  Open this URL in your browser:

    https://mcp.linear.app/authorize?response_type=code&...

  Or paste the redirect URL here (or the ?code=...&state=... portion) and press Enter:
> https://mcp.linear.app/callback?code=abc123&state=xyz
  Got authorization code from paste — completing flow.

?code=...&state=... のクエリ文字列だけでも受け付けます。これは auth: oauth のどの MCP サーバーでも使え、SSH の設定を変える必要もありません。

方法 2 — SSH のポート転送(Spotify と同じ)。 Hermes は SSH セッション向けの案内に、実際に使ったポートを表示します。手元のノート PC で別の端末を開いてください。

ssh -N -L <port>:127.0.0.1:<port> user@remote-host

あとは、いつもどおり認可用の URL をブラウザで開けば、転送がトンネルを通って待ち受けに届きます。人が付かずに完了させたいとき(貼り付け操作ができない自動の再認証など)は、こちらを使ってください。

落とし穴 — 30 秒で打ち切られる設定の読み込み直し。 Hermes のセッションを動かしたまま ~/.hermes/config.yaml を編集して OAuth の MCP サーバーを足すと、CLI が 30 秒のタイムアウト付きで MCP の接続を読み込み直します。対話的な OAuth を終えるには短すぎて、読み込み直しは途中であきらめてしまいます。代わりに、新しい端末から hermes mcp login <server> を実行してください。こちらには打ち切りがなく、貼り戻すまで 5 分間待ってくれます。

待ち受けを 0.0.0.0 に開けない理由

Spotify と多くの MCP の OAuth サーバーは、redirect_uri のパラメーターを許可リストと照らし合わせます。どちらもループバックの形(http://127.0.0.1:<exact-port>/callback)を要求します。待ち受けを 0.0.0.0 や別のポートに開くと、認証サーバーは redirect_uri の不一致としてリクエストを拒否します。SSH のトンネルなら、ループバックの URI を端から端までそのまま保てます。

手順: SSH が 1 段の場合

1. 手元のマシンからトンネルを張る

# Spotify (port 43827)
ssh -N -L 43827:127.0.0.1:43827 user@remote-host

-N は「リモートのシェルは開かず、トンネルを保つだけ」という意味です。ログインが終わるまで、この端末は開いたままにしておいてください。

2. 別の SSH セッションで認証のコマンドを実行する

ssh user@remote-host
hermes auth spotify --no-browser

Hermes は SSH のセッションであることを見分けてブラウザの自動起動をやめ、認可用の URL と Waiting for callback on http://127.0.0.1:<port>/callback の行を表示します。

3. 手元のブラウザでその URL を開く

リモートの端末から認可用 URL を写して、ノート PC のブラウザに貼り付けます。同意の画面で承認すると、認証サーバーが http://127.0.0.1:<port>/callback へ転送します。ブラウザがトンネルに入り、リクエストがリモートの待ち受けへ届いて、Hermes が Login successful! と表示します。

成功の行が出たら、最初の端末で Ctrl+C を押してトンネルを畳んで構いません。

手順: 踏み台を経由する場合

踏み台(bastion)を通って Hermes に届いている場合は、SSH に組み込みの -J(ProxyJump)を使います。

ssh -N -L 43827:127.0.0.1:43827 -J jump-user@jump-host user@final-host

これで、踏み台にループバックのポートを置かずに、SSH の接続を踏み台越しにつなげます。ノート PC の 127.0.0.1:43827 は、最終的なリモートホストの 127.0.0.1:43827 までまっすぐ通ります。

-J に対応していない古い OpenSSH では、長い書き方になります。

ssh -N \
    -o "ProxyCommand=ssh -W %h:%p jump-user@jump-host" \
    -L 43827:127.0.0.1:43827 \
    user@final-host

Mosh、tmux、ssh の ControlMaster

トンネルは、その下にある SSH の接続に属するものです。mosh のセッションの中の tmux で Hermes を動かしている場合、mosh の接続の移り変わりには -L の転送が付いてきません。-L のトンネル専用に、素の SSH セッションを*別に*開いてください。認証のあいだ生きている必要があるのは、その接続です。対話用の mosh / tmux のセッションのほうは、そのまま Hermes を動かし続けて構いません。

ssh -o ControlMaster=auto を使っている場合、多重化された接続でのポート転送は親の接続と寿命を共にします。トンネルが立ち上がらないときは、親を張り直してください。

ssh -O exit user@remote-host
ssh -N -L 43827:127.0.0.1:43827 user@remote-host

うまくいかないとき

bind [127.0.0.1]:43827: Address already in use と出る

手元のマシンで、そのポートをすでに何かが使っています。前のトンネルがきれいに終わっていないか、ローカルの Hermes も同じポートで待ち受けているかのどちらかです。犯人を見つけて止めてください。

# macOS / Linux
lsof -iTCP:43827 -sTCP:LISTEN
kill <PID>

そのうえで ssh -L のコマンドをやり直します。

ローカルのコールバックを待っている途中で承認がタイムアウトする

転送がリモートの待ち受けまで戻ってこなかった状態です。トンネルがまだ生きているか(ssh -N は何も出力しないので、起動した端末を見てください)、いちばん新しい Waiting for callback on ... の行にあるポートを使ったか(Hermes は希望のポートが埋まっていると自動でずらすことがあります)を確認し、必要ならトンネルを張り直して、認証のコマンドをやり直してください。

トークンが違う ~/.hermes に書かれる

トークンは hermes auth add ... を実行した Linux ユーザーの下に書かれます。ゲートウェイや systemd のサービスが別のユーザー(root や専用の hermes ユーザーなど)で動いているなら、そのユーザーとして認証して、トークンがそのユーザーの ~/.hermes/auth.json に入るようにしてください。sudo -u hermes -i などを使います。

あわせて読む