For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
主要導覽

身分驗證

外掛程式 MCP 伺服器的身分驗證模式。

驗證使用者身分

許多外掛程式 MCP 伺服器可以在唯讀、匿名模式下運作,但凡是提供客戶專屬資料或寫入動作的伺服器,都應驗證使用者身分。

已發布的外掛程式可在 ChatGPT 和 Codex 中執行。MCP 授權契約適用於這兩項產品;當回呼、中繼資料文件或連結介面因產品介面而異時,本指南會特別說明 ChatGPT 用戶端的相關細節。

當你需要連接現有的伺服器端應用程式,或在使用者之間共用資料時,可以整合自己的授權伺服器。

使用 OAuth 2.1 自訂身分驗證

對於需要身分驗證的 MCP 伺服器,你應實作符合 MCP 授權規格的 OAuth 2.1 流程。

組成元件

  • 資源伺服器: 你的 MCP 伺服器,負責提供工具,並在每次請求時驗證存取權杖。
  • 授權伺服器: 你的身分提供者或自訂實作,負責核發 Token 並發布探索中繼資料。
  • 用戶端: 代表使用者執行操作的 OpenAI 主機,例如 ChatGPT 或 Codex。 受支援的用戶端使用用戶端 ID 中繼資料文件(CIMD)、 動態用戶端註冊(DCR)、預先定義的 OAuth 用戶端及 PKCE。

MCP 授權規格要求

  • 在 MCP 伺服器上提供受保護資源的中繼資料
  • 透過授權伺服器發布 OAuth 中繼資料
  • 在整個 OAuth 流程中原樣傳遞 resource 參數
  • 選擇 OpenAI 主機識別或註冊其 OAuth 用戶端的方式:CIMD、DCR 或預先定義的 OAuth 用戶端
  • 發布授權伺服器接受的 Token 端點身分驗證方法

以下以淺白的方式說明規格要求。

在 MCP 伺服器上提供受保護資源的中繼資料

  • 你需要提供 HTTPS 端點,例如 GET https://your-mcp.example.com/.well-known/oauth-protected-resource(或在 401 Unauthorized 回應的 WWW-Authenticate 標頭中宣告相同的 URL),讓 ChatGPT 知道從何處取得中繼資料。
  • 該端點會傳回 JSON 文件,描述資源伺服器及其可用的授權伺服器:
{
  "resource": "https://your-mcp.example.com",
  "authorization_servers": ["https://auth.yourcompany.com"],
  "scopes_supported": ["files:read", "files:write"],
  "resource_documentation": "https://yourcompany.com/docs/mcp"
}
  • 必須填寫的主要欄位:
    • resource:MCP 伺服器的標準 HTTPS 識別碼。ChatGPT 會在 OAuth 流程中,將此值原樣用作 resource 查詢參數。
    • authorization_servers:一或多個指向身分提供者的簽發者基底 URL。ChatGPT 會逐一嘗試這些 URL,以尋找 OAuth 中繼資料。
    • scopes_supported:選用清單,可協助 ChatGPT 說明即將向使用者請求的權限。
    • RFC 9728 中的選用欄位(例如 resource_documentationresource_policy_uriresource_tos_uri)可讓用戶端與管理員更容易瞭解你的設定。

當你因請求未通過身分驗證而封鎖請求時,請傳回如下的驗證挑戰:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://your-mcp.example.com/.well-known/oauth-protected-resource",
                         scope="files:read"

即使 ChatGPT 先前未曾取得中繼資料 URL,也能透過這個標頭找到它。

透過授權伺服器發布 OAuth 中繼資料

  • 身分提供者必須提供下列其中一種位於已知位置的探索文件,讓 ChatGPT 能讀取其組態:
    • 位於 https://auth.yourcompany.com/.well-known/oauth-authorization-server 的 OAuth 2.0 中繼資料
    • 位於 https://auth.yourcompany.com/.well-known/openid-configuration 的 OpenID Connect 中繼資料
  • 每份文件都會向 OpenAI 主機說明三個主要事項:將使用者導向何處、如何交換授權碼,以及如何識別自身。典型的回應如下:
{
  "issuer": "https://auth.yourcompany.com",
  "authorization_response_iss_parameter_supported": true,
  "authorization_endpoint": "https://auth.yourcompany.com/oauth2/v1/authorize",
  "token_endpoint": "https://auth.yourcompany.com/oauth2/v1/token",
  "client_id_metadata_document_supported": true,
  "token_endpoint_auth_methods_supported": ["none", "private_key_jwt"],
  "registration_endpoint": "https://auth.yourcompany.com/oauth2/v1/register",
  "code_challenge_methods_supported": ["S256"],
  "scopes_supported": ["files:read", "files:write"]
}
  • 必須正確設定的欄位:
    • issuer:授權伺服器的標準識別碼。 請在受保護資源中繼資料的 authorization_servers 清單中使用完全相同的值。
    • authorization_response_iss_parameter_supported:只有在授權伺服器的每個授權回應 (包括錯誤回應)都傳回 iss 參數時, 才將此欄位設為 true
    • authorization_endpointtoken_endpoint:ChatGPT 執行完整 OAuth 授權碼 + PKCE 流程所需的 URL。
    • client_id_metadata_document_supported:若希望 ChatGPT 使用 CIMD 進行用戶端註冊,請設為 true。ChatGPT 會優先使用可用的 CIMD,但當 CIMD 和 DCR 都可用時,外掛程式開發者可以選擇 DCR。
    • token_endpoint_auth_methods_supported:列出授權伺服器接受的 Token 端點身分驗證方法。這適用於 CIMD、DCR 和預先定義的 OAuth 用戶端。對於 CIMD,ChatGPT 支援使用 none 進行公開用戶端的 Token 交換,以及使用 private_key_jwt 透過已簽署的用戶端斷言進行 Token 交換。其他 OAuth 用戶端通常使用 noneclient_secret_postclient_secret_basic
    • registration_endpoint:若支援動態用戶端註冊(DCR),請加入此欄位,讓 ChatGPT 能為 MCP 伺服器連線建立並重複使用專屬的 client_id
    • code_challenge_methods_supported:必須包含 S256。 若 MCP 伺服器的授權伺服器中繼資料省略此欄位, 或未依照 MCP 授權規格的要求宣告支援 S256,該 MCP 伺服器就不受支援。
    • 選用欄位遵循 RFC 8414 / OpenID Discovery;請加入有助於管理員設定政策的欄位。

OIDC 範圍

  • 如果身分提供者在其 .well-known/oauth-authorization-server.well-known/openid-configuration 文件的 scopes_supported 欄位中宣告支援 OIDC 範圍(例如 openidemailprofile),ChatGPT 預設會在 OAuth 流程中請求這些範圍。
  • 有些身分提供者可能不會預設啟用已宣告支援的 OIDC 範圍。請檢查身分提供者的組態設定,確保 OAuth 用戶端已啟用所有宣告支援的範圍,無論該用戶端使用 CIMD、由你手動建立,或透過 DCR 建立。

支援工作區網域限制

ChatGPT Enterprise 工作區可以驗證電子郵件網域的擁有權。當透過 OAuth 連結的外掛程式提供使用者已驗證的電子郵件地址時,ChatGPT 可以根據該電子郵件網域,防止使用者以此企業身分在個人工作區或組織外的其他工作區連結外掛程式。

若要支援這項保護措施,請將授權伺服器設定為:

  • 發布 OpenID Connect 探索中繼資料。
  • 宣告支援並啟用 openidemail 範圍。
  • 宣告提供 UserInfo 端點,傳回使用者的 email 宣告及 email_verified: true

你也可以在 OAuth 流程中透過 ID Token 傳回這些宣告,但工作區網域限制仍需要 UserInfo 端點。

企業工作區也必須驗證其網域。授權伺服器提供使用者身分,讓 ChatGPT 與工作區設定的已驗證網域比對;授權伺服器本身不會驗證工作區是否擁有該網域。

重新授權時保留登入上下文

當 ChatGPT 為現有連結重新授權時,包括請求額外 OAuth 範圍的情況,可能會將先前的 OIDC ID Token 作為標準 id_token_hint 參數加入授權請求。若要讓使用者授予額外範圍,而不必從頭登入,請將授權伺服器設定為在最初的 OAuth 流程中核發 ID Token,並在授權時採用 id_token_hint

這項最佳化為選用功能。即使沒有可用的 ID Token,或授權伺服器不使用此提示,重新授權仍可正常運作。

使用簽發者識別保護回呼

OpenAI 主機使用 RFC 9207 簽發者識別來保護 OAuth 回呼,防範授權伺服器混淆攻擊。若要讓 ChatGPT 和 Codex 在建立符合條件的 OAuth 用戶端時使用固定的重新導向 URI,請執行以下設定:

  • 授權伺服器 中繼資料中設定 authorization_response_iss_parameter_supported: true
  • 在中繼資料的 issuer 欄位及 受保護資源中繼資料的 authorization_servers 清單中,使用完全相同的簽發者識別碼。
  • 在每個成功及錯誤的授權回應中傳回 iss。其值 必須與中繼資料的 issuer 完全相符;用戶端會進行精確的字串 比對,不會將結尾斜線、路徑、連接埠或大小寫正規化。

ChatGPT 和 Codex 會在將使用者重新導向之前,記錄所選中繼資料的 issuer, 並在交換授權碼之前檢查傳回的 iss。 如果伺服器宣告支援簽發者識別,卻省略 iss 或 傳回不相符的值,ChatGPT 和 Codex 就會拒絕該回應。這些要求 遵循 MCP 授權回應驗證 規則

重新導向 URL

將 MCP 伺服器管理頁面上顯示的正式環境重新導向 URI 原封不動地複製到授權伺服器的允許清單中。

  • 如果你的授權伺服器不符合上述簽發者識別 要求,ChatGPT 會使用回呼 ID 專屬的重新導向 URI: https://chatgpt.com/connector/oauth/{callback_id}
  • 如果你的授權伺服器符合這些要求,ChatGPT 會使用 固定的重新導向 URI: https://chatgpt.com/connector_platform_oauth_redirect

在 ChatGPT 推出回呼 ID 專屬重新導向機制之前發布的 MCP 伺服器,也會繼續使用固定的重新導向 URI。

在整個 OAuth 流程中原樣傳遞 resource 參數

  • ChatGPT 會在授權請求和 Token 請求中附加 resource=https%3A%2F%2Fyour-mcp.example.com。這會將 Token 與上述受保護資源中繼資料連結起來。
  • 設定授權伺服器,將該值複製到存取 Token 中(通常放在 aud 宣告),讓 MCP 伺服器能驗證這個 Token 是專為它簽發,而非供其他對象使用。
  • 如果收到的 Token 未包含預期的對象或權限範圍,請拒絕該 Token,並透過 WWW-Authenticate 驗證挑戰,提示 ChatGPT 使用正確的參數重新授權。

支援授權碼流程

  • ChatGPT 作為 MCP 用戶端,會使用 S256 代碼挑戰執行搭配 PKCE 的授權碼流程,防止攻擊者重放攔截到的授權碼。
  • 你的授權伺服器必須公布 code_challenge_methods_supported,並在其中包含 S256,讓用戶端能從中繼資料確認是否支援 PKCE。

OAuth 流程

實作上述 MCP 授權規格後,OAuth 流程如下:

  1. ChatGPT 向你的 MCP 伺服器查詢受保護資源中繼資料。

  1. ChatGPT 表明自身的 OAuth 用戶端身分。當 MCP 伺服器使用 CIMD 時,ChatGPT 會略過動態用戶端註冊,並傳送 CIMD 文件 URL 作為 client_id。對於符合上述簽發者識別要求的授權伺服器,ChatGPT 會使用固定的 https://chatgpt.com/oauth/client.json;對於其他伺服器,則使用回呼 ID 專屬的 https://chatgpt.com/oauth/{callback_id}/client.json。MCP 伺服器的管理頁面會顯示該連線回呼模式所用的確切用戶端中繼資料文件及重新導向 URI。當 MCP 伺服器使用 DCR 時,ChatGPT 會針對該 MCP 伺服器連線呼叫一次授權伺服器的 registration_endpoint,取得產生的 client_id,之後便在該連線中重複使用這個用戶端。

使用 CIMD 時,不需要用戶端註冊步驟。以下畫面顯示 DCR 流程:

  1. 當使用者首次呼叫工具時,ChatGPT 用戶端會啟動 OAuth 授權碼 + PKCE 流程。使用者會進行身分驗證,並同意所要求的權限範圍。

  1. ChatGPT 以授權碼換取存取 Token,並將其附加到後續的 MCP 請求中(Authorization: Bearer <token>)。

  1. 你的伺服器會在執行工具前,驗證每個請求的 Token(簽發者、對象、到期時間、權限範圍)。

用戶端註冊

當授權伺服器支援,且外掛程式建置者選用時,請優先採用用戶端 ID 中繼資料文件(CIMD)作為用戶端註冊方式。使用 CIMD 時,ChatGPT 會以 HTTPS 中繼資料文件 URL 作為 client_id。你的授權伺服器會擷取該文件,驗證其中公布的用戶端中繼資料與重新導向資源識別碼,並將該 URL 視為 ChatGPT 固定的用戶端身分。

如果你支援 CIMD,請在授權伺服器中繼資料中設定 client_id_metadata_document_supported: true。這讓 ChatGPT 能對選用 CIMD 的 MCP 伺服器使用同一個固定的用戶端身分,授權伺服器則可依此套用重新導向 URI 允許清單、速率限制及其他政策。

ChatGPT 正在採用 MCP SEP-3149 提出的 CIMD 轉換方案。 其正式環境 CIMD 文件會公布 token_endpoint_auth_methods_supported,以陣列列出 ChatGPT 可使用的方法, 不設優先順序。在轉換期間,也會公布 舊版單數欄位 token_endpoint_auth_method,表示偏好使用的方法:

{
  "token_endpoint_auth_methods_supported": ["none", "private_key_jwt"],
  "token_endpoint_auth_method": "private_key_jwt"
}

複數欄位在這兩份文件中代表不同觀點:授權伺服器中繼資料列出 Token 端點接受的方法,而 ChatGPT 的 CIMD 文件則列出 ChatGPT 可使用的方法。ChatGPT 會從兩者的交集中選擇一種方法。如果舊版單數欄位所指定的偏好方法也在交集中,ChatGPT 就會使用該方法,以相容於仍將單數欄位視為強制要求的授權伺服器。否則,ChatGPT 可以使用交集中的其他方法。

讀取 CIMD 複數欄位的授權伺服器,應接受交集中的任何方法, 除非本地安全性政策不允許該用戶端使用該方法。 伺服器必須拒絕交集以外的方法。client_id URL 會保持固定,不會透過查詢參數選擇 特定方法的文件。

支援的方法如下:

  • none:當你的 Token 端點支援以 PKCE 交換授權碼,且不需要用戶端身分驗證時,請使用此公開用戶端流程。ChatGPT 不會儲存個別用戶端的密鑰。
  • private_key_jwt:當你的 Token 端點要求用戶端身分驗證時,請使用此簽署用戶端斷言的流程。ChatGPT 會在 CIMD 中繼資料中公布公開的 JWKS URL。JWKS 由中繼資料來源的 /oauth/jwks.json 提供。ChatGPT 會在伺服器端使用受管理的私密金鑰和 kid 簽署 Token 請求;你的授權伺服器則根據公開的 JWKS 驗證斷言。

DCR 仍受支援。如果你提供 registration_endpoint,當外掛程式建置者選用 DCR,或 CIMD 無法使用時,ChatGPT 就能進行動態註冊。ChatGPT 會針對每個 MCP 伺服器連線執行一次 DCR,接著保留已註冊的 OAuth 用戶端,並在該連線中重複使用。若有許多獨立連線,DCR 仍可能產生大量已註冊的用戶端,因此大規模使用時,CIMD 通常較容易管理。

在 MCP 伺服器連線使用期間,請確保已註冊的 OAuth 用戶端及任何用戶端密鑰持續有效。如果授權伺服器使任一憑證到期,或將其刪除或替換,使用者和審查者在連線時可能會收到 invalid_client 錯誤。存取 Token 和更新 Token 仍可正常到期或輪替。

用戶端識別

常見的問題是:MCP 伺服器如何確認請求確實來自 ChatGPT?ChatGPT 在連線至 MCP 伺服器時,會出示由 OpenAI 管理的用戶端憑證,因此你可以透過 mTLS 在傳輸層驗證用戶端。你也可以將 ChatGPT 公布的對外連線 IP 範圍加入允許清單。ChatGPT 支援機器對機器的 OAuth 授權類型,例如用戶端憑證、服務帳戶或 JWT bearer 斷言,也無法出示自訂 API 金鑰或客戶提供的 mTLS 憑證。

CIMD 會向授權伺服器提供一份固定且透過 HTTPS 託管的 ChatGPT 身分聲明,進一步強化用戶端識別。使用 private_key_jwt 時,請根據 CIMD 中繼資料中公布的公開 JWKS,驗證 ChatGPT 傳送至 Token 端點的用戶端斷言。

雙向 TLS(mTLS)

ChatGPT 現在會在與 MCP 伺服器建立 TLS 連線時,出示由 OpenAI 管理的用戶端憑證。如果你的應用程式會驗證用戶端憑證,請將其設定為信任以下 OpenAI 憑證鏈。

與 MCP 伺服器建立 TLS 連線時,請依下列步驟驗證用戶端憑證:

  • 確認葉憑證存在,且其憑證鏈可追溯至 OpenAI Connectors mTLS 中繼 CA。
  • 確認葉憑證可有效用於用戶端身分驗證。
  • 確認葉憑證的 SAN dnsNamemtls.prod.connectors.openai.com
  • 避免釘選葉憑證指紋;OpenAI 可能會輪替葉憑證,同時維持其隸屬於已公布的 CA 鏈。

使用 mTLS 驗證 ChatGPT 的 MCP 用戶端身分。請繼續使用 OAuth 2.1 驗證終端使用者身分,並授權工具存取。

選擇身分提供者

大多數 OAuth 2.1 身分提供者只要提供探索文件、支援搭配 noneprivate_key_jwt 的 CIMD、在需要時支援 DCR,並將 resource 參數原樣寫入簽發的 Token,就能符合 MCP 授權要求。請優先選擇支援以 CIMD 註冊用戶端的提供者。

我們 強烈 建議你使用現有且成熟的身分提供者,而非自行從頭實作身分驗證。

以下是一些常用身分提供者的操作說明。

Auth0

Auth0 提供中繼資料探索、CIMD 註冊、API 安全性,以及供第一方和第三方工具呼叫使用的 Token 交換功能,讓 MCP 用戶端能安全地連線至 MCP 伺服器。

託管式提供者範例

實作 Token 驗證

OAuth 流程完成後,ChatGPT 會直接將收到的存取 Token 附加到後續的 MCP 請求中(Authorization: Bearer …)。請求抵達 MCP 伺服器後,你必須將 Token 視為不可信,並自行執行完整的資源伺服器檢查,包括簽章驗證、簽發者與對象比對、到期檢查、重放風險考量,以及權限範圍管制。這是你的責任,而非 ChatGPT 的責任。

實務上,你應該:

  • 擷取授權伺服器公布的簽署金鑰(通常透過 JWKS),並驗證 Token 的簽章與 iss
  • 拒絕已到期或尚未生效的 Token(exp/nbf)。
  • 確認 Token 是為你的伺服器簽發(audresource 宣告),且包含你標記為必要的權限範圍。
  • 執行伺服器專屬的各項政策檢查,然後將解析出的身分附加至請求上下文,或回傳帶有 WWW-Authenticate 驗證挑戰的 401 回應。

如果驗證失敗,請回傳 401 Unauthorized,並附上指向受保護資源中繼資料的 WWW-Authenticate 標頭。這會告知用戶端重新執行 OAuth 流程。

SDK Token 驗證基礎功能

Python 和 TypeScript 的 MCP 軟體開發套件都提供輔助功能,讓你不必從零開始實作。

支援多個帳戶

多帳戶功能讓使用者能將多個帳戶連線至同一個外掛程式,例如個人與工作帳戶。OpenAI 會使用所選連線的身分驗證憑證來路由每次工具呼叫。即使沒有帳戶資料工具,使用者仍可連線多個帳戶。若要協助使用者區分各個連線,並在重新連線後辨識出同一份帳戶資料,請提供需要身分驗證的帳戶資料工具,傳回穩定的 ID 和實用的顯示中繼資料。

使用者如何使用多帳戶功能

使用者可以從外掛程式的設定頁面連線其他帳戶。模型可以使用所有已連線的帳戶,並在呼叫工具時,根據使用者的要求選擇相關的一個或多個帳戶。每次工具呼叫都會使用所選帳戶的憑證和權限。

改善帳戶識別

若要協助 OpenAI 辨識已連線的帳戶資料並顯示實用的標籤:

  • 提供需要身分驗證的帳戶資料工具,傳回不透明 ID,以唯一且穩定地識別要求憑證所代表的帳戶資料。這能讓 OpenAI 在重新連線後辨識出同一份帳戶資料,並將其與其他帳戶資料區分開來。名為 id 的欄位,只有在其值符合這些保證時,才能用於此用途。
  • 在 MCP 中繼資料中指定帳戶資料工具,讓 OpenAI 能探索應呼叫哪個工具,以取得經身分驗證的帳戶資料。

需要帳戶資料時,OpenAI 會在執行階段探索指定的工具,使用連線的憑證呼叫該工具,並在使用帳戶資料前驗證回應。即使沒有帳戶資料工具,使用者仍可連線帳戶,但帳戶標籤、辨識或重複偵測的可靠性可能較低。如果宣告了帳戶資料工具,請傳回有效的身分識別資訊;無效的回應可能導致帳戶無法連線。

定義穩定的帳戶身分識別

帳戶資料用來識別要求的身分驗證憑證所代表的身分。哪些帳戶資料可以獨立連線,由你的服務定義;此契約並未規定服務的組織或授權模型。

傳回在應用程式內具唯一性的不透明帳戶資料 ID。同一份帳戶資料在 Token 更新及重新連線後,必須保留相同的 ID;不同帳戶資料必須使用不同的 ID。OpenAI 會比較這些 ID,但不會解讀其內容。

如果供應商現有的不可變、不透明 ID 能識別完整帳戶資料,請使用該 ID。否則,請為帳戶資料指派一次不透明 ID,持久儲存該 ID 與帳戶資料的關聯,並在後續要求中擷取相同的 ID。所有內部關係都應保留在你的服務中;請勿將名稱、電子郵件地址或組織關係編碼至傳回的 ID。

你的 id 必須:

  • 為非空且不僅含空白字元的字串。請將數值型的供應商 ID 序列化為字串。
  • 對於同一份帳戶資料,在 Token 更新、重新連線及權限範圍升級後保持不變。
  • 對於可透過應用程式連線的不同帳戶資料,使用不同的值。
  • 在帳戶資料的電子郵件地址、名稱或顯示標籤變更時保持不變。
  • 在帳戶資料刪除後,絕不重新指派給其他帳戶資料。

請勿為每次登入、每個 Token、每個工作階段或每次工具呼叫產生新的 ID。電子郵件地址和可編輯的名稱應放在顯示中繼資料中:可能變更或被重新指派的電子郵件地址,不能作為穩定的帳戶資料 ID。對於 Google OIDC,請使用穩定的 sub,而非電子郵件宣告;Google 文件指出,電子郵件地址可能變更,但 sub 會保持不變,且絕不重複使用。請參閱 Google 身分識別文件

更新整合時,請保留現有的帳戶資料 ID。顯示名稱變更、新的 Token 或新的連線,都不得建立新的帳戶身分識別。

實作並宣告帳戶資料工具

提供需要身分驗證的唯讀工具,接受空的引數物件並傳回目前的帳戶資料。工具可以命名為 get_profilewhoami 或其他名稱;其中繼資料會將它標示為帳戶資料工具,供執行階段探索。回應必須符合下列身分識別要求,OpenAI 才能正確使用。

  • 根據要求中已通過驗證的憑證判定身分。
  • 確保此操作為唯讀,且使用一般連線的權限即可執行。
  • 僅傳回一份帳戶資料:目前要求的憑證所代表的帳戶資料。
  • 不要要求呼叫端提供使用者 ID、電子郵件地址或帳戶選擇參數。
  • 身分驗證失敗時,請傳回適當的身分驗證錯誤,而非佔位用的 ID 或其他帳戶的資料。

帳戶資料回應必須符合此 JSON Schema:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "minLength": 1,
      "pattern": "\\S",
      "description": "Opaque profile identifier, unique within this app and unchanged across token refresh, reconnection, and display-metadata changes. Never reassigned to another profile."
    },
    "name": {
      "type": "string",
      "description": "Display name for the authenticated profile."
    },
    "email": {
      "type": "string",
      "description": "Email address for display; not used as the profile identity."
    },
    "nickname": {
      "type": "string",
      "description": "A useful label that helps users distinguish connected profiles."
    }
  },
  "required": ["id"],
  "additionalProperties": false
}

回應必須包含字串 id,其值不得為空或僅含空白字元。顯示欄位為選用。工具的中繼資料會告知 OpenAI 從何處擷取帳戶資料;回應則用來識別目前憑證所代表的帳戶資料。

結構描述驗證會檢查回應是否具備處理帳戶資料所需的結構和欄位型別。你的服務還必須保證 ID 的唯一性、穩定性,以及憑證範圍的正確性;中繼資料或通過結構描述檢查,都無法證明這些行為特性。

若有 nameemail 和/或 nickname,請將其納入回應,讓使用者能區分各份帳戶資料。無法取得的選用值應予以省略;請勿捏造這些值或加入無關的個人資料。實用且便於閱讀的背景資訊應放在 nickname 中,而非 ID 中。

_meta["openai/profile"]: true 標記工具,並將帳戶資料回應的結構描述發布為該工具的 outputSchema。此標記會告知 OpenAI 哪個工具提供帳戶資料;它不會啟用功能,也不會授予使用資格。若標記不存在或為 false,表示此工具未透過此機制被指定為帳戶資料來源。字串、數字和 null 都是無效的標記值。

{
  "name": "get_profile",
  "description": "Return the profile represented by this request's authenticated credentials. The opaque id is unique within this app and remains unchanged across token refresh, reconnection, and display-metadata changes.",
  "inputSchema": {
    "type": "object",
    "properties": {},
    "additionalProperties": false
  },
  "outputSchema": {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "type": "object",
    "properties": {
      "id": {
        "type": "string",
        "minLength": 1,
        "pattern": "\\S",
        "description": "Opaque profile identifier, unique within this app and unchanged across token refresh, reconnection, and display-metadata changes. Never reassigned to another profile."
      },
      "name": {
        "type": "string",
        "description": "Display name for the authenticated profile."
      },
      "email": {
        "type": "string",
        "description": "Email address for display; not used as the profile identity."
      },
      "nickname": {
        "type": "string",
        "description": "A useful label that helps users distinguish connected profiles."
      }
    },
    "required": ["id"],
    "additionalProperties": false
  },
  "annotations": {
    "readOnlyHint": true,
    "destructiveHint": false,
    "openWorldHint": false
  },
  "securitySchemes": [
    {
      "type": "oauth2",
      "scopes": []
    }
  ],
  "_meta": {
    "openai/profile": true
  }
}

如果存取帳戶資料需要 OAuth 權限範圍,請使用整合實際採用的範圍。這項宣告不會實作身分驗證;伺服器必須驗證憑證並強制執行權限控管。請參閱實作 Token 驗證工具參考資料

structuredContent 中傳回帳戶資料,以便依據 outputSchema 進行驗證。為確保相容性,也請將同一份帳戶資料序列化為 JSON,放入文字內容項目中:

{
  "content": [
    {
      "type": "text",
      "text": "{\"id\":\"prf_8d7e4b19\",\"name\":\"Alex Chen\",\"email\":\"alex@example.com\",\"nickname\":\"Alex — Moonwaffle work\"}"
    }
  ],
  "structuredContent": {
    "id": "prf_8d7e4b19",
    "name": "Alex Chen",
    "email": "alex@example.com",
    "nickname": "Alex — Moonwaffle work"
  },
  "isError": false
}

使用單一 JSON 物件,並將帳戶資料欄位放在最上層。

已經有帳戶資料工具了嗎? 請保留其名稱,加入帳戶資料中繼資料宣告,並傳回標準帳戶資料回應。如果現有回應的結構不同,請在伺服器上調整,或提供符合結構描述的簡單包裝工具。標準整合方式會對每個應用程式使用相同的宣告和回應結構。

具體範例:持久儲存的 Moonwaffle 帳戶資料

假設虛構服務 Moonwaffle 讓 Alex 能獨立連線兩份帳戶資料。Moonwaffle 為每份帳戶資料儲存不同的不透明 ID。系統會根據要求憑證找到其中一份已儲存的帳戶資料,帳戶資料工具則會傳回該帳戶資料現有的 ID。

已儲存帳戶資料的範例。 標籤可以變更,識別碼則保持不變:

Alex — Moonwaffle personal: prf_42a9c6e0
Alex — Moonwaffle work:     prf_8d7e4b19

這些範例 ID 不會將帳戶資料標籤或內部關係編碼其中。每份帳戶資料的 ID 只需持久儲存一次,並在重新連線、Token 更新,以及電子郵件地址或顯示名稱變更後繼續使用。

根據經身分驗證的帳戶資料建立回應。 此 JavaScript 範例展示可連接至 MCP SDK 的處理常式邏輯。loadAuthenticatedProfile 是應用程式的整合程式碼:它會驗證要求憑證、強制執行其權限控管,並擷取對應帳戶資料已持久儲存的 ID 和顯示中繼資料。requestContext 來自伺服器的要求處理流程,並非模型提供的工具引數。

async function getProfile(requestContext) {
  // Your auth/provider integration validates credentials and loads
  // the existing profile. Auth failures use normal MCP auth handling.
  const account = await loadAuthenticatedProfile(requestContext);
  const id = account.profileId;

  if (typeof id !== "string" || id.trim().length === 0) {
    return {
      isError: true,
      content: [{ type: "text", text: "Profile identity unavailable." }],
    };
  }

  // Return the persisted ID unchanged; do not generate an ID per call.
  const profile = {
    id,
    ...(typeof account.name === "string" ? { name: account.name } : {}),
    ...(typeof account.email === "string" ? { email: account.email } : {}),
    ...(typeof account.nickname === "string"
      ? { nickname: account.nickname }
      : {}),
  };

  return {
    isError: false,
    structuredContent: profile,
    content: [{ type: "text", text: JSON.stringify(profile) }],
  };
}

使用上述中繼資料宣告與輸入/輸出結構描述註冊此處理常式。對於等效的憑證,以及重新連線後的情況,loadAuthenticatedProfile 必須找到同一份已儲存的帳戶資料。它不得為每次 OAuth 授權或每個工作階段建立新的帳戶資料 ID。所有其他工具都必須使用要求的憑證,強制執行同一帳戶資料的權限控管。

驗證身分識別行為:

測試預期結果
針對 Moonwaffle 工作帳戶資料重複呼叫每次皆為 prf_8d7e4b19
Token 更新、重新連線或權限範圍升級後的同一份帳戶資料prf_8d7e4b19
電子郵件地址或顯示標籤變更後的同一份帳戶資料prf_8d7e4b19;標籤可以變更
Moonwaffle 個人帳戶資料prf_42a9c6e0,與工作帳戶資料不同
已持久儲存的帳戶資料 ID 遺失或空白傳回錯誤結果;不捏造身分識別,也不退回使用其他帳戶資料

身分識別保證必須適用於所有帳戶資料,且在未來整合變更後仍然成立。請確保此保證不受顯示中繼資料、Token 內容及連線生命週期事件的影響。

測試與推出

  • 本機測試: 先使用會核發短效 Token 的開發租用戶,以便快速反覆測試與調整。
  • 內部試用: 身分驗證正常運作後,先只開放給可信任的測試人員,再廣泛推出。你可以要求使用者先連結帳戶,才能使用特定工具或整個 MCP 伺服器。
  • 輪替: 預先規劃 Token 撤銷、更新及權限範圍變更的處理方式。Token 缺失或失效時,伺服器應將請求視為未通過身分驗證,並傳回有助於排解問題的錯誤訊息。
  • OAuth 偵錯: 使用 MCP Inspector 的身分驗證設定逐步檢查 OAuth 流程,在發布前找出流程出錯的位置。

設定好身分驗證後,你就能向 ChatGPT 和 Codex 使用者提供個人專屬資料與寫入操作。

觸發身分驗證 UI

只有在 MCP 伺服器表明 OAuth 可用或有必要使用時,ChatGPT 才會顯示 OAuth 帳戶連結 UI。

若要觸發工具層級的 OAuth 流程,必須同時提供中繼資料(securitySchemes 和資源中繼資料文件) 以及 帶有 _meta["mcp/www_authenticate"] 的執行階段錯誤。兩者缺一不可,否則 ChatGPT 不會顯示該工具的帳戶連結 UI。

  1. 發布資源中繼資料。 MCP 伺服器必須透過 https://your-mcp.example.com/.well-known/oauth-protected-resource 這類已知 URL 提供 OAuth 組態。

  2. 使用 securitySchemes 描述各工具的身分驗證政策。 為每個工具宣告 securitySchemes,可讓 ChatGPT 知道哪些工具需要 OAuth,哪些可以匿名執行。即使整個伺服器採用相同政策,也應逐一為工具宣告;使用伺服器層級的預設值,會讓日後個別調整工具變得困難。

    目前有兩種方案類型可用,你可以列出多種類型,表示身分驗證為選用:

    • noauth:可匿名呼叫此工具;ChatGPT 能立即執行。
    • oauth2:此工具需要 OAuth 2.0 存取 Token;請列出將要求的權限範圍,確保同意畫面顯示正確的資訊。

    如果完全省略此陣列,工具就會繼承伺服器公布的預設設定。同時宣告 noauthoauth2,可讓 ChatGPT 知道它能先匿名呼叫工具,而連結帳戶後即可使用需要額外權限的功能。無論向用戶端傳達了什麼資訊,伺服器仍必須在每次呼叫時驗證 Token、權限範圍及目標對象。

    範例(公開存取 + 選用身分驗證):TypeScript SDK

    import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
    import { z } from "zod";
    
    declare const server: McpServer;
    
    server.registerTool(
      "search",
      {
        title: "Public Search",
        description: "Search public documents.",
        inputSchema: {
          q: z.string(),
        },
        outputSchema: {},
        securitySchemes: [
          { type: "noauth" },
          { type: "oauth2", scopes: ["search.read"] },
        ],
      },
      async ({ q }) => {
        return {
          content: [{ type: "text", text: `Results for ${q}` }],
          structuredContent: {},
        };
      }
    );

    範例(必須通過身分驗證):TypeScript SDK

    import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
    import { z } from "zod";
    
    declare const server: McpServer;
    
    server.registerTool(
      "create_doc",
      {
        title: "Create Document",
        description: "Make a new doc in your account.",
        inputSchema: {
          title: z.string(),
        },
        outputSchema: {},
        securitySchemes: [{ type: "oauth2", scopes: ["docs.write"] }],
      },
      async ({ title }) => {
        return {
          content: [{ type: "text", text: `Created doc: ${title}` }],
          structuredContent: {},
        };
      }
    );
  3. 若要讓 ChatGPT 觸發身分驗證 UI,請在工具處理函式中檢查 Token 並傳回 _meta["mcp/www_authenticate"] 。檢查 Token,並驗證核發者、目標對象、到期時間及權限範圍。若沒有有效的 Token,請傳回包含 _meta["mcp/www_authenticate"] 的錯誤結果,並確保其值同時包含 errorerror_description 參數。完成步驟 1 和 2 後,真正觸發工具層級 OAuth UI 的就是這個 WWW-Authenticate 酬載。當驗證要求觸發重新授權時,你的供應商可以在該流程中保留使用者現有的登入上下文

    範例

    {
      "jsonrpc": "2.0",
      "id": 4,
      "result": {
        "content": [
          {
            "type": "text",
            "text": "Authentication required: no access token provided."
          }
        ],
        "_meta": {
          "mcp/www_authenticate": [
            "'Bearer resource_metadata=\"https://your-mcp.example.com/.well-known/oauth-protected-resource\", error=\"insufficient_scope\", error_description=\"You need to login to continue\"'"
          ]
        },
        "isError": true
      }
    }