Move to remote HTTP safely

Turn the factory into an HTTP handler

Serve the same capability factory over remote HTTP with the v2 web-standard handler instead of duplicating server definitions.

8 minute lesson

~~~

Stdio gives a local child process one protocol connection. Remote clients need an HTTP endpoint.

Create src/worker.ts:

import { createMcpHandler } from '@modelcontextprotocol/server'
import { createServer } from './server.js'

const handler = createMcpHandler(createServer)

export default {
  async fetch(request: Request) {
    const url = new URL(request.url)

    if (url.pathname !== '/mcp') {
      return new Response('Not found', { status: 404 })
    }

    return handler.fetch(request)
  }
}

createMcpHandler() returns a web-standard { fetch, close, notify, bus } handler. The wrapper mounts its fetch function at one /mcp endpoint.

The handler serves modern 2026-07-28 requests and, by default, a stateless fallback for 2025-era clients. If you want a modern-only endpoint, pass { legacy: 'reject' } and test every intended client against it.

The factory creates a fresh server for each HTTP request. This is why we registered capabilities in one function without storing caller state in the server instance.

The same registered tools, resource, and prompt now back the local stdio and remote HTTP entry points.

createMcpHandler() does not authenticate requests or validate deployment-specific origins and hosts for you. Put those controls in front of handler.fetch() before exposing the endpoint.

Run this handler only in a local development runtime for now. Use the Inspector to list capabilities and call both tools at /mcp. Confirm the surface matches stdio exactly.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →