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 吧 👇

相关推荐
夏悠15 分钟前
安装PaddlePaddle进行本地OCR教程及避坑指南
人工智能·ocr·paddlepaddle
AI你一生一世1 小时前
Cloudflare OS:当边缘网络开始承载 Agent 运行时
人工智能·serverless·边缘计算·容器编排·cloudflare os·agent 运行时
JJJennie7771 小时前
2026年大模型网关自建还是买?MAI Gateway等主流方案横评
人工智能·开源·gateway·ai网关
拆房老料2 小时前
【第四部分:Agentic 智能体设计模式】16. 一个 Prompt 搞不定复杂任务?试试 Prompt Chaining
java·前端·人工智能·设计模式·prompt
运维行者_3 小时前
应用性能监控怎么选?从调用链到用户体验的五个能力维度
运维·服务器·数据库·人工智能·mysql·性能优化·应用性能监控
张张123y3 小时前
后端第十四课:Agent 记忆系统(让 Agent 记住上下文和用户,跨会话不健忘)
java·大数据·人工智能·python·agent·记忆
国科安芯7 小时前
四重证据,一条逻辑链:商业航天级微控制器MCU抗辐射验证方法学综述——以国科安芯AS32S601为例
人工智能·单片机·嵌入式硬件·mcu·安全·抗辐射
dk_tjy8 小时前
AI驱动的自动化攻击背景下:企业端点安全体系的技术架构与建设路径
网络·人工智能·安全·自动化·终端安全管理·数据防泄漏
布吉岛的石头8 小时前
Java 程序员第 50 阶段2:预训练的目标函数:自回归语言建模本质
java·开发语言·人工智能·深度学习·回归·transformer
2601_965454238 小时前
用AI把开源项目功能清单做成MG动画介绍视频
人工智能·开源·音视频