MCP 协议实战:从零搭建一个 MCP 服务器(Node.js 版)

MCP 协议实战:从零搭建一个 MCP 服务器(Node.js 版)

一、背景

说实话,MCP(Model Context Protocol)最近是真的火。Anthropic 搞出来这个协议之后,各种 AI 工具都在接入。说白了,MCP 就是一套标准接口,让 AI 模型能直接调用外部工具、读取文件、查数据库------不再局限在聊天框里。

但我发现一个问题:网上聊 MCP 概念的文章很多,真正教你手写一个 MCP 服务器的,真没几个。今天就来填这个坑,从零开始搭一个 MCP 服务器,附带完整的 TypeScript 代码。

二、MCP 是个啥

先简单说下 MCP 的核心概念。它本质上就是一个 JSON-RPC 协议,定义了三种角色:

  • Host:发起请求的一方(比如 Claude Desktop、Cursor)
  • Client:在 Host 内部和 Server 建立连接
  • Server:提供工具、资源、提示的服务端

MCP 支持两种传输方式:stdio (通过标准输入输出通信)和 SSE(通过 HTTP 流式通信)。我们今天用 stdio 方式,因为本地开发最方便。

三、环境准备

需要的东西很少:

  • Node.js 18+
  • npm 或 yarn
  • 一个支持 MCP 的客户端(比如 Claude Desktop)

四、项目初始化

直接开干:

bash 复制代码
mkdir mcp-demo-server
cd mcp-demo-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx

这里的关键依赖是 @modelcontextprotocol/sdk,Anthropic 官方提供的 TypeScript SDK。我们直接用 tsx 来运行,省去编译步骤。

五、写一个 MCP 服务器

创建 src/index.ts

typescript 复制代码
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

// 1. 创建服务器实例
const server = new Server(
  {
    name: "mcp-demo-server",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

说白了这个代码就是注册一个 MCP 服务器,告诉客户端我叫什么名字、有什么能力。

注册工具列表

MCP 客户端会先问服务器"你有什么工具",所以我们要实现 ListTools 请求:

typescript 复制代码
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "calculate",
        description: "执行数学计算",
        inputSchema: {
          type: "object",
          properties: {
            expression: {
              type: "string",
              description: "数学表达式,如 1 + 2 * 3",
            },
          },
          required: ["expression"],
        },
      },
      {
        name: "get_weather",
        description: "获取指定城市的天气",
        inputSchema: {
          type: "object",
          properties: {
            city: {
              type: "string",
              description: "城市名称",
            },
          },
          required: ["city"],
        },
      },
    ],
  };
});

实现工具调用

当客户端调某个工具时,会触发 CallTool 请求:

typescript 复制代码
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  switch (name) {
    case "calculate": {
      const expression = String(args?.expression || "");
      try {
        // 安全起见,用 mathjs 之类的库,这里用 Function 做演示
        const result = new Function(`return (${expression})`)();
        return {
          content: [{ type: "text", text: String(result) }],
        };
      } catch (e) {
        return {
          content: [{ type: "text", text: `计算错误: ${e}` }],
          isError: true,
        };
      }
    }

    case "get_weather": {
      const city = String(args?.city || "");
      // 这里本该调用天气 API,但为了演示直接返回模拟数据
      return {
        content: [
          {
            type: "text",
            text: `${city} 今天天气:晴,温度 28°C,湿度 65%`,
          },
        ],
      };
    }

    default:
      throw new Error("未知工具: " + name);
  }
});

启动服务器

typescript 复制代码
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("MCP 服务器已启动");
}

main().catch(console.error);

六、配置客户端

用 Claude Desktop 连接时,需要在 claude_desktop_config.json 中添加:

json 复制代码
{
  "mcpServers": {
    "mcp-demo": {
      "command": "npx",
      "args": ["tsx", "src/index.ts"]
    }
  }
}

重启 Claude Desktop,就能看到两个新工具了。

七、踩坑记录

说几个坑:

  1. SDK 版本问题 - 最新版 SDK 用 @modelcontextprotocol/sdk,别用旧版的 mcp-sdk。引入路径要写全 /index.js,不然会报模块找不到。

  2. stdio 方式别用 console.log - MCP 用 stdio 通信,如果代码里用了 console.log,会污染通信流。统一用 console.error 或专门的 logger。

  3. zod 校验 - 推荐用 zod 做输入参数校验,避免客户端传了非法参数导致服务器崩溃。

八、总结

说实话,MCP 的入门门槛比我想象的低很多。核心代码就几十行,跑通 stdio 通信之后,后面加工具就跟写 API 接口一样简单。

回顾一下我们今天做了什么:

  1. 创建了一个 MCP 服务器项目
  2. 注册了两个工具(计算器和天气查询)
  3. 用 stdio 方式启动
  4. 配置了 Claude Desktop 客户端

下一步可以试试 SSE 方式------支持远程连接,更适合生产环境部署。或者用 Python 的 SDK 再写一遍,对比一下两种语言的差异。

代码已上传到 github.com/xxx/mcp-demo-server,有用的话点个 star 吧 👇

相关推荐
火山引擎开发者社区1 小时前
TLS for DeepSeek Harness 可观测实践:从系统总览到会话复盘
人工智能
数字融合3 小时前
透明化地铁线视频孪生综合监控项目技术
大数据·人工智能·virtualenv
鼎艺创新科技4 小时前
不依赖 UE/Unity:我们如何从零搭建一套国产三维 GIS 渲染引擎
人工智能·算法·unity·游戏引擎·三维电子沙盘
你别说话了4 小时前
Vue项目解决跨域
前端·javascript·vue.js
十三画者4 小时前
【文献分享】ConfRetro:融合3D构象信息的逆合成预测Transformer框架
人工智能·深度学习·数据挖掘·数据分析·transformer·数据可视化
前沿在线4 小时前
百度文心助手推出任务引擎 2.0,日活用户同比增长 83%,日均对话轮次增长超 2 倍
人工智能·ai·大模型
zandy10114 小时前
AI办公工具选哪个?千问办公、百度搭子、WorkBuddy三款高阶智能体深度拆解
人工智能·ai办公工具
mengpp_1234564 小时前
AIoT平台 vs 普通IoT平台 核心区别
人工智能
canonical_entropy4 小时前
可逆不是逆向运行:DeepSeek Harness 架构的数学本质
人工智能·架构·agent
别动我齐刘海5 小时前
机器人运动控制学习2——基础进阶
c++·人工智能·神经网络·学习·目标检测·机器学习·机器人