schedule_tool
Create, cancel, or list scheduled tasks for executing other tools on the ToolBox MCP Server. Specify execution time, delays, or recurring intervals to automate workflows efficiently.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | Action type (create/cancel/list) | |
| delaySeconds | No | Delay execution by N seconds | |
| id | No | Task ID (required for cancel) | |
| interval | No | Recurring interval pattern (e.g. 'every@5m') | |
| time | No | Absolute execution time (YYYY-MM-DD HH:mm:ss) | |
| toolArgs | No | Parameters for the target tool | |
| toolName | No | Tool to execute (e.g. 'time_tool') |
Implementation Reference
- src/tools/schedule_tool.ts:213-353 (handler)The primary handler function for the schedule_tool. It processes incoming requests based on the 'action' parameter (create, cancel, list, cancel_all_once, cancel_all_recurring) to manage scheduled tasks that execute other tools at specified times or intervals.export default async (request: any) => { const action = request.params.arguments?.action; const toolName = request.params.arguments?.toolName; const toolArgs = request.params.arguments?.toolArgs; const id = request.params.arguments?.id; const messages = { taskCreated: (id: string) => `Scheduled task created. ID: ${id}`, taskCanceled: (id: string) => `Task canceled. ID: ${id}`, allOnceTasksCleared: "All one-time tasks cleared", allRecurringCleared: "All recurring tasks cleared", invalidTime: "Scheduled time must be in the future", missingParams: "Missing required parameters: time/delaySeconds/interval", invalidAction: "Invalid action type" }; switch (action) { case "create": let newTask: ScheduledTask; const { time, delaySeconds, interval } = request.params.arguments; if (time && time.startsWith('every@')) { newTask = { id: uuidv4(), toolName: toolName, toolArgs: toolArgs, executed: false, creationTime: new Date().toISOString(), type: 'recurring', interval: time, }; } else if (time) { const targetTime = new Date(time); const timeDiff = targetTime.getTime() - Date.now(); if (timeDiff <= 0) { throw new Error("Scheduled time must be in the future"); } newTask = { id: uuidv4(), toolName: toolName, toolArgs: toolArgs, executed: false, creationTime: new Date().toISOString(), type: 'once_absolute', time: time, }; } else if (delaySeconds) { newTask = { id: uuidv4(), toolName: toolName, toolArgs: toolArgs, executed: false, creationTime: new Date().toISOString(), type: 'once_relative', delaySeconds: delaySeconds, }; } else if (interval) { newTask = { id: uuidv4(), toolName: toolName, toolArgs: toolArgs, executed: false, creationTime: new Date().toISOString(), type: 'recurring', interval: interval, }; } else { throw new Error("Missing required parameters: time/delaySeconds/interval"); } await createTask(newTask); return { content: [ { type: "text", text: JSON.stringify(messages.taskCreated(newTask.id), null, 2), }, ], }; case "cancel": if (!id) { throw new Error("Missing parameter: id"); } cancelTask(id); return { content: [ { type: "text", text: JSON.stringify(messages.taskCanceled(id), null, 2), }, ], }; case "list": const tasksWithoutTimerId = scheduledTasks.map(task => { const { timerId, ...taskWithoutTimerId } = task; return taskWithoutTimerId; }); return { content: [ { type: "text", text: JSON.stringify(tasksWithoutTimerId, null, 2), }, ], }; case "cancel_all_once": scheduledTasks.forEach(task => { if ((task.type === 'once_absolute' || task.type === 'once_relative') && task.timerId) { clearTimeout(task.timerId); } }); scheduledTasks = scheduledTasks.filter(task => task.type !== 'once_absolute' && task.type !== 'once_relative'); saveTasks(); return { content: [ { type: "text", text: JSON.stringify(messages.allOnceTasksCleared, null, 2), }, ], }; case "cancel_all_recurring": scheduledTasks.forEach(task => { if (task.type === 'recurring' && task.timerId) { clearTimeout(task.timerId); } }); scheduledTasks = scheduledTasks.filter(task => task.type !== 'recurring'); saveTasks(); return { content: [ { type: "text", text: JSON.stringify(messages.allRecurringCleared, null, 2), }, ], }; default: throw new Error(messages.invalidAction); } };
- src/tools/schedule_tool.ts:161-196 (schema)The input schema for schedule_tool, defining the structure and validation for parameters such as action, time, delaySeconds, interval, toolName, toolArgs, and id.export const schema = { name: "schedule_tool", description: "Manage scheduled tasks (create/cancel/list)", type: "object", properties: { action: { type: "string", enum: ["create", "cancel", "list", "cancel_all_once", "cancel_all_recurring"], description: "Action type (create/cancel/list)" }, time: { type: "string", description: "Absolute execution time (YYYY-MM-DD HH:mm:ss)" }, delaySeconds: { type: "number", description: "Delay execution by N seconds" }, interval: { type: "string", description: "Recurring interval pattern (e.g. 'every@5m')" }, toolName: { description: "Tool to execute (e.g. 'time_tool')" }, toolArgs: { type: "object", description: "Parameters for the target tool" }, id: { type: "string", description: "Task ID (required for cancel)" } }, required: ["action"] };
- src/handler/ToolHandler.ts:91-139 (registration)Dynamic tool registration function that scans the tools directory, imports each tool module (including schedule_tool.ts), extracts schema, default handler, and destroy function, and registers them in the global handlers map using the filename as the tool name.export async function loadTools(reload: boolean = false): Promise<{ [key: string]: (request: ToolRequest) => Promise<ToolResponse> }> { // 如果是初始加载且已加载,则直接返回 if (!reload && isLoaded) return; // 如果是重新加载,则重置状态 if (reload) { for (const tool of tools) { await tool?.destroy?.(); delete handlers[tool.name]; } tools.length = 0; isLoaded = false; } // 获取所有工具文件 const toolFiles = fs.readdirSync(toolsDir).filter(file => file.endsWith('.js') || file.endsWith('.ts')); // 加载每个工具 for (const file of toolFiles) { const toolPath = path.join(toolsDir, file); try { // 如果是重新加载,清除模块缓存 if (reload) clearModuleCache(toolPath); // 导入模块,重新加载时添加时间戳防止缓存 const importPath = 'file://' + toolPath + (reload ? `?update=${Date.now()}` : ''); const { default: tool, schema, destroy } = await import(importPath); const toolName = path.parse(toolPath).name; // 注册工具 tools.push({ name: toolName, description: tool.description, inputSchema: schema, destroy: destroy }); // 注册处理函数 handlers[toolName] = async (request: ToolRequest) => { return await tool(request); }; } catch (error) { console.error(`Failed to ${reload ? 'reload' : 'load'} tool ${file}:`, error); } } isLoaded = true; if (reload) console.log(`Successfully reloaded ${tools.length} tools`); return handlers; }