Authenticate MCP server to self-hosted apps
Cloudflare Access can delegate access from any self-hosted application to an Access for SaaS MCP server via OAuth ↗. The OAuth access token authorizes the MCP server to make requests to your self-hosted applications on behalf of the user, using the user's specific permissions and scopes.
For example, your organization may wish to deploy an MCP server that helps employees interact with internal applications. You can configure Access policies to ensure that only authorized users can access those applications, either directly or by using an MCP client.
flowchart LR
accTitle: Link MCP servers and self-hosted applications in Access
subgraph SaaS["Access for SaaS <br> OIDC app"]
mcp["MCP server <br> for internal apps"]
end
subgraph "Access self-hosted app"
app1[Admin dashboard]
end
subgraph "Access self-hosted app"
app2[Company wiki]
end
User --> client["MCP client"]
client --> mcp
mcp -- Access token --> app1
mcp -- Access token --> app2
idp[Identity provider] <--> SaaS
This guide covers how to use the Cloudflare API to link a self-hosted application to a remote MCP server. The core of this feature is the linked_app_token rule type, which allows an Access policy on one application to accept OAuth access tokens generated for another.
The first step is to add the MCP server to Cloudflare Access as an OIDC-based SaaS application. For step-by-step instructions on how to add an MCP server, refer to Secure MCP servers with Access for SaaS.
Get the id of the MCP server SaaS application:
Required API token permissions
At least one of the following token permissions
is required:
Access: Apps and Policies RevokeAccess: Apps and Policies WriteAccess: Apps and Policies Read
curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/apps" \ --request GET \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"{ "id": "3537a672-e4d8-4d89-aab9-26cb622918a1", "uid": "3537a672-e4d8-4d89-aab9-26cb622918a1", "type": "saas", "name": "mcp-server-cf-access", ...}-
Create the following Access policy, replacing the
app_uidvalue with theidof your SaaS application:
At least one of the following token permissions is required:Required API token permissions
Access: Apps and Policies Write
Create an Access reusable policy curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/policies" \--request POST \--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \--json '{"name": "Allow MCP server","decision": "non_identity","include": [{"linked_app_token": {"app_uid": "3537a672-e4d8-4d89-aab9-26cb622918a1"}}]}' -
Copy the Access policy
idreturned in the response:Response {"created_at": "2025-08-06T20:06:23Z","decision": "non_identity","exclude": [],"id": "a38ab4d4-336d-4f49-9e97-eff8550c13fa","include": [{"linked_app_token": {"app_uid": "6cdc3892-f9f1-4813-a5ce-38c2753e1208"}}],"name": "Allow MCP server",...}
This policy will allow requests if they present a valid OAuth access token that was issued for the specified SaaS application.
You can add the linked_app_token policy to any self_hosted application in your Zero Trust account. Other app types (such as saas) are not currently supported.
-
Get your existing self-hosted application configuration:
At least one of the following token permissions is required:Required API token permissions
Access: Apps and Policies WriteAccess: Apps and Policies Read
Get an Access application curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/apps/$APP_ID" \--request GET \--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" -
Add the Access policy to the self-hosted application. To avoid overwriting your existing configuration, the
PUTrequest body should contain all fields returned by the previousGETrequest.
At least one of the following token permissions is required:Required API token permissions
Access: Apps and Policies Write
Update an Access application curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/apps/$APP_ID" \--request PUT \--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \--json '{"policies": ["a38ab4d4-336d-4f49-9e97-eff8550c13fa"]}'
With the policy in place, every API request to the self-hosted application must now include a valid access_token from Cloudflare Access. You will need to configure the MCP server to forward the access_token in an HTTP request header:
Authorization: Bearer ACCESS_TOKENThe end-to-end authorization flow is as follows:
- The MCP server authenticates against the Access for SaaS app via OAuth.
- Upon success, the MCP server receives an
access_token. - The MCP server makes an API request to the self-hosted application with the token in the request headers.
- Cloudflare Access intercepts the request to the self-hosted app, inspects the token, and validates it against the
linked_app_tokenrule in the policy. - If the token is valid and was issued for the linked SaaS app, the request is allowed. Otherwise, it is blocked.
The MCP OAuth feature only works with self-hosted applications that rely on the Cloudflare Access JWT to authenticate and identify the user. If the application implements its own layer of authentication after Cloudflare Access, then this feature is at best a partial solution. Requests that are successfully authenticated by Access may still be blocked by the application itself, resulting in an HTTP 401 or 403 error.
Was this helpful?
- Resources
- API
- New to Cloudflare?
- Directory
- Sponsorships
- Open Source
- Support
- Help Center
- System Status
- Compliance
- GDPR
- Company
- cloudflare.com
- Our team
- Careers
- © 2025 Cloudflare, Inc.
- Privacy Policy
- Terms of Use
- Report Security Issues
- Trademark