---
title: Protect an MCP server with PingOne Advanced Identity Cloud
description: Tutorial to protect a sample MCP server using PingGateway and PingOne Advanced Identity Cloud as the OAuth 2.0 authorization server
component: pinggateway
version: 2026
page_id: pinggateway:mcp:tutorial-aic
canonical_url: https://docs.pingidentity.com/pinggateway/2026/mcp/tutorial-aic.html
llms_txt: https://docs.pingidentity.com/pinggateway/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
revdate: 2026-09-15T10:10:08Z
keywords: ["AI", "Model Context Protocol", "OAuth 2.1", "Security"]
section_ids:
  before-you-begin: "Task 1: Before you begin"
  configure-as: "Task 2: Prepare Advanced Identity Cloud as the AS"
  configure-gateway: "Task 3: Configure PingGateway"
  start-mcp-agent: "Task 4: Start the MCP agent"
  validate-mcp: Validation
---

# Protect an MCP server with PingOne Advanced Identity Cloud

## Task 1: Before you begin

* Complete the preparation described in [Prepare the sample MCP software](index.html#preparation).

* Make sure you can access the PingOne Advanced Identity Cloud tenant as an administrator.

* Choose the realm to use in the PingOne Advanced Identity Cloud tenant.

  The following tasks use the `alpha` realm.

* Prepare PingGateway as described in [PingGateway and PingOne Advanced Identity Cloud](../aic/preface.html).

  After you follow the instructions to [register the PingGateway agent in Advanced Identity Cloud](../aic/preface.html#register-agent-idc), the PingGateway profile is registered with Advanced Identity Cloud as `ig_agent`.

* Update the agent profile to set the token introspection scope:

  1. Open the AM admin UI at [icon: open_in_new, set=material, size=inline] Native Consoles > Access Management.

  2. In the AM admin UI, go to Applications > Agents > Identity Gateway > ig_agent.

  3. Set Token Introspection to `Realm Only`.

  4. Click Save Changes.

* For other AS options, learn more in:

  * [Protect an MCP server with PingOne](tutorial-pingone.html)

  * [Protect an MCP server with PingFederate](../reference/McpProtectionFilter.html#McpProtectionFilter-example-pingfederate)

## Task 2: Prepare Advanced Identity Cloud as the AS

1. Sign on to the Advanced Identity Cloud admin UI as an administrator.

2. Ensure the OAuth2 Provider for your realm has an OAuth2 Access Token Modification script to support [RFC 8707, Resource Indicators for OAuth 2.0](https://www.rfc-editor.org/rfc/rfc8707.html) as required by MCP.

   If the OAuth2 Provider for your realm already uses an OAuth2 Access Token Modification script, add code to set the audience claim in the access token as shown for the following script.

   To add a new script, go to [icon: code, set=material, size=inline] Scripts > Auth Scripts > New Script > OAuth2 / OIDC > OAuth2 Access Token Modification, click Next, add the following script, and click Save and Close:

   * Name: `MCP aud script`

   * JavaScript:

     ```js
     // Make sure the `audience` claim matches the resource identifier
     (function () {
     	  accessToken.setField("audience", requestProperties.get("requestParams").get("resource").get(0));
     	  // No return value is expected. Leave it undefined.
     	  }());
     ```

     The PingGateway [McpProtectionFilter](../reference/McpProtectionFilter.html) consumes the claim specified in its `"resourceIdPointer"` setting.

3. Using the AM admin UI, update the `OAuth2 Provider` service settings for the realm.

   In the AM admin UI at [icon: open_in_new, set=material, size=inline] Native Consoles > Access Management, go to Services and change the following settings for the `OAuth2 Provider` service:

   * Advanced tab > Client Registration Scope Allowlist: Add `test`.

   * Client Dynamic Registration tab > Allow Open Dynamic Client Registration: Enable and click Save Changes.

   * Plugins tab > Access Token Modification Script: Set to `MCP aud script` if you added it as a new script and click Save Changes.

You have successfully prepared Advanced Identity Cloud to act as the AS.

## Task 3: Configure PingGateway

Previously, you prepared PingGateway for HTTPS as described in [Task 1: Before you begin](#before-you-begin). Now, configure PingGateway to protect the sample MCP server:

1. If the MCP server uses [server-sent events (SSE)](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events), update the `admin.json` file for PingGateway to [enable streaming](../reference/AdminHttpApplication.html#AdminHttpApplication-streamingEnabled), and restart PingGateway.

   Skip this step for the sample MCP server.

2. Add the following route to PingGateway updating `"properties"` as needed for your deployment:

   * Linux

     `$HOME/.openig/config/routes/mcp-aic.json`

   * Windows

     `%appdata%\OpenIG\config\routes\mcp-aic.json`

   ```json
   {
     "name": "mcp-aic",
     "condition": "${find(request.uri.path, '^/aic-mcp')}",
     "properties": {
       "amRealm": "/alpha",
       "gatewayUrl": "https://ig.example.com:8443",
       "mcpServerUrl": "http://localhost:8000",
       "tenantHostname": "myTenant.forgeblocks.com"
     },
     "baseURI": "&{mcpServerUrl}",
     "heap": [
       {
         "name": "AuditService",
         "type": "AuditService",
         "config": {
           "eventHandlers": [
             {
               "class": "org.forgerock.audit.handlers.json.JsonAuditEventHandler",
               "config": {
                 "name": "json",
                 "logDirectory": "&{ig.instance.dir}/audit",
                 "topics": [
                   "access",
                   "mcp"
                 ]
               }
             }
           ]
         }
       },
       {
         "name": "SecretsPasswords",
         "type": "Base64EncodedSecretStore",
         "config": {
           "secrets": {
             "agent.secret.id": "cGFzc3dvcmQ="
           }
         }
       },
       {
         "name": "AmService",
         "type": "AmService",
         "config": {
           "realm": "&{amRealm}",
           "agent": {
             "username": "ig_agent",
             "passwordSecretId": "agent.secret.id"
           },
           "secretsProvider": "SecretsPasswords",
           "sessionCache": {
             "enabled": true
           },
           "url": "https://&{tenantHostname}/am/"
         }
       },
       {
         "name": "rsFilter",
         "type": "OAuth2ResourceServerFilter",
         "config": {
           "scopes": [
             "test"
           ],
           "accessTokenResolver": {
             "type": "TokenIntrospectionAccessTokenResolver",
             "config": {
               "amService": "AmService",
               "providerHandler": {
                 "type": "Chain",
                 "config": {
                   "filters": [
                     {
                       "type": "HttpBasicAuthenticationClientFilter",
                       "config": {
                         "username": "ig_agent",
                         "passwordSecretId": "agent.secret.id",
                         "secretsProvider": "SecretsPasswords"
                       }
                     }
                   ],
                   "handler": "ClientHandler"
                 }
               }
             }
           }
         }
       }
     ],
     "handler": {
       "type": "Chain",
       "capture": "all",
       "config": {
         "filters": [
           {
             "type": "McpAuditFilter",
             "config": {
               "auditService": "AuditService"
             }
           },
           {
             "type": "UriPathRewriteFilter",
             "config": {
               "mappings": {
                 "/aic-mcp": "/"
               }
             }
           },
           {
             "type": "McpProtectionFilter",
             "config": {
               "resourceId": "&{gatewayUrl}/aic-mcp",
               "authorizationServerUri": "https://&{tenantHostname}/am/oauth2/realms/root/realms&{amRealm}",
               "resourceServerFilter": "rsFilter",
               "supportedScopes": [
                 "test"
               ],
               "resourceIdPointer": "/audience"
             }
           },
           {
             "type": "McpValidationFilter",
             "config": {
               "acceptedOrigins": ".*"
             }
           }
         ],
         "handler": {
           "type": "ReverseProxyHandler",
           "config": {
             "soTimeout": "20 seconds"
           }
         }
       }
     }
   }
   ```

   Source: [mcp-aic.json](../_attachments/config/routes/mcp-aic.json)

   Notice the following features of the route:

   * The sample route uses a base-64 encoded secret to connect to the AS. In production, don't include secrets in route files.

   * PingGateway acts as an OAuth 2.1 resource server (RS) when protecting the sample MCP server.

   * The [McpAuditFilter](../reference/McpAuditFilter.html) audits MCP requests. PingGateway records MCP audit events in an `audit/mcp.audit.json` file.

   * The [UriPathRewriteFilter](../reference/UriPathRewriteFilter.html) sends the request to the root resource of the MCP server. The MCP server expects requests at `/`.

   * The [McpProtectionFilter](../reference/McpProtectionFilter.html) uses the RS configuration, extending it for MCP.

   * PingGateway validates MCP requests with an [McpValidationFilter](../reference/McpValidationFilter.html).

   * The [ReverseProxyHandler](../reference/ReverseProxyHandler.html) uses a long `"soTimeout"` setting to accommodate an MCP agent receiving few or infrequent SSE updates.

   This simple route doesn't show [throttling](../reference/ThrottlingPolicies.html) or fine-grained access control. Add those features as needed to meet your security requirements.

3. Verify the PingGateway log shows the route loaded successfully.

You have successfully configured PingGateway to protect the sample MCP server.

## Task 4: Start the MCP agent

In the directory where you unpacked the sample MCP agent, start the sample MCP agent again. This time, point it to the PingGateway route for MCP requests:

```console
$ python3 sample-mcp-agent.py --mcp-server-url https://ig.example.com:8443/aic-mcp
```

You have successfully started the sample MCP agent.

## Validation

With PingGateway protecting the MCP server, the sample MCP agent directs your browser to the AS to sign on as an end user and authorize access to make MCP requests. If it can't open the browser, the sample MCP agent shows the URL you can paste into a private or incognito window.

1. Sign on with the end-user credentials (username: `demo` password: `Ch4ng3!t`) and consent to the requested `test` scope before closing the browser tab as prompted.

   You set these credentials when you [set up a demo user in PingOne Advanced Identity Cloud](../aic/preface.html#setup-user-idc).

2. In the terminal where the sample MCP agent runs, notice the available commands:

   ```text
   [INFO] Discovered tools [https://ig.example.com:8443/aic-mcp]:
   [INFO] - geocode: Returns a list of objects containing city name, latitude, longitude, country, admin1 (region), and timezone for each matching city
   [INFO] - forecast_daily: Returns a multi-day weather forecast for a given location
   [INFO] - forecast_periods: Returns weather forecasts for each representative period of the current day
   [INFO] - forecast_hourly: Returns an hourly weather forecast for the current day
   [INFO] - weather_at_time: Returns the forecasted weather for a specific time at a given location

   Enter your message (or 'exit|quit|q'):
   ```

3. Enter a prompt and get a response from the MCP server through PingGateway, then exit the agent:

   The following example uses the `forecast_daily` tool to get the daily forecast for Tokyo:

   ```text
   Enter your message (or 'exit|quit|q'): What is the daily forecast for Tokyo?
   Agent: The daily forecast for Tokyo is:

   <MCP server response with forecast details>

   Enter your message (or 'exit|quit|q'): exit
   User requested exit. Goodbye!
   ```

   Find additional details about the MCP request in the PingGateway log.

You have successfully validated PingGateway can protect the MCP server.
