# Deploy MCP servers to Vercel

Deploy your Model Context Protocol (MCP) servers on Vercel to [take advantage of features](/content/docs/mcp/deploy-mcp-servers-to-vercel#deploy-mcp-servers-efficiently/index.html) like [Vercel Functions](/content/docs/functions/index.html), [OAuth](/content/docs/mcp/deploy-mcp-servers-to-vercel#enabling-authorization/index.html), and [efficient scaling](/content/docs/fluid-compute/index.html) for AI applications.

- Get started with [deploying MCP servers on Vercel](/content/docs/mcp/deploy-mcp-servers-to-vercel#deploy-an-mcp-server-on-vercel/index.html)
- Learn how to [enable authorization](/content/docs/mcp/deploy-mcp-servers-to-vercel#enabling-authorization/index.html) to secure your MCP server

## Deploy a Template

\
HyperFrames on Vercel\
Preview HTML video compositions in the browser and render MP4s server-side on Vercel Sandbox.](/content/templates/next.js/hyperframes-on-vercel/index.html)

\
ChatGPT app with Next.js \ 
Ship a ChatGPT app on Vercel with Next.js and Model Context Protocol (MCP).](/content/templates/next.js/chatgpt-app-with-next-js/index.html)

\
x402 AI Starter\
A fullstack template for using x402 with MCP and AI SDK.](/content/templates/next.js/x402-ai-starter/index.html)

## [Deploy MCP servers efficiently](/content/docs/mcp/deploy-mcp-servers-to-vercel#deploy-mcp-servers-efficiently/index.html)

Vercel provides the following features for production MCP deployments:

- Optimized cost and performance: [Vercel Functions](/content/docs/functions/index.html) with [Fluid compute](/content/docs/fluid-compute/index.html) handle MCP servers' irregular usage patterns (long idle times, quick message bursts, heavy AI workloads) through [optimized concurrency](/content/docs/fundamentals/what-is-compute#optimized-concurrency/index.html), [dynamic scaling](/content/docs/fundamentals/what-is-compute#dynamic-scaling/index.html), and [instance sharing](/content/docs/fundamentals/what-is-compute#compute-instance-sharing/index.html). You only pay for compute resources you actually use with minimal idle time.
- [Instant Rollback](/content/docs/instant-rollback/index.html): Quickly revert to previous production deployments if issues arise with your MCP server.
- [Preview deployments with Deployment Protection](/content/docs/deployment-protection/index.html): Secure your preview MCP servers and test changes safely before production
- [Vercel Firewall](/content/docs/vercel-firewall/index.html): Protect your MCP servers from malicious attacks and unauthorized access with multi-layered security
- [Rolling Releases](/content/docs/rolling-releases/index.html): Gradually roll out new MCP server deployments to a fraction of users before promoting to everyone

## [Deploy an MCP server on Vercel](/content/docs/mcp/deploy-mcp-servers-to-vercel#deploy-an-mcp-server-on-vercel/index.html)

Use [`mcp-handler`](https://github.com/vercel/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:

```bash
pnpm i mcp-handler@2.1.1 @modelcontextprotocol/server@2 zod@4
```

```bash
yarn add mcp-handler@2.1.1 @modelcontextprotocol/server@2 zod@4
```

```bash
npm i mcp-handler@2.1.1 @modelcontextprotocol/server@2 zod@4
```

```bash
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`

```typescript
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](https://github.com/vercel/mcp-handler#migrating-from-1x) to update an existing server.

### [Test the MCP server locally](/content/docs/mcp/deploy-mcp-servers-to-vercel#test-the-mcp-server-locally/index.html)

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

1. Run the MCP inspector:

```bash
pnpm dlx @modelcontextprotocol/inspector@latest
```

```bash
yarn dlx @modelcontextprotocol/inspector@latest
```

```bash
npx @modelcontextprotocol/inspector@latest
```

```bash
bunx @modelcontextprotocol/inspector@latest
```

2. Open the inspector interface:
   - Browse to `http://127.0.0.1:6274` where the inspector runs by default
3. 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
4. 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`.

### [Configure an MCP host](/content/docs/mcp/deploy-mcp-servers-to-vercel#configure-an-mcp-host/index.html)

Using [Cursor](https://www.cursor.com/), add the URL of your MCP server to the [configuration file](https://docs.cursor.com/context/model-context-protocol#configuring-mcp-servers) in [Streamable HTTP transport format](https://modelcontextprotocol.io/docs/concepts/transports#streamable-http).

`cursor/mcp.json`

```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](https://docs.cursor.com/context/model-context-protocol#using-mcp-in-chat) or any other MCP client.

To call the same tool from your own application, follow the [AI SDK](/content/docs/mcp/integrations/ai-sdk/index.html) or [TanStack AI](/content/docs/mcp/integrations/tanstack-ai/index.html) example. Explore [MCP integrations](/content/docs/mcp/integrations/index.html) for connection and authentication options, including eve.

## [Enabling authorization](/content/docs/mcp/deploy-mcp-servers-to-vercel#enabling-authorization/index.html)

`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.

### [Secure your server with OAuth](/content/docs/mcp/deploy-mcp-servers-to-vercel#secure-your-server-with-oauth/index.html)

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`

```typescript
import type { AuthInfo } from '@modelcontextprotocol/server';
import { createMcpHandler, withMcpAuth } from 'mcp-handler';
import { z } from 'zod';

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`.

### [Expose OAuth metadata endpoint](/content/docs/mcp/deploy-mcp-servers-to-vercel#expose-oauth-metadata-endpoint/index.html)

To comply with the MCP specification, your server must expose a [metadata endpoint](https://modelcontextprotocol.io/specification/draft/basic/authorization#authorization-server-discovery) that provides OAuth configuration details.

#### [How to add OAuth metadata endpoint](/content/docs/mcp/deploy-mcp-servers-to-vercel#how-to-add-oauth-metadata-endpoint/index.html)

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](https://datatracker.ietf.org/doc/html/rfc9728#name-protected-resource-metadata).
5. Set `resourceUrl` to the public URL of your MCP route, including `/api/mcp`.

`app/.well-known/oauth-protected-resource/route.ts`

```typescript
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](https://datatracker.ietf.org/doc/html/rfc9728#name-protected-resource-metadata).

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.
