当前位置: 首页 > news >正文

构建 MCP 服务器:第 4 部分 — 创建工具

 

这是我们构建 MCP 服务器的四部分教程的最后一部分。在第一部分中,我们使用基本资源创建了第一个 MCP 服务器。第二部分添加了资源模板并改进了代码组织。在第三部分中,我们添加了提示符并进一步完善了服务器结构。现在,我们将通过添加工具来完成服务器的搭建。

什么是 MCP 工具?

工具是 LLM 可以调用来执行操作或检索动态信息的可执行函数。与只读的资源和构建 LLM 交互的提示不同,工具允许 LLM 主动执行诸如计算值、进行 API 调用或修改数据等操作。

为什么要使用工具?

工具使 LLM 能够与系统交互并执行操作。以下是一些实际示例:

文件操作

name: "write-file"
arguments: {path: "/logs/report.txt",content: "Daily summary..."
}

用户:

将此报告保存到文件”

人工智能:

我将使用写入文件工具...文件已成功保存。

API 交互

name: "fetch-weather"
arguments: {location: "San Francisco",units: "celsius"
}

用户

旧金山的天气怎么样?

人工智能:

让我查一下……根据天气 API,气温为 18°C,晴朗。

数据处理

name: "analyze-data"
arguments: {dataset: "sales_2024_q1",operation: "summary_stats"
}

用户:

计算第一季度销售额的汇总统计数据

人工智能:

正在运行分析…平均销售额为 342,中位数为 342,…

添加工具

为我们的新工具创建一个新文件,并添加一个“创建消息”工具:

// src/tools.ts// Allowed values
const messageTypes = ['greeting', 'farewell', 'thank-you'] as const;
const tones = ['formal', 'casual', 'playful'] as const;// tool definitions
export const tools = {'create-message': {name: 'create-message',description: 'Generate a custom message with various options',inputSchema: {type: 'object',properties: {messageType: {type: 'string',enum: messageTypes,description: 'Type of message to generate',},recipient: {type: 'string',description: 'Name of the person to address',},tone: {type: 'string',enum: tones,description: 'Tone of the message',},},required: ['messageType', 'recipient'],},},
};

到目前为止,我们所添加的只是我们工具的描述,它将允许使用该工具的模型了解它的作用以及它期望什么样的信息。

现在让我们添加实际的处理程序:

// src/tools.ts// Allowed values
const messageTypes = ['greeting', 'farewell', 'thank-you'] as const;
const tones = ['formal', 'casual', 'playful'] as const;// tool definitions
export const tools = {// ... existing defs
};type CreateMessageArgs = {messageType: typeof messageTypes[number];recipient: string;tone?: typeof tones[number];
};// Simple templates for the various message combinations
const messageFns = {greeting: {formal: (recipient: string) =>`Dear ${recipient}, I hope this message finds you well`,playful: (recipient: string) => `Hey hey ${recipient}! 🎉 What's shakin'?`,casual: (recipient: string) => `Hi ${recipient}! How are you?`,},farewell: {formal: (recipient: string) =>`Best regards, ${recipient}. Until we meet again.`,playful: (recipient: string) =>`Catch you later, ${recipient}! 👋 Stay awesome!`,casual: (recipient: string) => `Goodbye ${recipient}, take care!`,},"thank-you": {formal: (recipient: string) =>`Dear ${recipient}, I sincerely appreciate your assistance.`,playful: (recipient: string) =>`You're the absolute best, ${recipient}! 🌟 Thanks a million!`,casual: (recipient: string) =>`Thanks so much, ${recipient}! Really appreciate it!`,},
};const createMessage = (args: CreateMessageArgs) => {if (!args.messageType) throw new Error("Must provide a message type.");if (!args.recipient) throw new Error("Must provide a recipient.");const { messageType, recipient } = args;const tone = args.tone || "casual";if (!messageTypes.includes(messageType)) {throw new Error(`Message type must be one of the following: ${messageTypes.join(", ")}`,);}if (!tones.includes(tone)) {throw new Error(`If tone is provided, it must be one of the following: ${tones.join(", ")}`,);}const message = messageFns[messageType][tone](recipient);return {content: [{type: "text",text: message,},],};
};export const toolHandlers = {"create-message": createMessage,
};

现在让我们更新我们的处理程序:

// src/handlers.ts
import {CallToolRequestSchema, // <-- Add thisGetPromptRequestSchema,ListPromptsRequestSchema,ListResourcesRequestSchema,ListResourceTemplatesRequestSchema,ListToolsRequestSchema, // <-- and thisReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { resourceHandlers, resources } from "./resources.js";
import {getResourceTemplate,resourceTemplates,
} from "./resource-templates.js";
import { promptHandlers, prompts } from "./prompts.js";
import { toolHandlers, tools } from "./tools.js"; // <-- import our tools
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";export const setupHandlers = (server: Server): void => {// List available resources when clients request them// ... previously created handlers here// tools server.setRequestHandler(ListToolsRequestSchema, async () => ({tools: Object.values(tools),}));server.setRequestHandler(CallToolRequestSchema, async (request) => {type ToolHandlerKey = keyof typeof toolHandlers;const { name, arguments: params } = request.params ?? {};const handler = toolHandlers[name as ToolHandlerKey];if (!handler) throw new Error("Tool not found");type HandlerParams = Parameters<typeof handler>;return handler(...[params] as HandlerParams);});
};

最后,更新服务器初始化:

// src/index.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { setupHandlers } from "./handlers.js";const server = new Server({name: "hello-mcp",version: "1.0.0",},{capabilities: {resources: {},prompts: {},tools: {}, // <-- Add tools capability},},
);setupHandlers(server);// Start server using stdio transport
const transport = new StdioServerTransport();
await server.connect(transport);console.info('{"jsonrpc": "2.0", "method": "log", "params": { "message": "Server running..." }}',
);

理解代码

以下是我们目前所做的工作。

工具结构

  • 工具通过 inputSchema 定义其接口
  • 处理程序实现实际功能
  • 返回格式符合 MCP 规范

错误处理

  • 验证必需参数
  • 具体错误消息
  • 类型安全的处理程序访问

使用检查器进行测试

记住首先构建输出:

npm run build

然后启动检查器:

npx @modelcontextprotocol/inspector node build/index.js

测试工具:

  • 点击“工具”选项卡
  • 找到“创建消息”
  • 尝试不同的组合:
{"messageType": "thank-you","recipient": "Alice","tone": "playful"
}

使用 Claude Desktop 进行测试

尝试以下示例

注意:您可能会遇到授权使用工具的请求:

基本信息:

用户:

为 Bob 创建问候消息

克劳德:

我会使用消息工具……“嗨,鲍勃!你好吗?”

风格化消息:

用户:

向爱丽丝致以俏皮的谢意

克劳德:

使用消息工具……“你真是太棒了,爱丽丝!🌟 非常感谢!”

不同的消息类型:

用户:

您可以创建哪些类型的消息?

克劳德:

我可以帮助您使用 create-message 函数创建不同类型的消息。您可以生成:

1. 问候
2. 告别
3. 感谢信息

对于每种类型,您可以指定收件人,并可选择将语气设置为正式、随意或俏皮。您想让我演示如何创建特定类型的消息吗?

您的结果可能与上述不同,特别是如果您将此 MCP 与 Claude 以外的工具或 Sonnet 3.5 以外的模型一起使用

总结

恭喜!您现在已经构建了一个完整的 MCP 服务器,其中包含:

  • 静态和基于模板的资源
  • 可自定义的提示
  • 动态工具
  • 组织良好、类型安全的代码

您已学习了如何:

  • 构建 MCP 服务器
  • 实现不同的 MCP 功能
  • 有效地组织代码
  • 优雅地处理错误
  • 使用检查器进行测试
  • 与 Claude Desktop 集成

从这里,您可以:

  • 添加更复杂的工具
  • 与外部 API 集成
  • 实现文件操作
  • 添加数据库连接
  • 创建您自己的自定义功能

请记住,MCP 是一个不断发展的协议,因此请关注官方文档以了解新功能和最佳实践。

资料来源及其他阅读材料:

  • Tools - Model Context Protocol
  • https://github.com/modelcontextprotocol/typescript-sdk
  • https://github.com/modelcontextprotocol/inspector
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dtcms.com/a/235189.html

相关文章:

  • 【零基础 快速学Java】韩顺平 零基础30天学会Java[学习笔记]
  • 打造你的 Android 图像编辑器:深入解析 PhotoEditor 开源库
  • 用设计模式重新思考(类FSM)验证:从混乱到优雅
  • ES6——数组扩展之Set数组
  • [TIP] Ubuntu 22.04 配置多个版本的 GCC 环境
  • 第7篇:中间件全链路监控与 SQL 性能分析实践
  • 如何理解 IP 数据报中的 TTL?
  • 高效Excel合并拆分软件
  • 论文阅读:HySCDG生成式数据处理流程
  • 《ERP原理与应用教程》第3版习题和答案
  • MySQL安装与配置详细讲解
  • LINUX 66 FTP 2 ;FTP被动模式;FTP客户服务系统
  • Nestjs框架: nestjs-schedule模块注册流程,源码解析与定时备份数据库
  • Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
  • 飞云智能波段主图+多空短线决策副图指标,组合操盘技术图文解说
  • 预训练语言模型T5-11B的简要介绍
  • 【Dv3Admin】系统视图菜单字段管理API文件解析
  • 如何以 9 种方式将照片从手机传输到笔记本电脑
  • 智谱清言沉思智能体,天工智能体,agenticSeek等AI Agent测试记录
  • Linux缓冲区与glibc封装:入门指南
  • 2025年全国青少年信息素养大赛 scratch图形化编程挑战赛 小高组初赛 真题详细解析
  • 【更新至2024年】2000-2024年上市公司财务困境MertonDD模型数据(含原始数据+结果)
  • Shopify 主题开发:店铺品牌色在主题中的巧妙运用
  • Oracle 用户名大小写控制
  • 12.5Swing控件3Jpanel JOptionPane
  • 设计模式——模板方法
  • Qt生成日志与以及报错文件(mingw64位,winDbg)————附带详细解说
  • 《深度体验 Egg.js:打造企业级 Node.js 应用的全景指南》
  • AI生成的基于html+marked.js实现的Markdown转html工具,离线使用,可实时预览 [
  • 如何使用Webhook触发器,在 ONLYOFFICE 协作空间构建智能工作流