首页Home 产品Products 服务Services 案例Work 知识库Blog 关于About 联系Contact
KNOWLEDGE · 2026-09

MCP Server 开发实战:从零搭建你的第一个 AI 工具服务器

MCP Server from Scratch: Build Your First AI Tool Server

#MCP #AI Agent #Node.js #开发实战

背景

MCP(Model Context Protocol)是 AI 客户端与外部工具之间的开放协议:Claude 系列、Hermes、Cursor 等 客户端通过它调用你写的工具,获得实时数据与执行能力。上一篇《MCP 协议入门》讲清了协议概念, 这篇直接动手:用 TypeScript 从零写一个可运行的 MCP Server,暴露「查 GitHub 仓库信息」工具, 并接入客户端调试运行。全部代码不超过 60 行,照着敲一遍就能跑。

环境准备

需要 Node.js 18+(自带全局 fetch,无需安装 axios)。初始化项目并安装官方 SDK:

mkdir mcp-github-info && cd mcp-github-info
npm init -y
npm install @modelcontextprotocol/sdk zod

SDK 当前主版本为 1.x,下面的写法均基于 1.x。如果你装到的是 0.x 旧版, 先 npm install @modelcontextprotocol/sdk@latest 升级。

最小实现:一个工具服务器

新建 server.js,完整代码如下:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({
  name: "github-info",
  version: "1.0.0",
});

server.tool(
  "get_repo_info",
  "查询 GitHub 仓库的基本信息(stars、语言、描述)",
  { owner: z.string().describe("仓库所属用户或组织"), repo: z.string().describe("仓库名") },
  async ({ owner, repo }) => {
    const r = await fetch(`https://api.github.com/repos/${owner}/${repo}`, {
      headers: { "User-Agent": "mcp-github-info" },
    });
    if (!r.ok) {
      return { content: [{ type: "text", text: `请求失败:HTTP ${r.status}` }] };
    }
    const d = await r.json();
    return {
      content: [{
        type: "text",
        text: `${d.full_name}:${d.description ?? "无描述"},stars ${d.stargazers_count},语言 ${d.language ?? "未知"},最近更新 ${d.updated_at}`,
      }],
    };
  },
);

const transport = new StdioServerTransport();
await server.connect(transport);

三个关键点:

  • McpServer:SDK 提供的高层封装,内部处理 JSON-RPC 2.0 握手与请求分发
  • server.tool:注册工具,参数用 zod 描述,客户端会拿到 JSON Schema 自动补全参数
  • StdioServerTransport:通过标准输入输出与客户端通信,适合本地直接启动

先手动验证一次

不接客户端也能自测:向 stdin 发一条初始化消息,看 stdout 是否回包:

echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0.0.1"}}}' | node server.js | head -c 300

能收到带 serverInfo 的 JSON-RPC 响应,说明服务器本身没问题。

用 Inspector 可视化调试

官方调试器 @modelcontextprotocol/inspector 提供网页界面,能看到工具列表、手动调用、参数校验错误:

npx @modelcontextprotocol/inspector node server.js

启动后浏览器打开提示的地址,左侧选工具 get_repo_info,填 owner=octocat、repo=Hello-World 调用,右侧会显示返回文本和耗时。参数缺省或类型错误时,Inspector 会直接展示 zod 的校验报错——这是排查「客户端说参数不对」的最快路径。

接入 Hermes 与 Claude Code

本地 stdio 型服务器通过客户端的 MCP 配置文件注册。以 Claude Code 为例,编辑 .mcp.json:

{
  "mcpServers": {
    "github-info": {
      "command": "node",
      "args": ["/绝对路径/server.js"]
    }
  }
}

Hermes 在设置页的 MCP 服务器面板添加同一条「本地命令」配置即可。配好后在对话里直接问「查一下 octocat/Hello-World 有多少 star」,客户端会自动调用工具并返回实时数据。注意:修改配置后要重启客户端会话,工具列表在连接时一次性加载。

进阶:参数校验与错误处理

上面的示例已经包含 zod 校验。再补两个实战惯例:

  • 限制枚举值:z.enum(["stars", "issues"]) 让客户端只能选合法参数,减少无效调用
  • 超时保护:用 AbortSignal.timeout(10000) 给 fetch 加 10 秒超时,避免工具卡死整个会话
  • 结构化错误:非 2xx 时返回 isError: true 的 content,客户端会把它当工具失败而非正常结果

远程部署的注意点

本地 stdio 适合个人使用;要给团队或线上服务用,需要换成 HTTP 传输:

  • 用 StreamableHTTPServerTransport 或社区框架(如 FastMCP)发布为 SSE/HTTP 端点
  • 必须加鉴权:Bearer Token 或 OAuth,否则任何能访问端点的人都能调用你的工具
  • 设置请求体大小与超时限制,防止恶意大 payload 打挂进程
  • 日志写到 stderr 而不是 stdout——stdout 是协议通道,混入日志会让客户端解析失败

常见坑清单

  • SDK 版本混用:客户端与服务器协议版本不兼容时,连接会静默失败,先统一升级到最新
  • 在工具函数里 console.log 调试:会污染 stdout 协议流,改用 console.error
  • 忘记 serve 静态资源:MCP 的 resources 也走同一连接,没有多余 HTTP 端口可访问
  • 长任务不回报:超过客户端超时(常见 60 秒)会被判定失败,用进度通知或拆小任务

结果

60 行代码,一个可用的 GitHub 查询工具服务器就完成了:本地自测通过、Inspector 验证参数校验、 接入客户端后对话即用。下一步可以给服务器加第二个工具(比如查询仓库 Issues), 或者换成 HTTP 传输部署到服务器上,把个人工具变成团队服务。

给 Agent 的任务书,要具体到「能写失败测试」才算合格;给维护者的 PR, 要具体到「红→绿证据链」才算专业。