讓 Claude Code 連上由 Cognito 保護的 MCP 伺服器 — 用事先註冊的用戶端 ID 或 headersHelper
MCP 伺服器在 Bedrock AgentCore Runtime 上運行、由 Amazon Cognito 負責認證,而 Cognito 並不支援動態用戶端註冊。本文說明如何用兩種方法讓 Claude Code 連上這種伺服器。

本頁目錄
引言
我在 Bedrock AgentCore Runtime 上運行了一個 MCP 伺服器,傳入請求的認證交給 Amazon Cognito 處理。我想把它註冊到 Claude Code,讓我能透過 /mcp → Authenticate 直接在瀏覽器登入。
直接執行不加任何選項的 claude mcp add,還沒開啟瀏覽器就會出現 Incompatible auth server: does not support dynamic client registration 錯誤而中止。把 Cognito 的存取 token 放進 header 傳過去雖然連得上,但 token 一過期(預設是一小時),伺服器就會回傳 Token has expired。
Claude Code 的 OAuth 認證和 header 認證各有兩種方式,其中能用在 Cognito 上的是事先註冊的應用程式用戶端 ID 和 headersHelper。用事先註冊的用戶端 ID 可以在瀏覽器登入,token 由 Claude Code 負責更新;headersHelper 則會在每次連線時用腳本簽發新的 token。這樣一來,不管用哪一種,token 過期時都不必重新註冊。
Claude Code 向遠端 MCP 伺服器認證的四種方式
Claude Code 連接 HTTP MCP 伺服器時有四種認證方式,依照由誰取得 token 分成兩組。兩種 OAuth 方式由 Claude Code 自己執行瀏覽器登入流程,並儲存 token。另外兩種 header 方式則由 Claude Code 以外的程式產生 token,Claude Code 只負責轉送。
| 認證方式 | 設定項目 | 瀏覽器登入 | token 過期時 | 能否用於 Cognito |
|---|---|---|---|---|
| OAuth(動態用戶端註冊) | 不需設定(預設) | 有 | 由 Claude Code 更新 | 否 |
| OAuth(事先註冊的用戶端) | oauth.clientId、oauth.callbackPort | 有 | 由 Claude Code 更新 | 可以 |
| 靜態 header | headers.Authorization | 無 | 手動換上新 token 之前,連線都會失敗 | 可以,但僅限一個 token 的有效期內 |
headersHelper | 一個會輸出 header 的指令 | 無 | 重新執行指令 | 可以 |
這幾種方式不能混用。Claude Code 的文件寫明,只要設定了 headers.Authorization,就不會退回到 OAuth(「does not fall back to OAuth」)。因此 header 被拒絕時,畫面上就會顯示連線失敗,而不是顯示需要認證、讓你改用瀏覽器登入。
為什麼預設的 OAuth 流程會卡在 Cognito?
動態用戶端註冊(RFC 7591)讓 OAuth 用戶端向授權伺服器的 registration_endpoint 發送 POST,自己建立用戶端 ID。Claude Code 預設就會使用這個機制,所以公開的 MCP 伺服器只要有 URL 就能連上。
在 AgentCore 上,尋找授權伺服器的探索步驟本身沒有問題。不帶 token 的請求會收到 401,回應的 WWW-Authenticate header 會指向 Runtime 的 RFC 9728 受保護資源中繼資料。這份中繼資料把 Cognito 使用者集區列為授權伺服器。問題出在下一步讀取的 Cognito 中繼資料:
輸入curl -s https://cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_XXXXXXXXX/.well-known/openid-configuration | jq '{registration_endpoint, code_challenge_methods_supported, scopes_supported}'輸出{"registration_endpoint":null,"code_challenge_methods_supported":null,"scopes_supported":["openid","email","phone","profile"]}少了 registration_endpoint,Claude Code 就沒辦法取得用戶端 ID,所以還沒開啟瀏覽器就中止了:
✘ Failed to connect — Incompatible auth server: does not support dynamic client registration另外,Cognito 對 RFC 8414 的路徑 /.well-known/oauth-authorization-server 會回傳 400,只提供 OpenID Connect 的 openid-configuration 文件。這份文件在後面設定事先註冊的方式時會派上用場。
最簡單的迴避方法是靜態 header。這樣雖然也連得上,但連線只能維持一個 token 的有效期。過期時就會顯示以下訊息:
Status: ✘ Failed to connectIssue: Server rejected the configured Authorization header (HTTP 401). … Error detail: {"jsonrpc":"2.0","error":{"code":-32001,"message":"Token has expired"}}用事先註冊的 Cognito 應用程式用戶端在瀏覽器登入
MCP 授權規範把事先註冊排在第一順位:如果用戶端已經持有某個授權伺服器的用戶端 ID,就會先使用這個 ID,再去考慮其他方式。Claude Code 透過 oauth.clientId 支援了這種做法:設定了 oauth.clientId 之後,Claude Code 會完全跳過註冊步驟,也就不會再要求 Cognito 提供它缺少的註冊端點。
Cognito 端的應用程式用戶端需要以下設定:
- 啟用授權碼授權類型,而且不產生用戶端密鑰。Claude Code 是公開用戶端,所以會自己送出 PKCE。
- callback URL 需要設定成
http://localhost:<port>/callback。Cognito 會嚴格比對 callback URL,所以連接埠必須固定。 - 必須把這個應用程式用戶端的 ID 加進 AgentCore Runtime 的
allowedClients。否則 Runtime 會以 401 拒絕透過它取得的 token,而這個 401 和 token 無效時的 401 一模一樣,所以無法區別。
接著註冊伺服器,指定同一個連接埠,並直接寫明中繼資料 URL:
claude mcp add-json my-mcp-server '{ "type": "http", "url": "https://bedrock-agentcore.ap-northeast-1.amazonaws.com/runtimes/<URL-encoded runtime ARN>/invocations?qualifier=DEFAULT", "oauth": { "clientId": "YOUR_APP_CLIENT_ID", "callbackPort": 8765, "authServerMetadataUrl": "https://cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_XXXXXXXXX/.well-known/openid-configuration", "scopes": "openid email profile" }}'callbackPort 會讓 Claude Code 去監聽指定的連接埠,也就是應用程式用戶端 callback URL 裡的那個連接埠,而不是隨便選一個;authServerMetadataUrl 則會讓 Claude Code 直接讀取 Cognito 實際提供的 openid-configuration 文件。
現在 /mcp 會顯示這個伺服器需要認證,而不是連線失敗;選擇 Authenticate 就會開啟 Cognito Hosted UI:



登入之後,瀏覽器會透過 callback 連接埠,把授權碼交回給 Claude Code:

透過這個已連線的伺服器呼叫工具之後,成功得到了回應。這表示 AgentCore 確實接受了這個 token,而並非只是 Claude Code 把 token 存了下來而已。
在沒有明確指定權限範圍之前,會一直出現 invalid_scope 的錯誤頁面
如果不設定 oauth.scopes 的話,瀏覽器登入就永遠不會成功。瀏覽器會被導回 Claude Code 的 callback 頁面,並顯示 Cognito 回傳的錯誤:

設定了 authServerMetadataUrl 之後,Claude Code 會讀取 openid-configuration 文件裡的 scopes_supported,決定要請求哪些權限範圍。這份文件是 Cognito 依 OpenID Connect 標準公開的,列出的權限範圍是 openid email phone profile,但應用程式用戶端只允許 openid email profile,因此請求裡多出來的 phone 導致 Cognito 拒絕了這次請求。
把 "scopes": "openid email profile" 明確寫進設定,讓它和應用程式用戶端允許的權限範圍一致之後,問題就解決了。只要請求的權限範圍全都在應用程式用戶端的允許清單內,怎麼組合都可以;相反地,只要多請求一個不允許的權限範圍,就會失敗。
使用 headersHelper 讓靜態 header 自動更新
headersHelper 設定的是一個指令(以下稱 helper),Claude Code 會把它的標準輸出當成請求的 header。helper 會在每次連線時執行;如果工具呼叫回傳 401 或 403,Claude Code 會重新執行 helper、重新連線,並重試一次。只要 helper 每次都簽發新的 Cognito token,就不會再碰到過期的問題。
#!/usr/bin/env bashset -euo pipefailcd "$(dirname "$0")/.."source .cognito.env # COGNITO_CLIENT_ID, COGNITO_USERNAME, COGNITO_PASSWORD, AWS_REGION
TOKEN=$(aws cognito-idp initiate-auth --no-sign-request \ --client-id "$COGNITO_CLIENT_ID" \ --auth-flow USER_PASSWORD_AUTH \ --auth-parameters "USERNAME=${COGNITO_USERNAME},PASSWORD=${COGNITO_PASSWORD}" \ --region "$AWS_REGION" \ --query 'AuthenticationResult.AccessToken' --output text)
printf '{"Authorization": "Bearer %s"}\n' "$TOKEN"InitiateAuth 是不需要用 AWS 憑證簽署請求的 Cognito API,所以加上 --no-sign-request 之後,即使沒有 AWS 憑證也能執行。否則腳本就得透過憑證代理程式取得 AWS 憑證,而代理程式可能會跳出 MFA 提示、等人回應;helper 的逾時只有 10 秒,等不到回應就會失敗。
另外還有兩個條件:
- 應用程式用戶端必須啟用
USER_PASSWORD_AUTH。 - AgentCore 會要求存取 token,因為它會拿存取 token 裡的
client_id宣告去比對allowedClients。
claude mcp add-json my-mcp-server '{ "type": "http", "url": "https://bedrock-agentcore.ap-northeast-1.amazonaws.com/runtimes/<URL-encoded runtime ARN>/invocations?qualifier=DEFAULT", "headersHelper": "/absolute/path/to/scripts/mcp_headers.sh"}'第一次註冊之後並沒有連上,而是出現了這則警告:
MCP server 'my-mcp-server': headersHelper not run — this workspace has no persisted trust; accept the trust dialog here once interactivelyhelper 需要交給 Claude Code 來執行,而 Claude Code 只會在已信任的工作區裡執行它,因為文件把 helper 定位為任意的 shell 指令(「an arbitrary shell command」)。方法很簡單,只要在目前的工作目錄開啟終端機並執行 claude,就會出現一個對話框,詢問你是否信任目前的目錄,選擇信任即可。下一次啟動時,伺服器就會自動連上。
和事先註冊的用戶端相比,取捨在於憑證放在哪裡:helper 需要把密碼存在磁碟上,也需要一個啟用了密碼認證的應用程式用戶端;OAuth 方式則只會留下一個由 Claude Code 儲存的 refresh token。另一方面,helper 在 headless 環境和全自動腳本裡也能運作,適合想跳過瀏覽器登入的情況。
如果真的需要動態用戶端註冊
事先註冊代表每個使用者的 Claude Code 都得先設定好用戶端 ID。只給一個團隊用沒有問題,但如果伺服器是要讓任何拿到 URL 的人都能加入,就會變得很麻煩。
對於和授權伺服器事先沒有往來的用戶端,目前的 MCP 授權規範把 Client ID Metadata Documents(CIMD) 定為首選方式,並把動態用戶端註冊降級為向後相容的選項。在 CIMD 裡,用戶端 ID 本身就是一個 HTTPS URL,指向描述這個用戶端的 JSON 文件,授權伺服器會去抓取這份文件。只要伺服器宣告了 client_id_metadata_document_supported,Claude Code 就會使用這個方式;但 Cognito 並沒有宣告,所以這裡用不了 CIMD。
剩下的是以下三種繞法。以下的選項這次都沒有實際試過,都是其他 Cognito 使用者和 AWS 的 AgentCore 指南提出的做法;其中能同時保留 Cognito 和 AgentCore 傳入認證(JWT 驗證)的,只有 /register 端點。
- 在 Cognito 前面加一個
/register端點。由一個小服務接收 RFC 7591 請求、呼叫CreateUserPoolClient,再回傳新的用戶端 ID;同時提供一份補上registration_endpoint的中繼資料文件。代價是要維護一個任何人都能存取、卻能夠直接呼叫管理 API 的公開端點。這個端點需要速率限制和重新導向 URI 的允許清單,而且使用者集區對應用程式用戶端的數量也有配額,所以還得清理不再使用的用戶端。每個新用戶端也都得加進 AgentCore 的allowedClients。 - OAuth 代理伺服器。FastMCP 的 Cognito 整合會自己回應動態註冊,再把所有請求轉給同一個實際存在的 Cognito 應用程式用戶端,所以 Cognito 完全看不到個別用戶端的註冊。不過這種做法適用於使用 FastMCP 自身認證層的伺服器;像本文這樣依靠 AgentCore 傳入認證(JWT 驗證)的伺服器,無法直接套用。
- 支援動態註冊的身分提供者。AWS 的 AgentCore Runtime MCP 指南示範自動 OAuth 時,用的是 Auth0 而不是 Cognito。如果還能選擇身分提供者,這會是最省事的做法。
總結
- Claude Code 預設的 OAuth 方式需要動態用戶端註冊,而 Cognito 沒有提供
registration_endpoint,所以會出現Incompatible auth server錯誤而失敗。 - 使用事先註冊的 Cognito 應用程式用戶端,就能在瀏覽器登入:設定
oauth.clientId、與應用程式用戶端 callback URL 一致的callbackPort、指向openid-configuration的authServerMetadataUrl,以及只包含應用程式用戶端允許的權限範圍的oauth.scopes。 headersHelper能提供自動更新的 header:在已信任的工作區裡,讓腳本呼叫initiate-auth --no-sign-request,再把存取 token 輸出成 header。- 設定了靜態的
Authorizationheader 之後,就算驗證失敗也不會退回到 OAuth,而且連線在 token 過期後就會失效。 - 如果要在沒有事先設定的情況下註冊,MCP 授權規範現在偏好 CIMD,但 Cognito 不支援。在 Cognito 加上 AgentCore 的架構下,能直接使用的只有
/register這類註冊用的中介服務,否則就得改用其他身分提供者。
參考連結
- MCP 規範 2025-11-25:Authorization,包含用戶端註冊的優先順序與 Client ID Metadata Documents
- Claude Code 文件:Connect Claude Code to tools via MCP,包含事先設定的 OAuth 憑證與 headersHelper
- RFC 7591:OAuth 2.0 Dynamic Client Registration Protocol
- RFC 9728:OAuth 2.0 Protected Resource Metadata
- OpenID Connect Discovery 1.0:
openid-configuration文件的格式 - OAuth Client ID Metadata Document 草案
- FastMCP:以 OAuth 代理伺服器整合 AWS Cognito OAuth
- Amazon Bedrock AgentCore:Authenticate and authorize with Inbound Auth and Outbound Auth




