Back to blog
Deployment • 7 min read

Deploy an MCP Server to Cloudflare Workers

Take a generated TypeScript MCP server from local bundle to a global HTTPS endpoint on Cloudflare Workers, with the runtime flags, fetch adapter, and secrets setup it needs.

Cloudflare Workers is a good fit for a TypeScript MCP server: it runs close to your users, scales automatically, and exposes an HTTPS endpoint without a container or a virtual machine. The trade-off is that Workers is not Node.js. You need to replace the generated server.ts entry point with a Worker entry point and enable Node compatibility for the pieces the generated tools rely on.

This guide starts from a downloaded TypeScript bundle and ends with a remote MCP endpoint at https://<worker>.<subdomain>.workers.dev/mcp.

Prerequisites

  • A TypeScript server bundle generated by MCP Studio.
  • Node.js 20 or newer installed locally.
  • A Cloudflare account and a Workers subdomain.
  • Wrangler, installed as a dev dependency in the bundle.

Python, Java, and PHP bundles are not covered here. Workers executes JavaScript and TypeScript, so this deployment path applies to the TypeScript output only.

1. Install the bundle

Unzip the generated bundle, open a terminal in that directory, and install dependencies.

terminal
npm install
npm install --save-dev wrangler

The bundle already contains the Hono MCP handler and the tool classes. Only the Node-specific entry point needs to change.

2. Add a Worker entry point

Create src/worker.ts. It reuses the generated server factory, mounts the MCP handler on /mcp, and exports the Hono app as the Worker's default export.

src/worker.ts
import axios from 'axios';
import { createMcpHandler, McpServer } from '@modelcontextprotocol/server';
import { createMcpHonoApp } from '@modelcontextprotocol/hono';

import { GeneratedApiServerTools } from './Tools/index.js';

axios.defaults.adapter = 'fetch';

function buildServer(): McpServer {
  const server = new McpServer({ name: 'My API', version: '1.0.0' });

  GeneratedApiServerTools.forEach((toolClass) => {
    toolClass.register(server);
  });

  return server;
}

const handler = createMcpHandler(buildServer);
const app = createMcpHonoApp();

app.all('/mcp', (c) => handler.fetch(c.req.raw));
app.get('/', (c) => c.text('MCP server is running. Connect to /mcp.'));

export default app;

Why the fetch adapter: generated tools call the upstream API with axios. Workers has no XMLHttpRequest, so the default axios adapter cannot run. Setting the adapter to 'fetch' before any tool is constructed keeps the generated request code unchanged.

If your exported tools symbol differs, check the last line of src/Tools/index.ts. The generated bundle exports a single array of tool classes from that file.

3. Configure Wrangler

Add wrangler.toml at the bundle root. Point main at the compiled Worker and enable the Node compatibility flag, which provides process.env and Buffer to the generated configuration and security modules.

wrangler.toml
name = "my-mcp-server"
main = "dist/worker.js"
compatibility_date = "2026-10-01"
compatibility_flags = ["nodejs_compat"]

[vars]
# Non-secret values only. Secrets are added with `wrangler secret put`.

Compile the bundle before deploying so dist/worker.js exists. The existing build script compiles every file under src, including the new Worker entry.

terminal
npm run build

4. Add secrets

Authentication credentials for the upstream API are never hard-coded in the generated output. The bundle README lists the environment variable names produced from your security schemes. Add each one as a Wrangler secret so it is encrypted and available at runtime.

terminal
npx wrangler secret put MCP_AUTH_API_TOKEN
npx wrangler secret put MCP_AUTH_API_KEY

Use the exact names from the README; they are prefixed with MCP_AUTH_ and derived from the scheme name in your specification. Non-secret overrides, such as a static tenant identifier, can go in the [vars] block.

5. Test locally and deploy

Wrangler can run the Worker locally with the same bindings and compatibility flags. Start it, then check the root route and the MCP endpoint.

terminal
npx wrangler dev
curl http://127.0.0.1:8787/

npx wrangler deploy

The deploy output prints the Worker URL. The MCP endpoint is that URL plus /mcp:

https://my-mcp-server.your-subdomain.workers.dev/mcp

Point any client that supports Streamable HTTP at that URL. Desktop clients that can only launch stdio processes need a bridge such as mcp-remote; the transport details are covered in Connecting Generated MCP Servers to Claude Desktop and Cursor.

Operational notes

  • Secure the endpoint. The Worker URL is public. Upstream credentials are protected, but the MCP endpoint itself has no built-in authentication. Put Cloudflare Access or your own authorization layer in front of it before sharing it.
  • Mind request and CPU limits. Workers plans cap CPU time and request duration. Long-lived streamed responses count against those limits, so test with your client's connection behavior.
  • Sessions stay simple. This entry point creates a server per request through the MCP handler. If you need durable per-user sessions or state between calls, run the server on a stateful runtime or add a Durable Object.
  • Redeploy on spec changes. When the API changes, regenerate the TypeScript bundle, reapply the Worker entry and Wrangler config, then build and deploy again.

Next steps

Workers is the lightest deployment path, but it is not the only one. If you prefer a managed Node.js function with zero-config Hono detection, read Deploy an MCP Server to Vercel. For any language, including Python, Java, and PHP, read Deploy an MCP Server to Google Cloud Run. A comparison of the options is available in Where to Deploy Your MCP Server.

If you have not generated a bundle yet, start with From OpenAPI to a Running MCP Server.

Need a TypeScript bundle?

Import a spec, choose TypeScript, and download a deployable MCP server.

Upload Spec