MCP 协议实践:鱼缸盐度计算
开发环境准备
创建 weather 目录,通过 npm 进行项目初始化:
mkdir memorandum
cd memorandum
npm init -y
# 安装依赖
npm install @modelcontextprotocol/sdk zod@3
npm install -D @types/node typescript
修改 package.json 中的 scripts 属性:
{
"scripts": {
"build": "tsc && chmod +x build/index.js",
"inspect": "npx @modelcontextprotocol/inspector node build/index.js"
}
}
inspect 命令调用 MCP 官方提供的调试工具,方便在开始的时候对 MCP Server 提供的能力进行测试。下面是 inspector 的界面:

在 src 下创建 index.ts 文件,然后引入相关的代码:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
这里使用 stdio 进行 MCP Client 和 MCP Server 之间的交互。所以 import 了 StdioServerTransport。
由于我们要实现的是 Tool,所以需要对 Tool 进行注册:
const server = new McpServer({
name: "weather",
version: "1.0.0",
});
server.registerTool(
"get_weather",
{
title: "Get weather for a city",
description:
"Get current weather information for a city (supports cities worldwide including Beijing, Shanghai, etc.)",
inputSchema: z.object({
city: z
.string()
.describe(
"The city name to get weather for (e.g., 'Beijing', 'Shanghai', 'New York')"
),
}),
},
async (input) => {
return {
content: [
{
type: "text",
text: "晴天☀️" + input.city,
},
],
structuredContent: {
content: [
{
type: "text",
text: "晴天☀️" + input.city,
},
],
}
};
}
);
structuredContent 上。当工具定义了 outputSchema,此字段必须在结果中存在,并包含一个符合模式的 JSON 对象。
执行 pnpm build 后,将此服务配置到 Cursor 中:
"weather": {
"command": "node",
"args": ["demo/wather-mcp/build/index.js"]
}
现在根据 MCP 网站写的 Demo 已经可以正常运行了。接下来将在此基础上进行修改。
修改 index.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { getSalt } from "./utils.js";
const server = new McpServer({
name: "fish-tank-calculator",
version: "1.0.0",
});
server.registerTool(
"get_salt",
{
title: "Get salt for a fish tank",
description:
"Get salt for a fish tank",
inputSchema: z.object({
length: z.number().describe("The length of the fish tank, cm"),
width: z
.number()
.describe(
"The width of the fish tank, cm"
),
height: z
.number()
.describe(
"The height of the fish tank, cm"
),
salinity: z
.number()
.describe(
"The salinity of the fish tank, in ‰"
),
}),
},
async (input) => {
const salt = getSalt(input.length, input.width, input.height, input.salinity);
const result = `缸体盛水${input.length}cm × 宽${input.width}cm × 高${input.height}cm = ${input.length * input.width * input.height}L,需要${salt}g海盐。`;
return {
content: [
{
type: "text",
text: result,
},
],
structuredContent: {
content: [
{
type: "text",
text: result,
},
],
}
};
}
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
src 目录下新增 utils.ts
export function getWaterVolumeInLiters(
length: number,
width: number,
height: number
) {
return Math.floor((length * width * height) / 1000);
}
export function getSalt(
length: number,
width: number,
height: number,
salinity: number
) {
// 「容器水量(公升) = 长(cm) × 宽(cm) ×高(cm) ÷ 1000」
// 「盐的份量(g) = 盐分浓度(%) × 容器水量(g) ÷ 100」
const tankVolume = getWaterVolumeInLiters(length, width, height);
return (salinity / 1000) * (tankVolume * 1000);
}

总结
本文介绍了如何使用 MCP(Model Context Protocol)协议开发一个实用的工具服务器。主要内容包括:
-
开发环境搭建:通过 npm 初始化项目,安装
@modelcontextprotocol/sdk和zod等必要依赖,配置 TypeScript 编译和 MCP Inspector 调试工具。 -
基础 MCP Server 实现:使用
StdioServerTransport作为传输层,通过registerTool方法注册工具。重点说明了structuredContent字段的重要性,当定义了outputSchema时,该字段必须存在并符合模式。 -
鱼缸盐度计算工具开发:将示例的天气查询工具改造为鱼缸盐度计算工具,实现了:
- 输入参数:鱼缸的长、宽、高(单位:cm)和盐度(单位:‰)
- 计算逻辑:根据容器水量公式和盐分浓度公式计算所需海盐重量
-
输出结果:返回包含计算结果的中文描述文本
-
配置与使用:将 MCP Server 配置到 Cursor 编辑器中,通过 JSON 配置文件指定命令和参数,实现与 AI 助手的集成。
通过这个实践案例,展示了 MCP 协议在实际场景中的应用,为开发自定义工具服务器提供了完整的参考示例。