MCP Vercel — MCP工具
v1.0.0[AI辅助] Deploy a remote MCP server on Vercel with Next.js and mcp-handler. Use this skill whenever the user wants to create an MCP server, deploy MCP to Vercel, set...
详细分析 ▾
运行时依赖
版本
Initial release of mcp-vercel. - Guides users to deploy a remote MCP server on Vercel using Next.js and mcp-handler. - Provides setup instructions, including tool registration and deployment steps. - Explains correct routing, parameter annotation, and safety best practices for MCP tools. - Details deployment caveats specific to Vercel’s serverless environment. - Includes tips for authentication and publishing to Smithery.
安装命令 点击复制
技能文档
Create a production-ready remote MCP server on Vercel using Next.js and mcp-handler. The server communicates via Streamable HTTP and works with Claude Desktop, claude.ai, Smithery, and any MCP client.
为什么 approach
Vercel's serverless functions are ideal for MCP servers because MCP's Streamable HTTP transport is stateless — each request is independent, which maps perfectly to serverless. No persistent connections needed. The mcp-handler package from Vercel handles all the protocol details.
Quick setup
1. Install dependencies
npm install mcp-handler @modelcontextprotocol/sdk zod
2. 创建 MCP 路由
Create app/api/mcp/route.ts:
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { createMcpHandler } from 'mcp-handler';
import { z } from 'zod';const handler = createMcpHandler(
(server: McpServer) => {
// Register your tools here
server.tool(
'example_tool',
'What this tool does — be specific',
{ query: z.string().describe('What the parameter is for') },
{ readOnlyHint: true, destructiveHint: false, title: 'Example Tool' },
async ({ query }) => ({
content: [{ type: 'text', text: Result for: ${query} }],
}),
);
},
{
serverInfo: { name: 'my-server', version: '1.0.0' },
},
{
streamableHttpEndpoint: '/api/mcp',
maxDuration: 60,
},
);
export { handler as GET, handler as POST, handler as DELETE };
3. Deploy 和 test
vercel deploy --prod# Verify
curl -X POST https://your-app.vercel.app/api/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}'
You should get back serverInfo with your server name and version.
Tool design
Safety annotations (必填)
Every tool must have annotations. MCP clients use these to decide how cautiously to invoke tools.
// Read-only (search, get, list, fetch)
{ readOnlyHint: true, destructiveHint: false, title: 'Search Items' }// Write but not destructive (create, add, update)
{ readOnlyHint: false, destructiveHint: false, title: 'Create Item' }
// Destructive (delete, remove, overwrite)
{ readOnlyHint: false, destructiveHint: true, title: 'Delete Item' }
Parameter descriptions
Every parameter needs a .describe() — this is how MCP clients know what to pass.
{
query: z.string().describe('Search query text'),
limit: z.number().optional().default(10).describe('Max results to return'),
type: z.enum(['artist', 'album', 'track']).describe('Type of content'),
}
MCP prompts (可选 但是 recommended)
Prompt templates improve discoverability on Smithery and give users ready-made starting points.
server.prompt('find_items', 'Search for items by name',
{ name: z.string().describe('Item name') },
({ name }) => ({
messages: [{
role: 'user' as const,
content: { type: 'text' as const, text: Find ${name} and show details },
}],
}),
);
Routing — streamableHttpEndpoint gotcha
Use streamableHttpEndpoint, NOT basePath:
// CORRECT — endpoint at /api/mcp
{ streamableHttpEndpoint: '/api/mcp' }// WRONG — creates endpoint at /api/mcp/mcp (doubled path)
{ basePath: '/api/mcp' }
The basePath option appends /mcp to whatever you give it. Since your route file is already at app/api/mcp/route.ts, that creates /api/mcp/mcp.
Vercel deployment pitfalls
Root Directory isolation
If your Vercel project uses a Root Directory (like site/), the deployed function CANNOT access files outside that directory. This means import from '../../dist/' will fail at runtime even if it compiles locally.
Solution: 复制 compiled files 进入 site directory 和 commit them. 使用 prebuild script 到 keep them 在...中 同步:
// scripts/copy-deps.js
const fs = require('fs');
const path = require('path');
const src = path.resolve(__dirname, '../../dist');
const dest = path.resolve(__dirname, '../lib/deps');
fs.mkdirSync(dest, { recursive: true });
for (const file of fs.readdirSync(src)) {
if (file.endsWith('.js') || file.endsWith('.d.ts')) {
fs.copyFileSync(path.join(src, file), path.join(dest, file));
}
}
Add to package.json: "prebuild": "node scripts/copy-deps.js"
Serverless 读取-仅 filesystem
Vercel functions run on a read-only filesystem with no home directory. If your code writes files (sessions, temp data), wrap in try/catch:
try {
fs.mkdirSync(dir, { recursive: true });
fs.writeFileSync(filepath, data);
} catch {
// Serverless environment — skip filesystem writes
}
Turbopack CJS/ESM mismatch
If importing CommonJS .js files while the parent package.json doesn't have "type": "module", Turbopack will error. Solution: import from compiled .js files bundled within the site directory, not from TypeScript source files in the parent.
Adding authentication
For OAuth-protected servers, see the mcp-oauth skill which covers the complete OAuth 2.0 PKCE flow with withMcpAuth, including dynamic client registration and token storage.
Publishing 到 Smithery
After deploying, publish to Smithery for broader distribution:
- Go 到 https://smithery.ai/新的
- Enter MCP server URL
- Choose namespace/server-id
- Smithery scans tools automatically
If your server requires auth, Smithery will prompt you to connect during scanning.
Reference
免费技能或插件可能存在安全风险,如需更匹配、更安全的方案,建议联系付费定制