跳轉到主要內容

教學:我是誰? (Tutorial: Who am I?)

本教學將引導你設定 MCP Auth,以驗證 (Authentication) 使用者並從授權 (Authorization) 伺服器取得其身分資訊。

完成本教學後,你將會:

  • ✅ 基本瞭解如何使用 MCP Auth 進行使用者驗證 (Authentication)。
  • ✅ 擁有一個 MCP 伺服器,並能提供工具來取得使用者身分資訊。

概覽 (Overview)

本教學將涉及以下元件:

  • MCP 伺服器:一個簡單的 MCP 伺服器,使用 MCP 官方 SDK 處理請求。
  • MCP inspector:MCP 伺服器的視覺化測試工具,同時作為 OAuth / OIDC 用戶端,啟動授權流程並取得存取權杖 (Access token)。
  • 授權伺服器 (Authorization server):一個 OAuth 2.1 或 OpenID Connect 提供者,負責管理使用者身分並簽發存取權杖 (Access token)。

以下是這些元件間互動的高階圖示:

瞭解你的授權伺服器 (Understand your authorization server)

取得使用者身分資訊 (Retrieving user identity information)

為完成本教學,你的授權伺服器應提供 API 以取得使用者身分資訊:

Logto 是一個 OpenID Connect 提供者,支援標準的 userinfo endpoint 來取得使用者身分資訊。

要取得可用於 userinfo endpoint 的存取權杖 (Access token),至少需兩個權限範圍 (Scopes):openidprofile。你可以繼續閱讀,稍後會介紹權限範圍設定。

動態用戶端註冊 (Dynamic Client Registration)

本教學不強制需要動態用戶端註冊,但如果你想自動化 MCP 用戶端在授權伺服器的註冊流程,這會很有幫助。詳情請參閱 是否需要動態用戶端註冊?

設定 MCP 伺服器 (Set up the MCP server)

我們將使用 MCP 官方 SDK 建立一個 MCP 伺服器,並實作一個 whoami 工具,從授權伺服器取得使用者身分資訊。

建立新專案 (Create a new project)

mkdir mcp-server
cd mcp-server
uv init # 或使用 `pipenv` 或 `poetry` 建立新虛擬環境

安裝 MCP SDK 與相依套件 (Install the MCP SDK and dependencies)

pip install "mcp[cli]" starlette uvicorn

或使用你偏好的套件管理工具,如 uvpoetry

建立 MCP 伺服器 (Create the MCP server)

首先,讓我們建立一個實作 whoami 工具的 MCP 伺服器。

建立名為 whoami.py 的檔案,並加入以下程式碼:

from mcp.server.fastmcp import FastMCP
from starlette.applications import Starlette
from starlette.routing import Mount
from typing import Any

mcp = FastMCP("WhoAmI")

@mcp.tool()
def whoami() -> dict[str, Any]:
    """回傳目前使用者資訊的工具。"""
    return {"error": "Not authenticated"}

app = Starlette(
    routes=[Mount('/', app=mcp.sse_app())]
)

以以下指令啟動伺服器:

uvicorn whoami:app --host 0.0.0.0 --port 3001

檢查 MCP 伺服器 (Inspect the MCP server)

下載並執行 MCP inspector (Clone and run MCP inspector)

現在 MCP 伺服器已啟動,我們可以使用 MCP inspector 檢查 whoami 工具是否可用。

由於目前實作上的限制,我們 fork 了 MCP inspector,讓其在驗證 (Authentication) 與授權 (Authorization) 上更靈活且可擴展。我們也已向原始倉庫提交 pull request。

執行 MCP inspector,請使用以下指令(需安裝 Node.js):

git clone https://github.com/mcp-auth/inspector.git
cd inspector
npm install
npm run dev

然後在瀏覽器開啟 http://localhost:6274/(或終端機顯示的其他網址)以進入 MCP inspector。

連接 MCP inspector 與 MCP 伺服器 (Connect MCP inspector to the MCP server)

在繼續之前,請檢查 MCP inspector 的以下設定:

  • Transport Type:設為 SSE
  • URL:設為你的 MCP 伺服器網址,本例應為 http://localhost:3001/sse

現在你可以點擊「Connect」按鈕,檢查 MCP inspector 是否能連接 MCP 伺服器。如果一切正常,應會看到 MCP inspector 顯示「Connected」狀態。

檢查點:執行 whoami 工具 (Checkpoint: Run the whoami tool)

  1. 在 MCP inspector 上方選單點選「Tools」分頁。
  2. 點擊「List Tools」按鈕。
  3. 你應該會在頁面上看到 whoami 工具,點擊它以開啟工具詳情。
  4. 右側會出現「Run Tool」按鈕,點擊執行工具。
  5. 你應該會看到工具回傳結果為 JSON:{"error": "Not authenticated"}

MCP inspector 首次執行畫面

與授權伺服器整合 (Integrate with your authorization server)

完成本節需考慮以下幾點:

你的授權伺服器簽發者 (Issuer) URL

通常是你的授權伺服器基礎網址,例如 https://auth.example.com。有些提供者可能會有路徑,如 https://example.logto.app/oidc,請參閱你的提供者文件。

如何取得授權伺服器中繼資料 (Metadata)
如何將 MCP inspector 註冊為授權伺服器用戶端
如何取得使用者身分資訊,以及如何設定授權請求參數
  • 對於 OpenID Connect 提供者:通常需在授權流程請求至少 openidprofile 權限範圍 (Scopes)。這可確保授權伺服器回傳的存取權杖 (Access token) 具備存取 userinfo endpoint 所需權限。

    注意:部分提供者可能不支援 userinfo endpoint。

  • 對於 OAuth 2.0 / OAuth 2.1 提供者:請查閱你的提供者文件,瞭解如何用存取權杖 (Access token) 取得使用者身分資訊,以及啟動授權流程時需帶哪些參數。

雖然每個提供者可能有不同需求,以下步驟將引導你整合 MCP inspector 與 MCP 伺服器,並進行提供者專屬設定。

註冊 MCP inspector 為用戶端 (Register MCP inspector as a client)

Logto 整合非常簡單,因為它是支援標準 userinfo endpoint 的 OpenID Connect 提供者。

由於 Logto 尚未支援動態用戶端註冊,你需手動將 MCP inspector 註冊為 Logto 租戶的用戶端:

  1. 開啟 MCP inspector,點擊「OAuth Configuration」按鈕。複製 Redirect URL (auto-populated),例如 http://localhost:6274/oauth/callback
  2. 登入 Logto Console(或你的自架 Logto Console)。
  3. 進入「應用程式」分頁,點擊「建立應用程式」。頁面底部點「不使用框架建立應用程式」。
  4. 填寫應用程式資訊,然後點擊「建立應用程式」:
    • 選擇應用程式類型:選「單頁應用程式」。
    • 應用程式名稱:如「MCP Inspector」。
  5. 在「設定 / Redirect URIs」區塊,貼上剛才複製的 Redirect URL (auto-populated),然後點擊底部「儲存變更」。
  6. 頁面上方會看到「App ID」,請複製。
  7. 回到 MCP inspector,將「App ID」貼到「OAuth Configuration」的「Client ID」欄位。
  8. 在「Auth Params」欄位輸入 {"scope": "openid profile email"},確保 Logto 回傳的存取權杖 (Access token) 具備存取 userinfo endpoint 所需權限。

設定 MCP Auth (Set up MCP auth)

在你的 MCP 伺服器專案中,需安裝 MCP Auth SDK 並設定使用你的授權伺服器中繼資料。

首先安裝 mcpauth 套件:

pip install mcpauth

或使用你偏好的套件管理工具,如 uvpoetry

MCP Auth 需要授權伺服器中繼資料才能初始化。根據你的提供者:

簽發者 (Issuer) URL 可在 Logto Console 的應用程式詳情頁「Endpoints & Credentials / Issuer endpoint」區塊找到,格式類似 https://my-project.logto.app/oidc

whoami.py 更新,加入 MCP Auth 設定:

from mcpauth import MCPAuth
from mcpauth.config import AuthServerType
from mcpauth.utils import fetch_server_config

auth_issuer = '<issuer-endpoint>'  # 請替換為你的簽發者 (Issuer) 端點
auth_server_config = fetch_server_config(auth_issuer, type=AuthServerType.OIDC)
mcp_auth = MCPAuth(server=auth_server_config)

接下來,我們需要建立一個自訂的存取權杖 (Access token) 驗證器,該驗證器會使用 MCP inspector 提供的存取權杖,從授權伺服器 (Authorization server) 取得使用者身分資訊。

import pydantic
import requests
from mcpauth.exceptions import (
    MCPAuthTokenVerificationException,
    MCPAuthTokenVerificationExceptionCode,
)
from mcpauth.types import AuthInfo

def verify_access_token(token: str) -> AuthInfo:
    """
    透過從授權伺服器 (Authorization server) 取得使用者資訊,驗證所提供的 Bearer 權杖 (Token)。
    若權杖有效,將回傳包含使用者資訊的 `AuthInfo` 物件。

    :param token: 從 MCP inspector 接收到的 Bearer 權杖 (Token)。
    """

    issuer = auth_server_config.metadata.issuer
    endpoint = auth_server_config.metadata.userinfo_endpoint # 提供者應支援 userinfo endpoint
    if not endpoint:
        raise ValueError(
            "auth server metadata 中未設定 userinfo endpoint。"
        )

    try:
        response = requests.get(
            endpoint,
            headers={"Authorization": f"Bearer {token}"}, # 標準 Bearer 權杖標頭
        )
        response.raise_for_status() # 確保 HTTP 錯誤時會拋出例外
        json = response.json() # 解析 JSON 回應
        return AuthInfo(
            token=token,
            subject=json.get("sub"), # 'sub' 是主體 (Subject, 使用者 ID) 的標準宣告 (Claim)
            issuer=issuer, # 使用 metadata 中的簽發者 (Issuer)
            claims=json, # 包含 userinfo endpoint 回傳的所有宣告 (Claims)
        )
    # `AuthInfo` 是 Pydantic 模型,驗證錯誤通常代表回應結構不符預期
    except pydantic.ValidationError as e:
        raise MCPAuthTokenVerificationException(
            MCPAuthTokenVerificationExceptionCode.INVALID_TOKEN,
            cause=e,
        )
    # 處理請求過程中可能發生的其他例外
    except Exception as e:
        raise MCPAuthTokenVerificationException(
            MCPAuthTokenVerificationExceptionCode.TOKEN_VERIFICATION_FAILED,
            cause=e,
        )

更新 MCP 伺服器 (Update MCP server)

快完成了!現在要更新 MCP 伺服器,套用 MCP Auth 路由與中介軟體,並讓 whoami 工具回傳實際的使用者身分資訊。

@mcp.tool()
def whoami() -> dict[str, Any]:
    """回傳目前使用者資訊的工具。"""
    return (
        mcp_auth.auth_info.claims
        if mcp_auth.auth_info # 由 Bearer auth middleware 填入
        else {"error": "Not authenticated"}
    )

# ...

bearer_auth = Middleware(mcp_auth.bearer_auth_middleware(verify_access_token))
app = Starlette(
    routes=[
        # 加入 metadata 路由 (`/.well-known/oauth-authorization-server`)
        mcp_auth.metadata_route(),
        # 以 Bearer auth middleware 保護 MCP 伺服器
        Mount('/', app=mcp.sse_app(), middleware=[bearer_auth]),
    ],
)

檢查點:以驗證 (Authentication) 執行 whoami 工具 (Checkpoint: Run the whoami tool with authentication)

重新啟動 MCP 伺服器,並在瀏覽器開啟 MCP inspector。當你點擊「Connect」按鈕時,應會被導向授權伺服器的登入頁面。

登入後回到 MCP inspector,重複前述步驟執行 whoami 工具。這次你應該會看到授權伺服器回傳的使用者身分資訊。

MCP inspector whoami 工具結果

資訊

完整 MCP 伺服器(OIDC 版本)程式碼請參考 MCP Auth Python SDK repository

結語 (Closing notes)

🎊 恭喜你!已成功完成本教學。讓我們回顧一下:

  • 建立具備 whoami 工具的基本 MCP 伺服器
  • 透過 MCP Auth 將 MCP 伺服器與授權伺服器整合
  • 設定 MCP Inspector 以驗證 (Authentication) 使用者並取得其身分資訊

你也可以進一步探索進階主題,包括:

歡迎參閱其他教學與文件,充分發揮 MCP Auth 的效能。