0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

セキュアなクラウドネイティブMCPサーバー: Auth0 + Cloudflare Workersの実装

Last updated at Posted at 2025-04-22

目次

1. はじめに

人工知能(AI)アプリケーションが普及するにつれて、これらのアプリケーションを外部APIやサービスに安全に接続する必要性が高まっています。Model Context Protocol(MCP)は、大規模言語モデル(LLM)を外部ツールやAPIと標準化された方法で接続するためのプロトコルです。

しかし、MCPを使用する際の重要な課題の一つがセキュリティです。AIアプリケーションが外部サービスに接続するとき、適切な認証と認可が必要です。

この記事では、Auth0の認証サービスとCloudflare Workersのサーバーレスプラットフォームを使用して、セキュアなクラウドネイティブなMCPサーバーを構築する方法を説明します。このアプローチにより、AIアプリケーションは認証されたユーザーの代わりに安全に外部APIを呼び出すことができるようになります。

具体的なユースケースとして、AIアプリケーション(Cloud Desktop)を保護されたToDo APIに接続するリモートMCPサーバーを実装します。このパターンは、様々な外部APIやサービスにAIアプリケーションを接続するための基盤となります。

2. アーキテクチャ概要

私たちが構築するシステムは、以下のコンポーネントで構成されています:

主要コンポーネント 🔍:

  1. Cloud Desktop: MCPクライアントとしてのAIアプリケーション。ローカル接続のみをサポートするため、外部のAPIに直接接続できません。

  2. MCP Remote: ローカルMCPクライアントとリモートMCPサーバーの間のギャップを埋める軽量プロキシ。HTTP/SSEリクエストをリモートMCPサーバーに転送し、認証・認可を処理します。

  3. リモートMCPサーバー: Cloudflare Workersにデプロイされ、Auth0との認証フローを管理し、保護されたAPIへのアクセスを仲介します。MCPクライアントに対してはOAuthサーバーとして機能し、Auth0に対してはOpenID Connectクライアントとして機能します。

  4. Auth0: 認証・認可のためのサードパーティサービス。JWTトークンの発行と検証を担当します。

  5. 保護されたToDo API: Cloudflare Workersにデプロイされた、Auth0ベースの認証で保護されたAPIです。

3. 前提条件と環境準備

このガイドに従うには、以下のアカウントとツールが必要です:

  1. Auth0アカウント: 無料で作成できます(Auth0サインアップ
  2. Cloudflareアカウント: 無料で作成できます(Cloudflareサインアップ
  3. Node.js: バージョン18以上
  4. Git: 最新バージョン
  5. コードエディタ: VSCode, Cursor など
  6. Cloudflare Wrangler CLI: Cloudflare Workersのデプロイに使用

Wrangler CLIのインストール:

npm install -g wrangler

サンプルコードのクローン:

git clone https://github.com/cloudflare/ai.git
cd ai/demos/remote-mcp-auth0/

このリポジトリには、2つの主要なディレクトリがあります:

  • todos-api: 保護されたToDo APIの実装
  • mcp-auth0-oidc: Auth0と統合するリモートMCPサーバーの実装

4. 保護されたToDo APIの構築

まず、Auth0で保護されたToDo APIを構築し、デプロイします。

4.1 APIの実装を理解する

todos-apiディレクトリに移動し、必要な依存関係をインストールします:

cd todos-api
npm install

このAPIの主な実装はindex.jsにあります:

// Honoフレームワークを使用したWebサーバーの実装
import { Hono } from 'hono';
import { faker } from '@faker-js/faker';
import { jwt, requireScope } from './middleware/jwt';

// アプリケーションの初期化
const app = new Hono();

// ヘルスチェックエンドポイント
app.get('/', (c) => c.text('Hello World!'));

// すべてのルートにJWT検証ミドルウェアを適用
app.use('*', jwt());

// ユーザー情報エンドポイント
app.get('/api/me', (c) => {
  // JWTペイロードからユーザークレームを取得
  const payload = c.get('jwtPayload');
  return c.json(payload);
});

// ToDosエンドポイント - 'read:todos'スコープを要求
app.get('/api/todos', requireScope('read:todos'), (c) => {
  // フェイカーを使用してランダムなToDosを生成
  const todos = Array.from({ length: 5 }, () => ({
    id: faker.string.uuid(),
    title: faker.lorem.sentence(),
    completed: faker.datatype.boolean(),
  }));
  return c.json(todos);
});

// 請求情報エンドポイント - 'read:billing'スコープを要求
app.get('/api/billing', requireScope('read:billing'), (c) => {
  // 静的な請求情報を返す
  return c.json({
    plan: 'Pro',
    amount: 99.99,
    nextBillingDate: faker.date.future(),
  });
});

export default app;

このAPIは、JWT(JSON Web Token)を使用して認証を行い、特定のエンドポイントにはスコープベースの認可を実装しています。

middleware/jwt.jsファイルには、JWTの検証やスコープの要求などの認証ロジックが実装されています。

JWTとは、情報を安全に送信するためのコンパクトで自己完結型の方法です。JWTの情報はJSON形式であり、デジタル署名されているため、信頼性が検証できます。

4.2 Auth0でのAPIの設定

  1. Auth0ダッシュボードにログインします。

  2. Applications > APIsに移動し、Create APIをクリックします。

  3. 以下の値を入力します:

    • Name: Todos API
    • Identifier: urn:todos-api
  4. Createをクリックします。

  5. APIの設定画面で、Settingsタブに移動します。

  6. Access Settingsセクションまでスクロールし、Allow Offline Accessをオンにします。

  7. Saveをクリックします。

  8. Permissionsタブに移動し、以下のパーミッションを追加します:

    • read:todos - "ToDo リストを読み取る"権限
    • read:billing - "請求情報を読み取る"権限

4.3 環境変数の設定

プロジェクトのルートディレクトリに.dev.varsファイルを作成し、以下の内容を追加します:

AUTH0_DOMAIN=あなたのAuth0ドメイン(例:dev-xxxx.us.auth0.com)
AUTH0_AUDIENCE=urn:todos-api

Auth0ドメインは、Auth0ダッシュボードの**Applications > Applications > Todos API (Test Application)**から取得できます。

4.4 ローカルでのAPIのテスト

APIをローカルで実行します:

npm run dev

APIはlocalhost:8789で実行されます。

Auth0ダッシュボードから一時的なアクセストークンを取得してAPIをテストします:

  1. Applications > APIs > Todos API > Testタブに移動します。
  2. 表示されているcURLコマンドをコピーして実行します:
curl --request POST \
  --url https://あなたのドメイン.auth0.com/oauth/token \
  --header 'content-type: application/json' \
  --data '{"client_id":"...","client_secret":"...","audience":"urn:todos-api","grant_type":"client_credentials"}'

返されたアクセストークンを使用してAPIにリクエストを送信します:

curl --request GET \
  --url http://localhost:8789/api/me \
  --header 'Authorization: Bearer あなたのアクセストークン'

4.5 Cloudflare Workersへのデプロイ

APIをCloudflare Workersにデプロイするには、まず環境シークレットを設定します:

wrangler secret put AUTH0_DOMAIN
wrangler secret put AUTH0_AUDIENCE

プロンプトが表示されたら、対応する値を入力します。

次に、APIをデプロイします:

wrangler deploy

デプロイが成功すると、Cloudflare WorkersのURLが表示されます。例:https://todos-api.あなたのサブドメイン.workers.dev

5. リモートMCPサーバーの実装

次に、Auth0と統合するリモートMCPサーバーを構築します。

5.1 Auth0でのアプリケーションの作成

  1. Auth0ダッシュボードのApplications > Applicationsに移動し、Create Applicationをクリックします。

  2. 以下の値を入力します:

    • Name: Remote MCP Server
    • Application Type: Regular Web Applications
  3. Createをクリックします。

  4. 作成したアプリケーションのSettingsタブに移動します。

  5. Application URIsセクションまでスクロールし、Allowed Callback URLsに以下を追加します:

    • ローカルテスト用: http://localhost:8788/callback
    • Cloudflareデプロイ用: https://mcp-auth0-oidc.あなたのサブドメイン.workers.dev/callback
  6. Save Changesをクリックします。

5.2 Cloudflare KVの設定

Cloudflare Workers KVネームスペースを作成します:

wrangler kv namespace create "OAUTH_KV"

表示されたIDをコピーし、mcp-auth0-oidcディレクトリ内のwrangler.jsoncファイルを編集します:

{
  "kv_namespaces": [
    {
      "binding": "OAUTH_KV",
      "id": "コピーしたID"
    }
  ]
}

Cloudflare Workers KVは、サーバーレス環境でのキー値ストレージサービスです。OAuthフローで必要な状態やトークンを保持するために使用します。

5.3 環境変数の設定

mcp-auth0-oidcディレクトリに.dev.varsファイルを作成し、以下の内容を追加します:

AUTH0_DOMAIN=あなたのAuth0ドメイン
AUTH0_CLIENT_ID=Remote MCPサーバーのクライアントID
AUTH0_CLIENT_SECRET=Remote MCPサーバーのクライアントシークレット
AUTH0_AUDIENCE=urn:todos-api
AUTH0_SCOPE=openid email profile offline_access read:todos
NODE_ENV=development
API_BASE_URL=http://localhost:8789

5.4 MCP Remote Serverコードの理解

リモートMCPサーバーの実装を見てみましょう。主なコードはsrc/index.tsにあります:

// MCPサーバーの実装
import { MCPServer } from '@cloudflare/mcp/server';
import { OAuthProvider } from 'workers-oauth-provider';

// 環境変数の取得
const {
  AUTH0_DOMAIN,
  AUTH0_CLIENT_ID,
  AUTH0_CLIENT_SECRET,
  AUTH0_AUDIENCE,
  AUTH0_SCOPE,
  API_BASE_URL,
} = env;

// MCPサーバーの作成
const mcpServer = new MCPServer();

// ToDosツールの実装
mcpServer.defineTool({
  name: 'list-todos',
  description: 'List user todos',
  async handler(params, context) {
    // アクセストークンを使用してToDo APIにリクエスト
    const response = await fetch(`${API_BASE_URL}/api/todos`, {
      headers: {
        Authorization: `Bearer ${context.token}`,
      },
    });
    
    if (!response.ok) {
      throw new Error(`Failed to fetch todos: ${response.status}`);
    }
    
    return await response.json();
  },
});

// その他のツール実装(whoami, list-billing)...

// OAuthプロバイダーの設定
const oauthProvider = new OAuthProvider({
  // OIDC設定
  oidc: {
    issuer: `https://${AUTH0_DOMAIN}`,
    client_id: AUTH0_CLIENT_ID,
    client_secret: AUTH0_CLIENT_SECRET,
    redirect_uri: '/callback',
    // その他の設定...
  },
  // OAuth設定
  oauth: {
    // デフォルトスコープなど
  },
  // KVストレージの設定
  storage: env.OAUTH_KV,
});

// OAuth関連のルートハンドラー
export default {
  // SSEエンドポイント - MCPサーバー処理
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    
    // OAuthエンドポイントの処理
    if (
      url.pathname === '/authorize' ||
      url.pathname === '/authorize/consent' ||
      url.pathname === '/callback' ||
      url.pathname.startsWith('/.well-known/') ||
      url.pathname === '/token' ||
      url.pathname === '/register'
    ) {
      return oauthProvider.handle(request, env, ctx);
    }
    
    // MCPサーバーのSSEエンドポイント
    if (url.pathname === '/sse') {
      // 認証確認
      const token = await oauthProvider.validateRequest(request);
      if (!token) {
        return new Response('Unauthorized', { status: 401 });
      }
      
      // MCPサーバーへのリクエスト処理
      return mcpServer.handleRequest(request, {
        token: token.access_token,
      });
    }
    
    // その他のリクエスト処理...
  }
};

このサーバーは主に2つの役割を果たしています:

  1. MCPサーバーとして 🛠️: AIアプリケーションにツール(list-todos, whoami, list-billing)を提供
  2. OAuthサーバーとして 🔐: 認証と認可のフローを処理

5.5 ローカルでのMCPサーバーのテスト

まず、Todo APIサーバーが実行されていることを確認します(localhost:8789)。

次に、MCPサーバーをローカルで実行します:

cd mcp-auth0-oidc
npm run dev

MCPサーバーはlocalhost:8788で実行されます。

テストにはMCP Inspectorを使用します:

npx @modelcontextprotocol/inspector

MCP Inspectorが起動したら、「Connect to MCP Server」セクションで以下の設定でサーバーに接続します:

  • Protocol: sse
  • URL: http://localhost:8788/sse

「Connect」ボタンをクリックすると、OAuth同意画面が表示されます。ここで「Allow Access」をクリックすると、Auth0の認証画面にリダイレクトされます。認証に成功すると、MCP Inspectorに利用可能なツールが表示されます。

5.6 Cloudflare Workersへのデプロイ

MCPサーバーをCloudflare Workersにデプロイするには、まず環境シークレットを設定します:

wrangler secret put AUTH0_DOMAIN
wrangler secret put AUTH0_CLIENT_ID
wrangler secret put AUTH0_CLIENT_SECRET
wrangler secret put AUTH0_AUDIENCE
wrangler secret put AUTH0_SCOPE
wrangler secret put API_BASE_URL

API_BASE_URLには、デプロイしたToDo APIのCloudflare WorkersのURLを指定します:

https://todos-api.あなたのサブドメイン.workers.dev

次に、MCPサーバーをデプロイします:

wrangler deploy

デプロイが成功すると、Cloudflare WorkersのURLが表示されます:

https://mcp-auth0-oidc.あなたのサブドメイン.workers.dev

6. 認証フローとOAuth 2.0の理解

このシステムで使用されているOAuth 2.0認証フローを詳しく見てみましょう。

6.1 OAuthの基本概念

OAuth 2.0の主要なエンティティは次のとおりです:

  1. リソースオーナー 👤: データの所有者(ユーザー)
  2. クライアント 💻: アクセスを要求するアプリケーション(MCPクライアント/Inspector)
  3. リソースサーバー 🗄️: 保護されたデータを提供するサーバー(ToDo API)
  4. 認可サーバー 🔑: 認証と認可を処理するサーバー(Auth0)

OAuth 2.0は、アプリケーションがユーザーのリソースに安全にアクセスするための標準プロトコルです。ユーザーは自分の認証情報を共有せずに、アプリケーションに特定のアクセス権を付与できます。

6.2 認証フローの図解

6.3 フローの詳細な説明

  1. 初期接続とディスカバリー 🔍:

    • MCPクライアントがリモートMCPサーバーに接続を試みます。
    • サーバーは401 Unauthorizedを返します。
    • クライアントは.well-known/oauth-authorization-serverエンドポイントを使用してOAuth設定情報を取得します。
    • クライアントは/registerエンドポイントでクライアント登録を行います。
  2. 認可リクエスト 🔒:

    • クライアントは/authorizeエンドポイントに認可リクエストを送信します。
    • MCPサーバーは同意画面を表示します。
    • ユーザーがアクセスを許可すると、MCPサーバーはユーザーをAuth0の認証画面にリダイレクトします。
  3. 認証と認可コードの交換 🔄:

    • ユーザーがAuth0で認証すると、Auth0はMCPサーバーの/callbackエンドポイントに認可コードを送信します。
    • MCPサーバーはクライアントをクライアントの/oauth/callbackエンドポイントにリダイレクトします。
    • クライアントはこの認可コードを使用して/tokenエンドポイントでアクセストークンとリフレッシュトークンを取得します。
  4. 保護されたAPIの呼び出し 🔌:

    • クライアントはアクセストークンを使用してMCPサーバーにツール呼び出しリクエストを送信します。
    • MCPサーバーはこのトークンを使用して保護されたAPIにリクエストを送信します。
    • APIはレスポンスをMCPサーバーに返し、MCPサーバーはそれをクライアントに転送します。

6.4 重要なセキュリティの考慮事項

  • JWT検証 ✅: APIはAuth0で発行されたJWTの署名を検証して、改ざんされていないことを確認します。
  • スコープの検証 🔍: APIは各エンドポイントで必要なスコープをチェックして、クライアントが適切な権限を持っていることを確認します。
  • リフレッシュトークン 🔄: リフレッシュトークンを使用すると、ユーザーは再認証せずに新しいアクセストークンを取得できます。
  • KVストレージ 💾: Cloudflare Workers KVは、認可コードとトークンの安全な保存に使用されます。

7. エンドツーエンドのテスト

システムの全コンポーネントがデプロイされたら、エンドツーエンドでテストしましょう。

7.1 MCPインスペクターを使用したテスト

MCPインスペクターを使用して、デプロイされたMCPサーバーに接続します:

npx @modelcontextprotocol/inspector

「Connect to MCP Server」セクションで以下の設定で接続します:

  • Protocol: sse
  • URL: https://mcp-auth0-oidc.あなたのサブドメイン.workers.dev/sse

認証フローを完了すると、利用可能なツールが表示されます:

  • list-todos: ToDoリストを取得
  • whoami: 現在のユーザー情報を表示
  • list-billing: 請求情報を取得(read:billingスコープがない場合はアクセス拒否)

7.2 ツールの呼び出しとレスポンスの確認

各ツールを呼び出して、期待どおりに動作することを確認します:

  1. whoami:

    {
      "sub": "auth0|1234567890",
      "email": "your-email@example.com",
      "iss": "https://your-domain.auth0.com/",
      "aud": "urn:todos-api",
      "iat": 1682345678,
      "exp": 1682349278,
      "scope": "openid email profile read:todos"
    }
    
  2. list-todos:

    [
      {
        "id": "123e4567-e89b-12d3-a456-426614174000",
        "title": "Complete project documentation",
        "completed": false
      },
      {
        "id": "223e4567-e89b-12d3-a456-426614174001",
        "title": "Buy groceries",
        "completed": true
      },
      // その他のToDoアイテム...
    ]
    
  3. list-billing (アクセス拒否の場合):

    {
      "error": "Insufficient scope",
      "required": "read:billing",
      "provided": "openid email profile read:todos"
    }
    

8. Cloud Desktopとの統合

最後に、このMCPサーバーをCloud DesktopなどのAIアプリケーションと統合します。

8.1 MCP Remoteの設定

MCP Remoteは、ローカルのMCPクライアント(Cloud Desktop)とリモートMCPサーバーの間のプロキシとして機能します。Cloud Desktopを設定するには、以下の手順に従います:

  1. Cloud Desktopを開き、Settings > Developerに移動します。
  2. Edit Configをクリックして、設定ファイル(claude_desktop_config.json)を開きます。
  3. 以下の設定を追加します:
{
  "mcpServers": {
    "remote-todos": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "https://mcp-auth0-oidc.あなたのサブドメイン.workers.dev/sse"
      ]
    }
  }
}

8.2 Cloud Desktopでのテスト

設定が完了したら、Cloud Desktopを再起動して、リモートMCPサーバーを使用してみましょう。

Cloud Desktopを起動すると、自動的にOAuth認証フローが開始されます。認証が完了すると、AIアシスタントに以下のようなプロンプトを試すことができます:

  1. "私のToDoリストを表示して"
  2. "自分の認証情報を教えて"

AIアシスタントは、リモートMCPサーバーを通じてこれらのリクエストを処理し、保護されたAPIからデータを取得して応答します。

9. まとめと次のステップ

この記事では、Auth0とCloudflare Workersを使用して、セキュアなクラウドネイティブMCPサーバーを構築しました。このアプローチにより、AIアプリケーションは認証されたユーザーの代わりに安全に外部APIを呼び出すことができるようになります。

実装のポイント:

  1. 保護されたAPI 🛡️: Auth0の認証と認可を使用してAPIを保護する方法
  2. リモートMCPサーバー 🌐: OAuthフローを処理し、保護されたAPIへのアクセスを仲介するサーバー
  3. MCP Remote 🔄: ローカルのAIアプリケーションとリモートMCPサーバーの間のギャップを埋めるプロキシ

このパターンは、さまざまな外部APIやサービスにAIアプリケーションを接続するための基盤となります。

次のステップ

  1. カスタムツールの追加: 独自のツールを実装して、MCPサーバーの機能を拡張
  2. 追加のAPIの統合: 他の保護されたAPIをシステムに統合
  3. セキュリティの強化: JWTの有効期限やスコープの細かい制御など、追加のセキュリティ機能の実装
  4. モニタリングとロギング: システム全体のモニタリングとロギングの実装

知識確認クイズ

  1. MCPサーバーの主な役割は何ですか?

    • a) AIモデルのトレーニング
    • b) AIアプリケーションと外部APIを接続
    • c) ユーザー認証のみ
    • d) データの暗号化
  2. Auth0がこのアーキテクチャで果たす役割は?

    • a) APIのホスティング
    • b) MCPサーバーのホスティング
    • c) 認証と認可の提供
    • d) AIモデルの提供
  3. Cloudflare Workers KVの主な用途は?

    • a) AIモデルの保存
    • b) ユーザーデータの保存
    • c) OAuth認可コードとトークンの保存
    • d) 静的ファイルのホスティング
  4. MCPサーバーがOAuthサーバーとして機能するとき、クライアントは何ですか?

    • a) Auth0
    • b) Cloudflare Workers
    • c) ToDo API
    • d) MCPクライアント(Inspector/Cloud Desktop)
  5. MCPサーバーがOpenID Connectクライアントとして機能するとき、サーバーは何ですか?

    • a) Auth0
    • b) Cloudflare Workers
    • c) ToDo API
    • d) MCPクライアント

答え:

  1. b
  2. c
  3. c
  4. d
  5. a
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?