普通视图

发现新文章,点击刷新页面。
昨天 — 2025年12月14日首页

深入MCP本质——编写自定义MCP Server并通过Cursor调用

作者 天天扭码
2025年12月14日 17:15

这篇文章将深入探讨 MCP (Model Context Protocol) 的核心原理,并通过一个简单的自定义天气工具示例,揭示 AI 模型如何与本地系统进行高效、安全的交互。


实战配置:启动你的自定义 MCP Server

首先,我们通过一个简单的步骤来配置并运行一个自定义的 MCP Server,该 Server 能够获取电脑所在地的实时时间和天气(不使用代理的前提下)。

步骤 1: 代码准备

下面是我编写的 MCP Server ,你可以将代码库拉取到本地目录

github.com/Objecteee/m…

步骤 2: Cursor 配置

在 Cursor IDE 的 mcp.json 配置文件中添加如下配置,指定你的本地 Server 脚本的路径:

{
  "Real Weather Tool": {
    "command": "node",
    "args": [
      "E:\project\mcp\myMCP\index.js"  # 请确保这里是你的本地文件路径
    ]
  }
}

配置完成后,您即可在 Cursor 的对话框中通过自然语言调用这个工具,例如询问:“现在的天气怎么样?”

image.png


1. 核心架构:什么是 MCP?

MCP (Model Context Protocol) 是由 Anthropic 提出的一种开放协议,旨在解决 大型语言模型 (LLM)外部世界(本地文件、数据库、API 等) 之间的信息鸿沟。

  • 没有 MCP 时: LLM 仅依赖训练数据,无法感知外部世界的实时状态(如当前时间、实时天气、本地代码结构)。它就像一个“孤岛上的智者”。
  • 有了 MCP: 我们为 LLM 提供了一个标准化的“工具插座”。任何遵循 MCP 协议的外部程序(即 MCP Server)都可以插入这个插座,使 LLM 能够 控制 这些工具并 获取 实时数据。

2. 本质原理:Cursor 如何连接并调用工具?

Cursor 连接和调用自定义 Server 的过程,本质上是基于 标准输入/输出 (Stdio)进程间通信 (IPC) ,它采用 JSON-RPC 格式进行数据交换。我们可以将整个过程分为两个阶段:

阶段一:握手(Handshake)与工具发现

  1. 启动子进程: 当你在 Cursor 中保存 mcp.json 配置后,Cursor 会在后台启动一个 子进程 (Child Process) ,执行你指定的 node index.js 脚本。
  2. 发送询问: Cursor(父进程)通过 标准输入 (stdin) 向你的脚本发送一条 JSON-RPC 格式的消息,请求获取可用的工具列表。
  3. 返回列表: 你的脚本(子进程)收到请求后,会通过 标准输出 (stdout) 返回一个包含其所有工具定义(如 TimeWeatherReporter)的 JSON 响应。这对应于代码中的 server.setRequestHandler(ListToolsRequestSchema...)

阶段二:待命与工具调用

  1. 待命: 只要 Cursor 不关闭,你的脚本进程就会在后台持续运行,等待调用指令。
  2. LLM 触发: 用户在聊天框输入指令(如“现在的天气怎么样?”),Cursor 内置的 AI 模型分析请求,决定调用哪个工具。
  3. 发送指令: Cursor 向你的脚本发送一条 JSON-RPC 调用请求,指定要执行的工具名称和参数。
  4. 执行任务: 你的脚本接收指令,执行相应的内部函数(例如请求 wttr.in 获取天气)。
  5. 反馈结果: 脚本将执行结果打包成 JSON,通过 stdout 发回给 Cursor。
  6. 结果展示: Cursor 接收到工具输出的原始数据,将其作为 上下文 传递给 AI 模型,由模型组织成自然语言的答案回复用户。

3. 代码层面的关键实现:MCP Server 运行机制 (index.js)

我们的注意力不要放在代码的实现上,要放在代码的流程上,因为MCP只是一种规范。

这个 Node.js 脚本通过遵循 MCP 规范,并利用标准输入/输出流 (Stdio) 实现通信。以下是驱动 MCP Server 运行的五个关键代码片段:

3.1 核心模块导入:定义协议与传输层

代码片段 作用描述 核心原理
import { Server } from "@modelcontextprotocol/sdk/server/index.js"; Server 实例 MCP 服务端核心类,负责处理 JSON-RPC 请求和响应。
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; Stdio 传输层 声明通信载体是基于 标准输入/输出 (stdin/stdout) ,而非网络端口。
import { CallToolRequestSchema, ListToolsRequestSchema } from ... 协议定义 导入请求的 JSON Schema,用于解析 Cursor 发来的不同类型的指令。

3.2 初始化 MCP 服务器

const server = new Server(
  {
    name: "simple-weather-server",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

作用: 创建服务器实例。capabilities.tools: {} 明确告诉 MCP,该服务器具备提供工具的能力。

3.3 注册工具列表:响应“握手”请求

server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "TimeWeatherReporter",
        description: "Get current system time and weather...",
        inputSchema: {
          type: "object",
          properties: {
            location: {
              type: "string",
              description: "Optional. City name (e.g. 'Beijing')...",
            },
          },
          required: [],
        },
      },
    ],
  };
});

作用 这是握手阶段(Handshake) 的关键。当 Cursor 首次启动子进程时,会发送 ListToolsRequestSchema 请求。该代码片段负责返回一个清晰的 JSON Schema 描述:

  • name: 工具的唯一标识符。
  • description: 供 AI 理解工具用途的自然语言描述。
  • inputSchema: JSON Schema 格式的参数定义,AI 依赖此信息来构造正确的调用参数。

3.4 处理工具调用:执行业务逻辑

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === "TimeWeatherReporter") {
    const location = request.params.arguments?.location;
    return await getSystemStyleWeather(location); // 调用实际的业务函数
  }
  throw new Error("Tool not found");
});

作用: 这是执行阶段(Execution) 的核心。当 Cursor 的 AI 决定调用工具时,会发送 CallToolRequestSchema 请求。这段代码根据 request.params.name 匹配到对应的业务逻辑 (getSystemStyleWeather),执行后将结果返回给 Cursor。

3.5 启动服务器:连接到 Stdio 流

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Simple Weather MCP Server running on stdio");
}

作用: 连接点。 StdioServerTransport() 创建了传输通道,server.connect(transport) 则将服务器实例绑定到这个通道上。至此,您的 Node.js 脚本准备就绪,可以通过 stdin/stdout 与 Cursor 进程进行双向通信。


4. 总结:MCP 的本质

角色 实体 职责
雇主 (Client) Cursor IDE (父进程) 启动并监控工具,发送调用指令,接收并处理结果。
雇员 (Server) node index.js (子进程) 接收指令,执行实际任务(如 API 调用、文件读写),返回原始数据。
工作合同 (Protocol) MCP 协议 规定了握手和调用过程中 JSON 数据的结构和标准。
对讲机 (Transport) Stdio (标准输入/输出) 实现本地父进程与子进程之间即时、安全的通信。

MCP 的精妙之处在于它的解耦性安全性:Cursor 客户端无需关心你的 Server 是用 Node.js、Python 还是 Go 编写。只要你的程序符合 MCP 协议,能够通过命令行流接收和发送 JSON 数据,它就能无缝地成为 AI 的外部工具,极大地扩展了 LLM 的能力边界。


自定义MCP Server代码

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import axios from "axios";
import { z } from "zod";

// 1. Initialize MCP Server
const server = new Server(
  {
    name: "simple-weather-server",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

// 2. Define Tool Logic using wttr.in (No API Key required)
async function getSystemStyleWeather(location) {
  // --- Get Real Local Time (System Time) ---
  const now = new Date();
  const localTime = now.toLocaleTimeString("zh-CN", {
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit",
    hour12: false,
  });
  const localDate = now.toLocaleDateString("zh-CN");

  // --- Determine URL ---
  // wttr.in automatically detects location by IP if no location is provided
  // format=j1 gives us a JSON response
  let url = "https://wttr.in/?format=j1";
  if (location) {
    url = `https://wttr.in/${encodeURIComponent(location)}?format=j1`;
  }

  try {
    const response = await axios.get(url);
    const data = response.data;
    
    // Parse wttr.in specific JSON structure
    const current = data.current_condition[0];
    const area = data.nearest_area[0];

    const weatherInfo = {
      location: location || area.areaName[0].value, // Use detected name if no input
      region: area.region[0].value,
      condition: current.weatherDesc[0].value,
      temperature_c: current.temp_C,
      feelslike_c: current.FeelsLikeC,
      humidity: current.humidity,
      wind_kph: current.windspeedKmph,
      data_source: "wttr.in (IP-based auto-location)"
    };

    // --- Construct Result ---
    const result = {
      status: "success",
      tool: "SystemWeatherReporter",
      system_time: `${localDate} ${localTime}`,
      weather: weatherInfo
    };

    return {
      content: [
        {
          type: "text",
          text: JSON.stringify(result, null, 2),
        },
      ],
    };

  } catch (error) {
    return {
      content: [{ type: "text", text: `Unable to fetch weather data. Please check your network connection. Error: ${error.message}` }],
      isError: true,
    };
  }
}

// 3. Register Tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "TimeWeatherReporter",
        description: "Get current system time and weather. Automatically detects location if not specified. No API key required.",
        inputSchema: {
          type: "object",
          properties: {
            location: {
              type: "string",
              description: "Optional. City name (e.g. 'Beijing'). If omitted, uses auto-detection.",
            },
          },
          required: [],
        },
      },
    ],
  };
});

// 4. Handle Tool Calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === "TimeWeatherReporter") {
    const location = request.params.arguments?.location;
    return await getSystemStyleWeather(location);
  }
  throw new Error("Tool not found");
});

// 5. Start Server
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Simple Weather MCP Server running on stdio");
}

main().catch((error) => {
  console.error("Server error:", error);
  process.exit(1);
});

解放双手!使用Cursor+Figma MCP 高效还原响应式设计稿

作者 天天扭码
2025年12月14日 16:07

在如今的快速迭代周期中,如何高效、精准地将设计稿转化为高质量的跨平台代码,一直是前端和移动端开发者的核心痛点。

传统的“切图”和“像素级还原”流程不仅耗时,还极易产生信息偏差。

好消息是,Figma 官方推出的 Model Component Protocol (MCP) 服务,结合 AI 代码神器 Cursor,正在彻底颠覆这一工作流。本文将为您揭示如何通过这一黄金组合,将设计到代码的流程缩短到分钟级,实现 90% 的视觉还原度。


Figma MCP 解决了什么实际问题?

一句话总结: 通过 MCP 直接读取 Figma 文件的结构化设计数据,结合 Cursor 的代码智能,实现多平台 UI 代码的自动化、精准生成。

痛点 解决方案(Cursor + Figma MCP) 效果
信息偏差 直接获取精确的尺寸、颜色、间距等核心数据。 消除“手抖”和“看错”的风险。
重复劳动 自动化生成基础 UI 结构代码 (如 Android XML, iOS SwiftUI, H5, RN)。 大幅减少模板代码的编写时间。
跨平台不一致 同一设计源生成多平台代码。 提升不同平台间 UI 的视觉和结构统一性。
迭代速度慢 从设计到可用代码耗时数天/数小时。 从设计到可用代码仅需几分钟

一、Cursor + Figma MCP 连接流程

Figma 官方在 9 月份推出 MCP 服务后,连接流程已经大大简化,告别了之前繁琐的第三方插件连接方式。

1.1 一键连接配置

整个配置过程现在是标准化的,简单可靠:

  1. 进入 Figma 官方 MCP 服务页面。服务页面

  2. 点击 Cursor 中的 “Add MCP to Cursor”image.png

  3. 系统将跳转至 Cursor 客户端,点击 Install

image.png

  1. 点击 Connect 开始身份验证。

  2. 在弹出的对话框中点击 Open,然后点击 Allow access 完成授权。

image.png

1.2 开始使用 MCP 服务

配置完成后,您就可以将设计数据喂给 Cursor 了:

  1. 在 Figma 客户端中,确保切换到 Dev Mode(这里需要将Figma升级到专业版或者教育版,可以看看某鱼)。
  2. 选择您想要生成代码的图层或组件
  3. 右键点击,选择 Copy link to selection

image.png

  1. 将复制的链接粘贴到 Cursor 的输入框或聊天界面中,并提出您的代码生成请求(例如:“为我生成这段设计的 Android XML 代码”)。

下面是我和AI对话的流程以及最后的效果图

# 任务:严格复刻响应式 Figma 组件
**1. 目标设计图链接(含 Node ID):**

{ https://www.figma.com/design/c4BVKzIN4oVNuxV9OzUhC8/Untitled?node-id=1-616&t=IiXRzf3Lq5QE7N3K-4 }

**2. 核心要求:**

- **复刻范围:** 请严格复刻链接指向的【首页/特定框架名称】中的**主要导航栏 (Header/Navbar)****英雄区 (Hero Section)**- **响应式处理:** 必须使用 Figma MCP 获取设计稿中的所有**响应式断点**(例如 Desktop、Tablet、Mobile)。代码必须使用媒体查询(Media Queries)或框架的响应式工具(如 Tailwind CSS 的 `md:``lg:` 前缀)来精确实现不同断点下的布局、间距和字体大小变化。

- **样式严格性:** 所有颜色、字体、圆角、内/外边距、阴影必须严格匹配 Figma 中定义的设计 Token。

**3. 技术栈和格式:**

- **语言/框架:** React (或 Next.js)。

- **样式方案:** Tailwind CSS (推荐用于响应式),或者 CSS Modules。

- **文件名:** 请将代码拆分成两个文件:`Header.jsx``HeroSection.jsx`**4. 额外功能/工具调用指示:**

- **Design Token:** 请优先调用 `figma/get_color_styles``figma/get_text_styles` 等 MCP 工具来提取并定义颜色变量和字体样式,作为代码的常量或 Tailwind 配置的扩展。

- **交互占位符:** 导航栏中的链接使用 `<a href="#">` 作为占位符。

---

请开始生成代码,位置为figmaMcp。

你要调用我配置好的 figmamcp server

image.png

再次根据设计稿检查有没有不合理的地方https://www.figma.com/design/c4BVKzIN4oVNuxV9OzUhC8/Untitled?node-id=1-616&t=IiXRzf3Lq5QE7N3K-4 ,并修改,要达成一比一复刻

image.png

二、使用Figma MCP的注意事项和规范

使用 Figma MCP(Model Component Protocol)规范与 Cursor 这样的 AI 编码工具结合时,要实现高效、准确的代码生成,您需要注意的要点可以总结为 "设计纪律""AI 引导" 两个方面。

Figma MCP 的作用是提供结构化数据,但数据的质量和清晰度完全取决于设计师在 Figma 中的操作。


1.设计师需要注意的“设计纪律”

AI 生成代码的质量,90% 取决于 Figma 文件的规范程度。 为了让 AI 能准确地“理解”设计稿,设计师必须做到以下几点:

(1) 结构化组件是基础

  • 使用 Auto Layout(自动布局): 这是实现响应式设计的核心。确保所有的布局(尤其是列表、卡片、侧边栏等)都使用 Auto Layout,并设置正确的填充(Padding)和间距(Gap)。AI 依赖 Auto Layout 来识别 FlexboxStackViewColumn/Row 等布局结构。
  • 清晰的图层命名: 这是最关键的一步。 图层名称应该是语义化的(例如:Item/ProductCardButton/PrimaryList/RecentOrders)。避免使用默认的名称(例如:Rectangle 1Group 4)。
  • 组件化和变体: 尽可能将设计元素抽象为 Figma 组件变体(Variants) 。这能让 AI 识别出哪些是可复用的模块,并生成组件代码(例如 React Components 或 SwiftUI Views)。

(2) 统一使用设计 Token/变量

  • 使用 Figma Variables(变量/令牌): 颜色、字体大小、间距(Spacing)等属性,应统一使用 Figma 的 Variables(设计令牌) 。AI 接收到的数据将是 $color-primary-500 而非 #007AFF,这能让生成的代码直接映射到您的企业代码主题
  • 字体和样式一致性: 确保所有文本都链接到同一套文本样式

(3) 明确的交付状态

  • 使用 Dev Mode Statuses: 设计师应该利用 Figma Dev Mode 中的状态标记(如 Ready for dev)来明确告知开发者和 AI 哪些部分可以开始使用了,避免 AI 读取到正在修改中的设计稿。

2. 开发者需要注意的“AI 引导”

即使设计稿非常规范,AI 默认生成的代码也可能不符合企业级项目的技术栈。开发者需要通过 Cursor Rules 等方式对 AI 进行二次约束和引导。

(1) 强制组件库替换

  • 制定 Cursor Rules: 针对上文提到的企业组件库适配问题,利用 Cursor 的规则配置能力,设定替换逻辑。

    • 示例规则: 如果 AI 识别到 Figma 中图层名为 Button/Primary,则强制生成的代码不是 <button><TextView>,而是 <MyCustomUIButton.Primary />
  • 输入提示(Prompt)引导: 在粘贴 Figma 链接时,明确告知 Cursor 应该使用哪个技术栈和组件库。

    • 示例 Prompt: “请为我生成这段设计的 Android Compose UI 代码,并确保使用我们团队的 "Dewu-Design-System" 中的组件。”

(2) 解决动态布局的语义化问题

  • 图层命名约定(与设计师协作): 与设计师团队约定一套统一的列表命名规则,例如:

    • 单个 Item: 图层名必须以 item__card 结尾。
    • 列表容器: 图层名必须以 list__container 结尾。
  • Rules 强制生成动态结构: 将上述命名约定植入 Cursor Rules 中,强制 AI 在识别到这些前缀时,生成 RecyclerViewLazyColumnFlatList 这样的动态列表结构,而不是一堆静态 View。

(3) 处理图片和本地资源

  • 资源缺失是常态: 目前,AI 无法自动下载本地图片资源。您需要手动下载并替换代码中的占位符。
  • Placeholder 命名: 确保设计稿中图片的图层命名是清晰的(例如:icon_user_avatar),这样生成的代码中对资源的引用名称也会更清晰,方便您替换。
❌
❌