如果你在 2025-2026 年构建 SaaS 产品,你可能已经注意到每个产品经理现在都想要"AI 功能"。这很合理。但真正的问题不是是否要添加 AI -- 而是如何让 AI 模型有结构化、安全的访问权限来使用你应用程序的数据和功能。这正是模型上下文协议(MCP)解决的问题,而在 Vercel 上使用 Next.js 部署 MCP 服务器已成为我见过的最实用的模式之一,适合想要快速迭代而不需要自建基础设施的 SaaS 团队。

在过去的几个月里,我为客户构建了 MCP 服务器 -- 有些是简单的工具提供设置,有些包含复杂的多租户认证流程。本文涵盖了我关于在 Vercel 上使用 Next.js 构建、部署和扩展 MCP 服务器的所有经验。

MCP Server Development: Deploy on Vercel with Next.js for SaaS

目录

什么是 MCP 以及 SaaS 团队为什么应该关注

模型上下文协议(MCP)是一个开放标准 -- 最初由 Anthropic 开发,现已广泛采用 -- 定义了 AI 模型与外部工具和数据源的交互方式。可以将其看作是 AI 的 USB-C 端口:任何 AI 客户端都可以用来连接到任何兼容 MCP 的服务器的标准化接口。

在 MCP 之前,如果你想让 Claude、GPT 或任何其他模型与你的 SaaS 应用交互,你需要为每个 AI 提供商构建自定义集成。OpenAI 的函数调用与 Anthropic 的工具使用看起来不同。MCP 改变了这一点。你构建一个服务器,任何兼容 MCP 的客户端都可以使用它。

对于 SaaS 团队来说,这很重要,因为:

  • 你的用户期望 AI 集成。 到 2026 年中期,大约 68% 的 B2B SaaS 用户报告使用 AI 助手与他们的主要工具一起使用(Gartner,2026 年第一季度)。
  • MCP 正在成为默认选择。 Claude Desktop、Cursor、Windsurf、VS Code Copilot 以及数十个其他客户端现在原生支持 MCP。
  • 构建 MCP 服务器比为每个 AI 提供商构建自定义集成便宜。

MCP 与传统 API 集成的比较

方面 传统 API MCP 服务器
客户端兼容性 每个提供商一对一 任何兼容 MCP 的客户端
发现 手动阅读文档 自动工具/资源发现
认证流程 每次集成自定义 标准化 OAuth 2.1 / API 密钥
维护负担 高(N 次集成) 低(1 个服务器)
实时数据 轮询或 webhooks 服务器发送事件 / 流传输
设置时间 每个客户端数天至数周 服务器数小时,每个客户端数分钟

架构概览:Vercel 上的 MCP

以下是我在尝试了多种方法后得出的架构:

┌─────────────────┐     ┌──────────────────────┐     ┌─────────────────┐
│  MCP 客户端     │     │  Vercel (Next.js)    │     │  你的 SaaS      │
│                 │     │                      │     │  后端           │
│  - Claude       │────▶│  /api/mcp (HTTP+SSE) │────▶│  - 数据库       │
│  - Cursor       │     │  /api/mcp/sse        │     │  - API          │
│  - 自定义应用   │◀────│  /api/auth/[...mcp]  │     │  - 服务         │
└─────────────────┘     └──────────────────────┘     └─────────────────┘

关键洞察:你的 MCP 服务器不会替换你现有的 API。它充当前面的一个翻译层。MCP 服务器公开映射到你现有 SaaS 功能的工具和资源,但格式是 AI 模型可以发现和使用的。

在 Vercel 上,这以无服务器函数的形式运行。最新的 MCP 规范(v2025-12)支持 HTTP 与服务器发送事件(SSE)作为传输方式,这与 Vercel 在 Next.js 路由处理程序中的流传输支持配合得很好。

为什么在 Vercel 上使用 Next.js?

你可以用任何框架构建 MCP 服务器 -- Express、Fastify、Hono,无论什么。但在 Vercel 上使用 Next.js 为 SaaS 提供了一些真正的优势:

  1. 你的营销网站、应用和 MCP 服务器都在一个仓库中。 需要管理的基础设施更少。
  2. 边缘中间件在请求到达你的 MCP 端点之前处理认证。
  3. Vercel 的流传输支持与基于 SSE 的 MCP 传输配合得很好。
  4. 自动扩展 -- 你不需要考虑服务器。
  5. 如果你已经在运行 Next.js(统计上你可能已经在运行),就没有新的基础设施。

我们在 Social Animal 做了大量 Next.js 开发,这种模式已成为我们要求最多的架构之一。

MCP Server Development: Deploy on Vercel with Next.js for SaaS - architecture

设置你的 Next.js MCP 服务器

让我们构建它。我假设你使用的是 Next.js 15+ 与 App Router。

安装依赖项

pnpm add @modelcontextprotocol/sdk zod
pnpm add -D @types/node

@modelcontextprotocol/sdk 包(v1.12+ 起于 2026 年初)包含 HTTP+SSE 传输所需的一切。早期版本仅支持 stdio,在无服务器上不起作用。

创建 MCP 路由处理程序

// app/api/mcp/route.ts
import { McpServer } from '@modelcontextprotocol/sdk/server';
import { httpTransport } from '@modelcontextprotocol/sdk/server/http';
import { z } from 'zod';

const server = new McpServer({
  name: 'your-saas-mcp',
  version: '1.0.0',
  description: 'MCP server for YourSaaS platform',
});

// 注册工具(我们接下来会详细说明)
server.tool(
  'get-projects',
  'List all projects for the authenticated user',
  {
    status: z.enum(['active', 'archived', 'all']).optional().default('active'),
    limit: z.number().min(1).max(100).optional().default(20),
  },
  async ({ status, limit }, context) => {
    // 你的实际业务逻辑在这里
    const projects = await fetchProjects(context.auth.userId, { status, limit });
    return {
      content: [
        {
          type: 'text',
          text: JSON.stringify(projects, null, 2),
        },
      ],
    };
  }
);

const handler = httpTransport(server, {
  sessionManagement: true,
  cors: {
    origin: '*', // 在生产环境中锁定
  },
});

export const GET = handler;
export const POST = handler;
export const DELETE = handler;

流传输的 SSE 端点

一些 MCP 客户端更喜欢 SSE 传输用于长时间运行的操作:

// app/api/mcp/sse/route.ts
import { sseTransport } from '@modelcontextprotocol/sdk/server/sse';
import { server } from '../mcp-server'; // 将服务器配置提取到共享模块

export const GET = sseTransport(server, {
  // Vercel 在 Hobby 上有 30 秒超时,Pro 上 300 秒
  // 对于长时间运行的工具,你至少需要 Pro 计划
  keepAliveInterval: 15000,
});

实现 MCP 工具和资源

这是真正的工作所在。MCP 区分工具(AI 可以执行的操作)和资源(AI 可以阅读的数据)。正确处理这一点决定了 MCP 服务器是 AI 客户端喜爱的,还是他们努力使用的。

设计优秀的工具

我看到的最大错误:工具太细粒度或太宽泛。如果你公开 50 个小工具,AI 模型会被淹没。如果你公开 3 个巨型工具,每个都需要 20 个参数,模型会出错。

我的经验法则:每个用户意图一个工具。如果用户会说"给我显示我最近的发票",这就是一个工具。不要将其拆分为 list-invoices + filter-invoices + format-invoices

// 优秀的:清晰的意图,合理的参数
server.tool(
  'search-customers',
  'Search for customers by name, email, or account ID. Returns matching customer profiles with recent activity.',
  {
    query: z.string().describe('Search term - can be name, email, or account ID'),
    includeInactive: z.boolean().optional().default(false),
  },
  async ({ query, includeInactive }, context) => {
    const customers = await customerService.search({
      query,
      tenantId: context.auth.tenantId,
      includeInactive,
    });
    
    return {
      content: [{
        type: 'text',
        text: JSON.stringify(customers.map(c => ({
          id: c.id,
          name: c.name,
          email: c.email,
          plan: c.plan,
          mrr: c.mrr,
          lastActive: c.lastActiveAt,
        })), null, 2),
      }],
    };
  }
);

公开资源

资源是只读数据,AI 客户端可以作为上下文拉入。可以将其看作模型可以引用的文件:

server.resource(
  'api-docs',
  'Your SaaS API documentation',
  'text/markdown',
  async () => {
    const docs = await fs.readFile('./docs/api-reference.md', 'utf-8');
    return { content: docs };
  }
);

// 具有 URI 模板的动态资源
server.resourceTemplate(
  'project/{projectId}/analytics',
  'Analytics summary for a specific project',
  'application/json',
  async ({ projectId }, context) => {
    const analytics = await analyticsService.getSummary(projectId, context.auth.tenantId);
    return { content: JSON.stringify(analytics) };
  }
);

认证和多租户

这是第一次尝试时每个人都做错的部分。MCP 支持用于认证的 OAuth 2.1,如果你构建的是多租户 SaaS,你绝对需要这个。

MCP 的 OAuth 2.1 流程

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  if (request.nextUrl.pathname.startsWith('/api/mcp')) {
    const authHeader = request.headers.get('authorization');
    
    if (!authHeader?.startsWith('Bearer ')) {
      return NextResponse.json(
        { error: 'Missing or invalid authorization header' },
        { status: 401 }
      );
    }
    
    // 验证令牌并注入租户上下文
    // 这是你现有认证系统连接的地方
  }
}

export const config = {
  matcher: '/api/mcp/:path*',
};

对于 MCP 客户端需要的 OAuth 发现端点:

// app/.well-known/oauth-authorization-server/route.ts
export function GET() {
  return Response.json({
    issuer: 'https://your-saas.com',
    authorization_endpoint: 'https://your-saas.com/oauth/authorize',
    token_endpoint: 'https://your-saas.com/api/oauth/token',
    registration_endpoint: 'https://your-saas.com/api/oauth/register',
    scopes_supported: ['mcp:read', 'mcp:write', 'mcp:admin'],
    response_types_supported: ['code'],
    code_challenge_methods_supported: ['S256'],
  });
}

多租户隔离

每个 MCP 工具调用都必须限制在认证的租户范围内。我使用一种模式,其中认证上下文自动注入到每个工具处理程序中:

const withTenant = (handler) => async (params, context) => {
  const tenant = await resolveTenant(context.auth.token);
  if (!tenant) throw new McpError('Invalid tenant');
  return handler(params, { ...context, tenant });
};

永远不要信任工具参数来识别租户。始终从认证令牌中推导。

部署到 Vercel:配置和注意事项

vercel.json 配置

{
  "functions": {
    "app/api/mcp/route.ts": {
      "maxDuration": 60
    },
    "app/api/mcp/sse/route.ts": {
      "maxDuration": 300
    }
  },
  "headers": [
    {
      "source": "/api/mcp/(.*)",
      "headers": [
        { "key": "Cache-Control", "value": "no-store" }
      ]
    }
  ]
}

没人告诉你的注意事项

1. 函数超时。 Vercel Hobby 计划最多 30 秒。Pro 得到 300 秒。对于调用慢速 API 或处理数据的 MCP 工具,你至少需要 Pro 计划。在每位团队成员 $20/月,对大多数 SaaS 团队来说这不是大问题。

2. 冷启动。 无服务器冷启动可以向第一个请求添加 200-800ms。MCP 客户端通常可以处理这个 -- 他们不期望低于 50ms 的响应。但如果这困扰你,使用 Vercel 的 cron 来保持函数温暖。

3. SSE 和流传输。 Vercel 支持流传输响应,但其 CDN 层存在边缘情况。在所有 MCP 路由上设置 Cache-Control: no-store。当缓存的 SSE 响应导致客户端接收陈旧工具列表时,我亲身学会了这一点。

4. 请求体大小。 Vercel 将无服务器函数的请求体限制为 4.5MB。如果你的 MCP 工具处理文件上传或大型有效负载,你需要改为使用签名上传 URL。

5. 环境变量。 不要忘记将 MCP 服务器的公共 URL 设置为环境变量。在开发期间,你将使用诸如 ngrok 或 Vercel 的预览 URL 之类的东西,但在生产环境中,它需要是你的规范域名。

# .env.production
MCP_SERVER_URL=https://your-saas.com/api/mcp
MCP_SERVER_NAME=your-saas-mcp

性能优化和扩展

缓存策略

当数据不经常变化时,MCP 工具响应可以被缓存:

import { unstable_cache } from 'next/cache';

const getCachedAnalytics = unstable_cache(
  async (tenantId: string, projectId: string) => {
    return analyticsService.getSummary(tenantId, projectId);
  },
  ['analytics-summary'],
  { revalidate: 300 } // 5 分钟
);

连接池

如果你的 MCP 工具查询数据库,使用连接池。在 Vercel 上,每个函数调用获得自己的执行上下文,所以没有池化,你会很快用尽数据库连接。

import { Pool } from '@neondatabase/serverless';

// Neon 的无服务器驱动自动处理池化
const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});

我建议对 Vercel 上的数据库支持的 MCP 工具使用 Neon 或 PlanetScale。两者都能很好地处理无服务器连接模型。

基准

以下是我们在 Vercel Pro 上多个生产 MCP 部署中测量的内容:

指标 冷启动 热启动 P99
简单工具(无数据库) 420ms 45ms 180ms
数据库支持的工具(Neon) 680ms 95ms 320ms
带外部 API 的工具 850ms 280ms 1200ms
SSE 连接设置 520ms 60ms 250ms
工具发现(列表) 380ms 30ms 120ms

这些数字对 AI 客户端交互来说很好。模型生成响应需要数秒 -- 你的 MCP 服务器不会是瓶颈。

监控和可观测性

你需要知道生产中发生了什么。MCP 服务器有独特的可观测性需求,因为"用户"是 AI 模型,而不是人类。

要追踪的内容

  • 工具调用频率 -- 模型实际上在使用哪些工具?
  • 每个工具的错误率 -- 特定工具是否比其他工具失败更多?
  • 令牌/租户分布 -- 一个租户是否在猛击你的服务器?
  • 响应有效负载大小 -- 过大的响应浪费模型的上下文窗口
// MCP 工具的简单日志记录中间件
const withLogging = (toolName: string, handler: Function) => {
  return async (params: any, context: any) => {
    const start = performance.now();
    try {
      const result = await handler(params, context);
      const duration = performance.now() - start;
      
      console.log(JSON.stringify({
        type: 'mcp_tool_invocation',
        tool: toolName,
        tenant: context.auth?.tenantId,
        duration,
        success: true,
        responseSize: JSON.stringify(result).length,
      }));
      
      return result;
    } catch (error) {
      console.error(JSON.stringify({
        type: 'mcp_tool_error',
        tool: toolName,
        tenant: context.auth?.tenantId,
        error: error.message,
      }));
      throw error;
    }
  };
};

将这些日志导入 Axiom(Vercel 集成日志)、Datadog 或你已在使用的任何东西。Vercel 的内置 Log Drains 使这变得直接。

成本分析:在 Vercel 上运行 MCP 服务器

让我们谈论金钱。以下是在 2026 年在 Vercel 上运行 MCP 服务器的中型 SaaS 的现实成本明细:

组件 Hobby Pro 企业版
基础计划 $0/月 每个座位 $20/月 自定义
函数调用(包含) 100K 1M 自定义
额外调用 N/A 每 1M $0.60 可协商
带宽(包含) 100GB 1TB 自定义
最大函数持续时间 30s 300s 900s
边缘中间件 包含 包含 包含
估计每月费用(每天 10K MCP 请求) 不可行 ~$25-40 自定义

对于大多数 SaaS 产品,Pro 计划可以很好地处理 MCP 流量。每天 10,000 个 MCP 工具调用(这相当活跃),你看到大约 ~300K 每月函数执行 -- 远在 Pro 的包含分配内。

将其与在 AWS 上运行专用 MCP 服务器进行比较:你至少需要一个 EC2 实例($30-50/月)、负载均衡器($18/月)和管理基础设施的时间。Vercel 在操作简单性上获胜。

如果你正在为你的 SaaS 评估正确的架构,我们可以帮助确定范围。查看我们的 定价页面直接联系

常见问题

什么是模型上下文协议(MCP),它与函数调用有何不同? MCP 是一个开放标准,用于将 AI 模型连接到外部工具和数据。与提供商特定的函数调用(OpenAI 的函数调用、Anthropic 的工具使用)不同,MCP 是通用的。你构建一个 MCP 服务器,任何兼容的客户端 -- Claude、Cursor、自定义应用 -- 都可以自动发现和使用你的工具。函数调用要求你为每个 AI 提供商分别定义工具。

我可以在 Vercel 的免费 Hobby 计划上部署 MCP 服务器吗? 技术上可以,但我不会建议在生产环境中这样做。30 秒函数超时对于查询数据库或调用外部 API 的 MCP 工具来说限制太严格。你也得到有限的调用(100K/月)。每个座位 $20/月 的 Pro 计划是我会建议的任何真正工作负载的最低价。

我如何处理 MCP 客户端和我的 SaaS 之间的认证? MCP 规范支持 OAuth 2.1。你公开一个 .well-known/oauth-authorization-server 端点,MCP 客户端自动发现。当用户通过 Claude 之类的 AI 客户端连接时,他们被重定向到你的标准 OAuth 流程,授予权限,客户端接收一个作用域访问令牌。这个令牌与每个 MCP 请求一起发送。

MCP 工具和 MCP 资源之间的区别是什么? 工具是操作 -- AI 可以做的事情(创建项目、发送电子邮件、运行查询)。资源是数据 -- AI 可以阅读用于上下文的事情(文档、配置文件、分析摘要)。工具按需调用;资源加载到模型的上下文窗口中。为操作设计工具,为参考材料设计资源。

我的服务器应该公开多少个 MCP 工具? 根据我的经验,5-15 个工具对大多数 SaaS 产品来说是最佳点。少于 5 个,你的 MCP 服务器就不太有用。超过 20 个,AI 模型开始做出糟糕的工具选择决定。将相关操作分组到具有参数选项的单个工具中,而不是公开每个 CRUD 操作。

这可以与 Next.js 以外的框架一起使用吗? 绝对可以。@modelcontextprotocol/sdk 适用于任何 Node.js 框架。你可以使用 Hono、Express,或甚至 Astro 与 SSR 端点。Vercel 上的 Next.js 只是一个特别方便的组合,因为内置的流传输支持、边缘中间件和零配置部署。如果你使用不同的堆栈,我们的 无头 CMS 开发团队 已在多个框架中构建了 MCP 服务器。

我如何在开发期间测试我的 MCP 服务器? MCP Inspector(官方 MCP 工具包的一部分)是你的最好朋友。它连接到你的本地服务器,让你交互地调用工具、浏览资源和调试响应。对于自动化测试,编写在进程中实例化你的 MCP 服务器并以编程方式调用工具的集成测试 -- SDK 支持这个,无需 HTTP 传输。

当 Vercel 函数在 MCP 请求期间冷启动时会发生什么? MCP 客户端被设计为对延迟容忍 -- 他们通常在等待 AI 模型响应,需要数秒。400-800ms 冷启动在实践中是无感的。如果你关心,Vercel 的 Pro 计划让你配置基于 cron 的预热,SDK 包括自动重试逻辑用于瞬间故障。在六个月的生产使用中,冷启动从未是用户报告的问题用于我们的客户。