0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

claude mcp loginの--no-browser、非TTYではssh -tが必須だった

0
Posted at

はじめに

Claude Code の CLI に claude mcp login / claude mcp logout コマンドが追加され、MCPサーバーの認証を /mcp メニューを開かずにシェルから完結できるようになりました。SSHやheadless環境向けに --no-browser フラグも用意されており、公式の変更履歴には「headless環境ではブラウザのポップアップをスキップし、URLを貼り付けるプロンプトに直接進む」と説明されています1

筆者はこの記事のために、実際にクラウド上のheadless(非TTY)なClaude Codeセッションで claude mcp login --no-browser を動かしてみました。結果、公式の説明どおりには進まず、「stdinがターミナルではない」という理由で認証が完了できないことが分かりました。この記事では、その実測結果と、CI・cron・スクリプトから自動化する際に気をつけるべき点をまとめます。

この記事で分かること

  • claude mcp login / logout コマンドの基本的な使い方
  • --no-browser フラグを付けても「非TTY」だと認証が完了しない実例
  • パイプで認可URLを流し込んでも通らないことの検証結果
  • 自動化パイプラインでMCPサーバー認証をどう扱うべきか

前提環境

  • Claude Code CLI: v2.1.202
  • 実行環境: クラウドのheadlessセッション(TTYなし、ブラウザなし)
  • 検証対象MCPサーバー: Sentry公式MCP(https://mcp.sentry.dev/mcp、OAuth認証必須)

TL;DR

  • claude mcp login <name> --no-browser は認可URLを表示してくれるが、認証完了には 本物のTTY が必要
  • stdin がパイプやリダイレクトの場合は「stdin isn't a terminal」で即座に失敗する(パイプに文字列を流し込んでも受け付けない)
  • CI・cronジョブなど完全headlessな自動化パイプラインからは claude mcp login を直接叩けない。ssh -t 等でPTYを割り当てた対話セッションを別途用意する必要がある

背景・課題

MCPサーバーの多くはOAuth認証が必要で、これまでは対話セッション内で /mcp メニューを開いてブラウザ経由で承認するのが基本でした。CLIから直接ログインできる claude mcp login の追加は、SSH接続やheadless環境での運用を楽にする狙いだと公式の変更履歴に明記されています1

具体的には以下のバージョンで段階的に機能が追加されています。

バージョン 変更内容
v2.1.186 claude mcp login <name> / logout <name> を追加。インタラクティブな /mcp メニューなしでCLIから認証可能に
v2.1.191 MCP OAuthの改善。「headless環境ではブラウザのポップアップをスキップし、URLを貼り付けるプロンプトに直接進む」という挙動を追加
v2.1.193 認証が必要なMCPサーバーがある場合、起動時に /mcp を指すstartup通知を追加

「headless環境なら自動でURL貼り付けモードに切り替わる」と読めるため、CI/cron的な完全自動実行のパイプラインからでも突破できそうに見えます。実際にどこまで動くのかを、本プロジェクトのクラウド実行セッション(このパイプライン自体が動いているheadless環境)で検証しました。

やったこと

ステップ1: 検証用MCPサーバーを追加

OAuth認証が必須の公式MCPサーバー(Sentry)を一時的に追加します。

claude mcp add --transport http sentrytest https://mcp.sentry.dev/mcp
Added HTTP MCP server sentrytest with URL: https://mcp.sentry.dev/mcp to local config

ステップ2: --no-browser なしでログインを試す

まずはフラグなしで実行します。このセッションはstdinを閉じたheadless実行です。

claude mcp login sentrytest < /dev/null
Starting authentication for "sentrytest"…
If the browser didn't open, visit:
  https://mcp.sentry.dev/oauth/authorize?response_type=code&client_id=...

Waiting for authorization… (^C to cancel)
Couldn't complete authentication for "sentrytest": stdin isn't a terminal,
so authentication can't be completed here. Re-run in an interactive terminal
— e.g. `ssh -t` — and paste the redirect URL when prompted.

認可URLは表示されるものの、最終的に「stdinがターミナルではない」というエラーで失敗しました。

ステップ3: --no-browser を明示して再検証

公式ドキュメントの説明どおりなら、--no-browser を付けることでこの制約を回避できるはずです。

claude mcp login sentrytest --no-browser < /dev/null
Starting authentication for "sentrytest"…
Visit this URL to authorize:
  https://mcp.sentry.dev/oauth/authorize?response_type=code&client_id=...

Waiting for authorization… (^C to cancel)
Couldn't complete authentication for "sentrytest": stdin isn't a terminal,
so authentication can't be completed here. Re-run in an interactive terminal
— e.g. `ssh -t` — and paste the redirect URL when prompted.

結果は変わらず、同じエラーで停止しました。--no-browser は「ブラウザを開こうとしない」「URLをprintする」動作の切り替えであって、stdinがTTYであることの要求は免除しない ようです。

ステップ4: パイプでリダイレクトURLを流し込んでみる

「貼り付けを待っている」だけなら、パイプでダミー文字列を流せば次のステップに進むのではと考え試しました。

echo "not-a-real-url" | claude mcp login sentrytest --no-browser
Starting authentication for "sentrytest"…
Visit this URL to authorize:
  https://mcp.sentry.dev/oauth/authorize?...

Waiting for authorization… (^C to cancel)
Couldn't complete authentication for "sentrytest": stdin isn't a terminal,
so authentication can't be completed here. Re-run in an interactive terminal
— e.g. `ssh -t` — and paste the redirect URL when prompted.

パイプ経由の入力すら読み取る前に「stdinがTTYか」の判定で弾かれることが確認できました。中身を検証する以前の段階でブロックされています。

ハマりポイント: 「headlessで自動化できる」わけではない

公式の変更履歴の文言「headless環境ではURL貼り付けプロンプトに直接進む」は、SSH越しの対話セッション(ssh -t でPTYを確保した状態) を指しており、「TTYがまったく存在しない完全自動実行」まではカバーしていません。

--no-browser はあくまで「ブラウザを自動起動しない」フラグであり、「非対話実行を許可する」フラグではありません。CI/cronのような真のheadless実行から claude mcp login を直接叩くパイプラインは、現状のバージョン(v2.1.202時点)では組めません。

自動化パイプラインでMCPサーバーの認証が必要な場合は、以下のいずれかで回避する必要があります。

  1. 初回セットアップだけ ssh -t で対話接続し、claude mcp login でOAuthトークンを取得してから、その認証情報を永続化した状態で自動実行に引き継ぐ
  2. OAuthではなくAPIキー/Bearerトークン方式に対応したMCPサーバーを選び、claude mcp add --transport http <name> <url> --header "Authorization: Bearer ..." で完全非対話に登録する
  3. claude mcp login の自動化は諦め、認証済みの ~/.claude.json 相当の状態を配布・同期する運用にする

本プロジェクトのようにクラウド上のスケジュール実行(cron的な完全headless実行)でMCPサーバーを使う場合、OAuth認証が必要なサーバーは実質的に「一度だけ対話セッションで手動ログインし、その後は認証済み状態を使い回す」設計にせざるを得ません。

著者視点の発見ポイント

公式の変更履歴だけを読むと「--no-browser を付ければheadlessでも認証できる」と誤読しやすい書き方でした。しかし実際に本プロジェクトのクラウドheadlessセッションで動かしてみると、--no-browser はブラウザ起動を止めるだけで、TTY要求そのものはstdinの種類(パイプ・リダイレクト・クローズ)に関わらず一律に効いていました。ドキュメントの「headless環境」という言葉は「SSHで -t を付けた対話セッション」を指しており、「完全に人間の入力なしで完結する自動化」とは別物だと実測して初めて分かりました。この区別は、MCPサーバー認証をCI/cronパイプラインに組み込もうとしている人にとって、事前に知っておく価値のある落とし穴です。

まとめ

  • claude mcp login <name> --no-browser はURLを表示してくれるが、stdinが本物のTTYでないと認証を完了できない
  • パイプでリダイレクトURLらしき文字列を流しても、TTY判定より前に弾かれる
  • 完全headlessな自動化パイプラインでOAuth必須のMCPサーバーを使うには、事前に対話セッションでログイン済みの状態を用意しておく必要がある
  • APIキー/Bearerトークン方式のMCPサーバーであれば claude mcp add --transport http <name> <url> --header "Authorization: Bearer ..." で完全非対話に登録できる

参考リンク

  1. Claude Code Changelog — v2.1.191「Improved MCP OAuth: discovery and token requests now retry once after transient network errors, and headless environments skip the browser popup and go straight to the paste-the-URL prompt」(2026年6月時点) 2

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?