---
title: Secure a Cloudflare Workers MCP server with PingOne
description: In this configuration, the Cloudflare Workers Model Context Protocol (MCP) server uses the Cloudflare Workers OAuth Provider, which delegates authentication to PingOne. This enables clients, such as AI agents, to call a protected API on behalf of an authenticated end user.
component: identity-for-ai
page_id: identity-for-ai:agents:idai-securing-cloudflare-pingone
canonical_url: https://developer.pingidentity.com/identity-for-ai/agents/idai-securing-cloudflare-pingone.html
section_ids:
  before-you-begin: Before you begin
  stack: Stack
  requirements: Requirements
  structure: Structure
  tasks: Tasks
  configuring-the-mcp-server-as-an-oidc-client-in-pingone: Configuring the MCP server as an OIDC Client in PingOne
  deploying-to-cloudflare: Deploying to Cloudflare
  testing-the-mcp-server-with-the-mcp-inspector: Testing the MCP Server with the MCP Inspector
  accessing-the-remote-mcp-server-from-claude-desktop: Accessing the remote MCP server from Claude Desktop
---

# Secure a Cloudflare Workers MCP server with PingOne

In this configuration, the Cloudflare Workers Model Context Protocol (MCP) server uses the Cloudflare Workers OAuth Provider, which delegates authentication to PingOne. This enables clients, such as AI agents, to call a protected API on behalf of an authenticated end user.

|   |                                                                                                                                                                                                                  |
| - | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | While serving as a resource server for MCP clients, this MCP server also fulfills two distinct OAuth roles:- An OAuth server to your MCP clients

- An OpenID Connect (OIDC) client for your PingOne environment |

This configuration uses Cloudflare to manage consent. To use this configuration with PingOne DaVinci-managed consent, refer to [Secure a Cloudflare Workers MCP server with PingOne DaVinci](idai-securing-cloudflare-davinci.html).

## Before you begin

This tutorial uses the `remote-mcp-pingone/mcp` directory in Ping Identity's [cloudflare-mcp Git repository](https://github.com/pingidentity/cloudflare-mcp/tree/main).

### Stack

| Role            | Name                                                                                      | Description                                                       |
| --------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| Platform        | [Cloudflare Workers](https://workers.cloudflare.com/)                                     | Serverless execution                                              |
| Framework       | [Hono](https://hono.dev/)                                                                 | Lightweight API endpoints                                         |
| Agent Execution | [Cloudflare Agents SDK](https://developers.cloudflare.com/agents)                         | Base class for implementing the stateful MCP server               |
| Session State   | [Cloudflare Durable Objects](https://developers.cloudflare.com/durable-objects)           | Provides stateful, isolated storage for each MCP connection       |
| OAuth Core      | [Cloudflare Workers OAuth Provider](https://github.com/cloudflare/workers-oauth-provider) | Orchestrates the OAuth flow, delegating authentication to PingOne |
| Ephemeral State | [Cloudflare Workers KV](https://developers.cloudflare.com/kv)                             | Stores OAuth state required by the workers oauth provider         |

### Requirements

* Node.js v20 or later

* A PingOne environment

* A Cloudflare account and [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/install-and-update) enabled

* [Todo API](https://github.com/pingidentity/cloudflare-mcp/tree/main/remote-mcp-pingone/api) deployed

* [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector) installed

### Structure

```
mcp/
├── package.json                     # Dependencies and scripts
├── tsconfig.json                    # TypeScript compiler settings
│── wrangler.jsonc                   # Worker configuration
└── src/
    ├── index.ts                     # OAuth server flow and MCP server routing
    ├── mcp.ts                       # Stateful MCP server as a Cloudflare McpAgent (durable object)
    ├── config.ts                    # Worker bindings and Cloudflare durable object session data
    ├── todoApi.client.ts            # HTTP client to the downstream Todo API
    └── auth/
        ├── workers-oauth-utils.ts   # Cloudflare OAuth utility functions
        ├── ping-handler.ts          # Endpoints that connect the auth flow between OAuth provider and PingOne
        ├── ping-utils.ts            # PingOne OAuth utility functions
        └── ping-types.ts            # PingOne OAuth types
```

## Tasks

### Configuring the MCP server as an OIDC Client in PingOne

This step enables the Cloudflare worker to exchange authorization codes on behalf of the end user. Note that the MCP server, not the MCP client, receives the PingOne access token. The MCP server then issues a separate reference token to the MCP client for session lookups. This distinction ensures proper audience scoping: the MCP client token is intended for the MCP server, while the MCP server token is intended for the target API.

1. In the PingOne admin console, go to **Applications** and click the [icon: plus, set=fa]icon to add a new application.

2. In the **Application Type** section, click **OIDC Web App** and then click **Save**.

3. On the **Configuration** tab of the application, ensure that:

   1. **Grant Type** is set to **Authorization Code**.

   2. **PKCE Enforcement** is set to **S256\_REQUIRED**.

   3. **Redirect URI** is set to your Cloudflare worker's callback endpoint, for example `<mcp_server>/callback`.\
      If the worker is not yet deployed, use a placeholder and update it later.

4. On the **Resources** tab of the application, allow the standard OIDC scopes, `openid` and `profile`, and the Todo API scopes, `todo_api:read` and `tode_api:write`.

5. On the **Policies** tab of the application, enable **Single\_Factor** or your preferred policy.

### Deploying to Cloudflare

1. In your terminal, install dependencies and build:

   ```
   npm install
   npm run build
   ```

2. Use the Wrangler CLI to set the following remote environment variables:

   | Name                       | Description                            | Example                                       |
   | -------------------------- | -------------------------------------- | --------------------------------------------- |
   | `PINGONE_ISSUER`           | PingOne environment domain             | `https://auth.pingone.<REGION>/<ENV_ID>/as`   |
   | `MCP_SERVER_CLIENT_ID`     | ID of the MCP server client            | `0c24f3a0-0522-4f76-9bcf-89643029e3e0`        |
   | `MCP_SERVER_CLIENT_SECRET` | Secret of the MCP server client        | `[A long, random, alphanumeric string]`       |
   | `API_IDENTIFIER`           | ID of the downstream Todo API resource | `https://todo.api.com`                        |
   | `API_URL`                  | URL of the downstream Todo API         | `https://todo-api-ping-aic.<ENV>.workers.dev` |
   | `COOKIE_ENCRYPTION_KEY`    | Key used to sign browser cookies       | `[A long, random, base64 string]`             |

   ```
   wrangler secret put PINGONE_ISSUER
   wrangler secret put MCP_SERVER_CLIENT_ID
   wrangler secret put MCP_SERVER_CLIENT_SECRET
   wrangler secret put API_IDENTIFIER
   wrangler secret put API_URL
   wrangler secret put COOKIE_ENCRYPTION_KEY
   ```

3. Configure remote KV storage.

   ```
   wrangler kv namespace create OAUTH_KV
   ```

   |   |                                                                                         |
   | - | --------------------------------------------------------------------------------------- |
   |   | After running this command, update `wrangler.jsonc` with the generated KV namespace ID. |

4. Deploy to Cloudflare.

   ```
   npm run deploy
   ```

### Testing the MCP Server with the MCP Inspector

The MCP Inspector is a developer tool that allows you to test and debug MCP servers by simulating a client connection. This enables you to validate the authentication flow and tool execution interactively. It confirms that the Cloudflare OAuth Provider successfully captures user consent locally before delegating identity verification to PingOne.

1. Launch the Inspector.

   ```
   npx @modelcontextprotocol/inspector
   ```

   The Inspector starts on port 6277 and initiates the authentication flow. No CORS rules are needed because authentication occurs server-to-server (MCP server to PingOne), bypassing browser restrictions.

   > **Collapse: Authentication flow**
   >
   > 1. The Inspector initiates a request to the MCP endpoint (`<mcp_server>/mcp`).
   >
   > 2. The MCP server intercepts the request and presents the local, worker-hosted consent dialog.
   >
   > 3. Upon approval, the MCP server redirects the user to PingOne for authentication.
   >
   > 4. The MCP server exchanges the returned authorization code for an downstream access token.
   >
   > 5. The server binds this downstream token to a new, isolated client session.
   >
   > 6. The server establishes the connection and issues a session handle to the Inspector.

2. Verify that the MCP server is working properly by using the Inspector to confirm the following behaviour:

   * Connection initiates the full Cloudflare consent and PingOne login sequence.

   * Reconnecting (without clearing cookies and using the same MCP client ID) recovers the existing session silently.

   * Clearing browser cookies forces a new consent and authentication cycle upon reconnect.

   * The server correctly populates the tool list in the Inspector.

   * The `whoAmI` tool returns the PingOne access token audienced for the Todo API.

   * Downstream API actions (adding/deleting todos) complete successfully.

### Accessing the remote MCP server from Claude Desktop

1. In Claude Desktop, click your profile icon, and then click **Settings**.

2. Go to **Connectors** and then click **Add Custom Connector**.

3. In the **Remote MCP server URL** field, enter the URL in this format: `https://remote-mcp-ping-federate.<ENV>.workers.dev/mcp`

   No OAuth Client ID or Secret is required, as Claude will perform Dynamic Client Registration.

4. Click **Save**.

5. Connect to the MCP server and authenticate with PingFederate.

6. After they're connected, you can ask Claude: "Can you tell me what is in my Todo list?"

7. Claude sees the connected tools and calls the appropriate tool after asking for consent.

**Video (Brightcove)**

\<https\://players.brightcove.net/771836189001/default\_default/index.html?videoId=6387826562112>
