ToolBox MCP Server
by xiaoguomeiyitian
Verified
# Toolbox Usage Guide
## How to Add a New Tool
Here are the detailed steps and precautions for adding a new tool:
1. **Create a Tool File:** Create a new TypeScript file (e.g., `my_tool.ts`) in the `src/tools/` directory.
2. **Define the Parameter List (schema):**
* In this file, export a `schema` object to describe the tool's parameters.
* The `schema` object must contain the following properties: `name` (tool name), `description` (tool description), `type` (must be `"object"`), `properties` (parameter definitions), `required` (list of required parameters).
* Each parameter definition in the `properties` object must include the `type` (parameter type, such as `"string"`, `"number"`, `"boolean"`) and `description` (parameter description) properties.
* If the parameter is an enumeration type, you can use the `enum` property to specify the enumeration values.
* **Precautions:**
* `name` must be unique and cannot be duplicated with other tools.
* `description` should be clear and concise, describing the function of the tool.
* The `required` array should contain all required parameters to avoid errors during tool execution.
3. **Implement Tool Logic (default Function):**
* Also in this file, export a `default` function to implement the specific function of the tool.
* The `default` function must receive a `request` parameter, which contains request information, such as parameters.
* The `default` function must return a Promise, and the resolved value should be an object containing the `content` property. The `content` property is an array containing an object, which contains the `type` (content type, such as `"text"`) and `text` (content text) properties. The `text` property should be a JSON string formatted with `JSON.stringify(results, null, 2)`.
* To avoid memory leaks during automatic tool reloading, it is recommended to add a destroy function.
* **Destroy Function:**
* In the tool file, export a `destroy` function to release memory, stop timers, disconnect, etc.
* The system automatically calls this function before the tool is reloaded.
* **Precautions:**
* The `request.params.arguments` object contains the parameters passed by the client.
* Parameters should be validated to ensure that the type and value of the parameters meet expectations.
* If an error occurs during tool execution, the Promise should be rejected and return an object containing `isError: true`.
* The `content` array can contain multiple objects to return multiple results.
* Tools can call other tools through the `callToolHandler` function:
```typescript
await callToolHandler(
{
params: {
name: "target_tool_name",
arguments: { key: "value" }
}
},
"caller_identifier"
);
```
* **Precautions:**
* Only use `callToolHandler` proactively when you need to form a tool call chain.
* Regular tool execution logs are automatically recorded by the system and do not need to be added manually.
* Error handling does not need to, and should not, call `callToolHandler` for logging.
* The first parameter: a request object containing the tool name and parameters.
* The second parameter: the unique identifier of the caller, used for log tracking.
* The called tool will record the call chain information:
```json
{
"caller": "caller_identifier",
"tool": "target_tool_name",
"tid": "associated task ID (optional)"
}
```
* The call chain identifier should follow the `<parent_tool>_<unique_suffix>` format, for example:
```typescript
`schedule_tool_${task.id}`
```
* Multi-level calls will automatically form a complete call chain, and the complete execution path can be tracked through the log fields.
4. **Tool Dynamic Loading:**
* Files in the `tools` directory are dynamically loaded. No need to modify `src/index.ts` or `src/handler/ToolHandler.ts`.
5. **Auto Build & Reload:**
# Execute through MCP client
call MCP Tool buildReload_tool
This will automatically:
- Compile source code
- Reload all tools
- Verify tool registry
6. **Testing Tools:**
After adding new tool code, directly call the MCP server's `buildReload_tool` to compile and load the new tool. If the execution is successful, you can immediately call the newly added MCP server tool for testing, thus achieving automated development and testing. If a test problem occurs, fix the problem, recompile, call the MCP server's `buildReload_tool` to compile and load, and then test again.
# Complete development cycle example:
# 1. After creating a new tool
call MCP Tool buildReload_tool
# 2. Immediately test the new tool
call MCP Tool your_new_tool --args '{"param1":"value1"}'
# 3. Fix and reload based on test results
## Logging Specifications
**Log File Path:** `./log/ToolBox.log`
### Unified Log Processing Mechanism
The system implements centralized log recording through callToolHandler:
1. **Automatic Log Recording**
* All tool calls are automatically logged through `callToolHandler` without manually adding log code.
* The recorded information includes: execution time, parameters, duration, and status (success/error).
* Error logs automatically capture error messages and stack traces.
2. **Call Chain Tracking**
* Caller identifiers follow the `<parent_tool>_<unique_suffix>` format.
* Multi-level calls automatically form a traceable execution path.
3. **Standardized Log Structure**
| Field | Source | Example |
| ------ | ------------------------ | ------------------------------- |
| ts | ISO 8601 Timestamp | "2025-03-15T02:29:40.123Z" |
| tool | Request Tool Name | "docker\_tool" |
| caller | Call Chain Identifier | "schedule\_tool\_123" |
| args | Execution Parameters | { "image": "nginx" } |
| stat | success/error | "success" |
| cost | Execution Duration (ms) | 158 |
| err | Error Message | "Invalid image format" |
| trace | Error Stack Trace | Error: Invalid image format... |
## Error Handling Best Practices
**Use try-catch to Wrap Key Code**:
```typescript
try {
// Key operations
} catch (error) {
// Handle errors
throw new Error(`Operation failed: ${error instanceof Error ? error.message : String(error)}`);
}
```
**Tool Development Example**:
```typescript
// Define parameter schema
export const schema = {
name: "hello_world",
description: "A simple Hello World tool that returns a greeting message",
type: "object",
properties: {
name: {
type: "string",
description: "The name to greet"
},
language: {
type: "string",
enum: ["en", "zh", "fr"],
description: "Greeting language (en: English, zh: Chinese, fr: French)"
}
},
required: ["name"]
};
// Implement tool logic
export default async function(request: any) {
try {
const { name, language = "en" } = request.params.arguments;
// Parameter validation
if (typeof name !== "string" || name.trim() === "") {
throw new Error("The name parameter must be a non-empty string");
}
// Generate greeting according to language
let greeting;
switch (language) {
case "zh":
greeting = `你好,${name}!`;
break;
case "fr":
greeting = `Bonjour, ${name}!`;
break;
case "en":
default:
greeting = `Hello, ${name}!`;
break;
}
// Return result
return {
content: [
{
type: "text",
text: greeting
}
]
};
} catch (error) {
// Error handling
return {
content: [
{
type: "text",
text: `Error: ${error instanceof Error ? error.message : String(error)}`
}
],
isError: true
};
}
}
// Destroy function
export async function destroy() {
// Release resources, stop timers, disconnect, etc.
console.log("Destroy hello_world tool");
}
```
**Tool Call Chain Example**:
```typescript
import { callToolHandler } from '../handler/ToolHandler.js';
export default async function(request: any) {
try {
const { city } = request.params.arguments;
// Call the weather API tool to get weather data
const weatherData = await callToolHandler(
{
params: {
name: "weather_api",
arguments: { city }
}
},
"weather_report_fetch"
);
// Call the text formatting tool to generate a report
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
};
}
}