ToolBox MCP Server
by xiaoguomeiyitian
Verified
# Toolbox 使用指南
## 如何添加新工具
以下是添加新工具的详细步骤和注意事项:
1. **创建工具文件:** 在 `src/tools/` 目录下创建一个新的 TypeScript 文件(例如,`my_tool.ts`)。
2. **定义参数列表(schema):**
* 在此文件中,导出一个 `schema` 对象来描述工具的参数。
* `schema` 对象必须包含以下属性:`name`(工具名称)、`description`(工具描述)、`type`(必须为 `"object"`)、`properties`(参数定义)、`required`(必需参数列表)。
* `properties` 对象中的每个参数定义必须包含 `type`(参数类型,例如 `"string"`、`"number"`、`"boolean"`)和 `description`(参数描述)属性。
* 如果参数是枚举类型,可以使用 `enum` 属性来指定枚举值。
* **注意事项:**
* `name` 必须唯一,不能与其他工具重复。
* `description` 应该清晰简洁,描述工具的功能。
* `required` 数组应包含所有必需参数,以避免工具执行期间出错。
3. **实现工具逻辑(default 函数):**
* 同样在此文件中,导出一个 `default` 函数来实现工具的特定功能。
* `default` 函数必须接收一个 `request` 参数,其中包含请求信息,例如参数。
* `default` 函数必须返回一个 Promise,并且 resolved 的值应该是一个包含 `content` 属性的对象。`content` 属性是一个包含对象的数组,该对象包含 `type`(内容类型,例如 `"text"`)和 `text`(内容文本)属性。`text` 属性应该是一个使用 `JSON.stringify(results, null, 2)` 格式化的 JSON 字符串。
* 为了避免自动工具重新加载期间的内存泄漏,添加一个 destroy 函数。
* **Destroy 函数:**
* 在工具文件中,导出一个 `destroy` 函数来释放内存、停止计时器、断开连接等。
* 系统会在重新加载工具之前自动调用此函数。
* **注意事项:**
* `request.params.arguments` 对象包含客户端传递的参数。
* 应该验证参数,以确保参数的类型和值符合预期。
* 如果在工具执行期间发生错误,应该拒绝 Promise 并返回一个包含 `isError: true` 的对象。
* `content` 数组可以包含多个对象以返回多个结果。
* 工具可以通过 `callToolHandler` 函数调用其他工具:
```typescript
await callToolHandler(
{
params: {
name: "target_tool_name",
arguments: { key: "value" }
}
},
"caller_identifier"
);
```
* **注意事项:**
* 仅在需要形成工具调用链时才主动使用 `callToolHandler`。
* 常规工具执行日志由系统自动记录,无需手动添加。
* 错误处理不需要,也不应该调用 `callToolHandler` 进行日志记录。
* 第一个参数:一个包含工具名称和参数的请求对象。
* 第二个参数:调用者的唯一标识符,用于日志跟踪。
* 被调用的工具将记录调用链信息:
```json
{
"caller": "caller_identifier",
"tool": "target_tool_name",
"tid": "关联任务 ID(可选)"
}
```
* 调用链标识符应遵循 `<parent_tool>_<unique_suffix>` 格式,例如:
```typescript
`schedule_tool_${task.id}`
```
* 多级调用将自动形成完整的调用链,并且可以通过日志字段跟踪完整的执行路径。
4. **工具动态加载:**
* `tools` 目录中的文件是动态加载的。无需修改 `src/index.ts` 或 `src/handler/ToolHandler.ts`。
5. **自动构建和重新加载:**
# 通过 MCP 客户端执行 buildReload_tool
这会自动执行:
- 编译源代码
- 重新加载所有工具
- 验证工具注册
6. **测试工具:**
添加新工具代码后,直接调用 MCP 服务器的 `buildReload_tool` 来编译和加载新工具。如果执行结果为成功,您可以立即调用新添加的 MCP 服务器工具进行测试,从而实现自动化开发和测试。如果出现测试问题,请修复问题,重新调用 MCP 服务器的 `buildReload_tool` 来编译和加载,然后再次测试。
# 完整的开发周期示例:
# 1. 创建新工具后
调用 MCP工具 buildReload_tool
# 2. 直接测试新工具
直接调用 MCP工具 your_new_tool --args '{"param1":"value1"}'
# 3. 根据测试结果修复并重新加载
## 日志规范
**日志文件路径:** `./log/ToolBox.log`
### 统一日志处理机制
系统通过 callToolHandler 实现集中式日志记录:
1. **自动日志记录**
* 所有工具调用都通过 `callToolHandler` 自动记录,无需手动添加日志代码。
* 记录的信息包括:执行时间、参数、持续时间和状态(成功/错误)。
* 错误日志自动捕获错误消息和堆栈跟踪。
2. **调用链跟踪**
* 调用者标识符遵循 `<parent_tool>_<unique_suffix>` 格式。
* 多级调用自动形成可跟踪的执行路径。
3. **标准化日志结构**
| 字段 | 来源 | 示例 |
| ------ | ------------------------ | ------------------------------- |
| ts | ISO 8601 时间戳 | "2025-03-15T02:29:40.123Z" |
| tool | 请求工具名称 | "docker\_tool" |
| caller | 调用链标识符 | "schedule\_tool\_123" |
| args | 执行参数 | { "image": "nginx" } |
| stat | success/error | "success" |
| cost | 执行持续时间 (ms) | 158 |
| err | 错误消息 | "Invalid image format" |
| trace | 错误堆栈跟踪 | Error: Invalid image format... |
## 错误处理最佳实践
**使用 try-catch 包装关键代码:**
```typescript
try {
// 关键操作
} catch (error) {
// 处理错误
throw new Error(`Operation failed: ${error instanceof Error ? error.message : String(error)}`);
}
```
**工具开发示例:**
```typescript
// 定义参数 schema
export const schema = {
name: "hello_world",
description: "一个简单的 Hello World 工具,返回问候消息",
type: "object",
properties: {
name: {
type: "string",
description: "要问候的名字"
},
language: {
type: "string",
enum: ["en", "zh", "fr"],
description: "问候语语言(en:英语,zh:中文,fr:法语)"
}
},
required: ["name"]
};
// 实现工具逻辑
export default async function(request: any) {
try {
const { name, language = "en" } = request.params.arguments;
// 参数验证
if (typeof name !== "string" || name.trim() === "") {
throw new Error("name 参数必须是非空字符串");
}
// 根据语言生成问候语
let greeting;
switch (language) {
case "zh":
greeting = `你好,${name}!`;
break;
case "fr":
greeting = `Bonjour, ${name}!`;
break;
case "en":
default:
greeting = `Hello, ${name}!`;
break;
}
// 返回结果
return {
content: [
{
type: "text",
text: greeting
}
]
};
} catch (error) {
// 错误处理
return {
content: [
{
type: "text",
text: `Error: ${error instanceof Error ? error.message : String(error)}`
}
],
isError: true
};
}
}
// Destroy 函数
export async function destroy() {
// 释放资源、停止计时器、断开连接等
console.log("Destroy hello_world tool");
}
```
**工具调用链示例:**
```typescript
import { callToolHandler } from '../handler/ToolHandler.js';
export default async function(request: any) {
try {
const { city } = request.params.arguments;
// 调用天气 API 工具获取天气数据
const weatherData = await callToolHandler(
{
params: {
name: "weather_api",
arguments: { city }
}
},
"weather_report_fetch"
);
// 调用文本格式化工具生成报告
const report = await callToolHandler(
{
params: {
name: "text_formatter",
arguments: {
template: "Weather report for {city}: {conditions}, {temperature}°C",
data: {
city,
conditions: weatherData.content[0].text.conditions,
temperature: weatherData.content[0].text.temperature
}
}
}
},
"weather_report_format"
);
return report;
} catch (error) {
return {
content: [
{
type: "text",
text: `Failed to generate weather report: ${error instanceof Error ? error.message : String(error)}`
}
],
isError: true
};
}
}