Cursor前端初体验-不懂MCP?那就做一个MCP

前言

AI越来越火了,从年初公司提出AI优先后,这股AI的风也是慢慢吹到了团队中,笔者所在的团队是一个有着十几个人的前端小团队。其他团队的小伙伴慢慢卷起来了,隔天就要开个AI工具分享会,当其他人卷起来时,你也不得不跟紧脚步,于是便开始了解cursor,慢慢发现他似乎对我们日常的工作帮助还是蛮大的,从被迫AI到接受AI再到主动AI。

了解Cursor后,会发现mcp其实是区分他与之前的AI工具非常大的一个变动,甚至于了解完Mcp后,我甚至有点想通过他搞钱的想法,加上钱的动力,让我下定决心搞懂MCP,赚钱嘛不寒碜

什么是MCP

在cursor的文档中,解释的很透彻了,虽然他有点儿很浓的技术味。MCP其实就是供LLM智能体直接使用的工具。你可以让大模型通过MCP直接调用某些能力。

拿现实类比,AI就好像电脑,MCP就好像U盘,可以让电脑用你U盘里的所有数据,或者软件。

而他最吸引我的功能,我认为就是通过MCP可以让大模型知道实时的数据,这也是我今天想分享的内容

众所周知GPT出世的那会,AI最为诟病的其实是数据的延后性与复杂性。数据的延后让你没办法实时通过AI获取到你想要的内容,比如,我今天该不该买股票啊!!我相信用到AI的时候,各位韭菜肯定动过让AI帮你买股票的心思。数据复杂性更不用说了,一股脑检索全网的数据,让AI一本正经的胡说八道。

开发MCP

关于MCP的开发,官方文档其实说的挺清晰了,但按着文档走,终归是会遇到点问题的,所以还是将开发的全过程分享出来 因为我是前端,所以自然而然的选择TS语言,其他的语言也有,奢俭由人吧

前端的话,能看到这的大家都是懂一点的,初始化工程的事长话短说
node>22 初始化package.json

js 复制代码
{
  "name": "mcp-cursor",
  "version": "1.0.0",
  "description": "",
  "main": "dist/index.js",
  "scripts": {
    "build": "tsc",
    "dev": "tsc --watch",
    "start": "node dist/index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.15.1",
    "zod": "^3.25.76"
  },
  "devDependencies": {
    "@types/node": "^24.0.13",
    "typescript": "^5.7.2"
  }
}

在入口文件src/index.ts我们进行代码的编写

编写之前,先分析下我们的需求:我想写一个MCP工具让cursor能够通过当前的工具,实时获取到某个地方的天气预报,例如获取到美国加州的当前天气。那么我们需要的就有以下几方面的内容

1、有个接口能让我实时获得天气预报,这个MCP文档中提供了

2、有现成工具包,能让我调用他以后,cursor就能自动调用上面的接口,这个便是MCP官方提供的工具包@modelcontextprotocol/sdk

一、初始化服务器,可以直接在本地运行

javascript 复制代码
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";// 基础MCP服务,官方提供
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";// 服务器与大模型通信桥梁
import { z } from "zod";// 校验工具,校验大模型调用接口时传的入参格式

const NWS_API_BASE = "https://api.weather.gov"; 
const USER_AGENT = "weather-app/1.0"; 

// 创建 server instance 
const server = new McpServer({ 
    name: "weather",
    version: "1.0.0",
    capabilities: { resources: {}, tools: {}, },
});

二、提供接口调用方法与数据处理

在该MCP工具中需要暴露出能够给AI调用的接口能力,大模型执行该方法后,能够获得到对应的数据给大模型

js 复制代码
// 定义请求方法
async function makeNWSRequest<T>(url: string): Promise<T | null> {
  const headers = {
    "User-Agent": USER_AGENT,
    Accept: "application/geo+json",
  };

  try {
    const response = await fetch(url, { headers });
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return (await response.json()) as T;
  } catch (error) {
    console.error("Error making NWS request:", error);
    return null;
  }
}
// 定义数据结构格式化方法
function formatAlert(feature: AlertFeature): string {
  const props = feature.properties;
  return [
    `Event: ${props.event || "Unknown"}`,
    `Area: ${props.areaDesc || "Unknown"}`,
    `Severity: ${props.severity || "Unknown"}`,
    `Status: ${props.status || "Unknown"}`,
    `Headline: ${props.headline || "No headline"}`,
    "---",
  ].join("\n");
}

三、注册Tool类,提供给大模型调用

这里只注册一个方法,就是根据缩写获取到对应州的地址 tool方法有四个参数

第一个是方法名

第二个是方法描述,

第三个是对于大模型调用该方法时入参的数据格式校验,这里用zod规定了大模型传的state只能是2个字符

第四个就是具体的方法了,return 的数据会提供给大模型

js 复制代码
server.tool(
  "get-alerts",
  "Get weather alerts for a state",
  {
    state: z.string().min(2).max(2).describe("Two-letter state code (e.g. CA, NY)"),
  },
  async ({ state }) => {
    const stateCode = state.toUpperCase();
    const alertsUrl = `${NWS_API_BASE}/alerts?area=${stateCode}`;
    //
    const alertsData = await makeNWSRequest<AlertsResponse>(alertsUrl);

    if (!alertsData) {
      return {
        content: [
          {
            type: "text",
            text: "Failed to retrieve alerts data",
          },
        ],
      };
    }

    const features = alertsData.features || [];
    if (features.length === 0) {
      return {
        content: [
          {
            type: "text",
            text: `No active alerts for ${stateCode}`,
          },
        ],
      };
    }

    const formattedAlerts = features.map(formatAlert);
    const alertsText = `Active alerts for ${stateCode}:\n\n${formattedAlerts.join("\n")}`;

    return {
      content: [
        {
          type: "text",
          text: alertsText,
        },
      ],
    };
  },
);

运行 server

完成业务逻辑开发后,启动服务

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

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

以上便完成了全部mcp的业务开发,接下来要做的就是执行build生成产物,这里生成的产物就在本地环境,dist/index.js,为了验证你的产物是否正常,可以让cursor为你生成一个测试脚本,这里就不再赘述,测试脚本内容也就是手动构造入参,然后调用对应的tool类

调试MCP

打开cursor配置,在tool目录下,将我们刚刚写的mcp工具添加进去,

这其实就是告诉cursor,执行 node dist/index.js命令就能拿到我提供的工具类了

js 复制代码
{
  "mcpServers": {
    "weather": {
      "command": "node",// 命令
      "args": ["/Users/mishi/Cursor/dist/index.js"],// 地址指向
      "env": {}
    }
  }
}

效果展示

可以看到大模型给工具类传入了{state:"CA"} 并且能够根据result给我们提供相应的建议

结语

能看到这的,你以为我们只是让大模型帮我们做天气预报吗?如果这里的数据不是天气预报,而是某个公司爬取下来的财报,亦或者就是某个公司的近半年股价。那么大模型,会帮助我们分析出什么呢?

我承认,一开始脑海中浮现的就是这个,才推动着我,手写一个MCP。不仅学到了点东西,甚至能让大模型真正为个人服务

相关推荐
mldong23 分钟前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排1 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60612 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角3 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!3 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰3 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi4 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen5 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马6 小时前
AI源码分析:拆解模型底层实现逻辑
前端
IT_陈寒6 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端