113 lines
3.9 KiB
JavaScript
113 lines
3.9 KiB
JavaScript
// 引入必要的模块
|
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
import { z } from "zod";
|
|
|
|
// 创建 MCP 服务器实例
|
|
// 为其设置一个名字和版本
|
|
const server = new McpServer({
|
|
name: "my-first-nodejs-mcp-server",
|
|
version: "1.0.0",
|
|
});
|
|
/**
|
|
* 完善版的打招呼工具
|
|
* 1. 使用 registerTool 方法进行更完整的描述
|
|
* 2. 利用 Zod 库定义严格的参数模式和验证规则
|
|
*/
|
|
server.registerTool('say_hello',
|
|
{
|
|
// 工具描述至关重要,它直接帮助AI理解工具的用途、适用场景和参数要求
|
|
description: "向指定的用户生成一条个性化的问候语。该工具适用于在对话开始时或需要欢迎用户时使用。",
|
|
// 使用 Zod 定义参数模式,这是确保AI正确传参的关键[8](@ref)
|
|
inputSchema: z.object({
|
|
// 第一个参数:用户名
|
|
name: z.string()
|
|
.min(1, { message: "姓名不能为空字符串。" }) // 基础验证:确保非空字符串
|
|
.max(50, { message: "姓名长度不能超过50个字符。" }) // 防止过长输入
|
|
.describe("被问候者的姓名。请尽量提供完整的姓名或常用称呼。"), // 清晰的参数描述
|
|
// 第二个参数(可选):语言/风格
|
|
language: z.enum(["casual", "formal", "warm"]) // 枚举类型,将AI的输入严格限制在预设的选项内
|
|
.default("casual") // 设置默认值,当AI未提供此参数时使用
|
|
.describe("问候的语言风格。'casual'为随意,'formal'为正式,'warm'为热情。默认为'casual'。"),
|
|
}),
|
|
},
|
|
async ({ name, language }) => {
|
|
// 根据不同的语言风格生成不同的问候语
|
|
const greetings = {
|
|
casual: `嘿,${name}!最近怎么样?`,
|
|
formal: `您好,${name}。很高兴见到您。`,
|
|
warm: `欢迎你,${name}!真高兴你今天能来!`,
|
|
};
|
|
|
|
const greetingMessage = greetings[language] || greetings.casual;
|
|
|
|
// MCP 工具要求返回特定的格式
|
|
return {
|
|
content: [
|
|
{
|
|
type: "text", // 内容类型为文本
|
|
text: greetingMessage,
|
|
},
|
|
],
|
|
};
|
|
});
|
|
|
|
// // 在 server.tool() 方法内,实现一个获取天气的工具
|
|
// server.registerTool(
|
|
// "get_weather",
|
|
// {
|
|
// city: z.string().describe("要查询天气的城市名称"),
|
|
// },
|
|
// async ({ city }) => {
|
|
// // 重要:API密钥等敏感信息应从环境变量读取
|
|
// const apiKey = process.env.WEATHER_API_KEY;
|
|
// if (!apiKey) {
|
|
// throw new Error("WEATHER_API_KEY 环境变量未设置");
|
|
// }
|
|
|
|
// try {
|
|
// // 调用外部天气 API
|
|
// const response = await fetch(
|
|
// `https://api.weatherapi.com/v1/current.json?key=${apiKey}&q=${city}&aqi=no`
|
|
// );
|
|
// const weatherData = await response.json();
|
|
|
|
// // 处理并返回需要的信息
|
|
// return {
|
|
// content: [
|
|
// {
|
|
// type: "text",
|
|
// text: `城市 ${city} 的天气情况:
|
|
// 温度:${weatherData.current.temp_c}°C
|
|
// 天气状况:${weatherData.current.condition.text}
|
|
// `,
|
|
// },
|
|
// ],
|
|
// };
|
|
// } catch (error) {
|
|
// // 良好的错误处理至关重要
|
|
// return {
|
|
// content: [
|
|
// {
|
|
// type: "text",
|
|
// text: `获取天气信息失败: ${error.message}`,
|
|
// },
|
|
// ],
|
|
// isError: true, // 标记这是一个错误结果
|
|
// };
|
|
// }
|
|
// }
|
|
// );
|
|
|
|
// 启动服务器,使用标准输入/输出(stdio)与客户端通信
|
|
async function main() {
|
|
const transport = new StdioServerTransport();
|
|
await server.connect(transport);
|
|
console.error("MCP 服务器已通过 stdio 启动"); // 日志输出到 stderr
|
|
}
|
|
|
|
// 运行主函数,并捕获可能的错误
|
|
main().catch((error) => {
|
|
console.error("服务器运行出现致命错误:", error);
|
|
process.exit(1);
|
|
}); |