跳到主内容
新主题测试

MCP Server 自己搭建教程:10 分钟写一个能用的工具服务

100%
MCP Server 自己搭建教程:10 分钟写一个能用的工具服务

一句话结论

搭一个 MCP Server 没你想的难:本质上就是「起一个服务 + 用 SDK 注册几个带输入描述的工具 + 选一种传输方式」。本文用 TypeScript 从零写一个天气查询 MCP Server,不到 10 分钟就能被 Claude Desktop / Cursor 等客户端调用。核心难点不在代码,而在把工具的输入 schema 写清楚——写模糊了,模型就不会用或乱用你的工具。

MCP 解决了什么问题

在 MCP(Model Context Protocol,模型上下文协议)出现前,每个 AI 应用想接数据库、API、文件系统,都要自己写一套私有适配。MCP 提出一个统一协议:你按规范暴露「工具 / 资源 / 提示词」,任何兼容 MCP 的客户端(Claude Code、Cursor、 Claude Desktop 等)都能即插即用地发现并调用。关于协议本身,先看《MCP 模型上下文协议是什么》。


MCP Server 的两种主流传输:stdio(客户端把你的服务当子进程拉起,走标准输入输出,本地最常用)和 HTTP/SSE(远程部署用)。新手先吃透 stdio,再考虑上 HTTP。

从零搭建天气 MCP Server


  1. 建目录并初始化:mkdir my-mcp-server && cd my-mcp-server && npm init -y

  2. 装依赖:npm install @modelcontextprotocol/sdk zod,开发依赖 npm install -D typescript @types/node

  3. 在 src/index.ts 里创建 McpServer 实例,用 registerTool 注册工具,输入用 zod 描述。

  4. 把工具 handler 写成真正的异步函数:这里去 wttr.in 免费接口取天气,返回文本块。

  5. 接 StdioServerTransport 并 connect,console.error 打日志(stdio 下千万别用 console.log,会污染 JSON-RPC)。

  6. 编译(npm run build)后,在客户端配置里把服务加进 mcpServers,重启客户端即可对话调用。

核心代码(TypeScript)

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: "weather-server", version: "1.0.0" });

server.registerTool(
  "get_weather",
  {
    title: "Get Weather",
    description: "Get current weather for a city",
    inputSchema: { city: z.string().describe("City name") },
  },
  async ({ city }) => {
    const res = await fetch(`https://wttr.in/${encodeURIComponent(city)}?format=j1`);
    const data = await res.json();
    const c = data.current_condition[0];
    return { content: [{ type: "text", text: `${city}: ${c.temp_C}°C, ${c.weatherDesc[0].value}` }] };
  }
);

const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Weather MCP server running on stdio");
为什么 STDIO 模式下不能用 console.log?

MCP 的 stdio 传输把 JSON-RPC 消息走标准输出(stdout)。如果你在代码里 console.log,日志会和协议消息混在一起,直接破坏 JSON-RPC 帧、让服务起不来。正确做法是写 console.error(走标准错误 stderr),或用一个写 stderr/文件的日志库。这是新手踩坑第一名。

工具的 description 不是装饰。LangGraph、OpenAI Agents SDK 这类框架会把这段描述直接喂给模型来判断「要不要调这个工具」。写「Get weather data」远不如「Returns current temperature and condition for a given city」——后者让模型在合适的时候才调用,避免误用。

怎么接进客户端

编译后,在客户端配置里加上你的服务即可(以 Claude Desktop 为例):

{
  "mcpServers": {
    "weather": {
      "command": "npx",
      "args": ["tsx", "/full/path/to/my-mcp-server/server.ts"]
    }
  }
}

重启客户端后问「Tokyo 现在天气怎样」,它就会调用你的 get_weather 工具。想不依赖客户端先自测,可用官方 MCP Inspectornpx @modelcontextprotocol/inspector npx tsx server.ts,打开网页 UI 手动调工具、排查问题。

官方 Quickstart:Build an MCP server

常见问题


MCP Server 一定要用 TypeScript 写吗?
不用。官方 SDK 同时提供 TypeScript 和 Python(pip install mcp),Go、C# 也有社区/Tier-1 SDK。本文用 TS 是因为工具链最成熟,但 Python 版写法几乎一一对应。

一个 Server 能注册多个工具吗?
能,而且常见。每个新工具就是一次 registerTool 调用,带独立 schema 与 handler。你可以把数据库查询、内部 API、文件检索都挂在一个 Server 上。

本地 stdio 卡住怎么办?
长任务优先换 HTTP/SSE 传输;另外确认编译产物路径正确、客户端命令/参数填对。用 MCP Inspector 先验证比直接挂客户端更高效。

搭好的 MCP 怎么和 Claude Code 配合?
Claude Code 原生支持 MCP Server,把你的服务加进它的配置即可让终端智能体调用你的工具,扩展命令行能力(如接 GitHub、数据库)。国内镜像与订阅方案见《Claude Code 国内怎么用》。

小结

一个 MCP Server = 实例化服务器 + 注册带 schema 的工具 + 选传输 + 挂客户端。先把天气这个最小例子跑通,再把它换成你的数据库查询、内部 API、文件检索——每个新能力都只是一次 registerTool。延伸阅读:MCP 模型上下文协议是什么

这篇有帮助吗?
云上的幻象
云上的幻象查看主页
1137文章4评论

相关文章

评论 (0)

发表回复

发表回复