Cloudflare Setup
This page covers only Cloudflare setup for a deployed relay. Local development
commands live in the root and package README.md files. The hostnames and
account-specific names below describe the project deployment; substitute the
custom domains, Access team domain, policies, and account names chosen for
another deployment.
Follow Get Started for the surrounding repository, bridge, and ChatGPT configuration steps.
Services
Section titled “Services”Mikoto uses these Cloudflare services:
- Workers for the relay Worker.
- Durable Objects for bridge/session coordination.
- Workers Custom Domains for production hostnames. In Wrangler config these
are represented as
routesentries withcustom_domain: true. - Cloudflare Access self-hosted applications, policies, and Managed OAuth.
- Cloudflare One Client in WARP mode for local computers that may connect to bridge-only endpoints.
Cloudflare Workers Builds are not used. Deployments are performed by GitHub Actions through Wrangler.
Hostnames
Section titled “Hostnames”Production hostnames are configured as Wrangler custom-domain routes:
mikoto.takuk.me: docs Worker.mcp.mikoto.takuk.me: relay Worker for ChatGPT-facing MCP traffic.bridge.mikoto.takuk.me: same relay Worker for local bridge and health traffic.
The relay production workers.dev route is disabled. The relay uses one Worker
served through two custom domains so Cloudflare Access can keep ChatGPT Managed
OAuth separate from WARP-restricted bridge authentication.
Access Applications
Section titled “Access Applications”Create Cloudflare Access protection for the relay hostnames before using a deployed relay for real traffic.
The relay needs two different Access protections because the ChatGPT-facing MCP endpoint and the local bridge endpoint have different callers.
Use separate hostnames for the two protections. Sharing one hostname and only splitting by path couples applications with different callers, policies, and authentication flows. Separate hostnames preserve that security boundary, but do not work around the WARP-connected Managed OAuth limitation described below.
MCP Endpoint
Section titled “MCP Endpoint”Create a Cloudflare Access MCP server application for the ChatGPT-facing Streamable HTTP endpoint.
- Cloudflare service: Zero Trust Access AI controls MCP servers.
- Access application name:
mikoto mcp. - MCP server ID:
mikoto. - HTTP URL:
https://mcp.mikoto.takuk.me/. - Authentication: enable Managed OAuth for the MCP server application.
- Managed OAuth Dynamic Client Registration allowed redirect URIs:
https://chatgpt.com/connector/oauth/*
- Access policy: allow only the Cloudflare Access users or groups that may add
the MCP server to ChatGPT. The current Cloudflare account uses the reusable
mikoto mcp userspolicy, which allowsrisunosu.comemail addresses and does not require Gateway/WARP. - Application AUD tag: record the generated value for troubleshooting.
Use a hostname dedicated to the MCP server and serve the MCP endpoint at the
hostname root. Cloudflare Access one-time-code verification URLs carry the
target hostname but not the MCP path, so path-scoped MCP applications can fail
after email submission with Unable to find your Access application!.
Do not require Cloudflare One Client, WARP, or Gateway for this application. After OAuth completes, ChatGPT is the caller of the MCP endpoint and cannot satisfy a local device/WARP policy.
The ChatGPT redirect URI wildcard is required for OpenAI’s ChatGPT Apps OAuth
flow. When a user connects the custom app, ChatGPT dynamically registers an
OAuth client with Cloudflare Access and supplies a callback URL under
https://chatgpt.com/connector/oauth/. Cloudflare rejects the registration with
invalid_client_metadata unless that callback is allowed in Managed OAuth’s
Dynamic Client Registration settings.
ChatGPT App Setup
Section titled “ChatGPT App Setup”After the Cloudflare MCP application is ready, add Mikoto as a custom ChatGPT app:
- Open ChatGPT.
- Go to Apps.
- Select Manage to open Settings > Apps.
- Scroll to Advanced settings.
- Select Create app.
- Fill in:
- Name:
Mikoto - Description:
Access Mikoto MCP tools through the Cloudflare-protected relay. - Connection: Server URL
- Server URL:
https://mcp.mikoto.takuk.me/ - Authentication: OAuth
- Name:
- Open Advanced OAuth settings and confirm that Dynamic Client
Registration is available. Cloudflare Managed OAuth should advertise:
- Authorization URL:
https://risu729.cloudflareaccess.com/cdn-cgi/access/oauth/authorization - Token URL:
https://risu729.cloudflareaccess.com/cdn-cgi/access/oauth/token - Registration URL:
https://risu729.cloudflareaccess.com/cdn-cgi/access/oauth/registration - Resource:
https://mcp.mikoto.takuk.me/
- Authorization URL:
- Check I understand and want to continue.
- Select Create.
- Select Sign in with Mikoto and complete the Cloudflare Access login.
If ChatGPT reports Dynamic client registration failed with
redirect_uri is not allowed by the account configuration, re-open the
mikoto mcp Access application in Cloudflare, go to Advanced settings >
Managed OAuth, and verify that
https://chatgpt.com/connector/oauth/* is present in Allowed redirect URIs.
If Cloudflare Access reports Unable to find your Access application! after
sending the login code, verify that the MCP application uses the hostname root
and not a path-scoped URL such as /mcp.
If an existing Cloudflare Protected MCP server record was created with
https://mcp.mikoto.takuk.me/mcp, Cloudflare may show the HTTP URL as
read-only. In that case, replace the Protected MCP server record with one that
uses https://mcp.mikoto.takuk.me/, then reconnect the ChatGPT app using the
root server URL.
WARP-Connected OAuth Login
Section titled “WARP-Connected OAuth Login”Cloudflare Access Managed OAuth login currently does not work for this deployment when the browser completing the login is connected through Cloudflare One Client in WARP/Gateway mode. Access may classify the authorization as a private-application flow even when:
- the MCP and bridge applications use separate hostnames;
- Authenticate with Cloudflare One Client is disabled for the MCP
application (
allow_authenticate_via_warpisfalse); - the MCP application is served at the hostname root.
After the one-time code is submitted, the verification page then reports
Unable to find your Access application!. This behavior is tracked in
issue #123.
As a workaround, disconnect WARP before selecting Sign in with Mikoto,
complete the Cloudflare Access OAuth login, and then reconnect WARP. The bridge
remains WARP-restricted and requires WARP after the OAuth login is complete.
Do not permanently exclude the Access team domain, such as
risu729.cloudflareaccess.com, with Split Tunnels: Cloudflare One Client also
uses that domain for its own authentication and session handling.
Bridge And Health Endpoints
Section titled “Bridge And Health Endpoints”Create a separate Cloudflare Access self-hosted application for the local bridge WebSocket endpoint and health check.
- Cloudflare service: Zero Trust Access Applications.
- Access application name:
mikoto bridge. - Public hostname:
bridge.mikoto.takuk.me. - Protected paths:
/bridge*/health*
- Access policy: allow only intended local operators and require the local
computer to be connected through Cloudflare One Client in WARP mode.
The current Cloudflare account uses the reusable
defaultpolicy for this, backed by thedefaultrule group that allowsrisunosu.comemail addresses and requires Gateway/WARP. - Managed OAuth: leave disabled for this application. The bridge is not an MCP OAuth client.
Keep bridge traffic on bridge.mikoto.takuk.me, separate from the
ChatGPT-facing mcp.mikoto.takuk.me hostname. ChatGPT should authenticate to
https://mcp.mikoto.takuk.me/ through Access Managed OAuth, while bridge
connections should use wss://bridge.mikoto.takuk.me/bridge and be limited to
trusted local computers.
Each hostname is DNS-public when the Worker route exists. Until both Access applications and policies exist, treat deployed relay paths as internet-reachable.
Official References
Section titled “Official References”- Secure MCP servers with Cloudflare Access
- Managed OAuth for self-hosted applications
- OpenAI Apps SDK authentication
- Access policies
- Access application tokens
GitHub Actions Inputs
Section titled “GitHub Actions Inputs”GitHub Actions needs:
- Repository variable
CLOUDFLARE_ACCOUNT_ID. - Repository secret
CLOUDFLARE_API_TOKEN.
Minimum Cloudflare API token permissions for the current docs and relay deployments:
- Account
risu:Workers Scripts: Edit. - Zone
takuk.me:Workers Routes: Read.
Wrangler reads the zone’s Worker routes before publishing each configured route
to detect assignments to another Worker. That preflight requires
Workers Routes: Read even though the current routes are Workers Custom
Domains (custom_domain: true). Custom Domains create their own DNS records
and certificates, so they do not require DNS: Edit.
If an ordinary route is added later, replace Workers Routes: Read with
Workers Routes: Edit for its zone. Such a route also needs a separately
configured proxied DNS record; grant DNS: Edit only if the workflow will
create or change that record. Account Settings: Read and
User Details: Read are not required for deployment.
The relay Worker does not currently require runtime Worker secrets or GitHub
environment variables beyond CLOUDFLARE_ACCOUNT_ID.
Do not store Cloudflare API tokens in repository files or local config.