Skip to content
Docs

Deploy MCP servers to Vercel

Deploy your Model Context Protocol (MCP) servers on Vercel to take advantage of features like Vercel Functions, OAuth, and efficient scaling for AI applications.

Vercel provides the following features for production MCP deployments:

Use mcp-handler to create an MCP server in an existing Next.js App Router application. You'll need Node.js 20 or later.

Install mcp-handler v2, the MCP server SDK v2, and Zod v4:

Terminal
pnpm i mcp-handler@2.1.1 @modelcontextprotocol/server@2 zod@4
Terminal
yarn add mcp-handler@2.1.1 @modelcontextprotocol/server@2 zod@4
Terminal
npm i mcp-handler@2.1.1 @modelcontextprotocol/server@2 zod@4
Terminal
bun add mcp-handler@2.1.1 @modelcontextprotocol/server@2 zod@4

Create a route that exposes a tool for rolling an N-sided die:

app/api/mcp/route.ts
import { createMcpHandler } from 'mcp-handler';
import { z } from 'zod';
 
const handler = createMcpHandler((server) => {
  server.registerTool(
    'roll_dice',
    {
      description: 'Roll an N-sided die',
      inputSchema: z.object({ sides: z.number().int().min(2) }),
    },
    async ({ sides }) => {
      const value = 1 + Math.floor(Math.random() * sides);
      return {
        content: [{ type: 'text', text: `🎲 You rolled a ${value}!` }],
      };
    },
  );
});
 
export { handler as GET, handler as POST };

Clients connect to /api/mcp using Streamable HTTP. Your framework determines the route, so you don't need to configure a base path in mcp-handler.

Version 2 of mcp-handler uses @modelcontextprotocol/server instead of @modelcontextprotocol/sdk, changes tool registration, and removes legacy HTTP+SSE transport and Redis configuration. Follow the migration guide to update an existing server.

Start your Next.js development server at http://localhost:3000 before opening the MCP Inspector.

  1. Run the MCP inspector:
Terminal
pnpm dlx @modelcontextprotocol/inspector@latest
Terminal
yarn dlx @modelcontextprotocol/inspector@latest
Terminal
npx @modelcontextprotocol/inspector@latest
Terminal
bunx @modelcontextprotocol/inspector@latest
  1. Open the inspector interface:
    • Browse to http://127.0.0.1:6274 where the inspector runs by default
  2. Connect to your MCP server:
    • Select Streamable HTTP in the drop-down on the left
    • In the URL field, use http://localhost:3000/api/mcp
    • Expand Configuration
    • In the Proxy Session Token field, paste the token printed in the terminal where MCP Inspector is running
    • Click Connect
  3. Test the tools:
    • Click List Tools under Tools
    • Click on the roll_dice tool
    • Test it through the available options on the right of the tools section

When you deploy your application on Vercel, you will get a URL such as https://my-mcp-server.vercel.app.

Using Cursor, add the URL of your MCP server to the configuration file in Streamable HTTP transport format.

.cursor/mcp.json
{
  "mcpServers": {
    "server-name": {
      "url": "https://my-mcp-server.vercel.app/api/mcp"
    }
  }
}

You can now use your MCP roll dice tool in Cursor's AI chat or any other MCP client.

To call the same tool from your own application, follow the AI SDK or TanStack AI example. Explore MCP integrations for connection and authentication options, including eve.

mcp-handler includes helpers for verifying bearer tokens and publishing OAuth protected resource metadata. You provide an authorization server and the logic that validates its tokens. The package does not issue tokens or run an authorization server.

Wrap your MCP handler with withMcpAuth and set required: true to require a valid token. Return the verified client's identity and scopes from verifyToken.

The following example uses a token from the MCP_DEMO_TOKEN environment variable for local testing. Set that variable in .env.local before starting your development server. For production, replace the comparison with your authorization server's token verification, including issuer, audience, expiration, and granted scopes.

Replace your MCP route with the following code:

app/api/mcp/route.ts
import type { AuthInfo } from '@modelcontextprotocol/server';
import { createMcpHandler, withMcpAuth } from 'mcp-handler';
import { z } from 'zod';
 
const handler = createMcpHandler((server) => {
  server.registerTool(
    'roll_dice',
    {
      description: 'Roll an N-sided die',
      inputSchema: z.object({ sides: z.number().int().min(2) }),
    },
    async ({ sides }) => {
      const value = 1 + Math.floor(Math.random() * sides);
      return {
        content: [{ type: 'text', text: `🎲 You rolled a ${value}!` }],
      };
    },
  );
});
 
const verifyToken = async (
  _req: Request,
  bearerToken?: string,
): Promise<AuthInfo | undefined> => {
  if (!bearerToken || bearerToken !== process.env.MCP_DEMO_TOKEN) {
    return undefined;
  }
 
  return {
    token: bearerToken,
    scopes: ['read:dice'],
    clientId: 'demo-client',
  };
};
 
const authHandler = withMcpAuth(handler, verifyToken, {
  required: true,
  requiredScopes: ['read:dice'],
  resourceMetadataPath: '/.well-known/oauth-protected-resource',
});
 
export { authHandler as GET, authHandler as POST };

With this configuration, requests without a valid token receive 401. If a verified token lacks a required scope, the handler returns 403.

To comply with the MCP specification, your server must expose a metadata endpoint that provides OAuth configuration details. Among other things, this endpoint allows MCP clients to discover how to authorize with your server, which authorization servers can issue valid tokens, and what scopes are supported.

  1. In your app/ directory, create a .well-known folder.
  2. Inside this directory, create a subdirectory called oauth-protected-resource.
  3. In this subdirectory, create a route.ts or route.js file with the following code.
  4. Replace the https://example-authorization-server-issuer.com URL with your own Authorization Server (AS) Issuer URL.
  5. Set resourceUrl to the public URL of your MCP route, including /api/mcp.
app/.well-known/oauth-protected-resource/route.ts
import {
  protectedResourceHandler,
  metadataCorsOptionsRequestHandler,
} from 'mcp-handler';
 
const handler = protectedResourceHandler({
  authServerUrls: ['https://example-authorization-server-issuer.com'],
  resourceUrl: 'https://my-mcp-server.vercel.app/api/mcp',
});
 
const corsHandler = metadataCorsOptionsRequestHandler();
 
export { handler as GET, corsHandler as OPTIONS };

To view the full list of values available to be returned in the OAuth Protected Resource Metadata JSON, see the protected resource metadata RFC.

MCP clients that are compliant with the latest version of the MCP spec can now securely connect and invoke tools defined in your MCP server, when provided with a valid OAuth token.

Learn how to deploy MCP servers on Vercel, connect to them using the AI SDK, and explore curated lists of public MCP servers.

Last updated September 18, 2026

Was this helpful?

supported.