MCP OAuth with OCI Identity Domains
This guide describes OAuth protection for the remote MCP server using OCI IAM
Identity Domains. OAuth is optional. With no MCP_OAUTH_* settings, the MCP
server continues to run without bearer-token protection. OAuth is enabled only
when MCP_OAUTH_ENABLED=true.
There are three different roles to keep separate:
Resource server: the MCP API. It owns the audience and scopes and validates access tokens.
Authorization server: OCI IAM Identity Domains. It authenticates users, issues tokens, and manages grants.
OAuth client: the application or MCP client that requests a token and calls the MCP API.
OCI supports configuring one confidential application as both a resource server and an OAuth client. That is a valid option for this deployment. It does not make the MCP server the authorization server: OCI IAM remains the authorization server.
The recommended resource-server scope values are:
read— required for every MCP tool call.update— required only for thereloadoperation.
Depending on the OCI IAM application configuration, the issued token may contain either the configured scope value or a fully qualified scope (FQS). The MCP server must validate the value actually present in the token. In this deployment, the issued token contains the configured values directly:
read— required for every MCP tool call.update— required only for thereloadoperation.
Set MCP_OAUTH_REQUIRED_SCOPES and MCP_OAUTH_UPDATE_SCOPE to the exact
values in the JWT scope claim.
The token request may still require the fully qualified scope. With primary
audience oci-policy-analysis-mcp and configured scope value read, request
oci-policy-analysis-mcpread; OCI IAM then issues a token whose scope claim
is read.
If a different application configuration emits a fully qualified scope, use that exact value instead.
The MCP server validates the token signature, issuer, audience, and read scope. OAuth identifies and authorizes the caller; the MCP server still reads OCI using its configured profile, instance principal, resource principal, or session token.
1. App Creation: resource server, OAuth client, and scopes
Create one Confidential Application in the target OCI IAM Identity Domain. The same application may be configured in both sections below.
Resource-server configuration
Open the Identity Domain and select Integrated applications.
Select Add application → Confidential Application → Launch workflow.
Give the application a name such as
OCI Policy Analysis MCP.In OAuth configuration, enable Configure this application as a resource server now.
Set the Primary audience to a stable value such as
oci-policy-analysis-mcp. This becomesMCP_OAUTH_AUDIENCE; it is not necessarily the client ID.Add these scopes:
read update
The resource-server application defines what access to MCP means. A client must later be granted these scopes before OCI IAM will issue a token that contains them.
Granting access to a group of users
For Authorization Code access, assign the permitted Identity Domain group to the OAuth client application. Users in that group can then authenticate through the application and receive its allowed resource scope. The MCP server validates the resulting token; it does not query Identity Domain group membership during each request.
If the server must enforce a group independently of application assignment, configure an OCI IAM custom token claim containing group membership and add application-level authorization for that claim. Scope validation alone does not distinguish one user group from another.
Client configuration
If this same application will request tokens, also enable Configure this application as a client now and select only the grant types needed by the deployment:
Client Credentials for a public/service-to-service integration.
Authorization Code for a browser-based three-legged integration.
Refresh Token if long-lived user sessions need token renewal.
Resource Owner only for a tightly trusted integration that explicitly collects the user’s credentials. Authorization Code is preferred for interactive users because user credentials are not exposed to the client.
For a separate caller application, configure that application as a client and grant it the MCP resource scopes instead. The resource-server app and caller app do not have to be the same application.
For Authorization Code, register the caller’s exact HTTPS redirect URL in the client application. The redirect URL belongs to the OAuth client handling the browser flow, not to the MCP bearer-token validation endpoint.
Activate the application after saving the configuration. Record:
Identity Domain issuer URL, matching the token
issclaim exactly.Signing certificate JWKS URL, normally ending in
/admin/v1/SigningCert/jwk.Resource-server primary audience.
Authorization server URL.
Client ID and client secret, if the application is configured as a confidential client.
The two resource scopes.
See Oracle’s Register the Application in OCI IAM and Configuring OAuth documentation.
Start the MCP server
Set the OAuth resource-server settings on the container instance and start or restart the existing MCP container:
export MCP_OAUTH_ENABLED="true"
export MCP_OAUTH_ISSUER="https://idcs-<id>.identity.oraclecloud.com/"
export MCP_OAUTH_JWKS_URI="https://idcs-<id>.identity.oraclecloud.com/admin/v1/SigningCert/jwk"
export MCP_OAUTH_AUDIENCE="oci-policy-analysis-mcp"
export MCP_OAUTH_REQUIRED_SCOPES="read"
export MCP_OAUTH_UPDATE_SCOPE="update"
export MCP_OAUTH_RESOURCE_SERVER_URL="https://<mcp-public-host>/mcp"
export MCP_OAUTH_AUTHORIZATION_SERVER_URL="https://idcs-<id>.identity.oraclecloud.com/"
export MCP_OAUTH_ALGORITHM="RS256"
The deployment script or container entrypoint then starts the server with the
configured transport, host, port, and OCI authentication mode. If
MCP_OAUTH_ENABLED=true and a required value is missing, startup fails before
loading tenancy data and prints a setup error.
MCP_OAUTH_REQUIRED_SCOPES is space- or comma-separated and applies to every
MCP tool. MCP_OAUTH_UPDATE_SCOPE is checked separately for reload.
2. Connecting with a Bearer Token
The MCP server is a protected resource. A caller presents an access token in the HTTP request:
curl -i \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}' \
https://<mcp-public-host>/mcp
The JWT should contain:
issequal toMCP_OAUTH_ISSUER.audcontainingMCP_OAUTH_AUDIENCE.scopecontainingread.updateonly for callers allowed to reload.
Expected behavior:
No bearer token: MCP access is rejected.
Read scope: normal search and analysis tools work.
Read without update scope:
reloadis rejected.Read plus update scope:
reloadis authorized, subject to the server’s OCI authentication mode and loaded-data requirements.
Start the MCP server
Use the same environment block from App Creation, then restart the container. No callback is required for this bearer-token connection: the caller obtains the token, and the MCP server only validates it.
3. Two-legged service integration: Client Credentials
Client Credentials is the two-legged machine-to-machine flow. In this section, “public” means an externally reachable service integration; it does not mean an OAuth public client. Client Credentials requires the client to protect its credentials. There is no resource owner signing in through a browser and no callback. The OAuth client authenticates to OCI IAM with its client ID and secret and requests the MCP resource scope.
If using the same app as both resource server and client, grant that app its own MCP scopes under its client Resources configuration. A separate client application can be granted the same scopes instead.
Example token request:
export BASIC_AUTH="$(printf '%s:%s' "$CLIENT_ID" "$CLIENT_SECRET" | base64)"
curl -sS \
-H "Authorization: Basic $BASIC_AUTH" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&scope=oci-policy-analysis-mcpread" \
"https://idcs-<id>.identity.oraclecloud.com/oauth2/v1/token"
Request oci-policy-analysis-mcpupdate only for a service that is authorized
to invoke reload. Use the returned access_token as $ACCESS_TOKEN in the
Bearer Token example. The resulting JWT scope is still validated as update.
Start the MCP server
Start the MCP server with the resource-server environment block from App Creation. The server does not need the client ID or client secret; those remain with the calling service. The server validates the resulting JWT against the issuer, JWKS endpoint, audience, and scopes.
See Oracle’s Client Credentials Grant Type documentation.
Diagnostics and troubleshooting
At MCP_LOG_LEVEL=WARNING, each MCP tool invocation logs the caller and granted
scopes without logging the bearer token or client secret:
MCP OAuth invoke policy_search client_id=<caller> user_displayname=<user> ca_name=<account> scopes=<granted-scopes>
OCI IAM commonly supplies the human-readable fields as user_displayname and
ca_name; the fallback client_id is usually the token subject (sub). These
identity fields are useful for audit diagnostics but are still user data. Keep
the warning logs access-controlled and avoid enabling request-input logging at
INFO in production unless policy text and request filters are acceptable to
store in logs.
Common failures:
issmismatch: copy the exactissvalue from the JWT intoMCP_OAUTH_ISSUER.audmismatch: use the resource server’s primary audience, not the client ID unless they are intentionally identical.Missing scope: grant the client access to the MCP resource scope and request the fully qualified scope from the token endpoint. Configure
MCP_OAUTH_REQUIRED_SCOPESandMCP_OAUTH_UPDATE_SCOPEwith the exact value present in the JWTscopeclaim.JWKS failure: verify that the JWKS endpoint is reachable anonymously by the container.
Reload denied: ensure the token contains the configured
MCP_OAUTH_UPDATE_SCOPEvalue.Callback mismatch: ensure the
redirect_uriexactly matches the URL registered on the OAuth client, including scheme, host, path, and port.