从零搭建一个 Cursor MCP Server

🎯 目标

30分钟完成:创建天气查询 MCP Server,在 Cursor 中可用


第一部分:准备工作 (5分钟)

1. 基本概念

MCP Server 是什么?

  • 为 AI 助手提供自定义工具的服务器
  • Cursor 通过 MCP 调用你的工具
  • 本教程:创建天气查询工具

两种模式

  • STDIO: 本地开发,Cursor 自动管理
  • SSE: 远程访问,需手动启动服务器

2. 环境搭建

bash 复制代码
# 创建项目
mkdir weather-mcp && cd weather-mcp
npm init -y

# 安装依赖
npm install @modelcontextprotocol/sdk zod express node-fetch
npm install -D typescript @types/node @types/express

# 创建 TypeScript 配置
echo '{"compilerOptions":{"target":"ES2022","module":"ESNext","moduleResolution":"node","outDir":"build","strict":true,"esModuleInterop":true}}' > tsconfig.json

# 创建源码目录
mkdir src

手动编辑 package.json,添加 scripts 部分:

json 复制代码
{
  "scripts": {
    "build": "tsc",
    "start": "node build/index.js --stdio",
    "debug": "tsc && npx @modelcontextprotocol/inspector node build/index.js --stdio"
  }
}

第二部分:核心实现 (15分钟)

3. 完整代码实现

创建 src/index.ts 文件:

typescript 复制代码
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import { z } from "zod";
import express from "express";
import fetch from "node-fetch";

// 创建服务器
const server = new McpServer({
  name: "weather-server",
  version: "1.0.0",
}, {
  capabilities: { tools: {} }
});

// 工具1:获取天气警报
server.tool("get_weather_alerts", "获取美国各州天气警报", {
  state: z.string().length(2).describe("州代码,如 CA")
}, async ({ state }) => {
  const url = `https://api.weather.gov/alerts/active/area/${state.toUpperCase()}`;
  const response = await fetch(url, {
    headers: { "User-Agent": "weather-mcp/1.0" }
  });
  
  if (!response.ok) {
    return { content: [{ type: "text", text: "获取失败" }] };
  }
  
  const data = await response.json();
  const alerts = data.features || [];
  
  if (alerts.length === 0) {
    return { content: [{ type: "text", text: `${state} 暂无警报` }] };
  }
  
  const alertText = alerts.map(alert => 
    `事件: ${alert.properties.event}\n区域: ${alert.properties.areaDesc}`
  ).join("\n---\n");
  
  return { content: [{ type: "text", text: alertText }] };
});

// 工具2:获取天气预报
server.tool("get_weather_forecast", "获取天气预报", {
  lat: z.number().describe("纬度"),
  lon: z.number().describe("经度")
}, async ({ lat, lon }) => {
  // 第一步:获取预报网格
  const pointUrl = `https://api.weather.gov/points/${lat},${lon}`;
  const pointResponse = await fetch(pointUrl, {
    headers: { "User-Agent": "weather-mcp/1.0" }
  });
  
  if (!pointResponse.ok) {
    return { content: [{ type: "text", text: "位置不支持(仅限美国)" }] };
  }
  
  const pointData = await pointResponse.json();
  const forecastUrl = pointData.properties.forecast;
  
  // 第二步:获取预报数据
  const forecastResponse = await fetch(forecastUrl, {
    headers: { "User-Agent": "weather-mcp/1.0" }
  });
  const forecastData = await forecastResponse.json();
  const periods = forecastData.properties.periods || [];
  
  const forecast = periods.slice(0, 3).map(period => 
    `${period.name}: ${period.temperature}°${period.temperatureUnit} - ${period.shortForecast}`
  ).join("\n");
  
  return { content: [{ type: "text", text: forecast }] };
});

// STDIO 模式
if (process.argv.includes("--stdio")) {
  const transport = new StdioServerTransport();
  server.connect(transport);
}

// SSE 模式
else {
  const app = express();
  app.use(express.json());
  const sessions = new Map();
  
  app.get('/sse', (req, res) => {
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Access-Control-Allow-Origin', '*');
    
    const transport = new SSEServerTransport('/sse', res);
    server.connect(transport);
    sessions.set(transport.sessionId, transport);
    
    req.on('close', () => sessions.delete(transport.sessionId));
  });
  
  app.post('/sse', (req, res) => {
    const sessionId = req.query.sessionId || req.headers['x-session-id'];
    const transport = sessions.get(sessionId);
    
    if (transport) {
      transport.handleMessage(req.body)
        .then(() => res.status(202).end())
        .catch(() => res.status(500).end());
    } else {
      res.status(404).end();
    }
  });
  
  app.listen(3000, () => console.log('SSE 服务器: http://localhost:3000'));
}

4. 编译和测试

bash 复制代码
# 编译
npm run build

# 测试 STDIO
npm run debug

# 测试 SSE
node build/index.js
# 浏览器访问: http://localhost:3000/sse

第三部分:Cursor 配置 (5分钟)

5. STDIO 配置

通过 UI 配置:Cursor 右上角设置 → MCP Tools → 添加服务器

json 复制代码
{
  "name": "weather-server",
  "command": "node",
  "args": ["/Users/username/weather-mcp/build/index.js", "--stdio"]
}

或者直接编辑 mcp.json

json 复制代码
{
  "mcpServers": {
    "weather-server": {
      "command": "node",
      "args": ["/Users/username/weather-mcp/build/index.js", "--stdio"]
    }
  }
}

注意:必须使用绝对路径!

6. SSE 配置

先启动服务器

bash 复制代码
node build/index.js

通过 UI 配置:Cursor 设置 → MCP Tools → 添加服务器

json 复制代码
{
  "name": "weather-sse",
  "type": "sse",
  "url": "http://localhost:3000/sse"
}

或者直接编辑 mcp.json

json 复制代码
{
  "mcpServers": {
    "weather-sse": {
      "type": "sse",
      "url": "http://localhost:3000/sse"
    }
  }
}

第四部分:验证成果 (3分钟)

7. 功能验证

在 Cursor 中测试:

  • "查询加州的天气警报"
  • "查询纽约(40.7128, -74.0060)的天气预报"

成功标志:AI 助手能调用工具并返回天气信息


第五部分:调试方法 (2分钟)

8. 问题排查

连接失败

  • 检查路径是否正确(必须是绝对路径)
  • 确认编译成功: npm run build

工具不可用

  • 使用 Inspector 测试: npm run debug
  • 检查 Cursor MCP Tools 中的连接状态

SSE 无法访问

  • 确认服务器启动: curl http://localhost:3000/sse
  • 检查端口是否被占用

🎯 总结

最终文件结构

bash 复制代码
weather-mcp/
├── src/index.ts      # 唯一源文件
├── build/index.js    # 编译输出
├── package.json      # 依赖配置
└── tsconfig.json     # TS 配置

核心要点

  1. 一个文件搞定 :所有代码在 src/index.ts
  2. 两种模式:STDIO 开发,SSE 生产
  3. 真实 API:美国国家气象局数据
  4. 即学即用:30分钟内在 Cursor 中可用

恭喜!您已经成功创建了一个完整的 MCP Server。

相关推荐
Sam_Deep_Thinking7 小时前
在 Cursor IDE 中配置 SQLTools 连接 MySQL 数据库指南(Windows 11)
ai编程·cursor
SamDeepThinking12 小时前
彻底让Cursor不要格式化Java代码
ai编程·cursor
SamDeepThinking13 小时前
使用Cursor生成【财务对账系统】前后端代码
后端·ai编程·cursor
SamDeepThinking18 小时前
在Windows 11上配置Cursor IDE进行Java开发
后端·ai编程·cursor
陈佬昔没带相机18 小时前
告别Token焦虑!我是如何用最低消费玩转AI编程的
claude·cursor·trae
yaocheng的ai分身1 天前
Browser MCP扩展
cursor·mcp
转转技术团队2 天前
让AI成为你的编程助手:如何高效使用Cursor
后端·cursor
SamDeepThinking2 天前
在 Cursor IDE 中配置 SQLTools 连接 MySQL 数据库指南(Windows 11)
后端·ai编程·cursor
SamDeepThinking3 天前
Cursor集成MCP MySQL服务器完整配置指南
后端·ai编程·cursor