🦀

Cloudflare Remote MCP に Access 認証・認可をくっつける

に公開

はじめに

Cloudflare Remote MCP server を試しているとき、Cloudflare Access を使えば、すでに Access で保護しているアプリケーション(Self-hosted や WARP)の認証に使われたトークンの再利用ができ、業務フローを円滑化できそうだなと思いました。

探してみたら、すでに OAuth のデモがありました(Access のほかにも)。

https://github.com/cloudflare/ai/tree/main/demos/remote-mcp-cf-access

私の環境では Access アプリケーションに Entra ID と Email one-time Pin を有効にしています。
Access を使えば複数の IdP を同時に利用できるので、異なる IdP を利用する組織でのアプリケーション共用環境など柔軟に利用でき、便利です。
ざっくりで正確性は欠きますが、下記のような構成です。

ローカルテスト

Access

Access アプリケーションを作ります

  • この場合は SaaS です
  • OIDC を選択します
  • リダイレクト URL には暫定で http://localhost/ など入れておきます
    後で書き換えます
  • 必要な情報をメモします

MCP サーバー

  • アプリケーションを作ります

    npm create cloudflare@latest -- my-mcp-server-access -template=cloudflare/ai/demos/remote-mcp-cf-access
    
  • ローカル用の変数を用意します
    各項目に Access アプリケーションでの表示内容を入れます。

    .dev.vars
    ACCESS_CLIENT_ID=677...
    ACCESS_CLIENT_SECRET=f9a...
    ACCESS_TOKEN_URL=https://...
    ACCESS_AUTHORIZATION_URL=https://...
    ACCESS_JWKS_URL=https://...
    COOKIE_ENCRYPTION_KEY=417...
    

    対応は下記のとおりです。

    変数キー Access OIDC 項目
    ACCESS_CLIENT_ID クライアント ID
    ACCESS_CLIENT_SECRET クライアント シークレット
    ACCESS_TOKEN_URL(/token) トークン エンドポイント
    ACCESS_AUTHORIZATION_URL(/authorization) 認証エンドポイント
    ACCESS_JWKS_URL(/jwks) キー エンドポイント
    COOKIE_ENCRYPTION_KEY 自作するe.g. openssl rand -hex 32
  • ローカル起動します。

    npx wrangler dev
    
    出力

    OAUTH_KV: <Add-KV-ID> [simulated locally] シミュレートされています。

    :
    Using vars defined in .dev.vars
    :
    Your worker has access to the following bindings:
    - Durable Objects:
      - MCP_OBJECT: MyMCP
    - KV Namespaces:
      - OAUTH_KV: <Add-KV-ID> [simulated locally]
    - AI:
      - Name: AI [connected to remote resource]
    - Vars:
      - ACCESS_CLIENT_ID: "(hidden)"
      - ACCESS_CLIENT_SECRET: "(hidden)"
      - ACCESS_TOKEN_URL: "(hidden)"
      - ACCESS_AUTHORIZATION_URL: "(hidden)"
      - ACCESS_JWKS_URL: "(hidden)"
      - COOKIE_ENCRYPTION_KEY: "(hidden)"
    ❓ Your types might be out of date. Re-run `wrangler types` to ensure your types are correct.
    ▲ [WARNING] Using Workers AI always accesses your Cloudflare account in order to run AI models, and so will incur usage charges even in local development.
    
    ⎔ Starting local server...
    [wrangler:inf] Ready on http://localhost:8788
    

    出力の最後に Ready on http://localhost:8788 とあるので、Access アプリケーションにもどり、リダイレクト URLhttp://localhost:8788/callback に設定します。

テスト

  • MCP inspectorを立ち上げます

    npx @modelcontextprotocol/inspector@latest
    
    出力
    Starting MCP inspector...
    ⚙️ Proxy server listening on port 6277
    🔍 MCP Inspector is up and running at http://127.0.0.1:6274 🚀
    New SSE connection
    

    running at http://127.0.0.1:6274 で立ち上がりました。

  • MCP サーバーの接続をテストします

    • ブラウザーで http://127.0.0.1:6274 にアクセス
    • Transport TypeSSE
    • URLhttp://localhost:8788/sse を入力 ➜ Connect
    • MCP Inspector の接続要求を承認するか ➜ 承認
    • Access(および連携する IdP)にリダイレクト ➜ 認証のプロセスを踏む
    • リモート MCP サーバーの add ツールを利用

    無事にアクセスできました。

インターネットにデプロイ

うまくいったらインターネットにデプロイします。

シークレット

  • それぞれシークレットを追加します
    npx wrangler secret put ACCESS_CLIENT_ID
    npx wrangler secret put ACCESS_CLIENT_SECRET
    :
    
    出力

    それぞれ値を入れていきます。

    ✔ Enter a secret value: …
    

KV

  • KV を作成し、バインドします
    npx wrangler kv namespace create OAUTH_KV
    
    出力
    Resource location: remote
    🌀 Creating namespace with title "OAUTH_KV"
    ✨ Success!
    Add the following to your configuration file in your kv_namespaces array:
    {
      "kv_namespaces": [
        {
          "binding": "OAUTH_KV",
          "id": "< ID >"
        }
      ]
    }
    
    Add the following to your configuration file と出てくるので、 wrangler.jsonc に追記します。
    wrangler.jsonc
    "kv_namespaces": [
            {
                    "binding": "OAUTH_KV",
                    "id": "< ID >"
            }
    ],
    

デプロイ

  • デプロイします
    npx wrangler deploy
    
    出力
    Your worker has access to the following bindings:
    :
    Deployed my-mcp-server-access triggers (0.94 sec)
    https://my-mcp-server-access.<your-subdomain>.workers.dev
    :
    
    https://my-mcp-server-access.<your-subdomain>.workers.dev とあるので、Access に戻り、リダイレクト URLhttps://my-mcp-server-access.<your-subdomain>.workers.dev/callback に書き換えます。

テスト

MCP inspector

MPC inspector でアクセスすると、同様に Access での認証・認可プロセスを経由し、Tools を利用できました。

Claude デスクトップ

Claude デスクトップに今回のデモが提供するリモート MCP サーバーを math として追加します。

Claude デスクトップを再起動すると、リモート MCP サーバが提供するツール(足し算)とローカル MCP サーバーが提供するツール(ファイル操作)を利用させることができました。

おまけ

ユーザーに応じた制御

  - AI:
    - Name: AI [connected to remote resource]

なんで Workers AI をバインドしているのかな?
みると、下記のコードがありました。

src/index.ts
// Dynamically add tools based on the user's login. In this case, I want to limit
// access to my Image Generation tool to just me
// @ts-ignore
if (ALLOWED_EMAILS.has(this.props.email)) {
    this.server.tool(
        'generateImage',
        'Generate an image using the `flux-1-schnell` model. Works best with 8 steps.',
        :
        async ({ prompt, steps }) => {
            // @ts-ignore
            const response = await this.env.AI.run('@cf/black-forest-labs/flux-1-schnell', {
                prompt,
                steps,
            })

トークン に含まれる Email 参照し、特定のユーザーだけ画像生成 AI モデル flux-1-schnell を使わせる、というデモのようです。

テスト

  • 許可する Email を指定します
  • 指定したメールアドレスでログインします
    generateImage ツールを選択できるようになり、画像が生成されました。
  • その他のメールアドレスでログインします
    最初と同じ様に add のみ表示され、generateImage は利用できません。

JWT の要素 Email などを用いた、アクセスコントロールもできそうです。
README にもしっかり書いてありました…)

まとめ

お使いのアプリケーションを Access アプリケーション化していくことで、業務体験を効率化しつつセキュア化に向けてコントロールすることができそうです。
ご自身の環境に応じ、いろんな可能性がありそうなので、是非お試しを。

つなげよう、ひろげよう、Access の輪

Discussion