Allow MCP servers to access self-hosted applications
MCP servers often need to call internal applications on behalf of authenticated users. For example, an MCP server that helps employees interact with internal tools needs to forward the user's identity to those downstream services (the internal applications the MCP server connects to) so that each request is authorized with the correct permissions.
The Linked App Token policy selector enables this by allowing an Access policy on one application to accept tokens issued for another. There are two ways to set this up depending on how your MCP server is deployed.
If your MCP server is a self-hosted Access application, Cloudflare Access handles authentication automatically. The MCP server receives the user's JWT from Access in the Cf-Access-Jwt-Assertion header and should forward it to downstream applications in the Cf-Access-Token header. No OAuth implementation is needed in your MCP server code.
flowchart LR
accTitle: Self-hosted MCP server accessing internal applications
User --> client["MCP client"]
client --> mcp["MCP server <br> (self-hosted app)"]
mcp -- "Cf-Access-Token: <JWT>" --> app1["Internal API <br> (self-hosted app)"]
mcp -- "Cf-Access-Token: <JWT>" --> app2["Company wiki <br> (self-hosted app)"]
idp[Identity provider] <--> mcp
- Add your downstream applications (for example, your
Internal APIandCompany wiki) as self-hosted Access applications. - Add your MCP server as a self-hosted Access application.
On each self-hosted application that the MCP server needs to access (for example, the Internal API and Company wiki apps), create a Linked App Token policy:
-
In the Cloudflare dashboard ↗, go to Zero Trust > Access controls > Applications.
-
Select the downstream application and select Edit.
-
Go to the Policies tab and select Create new policy.
-
Set the policy Action to Service Auth.
-
For Selector, select Linked App Token.
-
For Value, select the MCP server application. For example,
Action Rule type Selector Value Service Auth Include Linked App Token mcp-server-app -
Save the policy.
-
In the downstream application, add the policy to the Access policies list.
-
Save the application.
-
Get the
uidof the MCP server application:
At least one of the following token permissions is required:Required API token permissions
Access: Apps and Policies RevokeAccess: Apps and Policies WriteAccess: Apps and Policies Read
List Access applications curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/apps" \--request GET \--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"Response {"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890","uid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890","type": "self_hosted","name": "mcp-server-app",...} -
Create an Access policy on the downstream application, replacing the
app_uidvalue with theuidof the MCP server 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 requests from MCP server","decision": "non_identity","include": [{"linked_app_token": {"app_uid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}]}'
In your MCP server code, forward the Cf-Access-Jwt-Assertion header from incoming requests as the Cf-Access-Token header on outgoing requests to the downstream application:
Cf-Access-Token: <JWT from Cf-Access-Jwt-Assertion>Access will now validate the JWT token against the Linked App Token rule and propagate the user's identity to the downstream application.
If your MCP server is registered as an Access for SaaS OIDC application and implements MCP OAuth ↗, it receives an OAuth access_token from Cloudflare Access. The MCP server forwards this token to downstream self-hosted applications in the Authorization: Bearer header.
This approach requires your MCP server to implement the OAuth authorization code flow. Use the self-hosted MCP server approach if you want Cloudflare to handle authentication for you.
flowchart LR
accTitle: SaaS MCP server accessing internal applications
User --> client["MCP client"]
client --> mcp["MCP server <br> (Access for SaaS app)"]
mcp -- "Authorization: Bearer <token>" --> app1["Internal API <br> (self-hosted app)"]
mcp -- "Authorization: Bearer <token>" --> app2["Company wiki <br> (self-hosted app)"]
idp[Identity provider] <--> mcp
- Add your downstream applications (for example, your
Internal APIandCompany wiki) as self-hosted Access applications. - Add your MCP server as an Access for SaaS OIDC application.
On each self-hosted application that the MCP server needs to access (for example, the Internal API and Company wiki apps), create a Linked App Token policy:
-
In the Cloudflare dashboard ↗, go to Zero Trust > Access controls > Applications.
-
Select the downstream application and select Edit.
-
Go to the Policies tab and select Create new policy.
-
Set the policy Action to Service Auth.
-
For Selector, select Linked App Token.
-
For Value, select the MCP server application. For example,
Action Rule type Selector Value Service Auth Include Linked App Token mcp-server-app -
Save the policy.
-
In the downstream application, add the policy to the Access policies list.
-
Save the application.
-
Get the
uidof the MCP server application:
At least one of the following token permissions is required:Required API token permissions
Access: Apps and Policies RevokeAccess: Apps and Policies WriteAccess: Apps and Policies Read
List Access applications curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/apps" \--request GET \--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"Response {"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890","uid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890","type": "saas","name": "mcp-server-app",...} -
Create an Access policy on the downstream application, replacing the
app_uidvalue with theuidof the MCP server 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 requests from MCP server","decision": "non_identity","include": [{"linked_app_token": {"app_uid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}]}'
Configure the MCP server to forward the access_token in outgoing requests:
Authorization: Bearer ACCESS_TOKEN- The Linked App Token policy can only be added to self-hosted applications. It cannot be added to SaaS applications or other application types.
- This feature works best with applications that rely on the Cloudflare Access JWT for authentication and identity. If the downstream application implements its own authentication layer after Cloudflare Access, requests that pass Access validation may still be rejected by the application itself.