mcp-handler mounts an MCP server into any Fetch-style framework
Easily spin up an MCP Server on Next.js, Nuxt, Svelte, and more
At a glance
- What is it?
- mcp-handler is a framework-agnostic HTTP adapter that turns an MCP server definition into a Web-standard request handler for Next.js, Nuxt, SvelteKit and Hono. It serves the 2026-07-28 specification natively while falling back to 2025-era Streamable HTTP, and it drops the SSE transport and Redis entirely in 2.x.
- Who is it for?
- Adopt mcp-handler if you are shipping an MCP server from a Fetch-style JavaScript framework and want one handler that speaks both the 2026-07-28 specification and 2025-era clients without maintaining two endpoints. Skip it if your application runs on Node's IncomingMessage and ServerResponse stack, such as Express, because you would need a Web Request adapter or the official MCP framework middleware on top.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One handler, two protocol generations
mcp-handler is a framework-agnostic HTTP adapter for hosting Model Context Protocol servers in JavaScript and TypeScript applications. The core operation it performs is small and precise: it turns an MCP server definition into a Web-standard (Request) => Promise<Response> handler that can be mounted in Next.js, Nuxt/Nitro, SvelteKit, Hono and other Fetch-compatible frameworks. What makes it more than a convenience wrapper is the protocol story. It is built on MCP SDK v2 and serves the 2026-07-28 MCP specification natively, while transparently falling back to stateless Streamable HTTP for 2025-era clients, which the README summarises as one handler and both protocol generations. The 2026-07-28 spec is served stateless, with no sessions, a per-request _meta envelope and a server/discover method. The 2025-era path comes from the SDK's own stateless legacy fallback, using the same handler, and its GET and DELETE session operations answer 405 because the server is stateless. That answer is not a bug, it is the honest response to a sessionful protocol meeting a stateless design.
The SSE transport and Redis are gone in 2.x
The HTTP+SSE transport, dated 2024-11-05, was removed in 2.x, and the consequences are spelled out rather than left to be discovered. You mount only the Streamable HTTP handler, and any unmounted /sse and /message paths are handled by your own framework, which means if you were serving those routes before, your web server now has to answer them or return 404 itself. Redis is no longer needed or used, and the whole session model disappears with it, which is also why the session configuration options from 1.x were removed. The migration section lists what disappeared and what replaced it. The variadic server.tool, server.prompt and server.resource forms are removed in favour of registerTool, registerPrompt and registerResource. inputSchema and argsSchema now take a full Standard Schema, for example a z.object, instead of a raw zod shape. The handler signature changed from createMcpHandler(initialize, serverOptions, config) to createMcpHandler(initialize, options), with one options object combining the SDK's server options with serverInfo, verboseLogs and onEvent. Inside handler callbacks, extra.authInfo is now ctx.http?.authInfo. And the 1.x route and transport options, including basePath, streamableHttpEndpoint, sseEndpoint, sseMessageEndpoint, disableSse, redisUrl, maxDuration and sessionIdGenerator, are all removed, with the guidance to mount the handler at the desired route instead.
Installing the 2.x line with the right SDK major
The install pulls three packages together, and the version alignment matters more than usual because the SDK major changed.
npm install mcp-handler@^2 @modelcontextprotocol/server@^2 zod@^4The note under it says that mcp-handler 2.x requires the MCP SDK v2 packages at ^2.0.0, zod at ^4.2.0 and Node.js 20 or newer, and that anyone still on @modelcontextprotocol/sdk 1.x should use mcp-handler 1.x instead. The requirements section repeats the floor: Node.js 20+, a framework exposing Web-standard Request and Response APIs either directly or through an adapter, and Next.js 13+ or Nuxt 3+ when using those frameworks. The package manifest shows the rest of the shape. It is built with tsup, tested with vitest, released with changesets, and it ships three binaries pointing at the same CLI entry, create-mcp-route, mcp-handler and @vercel/mcp-adapter, which is a naming decision that helps people who reach for the Vercel adapter by habit. The runtime dependencies are only chalk and commander, both for the CLI, and the MCP server package is a peer dependency rather than a bundled one, so the version of the SDK your server is written against stays yours to choose.
Registering a tool and mounting the handler
The Next.js quick start shows the whole shape of a server in a few lines. The imports are the two you need.
import { createMcpHandler } from "mcp-handler";
import { z } from "zod";The handler is created from an initialise callback that receives the server, and tools are registered inside it with registerTool, passing a name, a definition object carrying the title, the description and an inputSchema built as a z.object, and an async callback that receives the parsed input and returns content. The example rolls dice, taking a sides number as a minimum 2 integer, and the callback returns a content array with a text element. The finished handler is exported under both HTTP verbs.
export { handler as GET, handler as POST };One detail saves a lot of confusion later. The path /api/mcp is a convention and not a requirement, because mcp-handler does not inspect the request pathname, so you can place the handler at any route in your framework and give clients that route's complete URL. The same shape works elsewhere. Nuxt and Nitro use fromWebHandler, and Hono routes use c.req.raw to get at the underlying request.
Connecting clients, including the stdio-only case
A client that supports Streamable HTTP connects directly, and the configuration is a small JSON object naming the server and giving its URL.
{
"remote-example": {
"url": "http://localhost:3000/api/mcp"
}
}A client that only speaks stdio needs a bridge, and the README points at mcp-remote for that, run through npx with the server URL as an argument.
{
"remote-example": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:3000/api/mcp"]
}
}This is the part of the story that keeps the adapter honest. The handler speaks HTTP because that is what a web framework route can serve, and MCP clients have historically been split between stdio and HTTP, so a bridge process is still part of the story for a large share of desktop clients. The client integration documentation in the repository covers Claude Desktop, Cursor and Windsurf setup, and there are further documents for authorization, advanced usage including dynamic routing and Nuxt, configuration options, an experimental WebMCP bridge for exposing allowlisted tools to in-page agents, and experimental MCP events for registering draft webhook subscription methods with application-owned storage and delivery.
The CIMD era and the two authorization helpers
The 2026-07-28 specification deprecates Dynamic Client Registration in favour of Client ID Metadata Documents, where the OAuth client identifies itself with an HTTPS URL that serves its metadata. That change belongs to the authorization server, not to the MCP server, and the README is careful about the division of responsibility. CIMD support has to be advertised and implemented by your authorization server through the client_id_metadata_document_supported flag in its RFC 8414 metadata, and this package's job is to keep the MCP server's resource-server surface up to date. Two helpers do that. withMcpAuth verifies bearer tokens and answers 401 and 403 with RFC 9728 compliant WWW-Authenticate challenges that point at your protected resource metadata. protectedResourceHandler serves the RFC 9728 Protected Resource Metadata document, which lists your authorization servers. The wiring details are in the authorization document in the repository. For a team that is new to this corner of OAuth, the practical reading is that the burden has not disappeared, it has moved to a metadata document and a URL instead of a registration endpoint.
Where mcp-handler is the wrong tool
The clearest boundary is stated in the compatibility section. Frameworks built on Node's IncomingMessage and ServerResponse, Express being the obvious case, require a Web Request adapter or the official MCP framework middleware, so for an Express application this package is one more translation layer rather than a clean fit. The second boundary is protocol coverage. If you need the 2024-11-05 HTTP+SSE transport with its session and message endpoints, that transport was removed in 2.x and you would have to stay on 1.x, which means the two protocol generations support is a migration path rather than a permanent state. The third is that the package is an adapter, not a server host, so the questions of authentication in front of your route, rate limiting, per-tenant isolation of tool calls, and audit logging of what an agent invoked are all yours. The docs point at an experimental WebMCP bridge for exposing allowlisted tools to in-page agents and experimental MCP events for draft webhook subscription methods, and the word experimental appears in both cases. The maintenance picture is healthy, with releases v2.1.2 and v2.2.0 on 2026-09-18, v2.3.0 on 2026-10-07, and the last push on 2026-10-19.
Editorial conclusion
Adopt mcp-handler if you are shipping an MCP server from a Fetch-style JavaScript framework and want one handler that speaks both the 2026-07-28 specification and 2025-era clients without maintaining two endpoints. Skip it if your application runs on Node's IncomingMessage and ServerResponse stack, such as Express, because you would need a Web Request adapter or the official MCP framework middleware on top. Before you migrate a 1.x deployment, read the migration notes, because the SSE transport, the session options and the variadic server.tool form are all gone, and confirm that the authorization server you use advertises CIMD support before relying on the CIMD-era helpers.
Frequently asked questions
What is mcp-handler and which frameworks does it support?
It is a framework-agnostic HTTP adapter that turns an MCP server definition into a Web-standard (Request) => Promise<Response> handler. It can be mounted in Next.js Route Handlers, Nuxt/Nitro server handlers via fromWebHandler, SvelteKit server routes, Hono routes using c.req.raw, and other Fetch-compatible frameworks.
Which MCP protocol versions does mcp-handler support?
The 2026-07-28 specification is served natively in stateless mode, with a per-request _meta envelope and a server/discover method, while 2025-era Streamable HTTP is served through the SDK's stateless legacy fallback from the same handler. The HTTP+SSE transport from 2024-11-05 was removed in 2.x.
How do I migrate an mcp-handler 1.x project to 2.x?
Install @modelcontextprotocol/server v2 and zod 4 and remove @modelcontextprotocol/sdk and redis. The variadic server.tool form becomes registerTool, inputSchema takes a full Standard Schema, createMcpHandler takes one options object, and the 1.x route and transport options including the SSE endpoints and sessionIdGenerator are removed in favour of mounting the handler where you want it.
How do I add bearer token verification to an mcp-handler server?
Use withMcpAuth, which verifies bearer tokens and answers 401 and 403 with RFC 9728 compliant WWW-Authenticate challenges, and protectedResourceHandler, which serves the RFC 9728 Protected Resource Metadata document listing your authorization servers. The 2026-07-28 spec deprecates dynamic client registration in favour of Client ID Metadata Documents, which your authorization server must advertise.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/vercel-labs-mcp-handler)Was this useful?