From 5bd8a1e5e23a91385826eb8f2ca80bd4626e401d Mon Sep 17 00:00:00 2001 From: Kenneth Johnson Date: Thu, 30 Jul 2026 13:44:52 -0500 Subject: [PATCH 1/3] [Access] Document MCP portal Code Mode policies --- ...26-07-30-mcp-portal-code-mode-policies.mdx | 25 ++++++ .../ai-controls/mcp-portals.mdx | 77 +++++++++---------- 2 files changed, 61 insertions(+), 41 deletions(-) create mode 100644 src/content/changelog/access/2026-07-30-mcp-portal-code-mode-policies.mdx diff --git a/src/content/changelog/access/2026-07-30-mcp-portal-code-mode-policies.mdx b/src/content/changelog/access/2026-07-30-mcp-portal-code-mode-policies.mdx new file mode 100644 index 00000000000..0f4844fce97 --- /dev/null +++ b/src/content/changelog/access/2026-07-30-mcp-portal-code-mode-policies.mdx @@ -0,0 +1,25 @@ +--- +title: Code Mode policies for MCP server portals +description: MCP server portals now support four Code Mode policies that control default behavior and client overrides. +date: 2026-07-30 +products: + - access +--- + +[MCP server portals](/cloudflare-one/access-controls/ai-controls/mcp-portals/) now support four Code Mode policies: _Off_, _Opt-in_, _On by default_, and _Enforced_. Admins can choose whether Code Mode is unavailable, optional, enabled by default, or required for every session. + +Existing portals retain their current behavior. Portals that previously allowed Code Mode use _Opt-in_, while portals that did not allow Code Mode use _Off_. New portals also use _Opt-in_ by default. + +Clients turn on Code Mode for an _Opt-in_ portal with `?codemode=search_and_execute`. The _On by default_ policy lets clients opt out with `?codemode=off`, which avoids nested code execution when a client runs its own Code Mode implementation. The _Off_ and _Enforced_ policies ignore client overrides. + +The Cloudflare API exposes these policies through the `code_mode` field: + +```json +{ + "code_mode": "default_on" +} +``` + +The supported values are `off`, `opt_in`, `default_on`, and `enforced`. The previous `allow_code_mode` boolean is deprecated. + +For configuration details and client behavior, refer to [Code Mode policies](/cloudflare-one/access-controls/ai-controls/mcp-portals/#code-mode-policies). diff --git a/src/content/docs/cloudflare-one/access-controls/ai-controls/mcp-portals.mdx b/src/content/docs/cloudflare-one/access-controls/ai-controls/mcp-portals.mdx index 873b48c664b..db89cf9abb0 100644 --- a/src/content/docs/cloudflare-one/access-controls/ai-controls/mcp-portals.mdx +++ b/src/content/docs/cloudflare-one/access-controls/ai-controls/mcp-portals.mdx @@ -33,7 +33,7 @@ MCP server portals provide the following capabilities: - **Non-browser client support**: MCP clients authenticate to the portal using a standard OAuth 2.0 authorization code flow via [managed OAuth](/cloudflare-one/access-controls/applications/http-apps/managed-oauth/). This managed OAuth configuration applies to the portal's Access application. It is separate from upstream OAuth used by individual MCP servers in the portal. Non-browser clients receive a `401` response with a `WWW-Authenticate` header pointing to Access's OAuth discovery endpoints, rather than a browser redirect. You can also connect using [Access service tokens](#connect-with-a-service-token) for machine-to-machine access. -- **Code Mode**: Code Mode is available by default on all portals. It collapses all upstream tools into a single `code` tool. The AI agent writes JavaScript that calls typed methods for each tool, and the code runs in an isolated [Dynamic Worker](/workers/runtime-apis/bindings/worker-loader/) environment. This keeps context window usage fixed regardless of how many tools are available. Refer to [Code Mode](#code-mode) for connection instructions. +- **Code Mode**: Code Mode collapses all upstream tools into two tools for search and code execution. The AI agent writes JavaScript that calls typed methods for each tool. The code runs in an isolated [Dynamic Worker](/workers/runtime-apis/bindings/worker-loader/) environment. Admins can control whether Code Mode is unavailable, optional, on by default, or required. Refer to [Code Mode](#code-mode) for configuration and connection instructions. - **Observability**: Once the user's AI agent is connected to the portal, Cloudflare Access logs the individual requests made using the tools in the portal. You can optionally route portal traffic through [Cloudflare Gateway](#route-portal-traffic-through-gateway) for richer HTTP logging and data loss prevention (DLP) scanning. @@ -531,7 +531,7 @@ Unlike the dashboard, the API does not automatically create a DNS record for you json={{ name: "Engineering Portal", hostname: "mcp.example.com", - allow_code_mode: true, + code_mode: "opt_in", secure_web_gateway: false, }} /> @@ -615,17 +615,45 @@ For the full list of supported resource arguments, refer to the [Terraform provi ## Code Mode -[Code Mode](/agents/tools/codemode/) is turned on by default on all MCP server portals. It reduces context window usage by collapsing all tools in the portal into a single `code` tool. Instead of loading a separate tool definition for each upstream MCP server tool, the connected AI agent writes JavaScript that calls typed `codemode.*` methods. The generated code runs in an isolated [Dynamic Worker](/workers/runtime-apis/bindings/worker-loader/) environment, which keeps authentication credentials and environment variables out of the model context. +[Code Mode](/agents/tools/codemode/) reduces context window usage by replacing upstream tool definitions with two tools for search and code execution. The connected AI agent writes JavaScript that calls typed `codemode.*` methods. The generated code runs in an isolated [Dynamic Worker](/workers/runtime-apis/bindings/worker-loader/) environment. Authentication credentials and environment variables remain outside the model context. -To use Code Mode, the MCP client must request it when connecting to the portal URL. Refer to [Connect with Code Mode](#connect-with-code-mode) for the required query parameter. +Code Mode is useful for portals with many MCP servers or tools. Context window usage stays fixed as the portal adds tools. -Code Mode is useful for portals that aggregate many MCP servers or servers that expose a large number of tools. Context window usage stays fixed regardless of how many tools are available through the portal. +### Code Mode policies + +Each portal has a Code Mode policy. The default policy is _Opt-in_. + +| Policy | API value | Default behavior | Client override | +| ------------- | ------------ | ------------------------ | ------------------------------------------------------ | +| Off | `off` | Code Mode is unavailable | Query parameters are ignored | +| Opt-in | `opt_in` | Code Mode is off | Add `?codemode=search_and_execute` to turn it on | +| On by default | `default_on` | Code Mode is on | Add `?codemode=off` to turn it off | +| Enforced | `enforced` | Code Mode is on | Query parameters are ignored | + +Use _Opt-in_ or _On by default_ if some clients run their own Code Mode implementation. These policies let clients avoid nested code execution. + +### Configure a Code Mode policy + + +1. Get your existing MCP portal configuration: + + + +2. Add `code_mode` to the response body. Set the value to `off`, `opt_in`, `default_on`, or `enforced`. +3. Send the complete body in a `PUT` request to the [Update a MCP Portal](/api/resources/zero_trust/subresources/access/subresources/ai_controls/subresources/mcp/subresources/portals/methods/update/) endpoint. Including the complete body prevents other portal settings from being overwritten. + + +The `allow_code_mode` API field is deprecated. Use `code_mode` for new integrations. ### Connect with Code Mode -To use Code Mode, append the `?codemode=search_and_execute` query string parameter to your portal URL when [connecting](#connect-to-a-portal) from an MCP client. +The portal policy determines whether the MCP client needs a query parameter. For _Opt-in_, append `?codemode=search_and_execute` to the portal URL. For _On by default_, clients can append `?codemode=off` instead. -For example, if your portal URL is `https://./mcp`, connect to: +For example, an _Opt-in_ portal at `https://./mcp` uses this URL: ```txt https://./mcp?codemode=search_and_execute @@ -648,43 +676,10 @@ For MCP clients with server configuration files, use the portal URL with the que } ``` -When Code Mode is active, the portal advertises a single `code` tool to connected MCP clients. The AI agent discovers available tools by inspecting the typed method signatures in the Dynamic Worker environment and composes multiple tool calls into a single code execution. +When Code Mode is active, the portal advertises `portal_codemode_search` and `portal_codemode_execute`. The AI agent can discover tools and compose multiple tool calls in one execution. For more information on building with Code Mode, refer to the [Code Mode SDK reference](/agents/tools/codemode/api-reference/). -### Turn off Code Mode - -To turn off Code Mode for a portal: - - - -1. In the [Cloudflare dashboard](https://dash.cloudflare.com/), go to **Zero Trust** > **Access controls** > **AI controls**. -2. Find the portal you want to configure, then select the three dots > **Edit**. -3. Under **Basic information**, turn off **Code Mode**. - - - -1. Get your existing MCP portal configuration: - - - -2. Send a `PUT` request to the [Update a MCP Portal](/api/resources/zero_trust/subresources/access/subresources/ai_controls/subresources/mcp/subresources/portals/methods/update/) endpoint with `allow_code_mode` set to `false`. To avoid overwriting your existing configuration, the `PUT` request body should contain all fields returned by the previous `GET` request. - - - - - ## Route portal traffic through Gateway When Gateway routing is turned on, calls to MCP servers protected by your MCP server portal are routed through [Cloudflare Gateway](/cloudflare-one/traffic-policies/). This makes portal traffic appear in your [Gateway HTTP logs](/cloudflare-one/insights/logs/dashboard-logs/gateway-logs/) alongside the rest of your organization's HTTP traffic. You can then create [Data Loss Prevention (DLP) policies](#example-gateway-policy) to detect and block sensitive data from being sent to your upstream MCP servers. From b51f535b80185df6511436482b552a4518ac9d17 Mon Sep 17 00:00:00 2001 From: Kenneth Johnson Date: Thu, 30 Jul 2026 13:48:23 -0500 Subject: [PATCH 2/3] [Access] Emphasize default-on Code Mode --- .../access/2026-07-30-mcp-portal-code-mode-policies.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/changelog/access/2026-07-30-mcp-portal-code-mode-policies.mdx b/src/content/changelog/access/2026-07-30-mcp-portal-code-mode-policies.mdx index 0f4844fce97..9be4f33727e 100644 --- a/src/content/changelog/access/2026-07-30-mcp-portal-code-mode-policies.mdx +++ b/src/content/changelog/access/2026-07-30-mcp-portal-code-mode-policies.mdx @@ -1,6 +1,6 @@ --- -title: Code Mode policies for MCP server portals -description: MCP server portals now support four Code Mode policies that control default behavior and client overrides. +title: Admins can turn on Code Mode by default for MCP portal users +description: New MCP portal policies let admins turn on Code Mode by default, drastically reducing token usage from large tool catalogs. date: 2026-07-30 products: - access From 59380349d5249d5a7a44fd7a17836378fa30abb0 Mon Sep 17 00:00:00 2001 From: Kenneth Johnson Date: Thu, 6 Aug 2026 11:05:05 -0500 Subject: [PATCH 3/3] [Access] Format MCP portal documentation --- .../ai-controls/mcp-portals.mdx | 117 ++++++++---------- 1 file changed, 52 insertions(+), 65 deletions(-) diff --git a/src/content/docs/cloudflare-one/access-controls/ai-controls/mcp-portals.mdx b/src/content/docs/cloudflare-one/access-controls/ai-controls/mcp-portals.mdx index db89cf9abb0..5ad49fde821 100644 --- a/src/content/docs/cloudflare-one/access-controls/ai-controls/mcp-portals.mdx +++ b/src/content/docs/cloudflare-one/access-controls/ai-controls/mcp-portals.mdx @@ -24,17 +24,11 @@ This guide explains how to add MCP servers to Cloudflare Access, create an MCP p MCP server portals provide the following capabilities: - **Streamlined access to multiple MCP servers**: MCP server portals support both unauthenticated MCP servers and MCP servers secured using OAuth (for example, via [Access for SaaS](/cloudflare-one/access-controls/ai-controls/secure-mcp-servers/) or a [third-party OAuth provider](/agents/model-context-protocol/protocol/authorization/)). Users log in to the portal URL through Cloudflare Access and are prompted to authenticate separately to each server that requires OAuth. - - **Customized tools per portal**: Admins can tailor an MCP portal to a particular use case by choosing the specific tools and prompt templates that they want to make available to users through the portal. This allows users to access a curated set of tools and prompts — the less external context exposed to the AI model, the better the AI responses tend to be. - - **Tool and prompt aliases**: Admins can [rename tools and prompts](#rename-tools-and-prompts-with-aliases) and edit their descriptions at the portal or server level without modifying the upstream MCP server. Aliases help end users find the right tool and help AI agents select the correct one. - - **Context optimization**: Portals support query parameter options that reduce context window usage by minimizing or hiding tool definitions. Refer to [Optimize context](#optimize-context) for details. - - **Non-browser client support**: MCP clients authenticate to the portal using a standard OAuth 2.0 authorization code flow via [managed OAuth](/cloudflare-one/access-controls/applications/http-apps/managed-oauth/). This managed OAuth configuration applies to the portal's Access application. It is separate from upstream OAuth used by individual MCP servers in the portal. Non-browser clients receive a `401` response with a `WWW-Authenticate` header pointing to Access's OAuth discovery endpoints, rather than a browser redirect. You can also connect using [Access service tokens](#connect-with-a-service-token) for machine-to-machine access. - - **Code Mode**: Code Mode collapses all upstream tools into two tools for search and code execution. The AI agent writes JavaScript that calls typed methods for each tool. The code runs in an isolated [Dynamic Worker](/workers/runtime-apis/bindings/worker-loader/) environment. Admins can control whether Code Mode is unavailable, optional, on by default, or required. Refer to [Code Mode](#code-mode) for configuration and connection instructions. - - **Observability**: Once the user's AI agent is connected to the portal, Cloudflare Access logs the individual requests made using the tools in the portal. You can optionally route portal traffic through [Cloudflare Gateway](#route-portal-traffic-through-gateway) for richer HTTP logging and data loss prevention (DLP) scanning. ## How it works @@ -55,11 +49,11 @@ For servers that use automatic OAuth registration, background synchronization of The portal connects to upstream MCP servers using [Streamable HTTP](https://spec.modelcontextprotocol.io/specification/2025-03-26/basic/transports/#streamable-http) or [SSE](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#server-sent-events-sse-deprecated) transport. You do not need to specify which transport your upstream server uses. The portal automatically detects the correct transport by trying multiple connection strategies in order: -| Upstream URL pattern | Connection strategies (in order) | -| -------------------- | -------------------------------- | -| Ends in `/mcp` | Streamable HTTP only | -| Ends in `/sse` | SSE (or Streamable HTTP if Gateway routing is turned on) | -| All other URLs | Streamable HTTP on original URL, then SSE on original URL, then Streamable HTTP on `{url}/mcp`, then SSE on `{url}/sse` | +| Upstream URL pattern | Connection strategies (in order) | +| -------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| Ends in `/mcp` | Streamable HTTP only | +| Ends in `/sse` | SSE (or Streamable HTTP if Gateway routing is turned on) | +| All other URLs | Streamable HTTP on original URL, then SSE on original URL, then Streamable HTTP on `{url}/mcp`, then SSE on `{url}/sse` | If a connection attempt returns a `404`, `405`, or `406` error, the portal falls back to the next strategy. All other errors stop the connection attempt. @@ -67,17 +61,17 @@ If a connection attempt returns a `404`, `405`, or `406` error, the portal falls Every portal exposes the following built-in tools to MCP clients, in addition to the upstream server tools: -| Tool | Description | -| ---- | ----------- | -| `portal_list_servers` | Lists all available upstream servers with their ID, name, and whether they are currently turned on. | -| `portal_toggle_servers` | Opens a URL-based server selection page where you can turn servers on or off. | -| `portal_toggle_single_server` | Turns a single server on or off by server ID, without leaving the MCP client. | +| Tool | Description | +| ----------------------------- | --------------------------------------------------------------------------------------------------- | +| `portal_list_servers` | Lists all available upstream servers with their ID, name, and whether they are currently turned on. | +| `portal_toggle_servers` | Opens a URL-based server selection page where you can turn servers on or off. | +| `portal_toggle_single_server` | Turns a single server on or off by server ID, without leaving the MCP client. | When [context optimization](#optimize-context) is turned on, additional tools are exposed depending on the mode: -| Mode | Additional tools | -| ---- | ---------------- | -| `minimize_tools` | `portal_query_tools` — Search tools by regex pattern and return full definitions. | +| Mode | Additional tools | +| -------------------- | ------------------------------------------------------------------------------------ | +| `minimize_tools` | `portal_query_tools` — Search tools by regex pattern and return full definitions. | | `search_and_execute` | `portal_query_tools` and `portal_execute` — Search tools and execute them via proxy. | ### Session lifecycle @@ -154,28 +148,27 @@ Manual credentials require per-user authentication. Leave **Require user auth** [MCP Apps](https://modelcontextprotocol.io/extensions/apps/overview) — tools that declare a UI resource in their description — will also be available after successfully connecting to an MCP server. A list of MCP clients that support MCP Apps is available in the [Extension Support Matrix](https://modelcontextprotocol.io/extensions/client-matrix). - ### Server status The MCP server status indicates the synchronization status of the MCP server to Cloudflare Access. -| Status | Description | -| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Error | The server could not be reached or returned an error. Refer to [error details](#error-details) for more information. To fix the issue, [reauthenticate the server](#reauthenticate-the-mcp-server). | -| Sync Required | The server's OAuth credentials can no longer be refreshed and the server needs to be reauthenticated. To fix the issue, [reauthenticate the server](#reauthenticate-the-mcp-server). | -| Waiting | The server's tools, prompts, and resources are being synchronized. A server with manual OAuth credentials remains in this state until its first user completes upstream OAuth. | -| Ready | The server was successfully synchronized and all tools, prompts, and resources are available. | +| Status | Description | +| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Error | The server could not be reached or returned an error. Refer to [error details](#error-details) for more information. To fix the issue, [reauthenticate the server](#reauthenticate-the-mcp-server). | +| Sync Required | The server's OAuth credentials can no longer be refreshed and the server needs to be reauthenticated. To fix the issue, [reauthenticate the server](#reauthenticate-the-mcp-server). | +| Waiting | The server's tools, prompts, and resources are being synchronized. A server with manual OAuth credentials remains in this state until its first user completes upstream OAuth. | +| Ready | The server was successfully synchronized and all tools, prompts, and resources are available. | #### Error details When an MCP server is in the **Error** or **Sync Required** state, Cloudflare Access surfaces structured information to help you diagnose the issue. In the dashboard, hover over the server's status to view the error message, the error category (upstream or connection), the HTTP status code, and the MCP protocol error code (if applicable). The same details are returned by the API as an `error_details` object: -| Field | Description | -| --- | --- | -| `message` | A human-readable description of the error. | -| `type` | The category of error — for example, `upstream_error` (the server returned an error response) or `unreachable` (the server could not be contacted). | -| `http_status_code` | The HTTP status code returned by the upstream server, if applicable. | -| `mcp_error_code` | The MCP protocol error code, if the server returned an MCP-level error. | +| Field | Description | +| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| `message` | A human-readable description of the error. | +| `type` | The category of error — for example, `upstream_error` (the server returned an error response) or `unreachable` (the server could not be contacted). | +| `http_status_code` | The HTTP status code returned by the upstream server, if applicable. | +| `mcp_error_code` | The MCP protocol error code, if the server returned an MCP-level error. | Common causes of server errors include expired OAuth credentials, unreachable server URLs, and upstream server misconfigurations. If the error type is `upstream_error`, check the HTTP and MCP error codes to identify the issue on the upstream server. If the type is `unreachable`, verify that the server URL is correct and accessible. @@ -245,7 +238,6 @@ To create an MCP server portal: 5. [Add MCP servers](#add-an-mcp-server) to the portal. 6. (Optional) Under **MCP servers**, [configure the tools and prompts](#manage-tools-and-prompts) available through the portal. 7. (Optional) Configure **Require user auth** for servers that support OAuth: - `Enabled`: (default) User will be prompted to utilize their own login credentials to establish a connection with the MCP server. - `Disabled`: Users who are connected to the portal will automatically have access to the MCP server via its [admin credential](#reauthenticate-the-mcp-server). - 8. Add [Access policies](/cloudflare-one/access-controls/policies/) to define the users who can connect to the portal URL. :::caution @@ -438,11 +430,11 @@ Choose short, descriptive server IDs when you plan to expose the server through The portal splits namespaced names on the **first** underscore only. Everything before the first underscore is the server ID, and everything after it is the tool or prompt name. This means tool names can contain underscores without ambiguity. -| Namespaced name | Server ID | Tool name | -| --- | --- | --- | -| `github_list_issues` | `github` | `list_issues` | -| `github_create_pull_request` | `github` | `create_pull_request` | -| `sentry_get_issue_details` | `sentry` | `get_issue_details` | +| Namespaced name | Server ID | Tool name | +| ---------------------------- | --------- | --------------------- | +| `github_list_issues` | `github` | `list_issues` | +| `github_create_pull_request` | `github` | `create_pull_request` | +| `sentry_get_issue_details` | `sentry` | `get_issue_details` | Because the split happens on the first underscore, server IDs themselves cannot contain underscores. Use hyphens instead when you need a multi-word server ID (for example, `my-server`). @@ -463,7 +455,6 @@ This sanitization happens automatically. You do not need to call any helper func If you are building an MCP client with the [Agents SDK](/agents/model-context-protocol/apis/client-api/), the SDK provides helper functions for working with server IDs and tool names: - **`normalizeServerId`** (exported from `agents/mcp/client`) normalizes a caller-supplied server ID into a safe string. For example, `"GitHub MCP!"` becomes `"github-mcp"`. The SDK calls this automatically when you pass an `id` option to `addMcpServer()`. - - **`sanitizeToolName`** (exported from `@cloudflare/codemode`) converts a tool name into a valid JavaScript identifier by replacing hyphens and dots with underscores. This is called automatically in Code Mode contexts. Refer to the [Code Mode SDK reference](/agents/tools/codemode/api-reference/#code-and-output-utilities) for details. :::note @@ -478,10 +469,10 @@ In addition to upstream MCP server tools, the portal exposes its own built-in to The following tools are available in every portal session, regardless of the connection mode: -| Tool | Description | -| --- | --- | -| `portal_list_servers` | Lists all upstream MCP servers with their IDs, names, and whether they are currently enabled in the session. | -| `portal_toggle_servers` | Opens a server selection flow. Returns a URL that the user visits in a browser to enable or disable servers and manage OAuth credentials. | +| Tool | Description | +| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `portal_list_servers` | Lists all upstream MCP servers with their IDs, names, and whether they are currently enabled in the session. | +| `portal_toggle_servers` | Opens a server selection flow. Returns a URL that the user visits in a browser to enable or disable servers and manage OAuth credentials. | | `portal_toggle_single_server` | Toggles a single server on or off without requiring a browser visit. Accepts a `server_id` and an `action` (`toggle` or `untoggle`). If the server requires OAuth and the user has not authenticated yet, the portal falls back to the browser-based `portal_toggle_servers` flow. | These tools power the [session management](#manage-portal-sessions) features described later in this guide. AI agents call them automatically when you ask to enable a server, disable a server, or return to the server selection page. @@ -490,18 +481,18 @@ These tools power the [session management](#manage-portal-sessions) features des When you connect with the [`optimize_context`](#optimize-context) query parameter, the portal exposes additional tools for discovering and calling upstream tools: -| Tool | Available in | Description | -| --- | --- | --- | +| Tool | Available in | Description | +| -------------------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `portal_query_tools` | `minimize_tools`, `search_and_execute` | Searches upstream tools by name, description, or schema using a regex pattern. Returns full tool definitions so the agent can call them. Required in `minimize_tools` mode because upstream tool schemas are stripped to reduce context size. | -| `portal_execute` | `search_and_execute` | Calls an upstream tool by name with the provided arguments. In `search_and_execute` mode, upstream tools are hidden from the tool list entirely, so agents must use `portal_query_tools` to discover them and `portal_execute` to call them. | +| `portal_execute` | `search_and_execute` | Calls an upstream tool by name with the provided arguments. In `search_and_execute` mode, upstream tools are hidden from the tool list entirely, so agents must use `portal_query_tools` to discover them and `portal_execute` to call them. | #### Code Mode tools When you connect with [Code Mode](#code-mode) enabled, the portal replaces all upstream tools with two code execution tools: -| Tool | Description | -| --- | --- | -| `portal_codemode_search` | Searches available tools by running JavaScript in a sandboxed Worker. The sandbox provides a `codemode.tools()` function that returns all upstream tool definitions with sanitized names. | +| Tool | Description | +| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `portal_codemode_search` | Searches available tools by running JavaScript in a sandboxed Worker. The sandbox provides a `codemode.tools()` function that returns all upstream tool definitions with sanitized names. | | `portal_codemode_execute` | Calls upstream tools by running JavaScript in a sandboxed Worker. The sandbox provides a `codemode` proxy object where each property maps to an upstream tool. Supports `Promise.all()` for parallel tool calls. | Refer to the [Code Mode SDK reference](/agents/tools/codemode/api-reference/) for details on writing code for these tools. @@ -623,12 +614,12 @@ Code Mode is useful for portals with many MCP servers or tools. Context window u Each portal has a Code Mode policy. The default policy is _Opt-in_. -| Policy | API value | Default behavior | Client override | -| ------------- | ------------ | ------------------------ | ------------------------------------------------------ | -| Off | `off` | Code Mode is unavailable | Query parameters are ignored | -| Opt-in | `opt_in` | Code Mode is off | Add `?codemode=search_and_execute` to turn it on | -| On by default | `default_on` | Code Mode is on | Add `?codemode=off` to turn it off | -| Enforced | `enforced` | Code Mode is on | Query parameters are ignored | +| Policy | API value | Default behavior | Client override | +| ------------- | ------------ | ------------------------ | ------------------------------------------------ | +| Off | `off` | Code Mode is unavailable | Query parameters are ignored | +| Opt-in | `opt_in` | Code Mode is off | Add `?codemode=search_and_execute` to turn it on | +| On by default | `default_on` | Code Mode is on | Add `?codemode=off` to turn it off | +| Enforced | `enforced` | Code Mode is on | Query parameters are ignored | Use _Opt-in_ or _On by default_ if some clients run their own Code Mode implementation. These policies let clients avoid nested code execution. @@ -815,11 +806,11 @@ A service token session is authorized twice: once at the portal URL, and once fo #### Required configuration -| Where | Policy action | Include rule | Purpose | -| --- | --- | --- | --- | -| Portal Access application | Service Auth | Your service token | Lets the bot connect to the portal URL. | -| Each linked MCP server Access app | Service Auth | Your service token | Lets the bot see and call that server's tools through the portal. | -| Server's portal mapping | n/a | n/a | **Require user auth** must be **off** so the portal uses the admin credential. | +| Where | Policy action | Include rule | Purpose | +| --------------------------------- | ------------- | ------------------ | ------------------------------------------------------------------------------ | +| Portal Access application | Service Auth | Your service token | Lets the bot connect to the portal URL. | +| Each linked MCP server Access app | Service Auth | Your service token | Lets the bot see and call that server's tools through the portal. | +| Server's portal mapping | n/a | n/a | **Require user auth** must be **off** so the portal uses the admin credential. | :::note **Require user auth** in the dashboard maps to the `on_behalf` field on the portal-server mapping in the API and Terraform. For each linked server you want a service token to reach, set `on_behalf` to `false`. Servers with `on_behalf: true` are excluded from service token sessions because they require a per-user OAuth grant that a service token cannot provide. @@ -1023,18 +1014,14 @@ To set up a Logpush job for MCP portal logs, refer to [Logpush integration](/clo MCP server portals have the following known limitations: - **Only remote HTTP MCP servers are supported.** MCP servers that use [stdio transport only](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports) (for example, `github/github-mcp-server`) do not expose a remote HTTP endpoint and cannot be added to an MCP server portal. To use a stdio-only server, you must self-host it behind an HTTP endpoint and authenticate with a [bearer token or custom headers](#create-an-mcp-server). - - **Some MCP servers block proxy-based clients.** Certain MCP servers reject requests from proxy-based clients like MCP server portals, returning a `403` error on the registration endpoint. These servers are not compatible with MCP server portals until those providers add Cloudflare as a supported MCP client. - - **Manual OAuth capabilities are captured during the first user authorization.** Servers configured with [manual OAuth credentials](#configure-manual-oauth-credentials) remain in **Waiting** status until a user completes upstream OAuth. Cloudflare stores the tools and prompts returned during that connection. Background and manual capability synchronization do not refresh them. - - **Admin OAuth tokens can expire silently.** The admin credential used to [authenticate an MCP server](#reauthenticate-the-mcp-server) is subject to the upstream provider's token expiration policy. When the token expires, the server status changes to **Error** or **Sync Required** and the server will not appear in the portal for end users. Admins are not notified when this happens. Periodically check the [server status](#server-status) and [reauthenticate](#reauthenticate-the-mcp-server) servers that show an error. - - **Each portal supports up to 40 MCP servers.** If you need to aggregate more than 40 servers into a single portal, contact your Cloudflare account team to request a higher limit. The dashboard displays a warning as you approach the limit. ## Policy limitations -MCP servers use a dedicated Access application type (*mcp*) that does not support the following Access policy features when the server is authorized through a portal. +MCP servers use a dedicated Access application type (_mcp_) that does not support the following Access policy features when the server is authorized through a portal. - **[Independent MFA](/cloudflare-one/access-controls/policies/mfa-requirements/#independent-mfa)** — Users will not be prompted to perform MFA through Cloudflare Access when authorizing a server, regardless of whether MFA global enforcement is enabled or whether an MFA policy is assigned to the server. - **[Purpose justification](/cloudflare-one/access-controls/policies/require-purpose-justification/)** — Users will not be prompted to provide a purpose justification when authorizing a server.