はじめに
当社(合同会社ジョインクラス)は、Claude Code を launchd で17個以上のジョブとして回し、記事公開・朝ダイジェスト・売上集計などをほぼ無人で動かしています。
その中で地味に痛かったのが リモートMCPサーバーのOAuth認証切れ です。無人実行(claude -p)のセッションでは OAuth のブラウザフローを開けないため、認証が切れたMCPサーバーは「要認証」のまま黙ってツールが消えます。ジョブ自体は成功扱いで終わるので、ログを見るまで誰も気づきません。
実際、この記事を書いている時点の無人セッションでも、Atlassian / Google Calendar / Linear / Windsor.ai / Vercel の5つが「requires authentication」状態でした。
この記事では次の3つを扱います。
-
claude mcp login/claude mcp logoutで認証を張り直す手順 - 無人ジョブの前に認証状態をチェックするシェル関数(当社の実装ベース)
- ハマりどころと検証方法
前提
- Claude Code CLI(2026年10月時点の版)
- リモートMCPサーバー(HTTP/SSE、OAuth 2.1対応)を
claude mcp add済み - macOS + launchd で
claude -pを定期実行している
サブコマンドの細かいオプションはバージョンで変わります。作業前に必ず claude mcp --help で手元の版を確認してください。
1. 認証の張り直し: login / logout
まず状態を確認します。
# 登録済みMCPサーバーと接続状態の一覧
claude mcp list
# 出力例(抜粋)
# github: npx -y @modelcontextprotocol/server-github - ✓ Connected
# linear: https://mcp.linear.app/sse (SSE) - ⚠ Needs authentication
# vercel: https://mcp.vercel.com (HTTP) - ⚠ Needs authentication
Needs authentication になっているサーバーに対して、対話できるターミナルで ログインします。
# ブラウザが開き、OAuth同意画面 → コールバックでトークン保存
claude mcp login linear
# トークンを破棄したいとき(アカウント切替・退職者の端末整理など)
claude mcp logout linear
# 張り直し後に再確認
claude mcp list | grep linear
ポイントは以下です。
-
ログインは人間のいるターミナルでしか完了しない。
claude -pや launchd 配下ではブラウザを開けません - トークンは macOS ではキーチェーンに保存されるため、
.mcp.jsonをgitに入れても秘密情報は漏れません(逆に言えば、別マシンには引き継がれません) - アカウントを切り替えたいときは
logout→loginの順。loginを重ねても古いトークンが使われ続けるケースがありました - 対話セッション内なら
/mcpからも同じ操作ができます
なお claude.ai 側で追加したコネクタ(claude.ai Linear のように表示されるもの)は、CLIではなく claude.ai のコネクタ設定画面 で認可します。CLIの login 対象ではないので混同しないように注意してください。
2. 無人ジョブの前に認証切れを検知する
当社では無人実行を lib/claude-run.sh の claude_run という共通ラッパーに統一しています(コスト記録用)。実物はこうです。
#!/bin/bash
# claude を無人実行するときの共通ラッパー。実コストを記録する。
# 注意: --bare は認証を読まないため "Not logged in" で失敗する。使わない。
_CLAUDE_RUN_LIB="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
claude_run() {
local label="$1"; shift
claude --output-format json \
--fallback-model claude-sonnet-5 \
--max-budget-usd 3 \
"$@" 2>/dev/null \
| python3 "$_CLAUDE_RUN_LIB/record-cost.py" "$label"
}
ここに「必要なMCPが認証済みか」を確認する関数を足します。認証切れなら claude を呼ばずに終了し、通知だけ出します(呼ぶと1回 $0.3 前後かかるうえ、結果も欠けるため)。
#!/bin/bash
# 使い方: require_mcp_auth linear github || exit 0
require_mcp_auth() {
local list missing=()
list="$(claude mcp list 2>/dev/null)" || {
echo "[mcp-auth] claude mcp list 失敗" >&2
return 1
}
for server in "$@"; do
local line
line="$(grep -E "^${server}:" <<<"$list")"
if [[ -z "$line" ]]; then
missing+=("${server}(未登録)")
elif ! grep -q "Connected" <<<"$line"; then
missing+=("$server")
fi
done
[[ ${#missing[@]} -eq 0 ]] && return 0
local msg="MCP認証切れ: ${missing[*]} → ターミナルで claude mcp login <name>"
echo "[mcp-auth] $msg" >&2
osascript -e "display notification \"$msg\" with title \"AI-CEO\"" 2>/dev/null
return 1
}
ジョブ側の呼び出しはこうなります。
source "$HOME/workspace/one-ceo/.company/scripts/lib/claude-run.sh"
source "$HOME/workspace/one-ceo/.company/scripts/lib/mcp-auth-check.sh"
# Linear を使うジョブなので、認証が無ければスキップ
require_mcp_auth linear || exit 0
RESULT=$(claude_run dept-dev --effort low -p "Linearの今週のIssueを要約して")
exit 0 にしているのは、launchd に失敗として再起動させないためです。認証は人間が login しない限り直らないので、リトライしても無駄にコストが積まれるだけです。
3. 落とし穴
--bare を付けると全部「未ログイン」になる
起動を軽くしようと --bare を付けたところ、認証情報を読まずに Not logged in で落ちました。上のラッパーのコメントはこの事故の名残です。MCPのOAuthトークンも同じく読まれないので、無人実行では付けないでください。
launchd 配下はキーチェーンにアクセスできないことがある
ログイン済みのはずなのにlaunchdからだけ Needs authentication になる場合は、ジョブが GUI セッション外(LaunchDaemons)で動いている可能性があります。当社はユーザーの ~/Library/LaunchAgents に置き、ログイン中のユーザーコンテキストで動かすことで解消しました。以前 cron がフルディスクアクセス問題で全滅し、launchd に全面移行したときと同じ系統のハマり方です。
claude mcp list 自体が遅い
list は各サーバーに実際に接続して確認するため、サーバーが多いと数秒かかります。ジョブごとに毎回呼ぶより、朝ダイジェストの前に1回だけ実行して結果をファイルに残し、他のジョブはそのファイルを見る、という形のほうが軽く済みます。
4. 検証方法
導入後は、わざと認証を切って検知されるか確かめてください。
claude mcp logout linear
bash -c 'source .company/scripts/lib/mcp-auth-check.sh; require_mcp_auth linear; echo "exit=$?"'
# [mcp-auth] MCP認証切れ: linear → ターミナルで claude mcp login <name>
# exit=1
claude mcp login linear
bash -c 'source .company/scripts/lib/mcp-auth-check.sh; require_mcp_auth linear; echo "exit=$?"'
# exit=0
macOS の通知が出て、exit が 1 → 0 に変われば完成です。
おわりに
自動化率を上げるほど「静かに壊れる箇所」が怖くなります。当社でも、AIが出したメールを確認なしで送って敬語の崩れたメールが取引先に届いたり、git push --force でブランチが消えたりしたことがあり、そのたびに「実行前に止まる仕組み」を足してきました。MCPの認証切れも同じで、login/logoutは人間がやり、切れていることの検知は機械にやらせる、という分担にしてからは無駄な実行がなくなりました。
MCPサーバーそのものの作り方や、OAuth対応のリモートMCPサーバーの設計については、書籍にまとめています。
📘 『Claude Code × MCP サーバー開発入門』
書籍一覧: https://zenn.dev/joinclass?tab=books