如何搭建一个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工具。

就这样,下课。

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

相关推荐
kaizq10 小时前
AI-MCP-SQLite-SSE本地服务及CherryStudio便捷应用
python·sqlite·llm·sse·mcp·cherry studio·fastmcp
太空眼睛13 小时前
【MCP】使用SpringBoot基于Streamable-HTTP构建MCP-Server
spring boot·sse·curl·mcp·mcp-server·spring-ai·streamable
康de哥21 小时前
MCP Unity + Claude Code 配置关键步骤
unity·mcp·claude code
田井中律.1 天前
MCP协议
mcp
通义灵码1 天前
Qoder 支持通过 DeepLink 添加 MCP Server
人工智能·github·mcp
酩酊仙人2 天前
fastmcp构建mcp server和client
python·ai·mcp
kwg1263 天前
本地搭建 OPC UA MCP 服务
python·agent·mcp
小小工匠3 天前
LLM - 从通用对话到自治智能体:Agent / Skills / MCP / RAG 三层架构实战
agent·rag·skill·mcp
小小工匠3 天前
LLM - 将业务 SOP 变成 AI 能力:用 Skill + MCP 驱动 Spring AI 应用落地不完全指南
人工智能·skill·spring ai·mcp
Esun_R4 天前
当 LLM 开始连接真实世界:MCP 的原理、通信与工程落地
node.js·openai·mcp