チュートリアル: 私は誰?
このチュートリアルでは、MCP Auth をセットアップしてユーザーを認証 (Authentication) し、認可 (Authorization) サーバーからアイデンティティ情報を取得する手順を案内します。
このチュートリアルを完了すると、次のことができるようになります:
- ✅ MCP Auth を使ってユーザーを認証 (Authentication) する基本的な理解
- ✅ ユーザーのアイデンティティ情報を取得するツールを提供する MCP サーバー
概要
このチュートリアルでは、以下のコンポーネントを使用します:
- MCP サーバー:MCP 公式 SDK を使ってリクエストを処理するシンプルな MCP サーバー
- MCP inspector:MCP サーバーのためのビジュアルテストツール。OAuth / OIDC クライアントとして認可フローを開始し、アクセス トークン (Access token) を取得する役割も担います。
- 認可 (Authorization) サーバー:ユーザーのアイデンティティを管理し、アクセス トークン (Access token) を発行する OAuth 2.1 または OpenID Connect プロバイダー
これらのコンポーネント間のやり取りを高レベルで示した図です:
認可 (Authorization) サーバーを理解する
ユーザーのアイデンティティ情報の取得
このチュートリアルを完了するには、認可 (Authorization) サーバーがユーザーのアイデンティティ情報を取得するための API を提供している必要があります:
- Logto
- Keycloak
- OIDC
- OAuth 2
Logto は OpenID Connect プロバイダーであり、標準の userinfo エンドポイント をサポートしてユーザーのアイデンティティ情報を取得できます。
userinfo エンドポイントにアクセスできるアクセス トークン (Access token) を取得するには、少なくとも openid
と profile
の 2 つのスコープ (Scope) が必要です。スコープ (Scope) の設定については後述しますので、そのまま読み進めてください。
Keycloak は、OpenID Connect (OIDC) を含む複数のプロトコルをサポートするオープンソースのアイデンティティおよびアクセス管理ソリューションです。OIDC プロバイダーとして、標準の userinfo エンドポイント を実装してユーザーのアイデンティティ情報を取得できます。
userinfo エンドポイントにアクセスできるアクセス トークン (Access token) を取得するには、少なくとも openid
と profile
の 2 つのスコープ (Scope) が必要です。スコープ (Scope) の設定については後述しますので、そのまま読み進めてください。
ほとんどの OpenID Connect プロバイダーは、userinfo エンドポイント をサポートしてユーザーのアイデンティティ情報を取得できます。
プロバイダーのドキュメントで、このエンドポイントがサポートされているか確認してください。プロバイダーが OpenID Connect Discovery をサポートしている場合、.well-known/openid-configuration
エンドポイントのレスポンスに userinfo_endpoint
が含まれているかも確認できます。
userinfo エンドポイントにアクセスできるアクセス トークン (Access token) を取得するには、少なくとも openid
と profile
の 2 つのスコープ (Scope) が必要です。スコープ (Scope) とユーザーアイデンティティクレーム (Claim) の対応は、プロバイダーのドキュメントを参照してください。
OAuth 2.0 ではユーザーのアイデンティティ情報を取得する標準的な方法は定義されていませんが、多くのプロバイダーは独自のエンドポイントを実装しています。プロバイダーのドキュメントで、アクセス トークン (Access token) を使ってユーザーのアイデンティティ情報をどのように取得するか、また認可フローでどのパラメーターが必要かを確認してください。
Dynamic Client Registration
Dynamic Client Registration はこのチュートリアルでは必須ではありませんが、MCP クライアントの登録プロセスを認可 (Authorization) サーバーと自動化したい場合に便利です。詳細は Dynamic Client Registration は必要ですか? をご覧ください。
MCP サーバーのセットアップ
MCP 公式 SDK を使って、認可 (Authorization) サーバーからユーザーのアイデンティティ情報を取得する whoami
ツール付きの MCP サーバーを作成します。
新しいプロジェクトの作成
- Python
- Node.js
mkdir mcp-server
cd mcp-server
uv init # または `pipenv` や `poetry` で仮想環境を作成
新しい Node.js プロジェクトをセットアップします:
mkdir mcp-server
cd mcp-server
npm init -y # または `pnpm init`
npm pkg set type="module"
npm pkg set main="whoami.js"
npm pkg set scripts.start="node whoami.js"
MCP SDK と依存パッケージのインストール
- Python
- Node.js
pip install "mcp[cli]" starlette uvicorn
または uv
や poetry
など、お好みのパッケージマネージャーを使用してください。
npm install @modelcontextprotocol/sdk express
または pnpm
や yarn
など、お好みのパッケージマネージャーを使用してください。
MCP サーバーの作成
まず、whoami
ツールを実装した MCP サーバーを作成します。
- Python
- Node.js
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 inspector 実装では認可 (Authorization) フローを扱えないため、SSE アプローチで MCP サーバーをセットアップします。MCP inspector が認可 (Authorization) フローに対応した際には、ここにコードを更新します。
pnpm
や yarn
も利用可能です。
whoami.js
というファイルを作成し、次のコードを追加します:
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
import express from 'express';
// MCP サーバーを作成
const server = new McpServer({
name: 'WhoAmI',
version: '0.0.0',
});
// 現在のユーザー情報を返すツールを追加
server.tool('whoami', async () => {
return {
content: [{ type: 'text', text: JSON.stringify({ error: 'Not authenticated' }) }],
};
});
// 以下は MCP SDK ドキュメントのボイラープレートコード
const PORT = 3001;
const app = express();
const transports = {};
app.get('/sse', async (_req, res) => {
const transport = new SSEServerTransport('/messages', res);
transports[transport.sessionId] = transport;
res.on('close', () => {
delete transports[transport.sessionId];
});
await server.connect(transport);
});
app.post('/messages', async (req, res) => {
const sessionId = String(req.query.sessionId);
const transport = transports[sessionId];
if (transport) {
await transport.handlePostMessage(req, res, req.body);
} else {
res.status(400).send('No transport found for sessionId');
}
});
app.listen(PORT);
サーバーを起動します:
npm start
MCP サーバーの検証
MCP inspector のクローンと起動
MCP サーバーが起動したので、MCP inspector を使って whoami
ツールが利用できるか確認します。
現状の実装制限のため、MCP inspector をフォークし、認証 (Authentication)・認可 (Authorization) により柔軟かつ拡張可能にしました。オリジナルリポジトリにもプルリクエストを提出済みです。
MCP inspector を起動するには、以下のコマンドを使用します(Node.js が必要です):
git clone https://github.com/mcp-auth/inspector.git
cd inspector
npm install
npm run dev
その後、ブラウザで http://localhost:6274/
(またはターミナルに表示された他の URL)にアクセスして MCP inspector を開きます。
MCP inspector を MCP サーバーに接続
進む前に、MCP inspector で次の設定を確認してください:
- Transport Type:
SSE
に設定 - URL:MCP サーバーの URL を設定(例:
http://localhost:3001/sse
)
「Connect」ボタンをクリックして、MCP inspector が MCP サーバーに接続できるか確認します。問題なければ MCP inspector に「Connected」ステータスが表示されます。
チェックポイント: whoami
ツールの実行
- MCP inspector の上部メニューで「Tools」タブをクリック
- 「List Tools」ボタンをクリック
- ページに
whoami
ツールが表示されているはずです。クリックして詳細を開きます。 - 右側に「Run Tool」ボタンが表示されるのでクリック
- ツールの結果として
{"error": "Not authenticated"}
という JSON レスポンスが表示されます。
認可 (Authorization) サーバーとの連携
このセクションを完了するには、いくつかの考慮事項があります:
認可 (Authorization) サーバーの発行者 (Issuer) URL
通常は認可 (Authorization) サーバーのベース URL です(例:https://auth.example.com
)。プロバイダーによっては https://example.logto.app/oidc
のようなパスが付く場合もあるので、ドキュメントを確認してください。
認可 (Authorization) サーバーのメタデータ取得方法
- 認可 (Authorization) サーバーが OAuth 2.0 Authorization Server Metadata または OpenID Connect Discovery に準拠していれば、MCP Auth の組み込みユーティリティで自動取得できます。
- 準拠していない場合は、MCP サーバーの設定でメタデータ URL やエンドポイントを手動指定する必要があります。詳細はプロバイダーのドキュメントを参照してください。
MCP inspector を認可 (Authorization) サーバーのクライアントとして登録する方法
- 認可 (Authorization) サーバーが Dynamic Client Registration をサポートしていれば、このステップはスキップできます。MCP inspector が自動でクライアント登録します。
- サポートしていない場合は、MCP inspector を手動でクライアント登録する必要があります。
ユーザーのアイデンティティ情報の取得方法と認可リクエストパラメーターの設定方法
-
OpenID Connect プロバイダーの場合:認可フロー開始時に
openid
とprofile
のスコープ (Scope) をリクエストする必要があります。これにより、認可 (Authorization) サーバーから返されるアクセス トークン (Access token) で userinfo エンドポイント にアクセスできます。※ 一部プロバイダーは userinfo エンドポイントをサポートしていない場合があります。
-
OAuth 2.0 / OAuth 2.1 プロバイダーの場合:アクセス トークン (Access token) でユーザーのアイデンティティ情報を取得する方法や必要なパラメーターはプロバイダーのドキュメントを参照してください。
プロバイダーごとに要件は異なりますが、以下の手順で MCP inspector と MCP サーバーをプロバイダー固有の設定で連携できます。
MCP inspector をクライアントとして登録
- Logto
- Keycloak
- OIDC
- OAuth 2
Logto との連携はシンプルです。OpenID Connect プロバイダーであり、標準の userinfo エンドポイント をサポートしています。
Logto は Dynamic Client Registration をまだサポートしていないため、MCP inspector を Logto テナントのクライアントとして手動登録する必要があります:
- MCP inspector を開き、「OAuth Configuration」ボタンをクリック。Redirect URL (auto-populated) の値(例:
http://localhost:6274/oauth/callback
)をコピー - Logto Console(またはセルフホスト Logto Console)にサインイン
- 「Applications」タブで「Create application」をクリック。ページ下部で「Create app without framework」をクリック
- アプリケーション詳細を入力し、「Create application」をクリック:
- Select an application type:「Single-page application」を選択
- Application name:例「MCP Inspector」など任意の名前
- 「Settings / Redirect URIs」セクションで、先ほどコピーした Redirect URL (auto-populated) を貼り付け、「Save changes」をクリック
- 上部カードに「App ID」が表示されるのでコピー
- MCP inspector に戻り、「OAuth Configuration」の「Client ID」欄に「App ID」を貼り付け
- 「Auth Params」欄に
{"scope": "openid profile email"}
を入力。これで Logto から返されるアクセス トークン (Access token) に必要なスコープ (Scope) が含まれます。
Keycloak は OpenID Connect プロトコルをサポートするオープンソースのアイデンティティ・アクセス管理ソリューションです。
Keycloak は Dynamic Client Registration をサポートしていますが、クライアント登録エンドポイントが CORS に対応していないため、ほとんどの MCP クライアントは直接登録できません。そのため、手動でクライアント登録が必要です。
Keycloak は さまざまな方法(ベアメタル、kubernetes など)でインストールできますが、このチュートリアルでは Docker を使って簡単にセットアップします。
Keycloak インスタンスをセットアップし、必要な設定を行います:
- まず、公式ドキュメント に従い Docker で Keycloak を起動:
docker run -p 8080:8080 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:26.2.4 start-dev
-
Keycloak Admin Console(http://localhost:8080/admin)にアクセスし、以下でログイン:
- ユーザー名:
admin
- パスワード:
admin
- ユーザー名:
-
新しい Realm を作成:
- 左上の「Create Realm」をクリック
- 「Realm name」に
mcp-realm
を入力 - 「Create」をクリック
-
テストユーザーを作成:
- 左メニューの「Users」をクリック
- 「Create new user」をクリック
- ユーザー詳細を入力(ユーザー名:
testuser
、名・姓は任意) - 「Create」をクリック
- 「Credentials」タブでパスワードを設定し、「Temporary」をオフ
-
MCP Inspector をクライアントとして登録:
- MCP inspector を開き、「OAuth Configuration」ボタンをクリック。Redirect URL (auto-populated)(例:
http://localhost:6274/oauth/callback
)をコピー - Keycloak Admin Console で左メニューの「Clients」をクリック
- 「Create client」をクリック
- クライアント詳細を入力:
- Client type: 「OpenID Connect」を選択
- Client ID:
mcp-inspector
を入力 - 「Next」をクリック
- 「Capability config」ページで「Standard flow」が有効になっていることを確認し、「Next」
- 「Login settings」ページで、先ほどコピーした MCP Inspector のコールバック URL を「Valid redirect URIs」に貼り付け
- 「Web origins」に
http://localhost:6274
を入力 - 「Save」をクリック
- 「Client ID」(
mcp-inspector
)をコピー
- MCP inspector を開き、「OAuth Configuration」ボタンをクリック。Redirect URL (auto-populated)(例:
-
MCP Inspector に戻り:
- コピーした Client ID を「OAuth Configuration」の「Client ID」欄に貼り付け
- 「Auth Params」欄に以下を入力して必要なスコープ (Scope) をリクエスト:
{ "scope": "openid profile email" }
これは汎用的な OpenID Connect プロバイダー連携ガイドです。詳細はプロバイダーのドキュメントを参照してください。
OpenID Connect プロバイダーが Dynamic Client Registration をサポートしていれば、下記 8 の設定に進んで MCP inspector を設定できます。サポートしていない場合は、手動で MCP inspector をクライアント登録する必要があります:
- MCP inspector を開き、「OAuth Configuration」ボタンをクリック。Redirect URL (auto-populated)(例:
http://localhost:6274/oauth/callback
)をコピー - OpenID Connect プロバイダーのコンソールにサインイン
- 「Applications」または「Clients」セクションで新しいアプリケーションまたはクライアントを作成
- クライアントタイプが必要な場合は「Single-page application」または「Public client」を選択
- アプリケーション作成後、リダイレクト URI を設定。コピーした Redirect URL (auto-populated) を貼り付け
- 新規アプリケーションの「Client ID」または「Application ID」をコピー
- MCP inspector に戻り、「OAuth Configuration」の「Client ID」欄に貼り付け
- 標準的な OpenID Connect プロバイダーの場合、userinfo エンドポイントにアクセスするために必要なスコープ (Scope) をリクエストするには「Auth Params」欄に以下を入力:
{ "scope": "openid profile email" }
これは汎用的な OAuth 2.0 / OAuth 2.1 プロバイダー連携ガイドです。詳細はプロバイダーのドキュメントを参照してください。
OAuth 2.0 / OAuth 2.1 プロバイダーが Dynamic Client Registration をサポートしていれば、下記 8 の設定に進んで MCP inspector を設定できます。サポートしていない場合は、手動で MCP inspector をクライアント登録する必要があります:
- MCP inspector を開き、「OAuth Configuration」ボタンをクリック。Redirect URL (auto-populated)(例:
http://localhost:6274/oauth/callback
)をコピー - OAuth 2.0 / OAuth 2.1 プロバイダーのコンソールにサインイン
- 「Applications」または「Clients」セクションで新しいアプリケーションまたはクライアントを作成
- クライアントタイプが必要な場合は「Single-page application」または「Public client」を選択
- アプリケーション作成後、リダイレクト URI を設定。コピーした Redirect URL (auto-populated) を貼り付け
- 新規アプリケーションの「Client ID」または「Application ID」をコピー
- MCP inspector に戻り、「OAuth Configuration」の「Client ID」欄に貼り付け
- アクセス トークン (Access token) でユーザーのアイデンティティ情報を取得する方法や必要なスコープ (Scope)・パラメーターはプロバイダーのドキュメントを参照してください。例えば、
profile
スコープ (Scope) が必要な場合は「Auth Params」欄に以下を入力:
{ "scope": "profile" }
MCP auth のセットアップ
MCP サーバープロジェクトで MCP Auth SDK をインストールし、認可 (Authorization) サーバーのメタデータを使うように設定します。
- Python
- Node.js
まず mcpauth
パッケージをインストール:
pip install mcpauth
または uv
や poetry
など、お好みのパッケージマネージャーを使用してください。
まず mcp-auth
パッケージをインストール:
npm install mcp-auth
MCP Auth は初期化のために認可 (Authorization) サーバーのメタデータが必要です。プロバイダーごとに設定方法が異なります:
- Logto
- Keycloak
- OIDC
- OAuth 2
発行者 (Issuer) URL は Logto Console のアプリケーション詳細ページ「Endpoints & Credentials / Issuer endpoint」セクションで確認できます。例:https://my-project.logto.app/oidc
- Python
- Node.js
whoami.py
を更新して MCP Auth の設定を追加します:
from mcpauth import MCPAuth
from mcpauth.config import AuthServerType
from mcpauth.utils import fetch_server_config
auth_issuer = '<issuer-endpoint>' # 発行者エンドポイントに置き換えてください
auth_server_config = fetch_server_config(auth_issuer, type=AuthServerType.OIDC)
mcp_auth = MCPAuth(server=auth_server_config)
whoami.js
を更新して MCP Auth の設定を追加します:
import { MCPAuth, fetchServerConfig } from 'mcp-auth';
const authIssuer = '<issuer-endpoint>'; // 発行者エンドポイントに置き換えてください
const mcpAuth = new MCPAuth({
server: await fetchServerConfig(authIssuer, { type: 'oidc' }),
});
次に、MCP インスペクターから提供されたアクセス トークン (Access token) を使用して認可サーバーからユーザーのアイデンティティ情報を取得するカスタム アクセス トークン (Access token) 検証関数を作成します。
- Python
- Node.js
import pydantic
import requests
from mcpauth.exceptions import (
MCPAuthTokenVerificationException,
MCPAuthTokenVerificationExceptionCode,
)
from mcpauth.types import AuthInfo
def verify_access_token(token: str) -> AuthInfo:
"""
提供された Bearer トークンを認可サーバーからユーザー情報を取得して検証します。
トークンが有効な場合、ユーザー情報を含む `AuthInfo` オブジェクトを返します。
:param token: MCP インスペクターから受け取った Bearer トークン。
"""
issuer = auth_server_config.metadata.issuer
endpoint = auth_server_config.metadata.userinfo_endpoint # プロバイダーは userinfo エンドポイントをサポートしている必要があります
if not endpoint:
raise ValueError(
"Userinfo エンドポイントが認証サーバーメタデータに設定されていません。"
)
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' はサブジェクト(ユーザー ID)の標準クレーム
issuer=issuer, # メタデータから発行者を使用
claims=json, # userinfo エンドポイントから返されたすべてのクレーム (Claims)(JSON フィールド)を含める
)
# `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,
)
import { MCPAuthTokenVerificationError } from 'mcp-auth';
/**
* 提供された Bearer トークンを認可サーバーからユーザー情報を取得して検証します。
* トークンが有効な場合、ユーザー情報を含む `AuthInfo` オブジェクトを返します。
*/
const verifyToken = async (token) => {
const { issuer, userinfoEndpoint } = mcpAuth.config.server.metadata;
if (!userinfoEndpoint) {
throw new Error('Userinfo エンドポイントがサーバーメタデータに設定されていません');
}
const response = await fetch(userinfoEndpoint, {
headers: { Authorization: `Bearer ${token}` },
});
if (!response.ok) {
throw new MCPAuthTokenVerificationError('token_verification_failed', response);
}
const userInfo = await response.json();
if (typeof userInfo !== 'object' || userInfo === null || !('sub' in userInfo)) {
throw new MCPAuthTokenVerificationError('invalid_token', response);
}
return {
token,
issuer,
subject: String(userInfo.sub), // 'sub' はサブジェクト(ユーザー ID)の標準クレーム
clientId: '', // この例ではクライアント ID は使用しませんが、必要に応じて設定可能
scopes: [],
claims: userInfo,
};
};
発行者 (Issuer) URL は Keycloak Admin Console の「mcp-realm」内、「Realm settings / Endpoints」セクションの「OpenID Endpoint Configuration」リンクで確認できます。JSON ドキュメントの issuer
フィールドが発行者 (Issuer) URL です(例:http://localhost:8080/realms/mcp-realm
)。
- Python
- Node.js
whoami.py
を更新して MCP Auth の設定を追加します:
from mcpauth import MCPAuth
from mcpauth.config import AuthServerType
from mcpauth.utils import fetch_server_config
auth_issuer = '<issuer-endpoint>' # 発行者エンドポイントに置き換えてください
auth_server_config = fetch_server_config(auth_issuer, type=AuthServerType.OIDC)
mcp_auth = MCPAuth(server=auth_server_config)
whoami.js
を更新して MCP Auth の設定を追加します:
import { MCPAuth, fetchServerConfig } from 'mcp-auth';
const authIssuer = '<issuer-endpoint>'; // 発行者エンドポイントに置き換えてください
const mcpAuth = new MCPAuth({
server: await fetchServerConfig(authIssuer, { type: 'oidc' }),
});
次に、MCP インスペクターから提供されたアクセス トークン (Access token) を使用して認可サーバーからユーザーのアイデンティティ情報を取得するカスタム アクセス トークン (Access token) 検証関数を作成します。
- Python
- Node.js
import pydantic
import requests
from mcpauth.exceptions import (
MCPAuthTokenVerificationException,
MCPAuthTokenVerificationExceptionCode,
)
from mcpauth.types import AuthInfo
def verify_access_token(token: str) -> AuthInfo:
"""
提供された Bearer トークンを認可サーバーからユーザー情報を取得して検証します。
トークンが有効な場合、ユーザー情報を含む `AuthInfo` オブジェクトを返します。
:param token: MCP インスペクターから受け取った Bearer トークン。
"""
issuer = auth_server_config.metadata.issuer
endpoint = auth_server_config.metadata.userinfo_endpoint # プロバイダーは userinfo エンドポイントをサポートしている必要があります
if not endpoint:
raise ValueError(
"Userinfo エンドポイントが認証サーバーメタデータに設定されていません。"
)
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' はサブジェクト(ユーザー ID)の標準クレーム
issuer=issuer, # メタデータから発行者を使用
claims=json, # userinfo エンドポイントから返されたすべてのクレーム (Claims)(JSON フィールド)を含める
)
# `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,
)
import { MCPAuthTokenVerificationError } from 'mcp-auth';
/**
* 提供された Bearer トークンを認可サーバーからユーザー情報を取得して検証します。
* トークンが有効な場合、ユーザー情報を含む `AuthInfo` オブジェクトを返します。
*/
const verifyToken = async (token) => {
const { issuer, userinfoEndpoint } = mcpAuth.config.server.metadata;
if (!userinfoEndpoint) {
throw new Error('Userinfo エンドポイントがサーバーメタデータに設定されていません');
}
const response = await fetch(userinfoEndpoint, {
headers: { Authorization: `Bearer ${token}` },
});
if (!response.ok) {
throw new MCPAuthTokenVerificationError('token_verification_failed', response);
}
const userInfo = await response.json();
if (typeof userInfo !== 'object' || userInfo === null || !('sub' in userInfo)) {
throw new MCPAuthTokenVerificationError('invalid_token', response);
}
return {
token,
issuer,
subject: String(userInfo.sub), // 'sub' はサブジェクト(ユーザー ID)の標準クレーム
clientId: '', // この例ではクライアント ID は使用しませんが、必要に応じて設定可能
scopes: [],
claims: userInfo,
};
};
以下のコードは、認可 (Authorization) サーバーが userinfo エンドポイント をサポートしていることを前提としています。サポートしていない場合は、プロバイダーのドキュメントで該当エンドポイントを確認し、userinfo エンドポイント変数を正しい URL に置き換えてください。
- Python
- Node.js
whoami.py
を更新して MCP Auth の設定を追加します:
from mcpauth import MCPAuth
from mcpauth.config import AuthServerType
from mcpauth.utils import fetch_server_config
auth_issuer = '<issuer-endpoint>' # 発行者エンドポイントに置き換えてください
auth_server_config = fetch_server_config(auth_issuer, type=AuthServerType.OIDC)
mcp_auth = MCPAuth(server=auth_server_config)
whoami.js
を更新して MCP Auth の設定を追加します:
import { MCPAuth, fetchServerConfig } from 'mcp-auth';
const authIssuer = '<issuer-endpoint>'; // 発行者エンドポイントに置き換えてください
const mcpAuth = new MCPAuth({
server: await fetchServerConfig(authIssuer, { type: 'oidc' }),
});
場合によっては、プロバイダーからのレスポンスが不正であったり、期待されるメタデータ形式に準拠していないことがあります。プロバイダーが準拠していると確信できる場合は、設定オプションを使ってメタデータをトランスパイルできます:
- Python
- Node.js
mcp_auth = MCPAuth(
server=fetch_server_config(
# ...other options
transpile_data=lambda data: {**data, 'response_types_supported': ['code']}
)
)
const mcpAuth = new MCPAuth({
server: await fetchServerConfig(authIssuer, {
// ...other options
transpileData: (data) => ({ ...data, response_types_supported: ['code'] }),
}),
});
プロバイダーが OpenID Connect Discovery をサポートしていない場合、メタデータ URL またはエンドポイントを手動で指定できます。詳細は MCP Auth を初期化するその他の方法 をご確認ください。
次に、MCP インスペクターから提供されたアクセス トークン (Access token) を使用して認可サーバーからユーザーのアイデンティティ情報を取得するカスタム アクセス トークン (Access token) 検証関数を作成します。
- Python
- Node.js
import pydantic
import requests
from mcpauth.exceptions import (
MCPAuthTokenVerificationException,
MCPAuthTokenVerificationExceptionCode,
)
from mcpauth.types import AuthInfo
def verify_access_token(token: str) -> AuthInfo:
"""
提供された Bearer トークンを認可サーバーからユーザー情報を取得して検証します。
トークンが有効な場合、ユーザー情報を含む `AuthInfo` オブジェクトを返します。
:param token: MCP インスペクターから受け取った Bearer トークン。
"""
issuer = auth_server_config.metadata.issuer
endpoint = auth_server_config.metadata.userinfo_endpoint # プロバイダーは userinfo エンドポイントをサポートしている必要があります
if not endpoint:
raise ValueError(
"Userinfo エンドポイントが認証サーバーメタデータに設定されていません。"
)
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' はサブジェクト(ユーザー ID)の標準クレーム
issuer=issuer, # メタデータから発行者を使用
claims=json, # userinfo エンドポイントから返されたすべてのクレーム (Claims)(JSON フィールド)を含める
)
# `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,
)
import { MCPAuthTokenVerificationError } from 'mcp-auth';
/**
* 提供された Bearer トークンを認可サーバーからユーザー情報を取得して検証します。
* トークンが有効な場合、ユーザー情報を含む `AuthInfo` オブジェクトを返します。
*/
const verifyToken = async (token) => {
const { issuer, userinfoEndpoint } = mcpAuth.config.server.metadata;
if (!userinfoEndpoint) {
throw new Error('Userinfo エンドポイントがサーバーメタデータに設定されていません');
}
const response = await fetch(userinfoEndpoint, {
headers: { Authorization: `Bearer ${token}` },
});
if (!response.ok) {
throw new MCPAuthTokenVerificationError('token_verification_failed', response);
}
const userInfo = await response.json();
if (typeof userInfo !== 'object' || userInfo === null || !('sub' in userInfo)) {
throw new MCPAuthTokenVerificationError('invalid_token', response);
}
return {
token,
issuer,
subject: String(userInfo.sub), // 'sub' はサブジェクト(ユーザー ID)の標準クレーム
clientId: '', // この例ではクライアント ID は使用しませんが、必要に応じて設定可能
scopes: [],
claims: userInfo,
};
};
前述の通り、OAuth 2.0 ではユーザーのアイデンティティ情報を取得する標準的な方法は定義されていません。以下のコードは、プロバイダーがアクセス トークン (Access token) でユーザーのアイデンティティ情報を取得できる独自エンドポイントを持っていることを前提としています。プロバイダーのドキュメントで該当エンドポイントを確認し、userinfo エンドポイント変数を正しい URL に置き換えてください。
- Python
- Node.js
whoami.py
を更新して MCP Auth の設定を追加します:
from mcpauth import MCPAuth
from mcpauth.config import AuthServerType
from mcpauth.utils import fetch_server_config
auth_issuer = '<issuer-endpoint>' # 発行者エンドポイントに置き換えてください
auth_server_config = fetch_server_config(auth_issuer, type=AuthServerType.OAUTH)
mcp_auth = MCPAuth(server=auth_server_config)
whoami.js
を更新して MCP Auth の設定を追加します:
import { MCPAuth, fetchServerConfig } from 'mcp-auth';
const authIssuer = '<issuer-endpoint>'; // 発行者エンドポイントに置き換えてください
const mcpAuth = new MCPAuth({
server: await fetchServerConfig(authIssuer, { type: 'oauth' }),
});
場合によっては、プロバイダーからのレスポンスが不正であったり、期待されるメタデータ形式に準拠していないことがあります。プロバイダーが準拠していると確信できる場合は、設定オプションを使ってメタデータをトランスパイルできます:
- Python
- Node.js
mcp_auth = MCPAuth(
server=fetch_server_config(
# ...other options
transpile_data=lambda data: {**data, 'response_types_supported': ['code']}
)
)
const mcpAuth = new MCPAuth({
server: await fetchServerConfig(authIssuer, {
// ...other options
transpileData: (data) => ({ ...data, response_types_supported: ['code'] }),
}),
});
プロバイダーが OAuth 2.0 Authorization Server Metadata をサポートしていない場合、メタデータ URL またはエンドポイントを手動で指定できます。詳細は MCP Auth を初期化するその他の方法 をご確認ください。
次に、MCP インスペクターから提供されたアクセス トークン (Access token) を使用して認可サーバーからユーザーのアイデンティティ情報を取得するカスタム アクセス トークン (Access token) 検証関数を作成する必要があります。
- Python
- Node.js
import pydantic
import requests
from mcpauth.exceptions import (
MCPAuthTokenVerificationException,
MCPAuthTokenVerificationExceptionCode,
)
from mcpauth.types import AuthInfo
def verify_access_token(token: str) -> AuthInfo:
"""
提供された Bearer トークンを認可サーバーからユーザー情報を取得することで検証します。
トークンが有効な場合、ユーザー情報を含む `AuthInfo` オブジェクトを返します。
:param token: MCP インスペクターから受け取った Bearer トークン。
"""
try:
# 以下のコードは、認可サーバーがアクセス トークン (Access token) を使って
# ユーザー情報を取得するエンドポイントを持っていることを前提としています。
# プロバイダーの API に応じて URL やヘッダーを調整してください。
response = requests.get(
"https://your-authorization-server.com/userinfo",
headers={"Authorization": f"Bearer {token}"},
)
response.raise_for_status() # HTTP エラー時に例外を発生させます
json = response.json() # JSON レスポンスをパースします
# 以下のコードは、ユーザー情報レスポンスがユーザーを識別する 'sub' フィールドを
# 含むオブジェクトであることを前提としています。プロバイダーの API に応じて調整してください。
return AuthInfo(
token=token,
subject=json.get("sub"),
issuer=auth_issuer, # 設定済みの発行者 (Issuer) を使用
claims=json, # エンドポイントから返されたすべてのクレーム (Claims)(JSON フィールド)を含めます
)
# `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,
)
import { MCPAuthTokenVerificationError } from 'mcp-auth';
/**
* 提供された Bearer トークンを認可サーバーからユーザー情報を取得することで検証します。
* トークンが有効な場合、ユーザー情報を含む `AuthInfo` オブジェクトを返します。
*/
const verifyToken = async (token) => {
// 以下のコードは、認可サーバーがアクセス トークン (Access token) を使って
// ユーザー情報を取得するエンドポイントを持っていることを前提としています。
// プロバイダーの API に応じて URL やヘッダーを調整してください。
const response = await fetch('https://your-authorization-server.com/userinfo', {
headers: { Authorization: `Bearer ${token}` },
});
if (!response.ok) {
throw new MCPAuthTokenVerificationError('token_verification_failed', response);
}
const userInfo = await response.json();
// 以下のコードは、ユーザー情報レスポンスがユーザーを識別する 'sub' フィールドを
// 含むオブジェクトであることを前提としています。プロバイダーの API に応じて調整してください。
if (typeof userInfo !== 'object' || userInfo === null || !('sub' in userInfo)) {
throw new MCPAuthTokenVerificationError('invalid_token', response);
}
return {
token,
issuer: authIssuer,
subject: String(userInfo.sub), // プロバイダーのユーザー ID フィールドに応じて調整してください
clientId: '', // この例ではクライアント ID は使用しませんが、必要に応じて設定可能です
scopes: [],
claims: userInfo,
};
};
MCP サーバーの更新
あと少しです!MCP Auth のルートとミドルウェア関数を適用し、whoami
ツールが実際のユーザーアイデンティティ情報を返すよう MCP サーバーを更新します。
- Python
- Node.js
@mcp.tool()
def whoami() -> dict[str, Any]:
"""現在のユーザー情報を返すツール"""
return (
mcp_auth.auth_info.claims
if mcp_auth.auth_info # Bearer auth ミドルウェアでセットされます
else {"error": "Not authenticated"}
)
# ...
bearer_auth = Middleware(mcp_auth.bearer_auth_middleware(verify_access_token))
app = Starlette(
routes=[
# メタデータルート(`/.well-known/oauth-authorization-server`)を追加
mcp_auth.metadata_route(),
# Bearer auth ミドルウェアで MCP サーバーを保護
Mount('/', app=mcp.sse_app(), middleware=[bearer_auth]),
],
)
server.tool('whoami', ({ authInfo }) => {
return {
content: [
{ type: 'text', text: JSON.stringify(authInfo?.claims ?? { error: 'Not authenticated' }) },
],
};
});
// ...
app.use(mcpAuth.delegatedRouter());
app.use(mcpAuth.bearerAuth(verifyToken));
チェックポイント: 認証 (Authentication) 付きで whoami
ツールを実行
MCP サーバーを再起動し、ブラウザで MCP inspector を開きます。「Connect」ボタンをクリックすると、認可 (Authorization) サーバーのサインインページにリダイレクトされます。
サインイン後 MCP inspector に戻り、前回と同じ手順で whoami
ツールを実行してください。今回は認可 (Authorization) サーバーから返されたユーザーのアイデンティティ情報が表示されるはずです。
- Python
- Node.js
MCP Auth Python SDK リポジトリ で MCP サーバー(OIDC 版)の完全なコードを確認できます。
MCP Auth Node.js SDK リポジトリ で MCP サーバー(OIDC 版)の完全なコードを確認できます。このディレクトリには TypeScript 版と JavaScript 版の両方が含まれています。
締めくくり
🎊 おめでとうございます!チュートリアルを無事完了しました。ここまでの内容を振り返りましょう:
whoami
ツール付きの基本的な MCP サーバーのセットアップ- MCP Auth を使った MCP サーバーと認可 (Authorization) サーバーの連携
- MCP Inspector でユーザー認証 (Authentication) とアイデンティティ情報の取得
さらに発展的なトピックとして、以下もぜひご検討ください:
- JWT (JSON Web Token) を使った認証 (Authentication)・認可 (Authorization)
- リソースインジケーター (RFC 8707) を活用したアクセスリソースの指定
- ロールベースのアクセス制御 (RBAC) や 属性ベースのアクセス制御 (ABAC) などのカスタムアクセス制御の実装
他のチュートリアルやドキュメントもぜひご覧いただき、MCP Auth を最大限に活用してください。