如何搭建一个MCP服务,然后在Cursor中调用,半小时,彻底掌握MCP

实践是最好的学习,看了很多MCP的文章,还是不懂MCP干啥的,不清楚原理,不如自己搭一个,半小时,彻底掌握MCP。

今天教大家来用typescript搭建一个简单的 MCP 服务,纯粹用于演示功能

这个案例不解决任何实际问题,只为直观地展示MCP的资源 (Resources)工具 (Tools)提示 (Prompts) 这三个核心概念。

实现下面几个功能:

  • 一个资源:用于查询服务器的运行状态(假的)。

  • 两个工具:一个用于回显消息,另一个用于执行简单的数学计算。

  • 一个提示:用于引导LLM生成口号。

一、项目搭建

1、项目设置 package.json

perl 复制代码
{
  "name": "simple-mcp-demo-server",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "build": "tsc",
    "start": "node --experimental-specifier-resolution=node build/index.js"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.12.1",
    "zod": "^3.25.53"
  },
  "devDependencies": {
    "@types/node": "^20.17.58",
    "typescript": "^5.8.3"
  }
}

2、 TypeScript 配置 tsconfig.json

json 复制代码
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
} 

3、核心代码 (src/index.ts)

typescript 复制代码
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod"; // 用于定义工具和提示的输入验证schema

// 1. 创建MCP服务器实例
// McpServer 是您与MCP协议的核心接口。
const server = new McpServer({
    name: "Demo互动服务器", // 服务器的名称
    version: "1.0.0",         // 服务器的版本
    capabilities: {           // 声明服务器支持的能力,使客户端可以发现这些功能
        resources: {},
        tools: {},
        prompts: {},
    },
});

// 2. 暴露一个只读的"资源 (Resource)"
// 资源用于向大型语言模型(LLM)暴露数据和内容,类似于Web API中的GET请求。
// 它们不应执行显著的计算或产生副作用。
server.resource(
    "status", // 资源的内部名称
    "resource://status/server", // 资源的URI模板,这是一个固定URI,表示服务器状态
    async (uri) => {
        // 当客户端请求此资源时,返回预设的服务器状态信息。
        return {
            contents: [
                {
                    uri: uri.href,
                    text: "服务器运行正常,无已知错误。自上次启动以来已处理 100 次请求。",
                    mimeType: "text/plain"
                },
            ],
        };
    }
);
console.error("已注册资源: resource://status/server"); // 使用console.error进行日志输出,避免干扰stdio传输

// 3. 提供两个"工具 (Tool)"
// 工具允许LLM通过服务器执行操作,预期会执行计算并产生副作用。
// 工具调用通常需要用户的批准。

// 工具 A: 消息回显器
server.tool(
    "echo_message", // 工具的内部名称
    "回显您输入的任何消息", // 对人类友好的描述
    {
        // 输入参数的Zod schema,Zod是一个用于schema验证的库。
        message: z.string().describe("要回显的文本消息"), // 消息内容
    },
    async ({ message }) => {
        // 工具的执行逻辑
        return {
            content: [
                {
                    type: "text",
                    text: `你说了:${message}`, // 返回原样消息,前面加上"你说了:"
                },
            ],
        };
    }
);
console.error("已注册工具: echo_message");

// 工具 B: 简单数字计算器
server.tool(
    "simple_calculation", // 工具的内部名称
    "执行两个数字之间的简单加减乘除运算", // 对人类友好的描述
    {
        a: z.number().describe("第一个数字"),
        b: z.number().describe("第二个数字"),
        operator: z.enum(["+", "-", "*", "/"]).describe("要执行的运算(+, -, *, /)"),
    },
    async ({ a, b, operator }) => {
        let result: number | string;
        try {
            switch (operator) {
                case "+":
                    result = a + b;
                    break;
                case "-":
                    result = a - b;
                    break;
                case "*":
                    result = a * b;
                    break;
                case "/":
                    if (b === 0) {
                        return { // 如果除数为零,返回错误信息
                            content: [{ type: "text", text: "错误:除数不能为零。" }],
                            isError: true, // 标记为错误结果
                        };
                    }
                    result = a / b;
                    break;
                default:
                    return {
                        content: [{ type: "text", text: "错误:不支持的运算符。" }],
                        isError: true,
                    };
            }
            return {
                content: [
                    {
                        type: "text",
                        text: `结果:${result}`, // 返回计算结果
                    },
                ],
            };
        } catch (error: any) {
            return {
                content: [{ type: "text", text: `执行计算时发生错误: ${error.message}` }],
                isError: true,
            };
        }
    }
);
console.error("已注册工具: simple_calculation");

// 4. 定义一个"提示 (Prompt)"
// 提示是可重用的模板,旨在帮助LLM与服务器有效互动,通常由用户控制,以UI元素(如斜杠命令)的形式呈现。
server.prompt(
    "generate_slogan", // 提示的内部名称
    "为给定主题生成一句口号", // 对人类友好的描述
    {
        theme: z.string().describe("口号的主题,例如"环保"或"创新""),
    },
    ({ theme }) => {
        // 返回一个消息数组,指导LLM如何生成口号
        return {
            messages: [
                {
                    role: "user", // 消息角色,这里模拟用户对LLM的请求
                    content: {
                        type: "text",
                        text: `请为"${theme}"主题生成一句有创意且吸引人的口号。要求口号简短有力,易于传播。`,
                    },
                },
            ],
        };
    }
);
console.error("已注册提示: generate_slogan");

// 5. 启动服务器并连接到Stdio传输
// Stdio传输通过标准输入/输出来通信,适用于本地进程和命令行工具。
async function main() {
    const transport = new StdioServerTransport();
    await server.connect(transport);
    console.error("MCP演示服务器已成功启动,并监听Stdio传输。"); // 使用console.error避免干扰Stdio通信
}

// 捕获可能发生的致命错误
main().catch((error) => {
    console.error("服务器启动时发生致命错误:", error);
    process.exit(1); // 以非零退出码表示错误
});

4、运行:

  1. 保存文件:

将上述 package.jsontsconfig.json 保存到您的项目根目录。

在项目根目录下创建 src 文件夹,并将 src/index.ts 文件保存到其中。

  1. 安装依赖:

打开终端或,导航到项目根目录,然后运行:

⚠️node版本用最新的24

复制代码
npm install
  1. 编译 TypeScript 代码:
arduino 复制代码
npm run build 

这将在 build 文件夹中生成 index.js 文件。

  1. 运行服务器:
sql 复制代码
npm start

服务器将启动,并打印启动日志

二、测试

使用 npx @modelcontextprotocol/inspector 来测试这个服务器,这是一个用于测试MCP服务器的工具。

另一个终端中,运行:

bash 复制代码
npx @modelcontextprotocol/inspector node --experimental-specifier-resolution=node build/index.js    

等待服务器启动

用浏览器打开http://127.0.0.1:6274

然后点击connect连接到我们的MCP服务

左下角显示MCP服务的日志:

顶部功能区,可以用来测试每个功能。

还记得我们实现的几个功能吗?切换按钮,就可以看到我们的服务提供哪些功能。

Resources资源

资源用于向大模型暴露数据,一般不执行计算和任务。

我们写一个显示服务器运行状态的资源,点击Stats,可以看到右侧返回了服务器状态。

3、 Prompts提示词

提示词是可复用的模板,帮用户快速生成提示词。

例如我们输入"紧跟时代步伐",就会输出我们设定的提示词模板。

4、Tools工具

工具允许LLM通过服务器执行操作,帮助运行任务。

5、输出MCP配置

点击Server Entry 就会复制配置

复制出来的配置长这样:

包含命令,参数,环境变量等。我们主要用到的是命令和参数。

三、如何在Cursor中配置MCP

添加MCP

  • 打开Cursor Setting

  • 点击添加MCP server

起个名称叫"mcp-demo",将下面的配置复制进去

注意build/index.js要换成完整的文件路径,可以参考我的,但是要换成你自己的。

json 复制代码
"mcp-demo": {
  "command": "node",
  "args": [
    "--experimental-specifier-resolution=node",
    "***/build/index.js"
  ]
}

2、启动

添加完成之后,可以看到,服务器亮起小绿点。就说明成功了。

不过cursor只支持工具,其他两个MCP功能不支持。

3、使用

直接在cursor的对话框说:使用simple_calculation计算1+2

之后会有一个Run tools的提示,点击运行就会调用MCP工具。

就这样,下课。

如果对你有帮助,别忘了一键三连🐶

相关推荐
阿湯哥23 分钟前
基于MCP协议的LLM-Agent数据流转与业务实现详解
llm·框架·agent·mcp·分工
阿湯哥1 小时前
MCP协议核心概念与通信机制
ai·mcp
许泽宇的技术分享4 小时前
解密Anthropic的MCP Inspector:从协议调试到AI应用开发的全栈架构之旅
人工智能·架构·typescript·mcp·ai开发工具
iFlow_AI10 小时前
知识驱动开发:用iFlow工作流构建本地知识库
前端·ai·rag·mcp·iflow·iflow cli·iflowcli
qdprobot10 小时前
齐护机器人AiTallpro小智AI图形化编程Mixly Scratch MQTT MCP远程控制
人工智能·mqtt·机器人·图形化编程·ai对话·mcp·小智ai
早川不爱吃香菜11 小时前
MCP 教程:使用高德地图 MCP Server 规划行程
mcp·trae
TeamDev1 天前
使用 MCP 自动化 JxBrowser
浏览器自动化·jxbrowser·mcp·模型上下文协议·mcp 自动化·jxbrowser 自动化·jxbrowser mcp
ChaITSimpleLove2 天前
使用 .net10 构建 AI 友好的 RSS 订阅机器人
人工智能·.net·mcp·ai bot·rss bot
妮妮分享2 天前
维智 MCP 接口服务技术支持指南
mcp·mcp server·维智 mcp·智能体接口
感谢地心引力2 天前
【AI】免费的代价?Google AI Studio 使用指南与 Cherry Studio + MCP 实战教程
人工智能·ai·google·chatgpt·gemini·mcp·cherry studio