Skip to main content
Glama

schedule_tool

Create, cancel, or list scheduled tasks for automated tool execution with recurring intervals or specific timing.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actionYesAction type (create/cancel/list)
timeNoAbsolute execution time (YYYY-MM-DD HH:mm:ss)
delaySecondsNoDelay execution by N seconds
intervalNoRecurring interval pattern (e.g. 'every@5m')
toolNameNoTool to execute (e.g. 'time_tool')
toolArgsNoParameters for the target tool
idNoTask ID (required for cancel)

Implementation Reference

  • Main handler function implementing the logic for scheduling, canceling, listing, and managing recurring tasks by executing other tools at specified times.
    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); } };
  • Input schema defining the structure and validation for schedule_tool parameters, including actions and scheduling options.
    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"] };
  • Dynamic registration of all tools, including 'schedule_tool', by scanning the tools directory, importing modules, extracting schema/handler/destroy, and populating global tools and handlers registries.
    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; }
  • Core helper function that sets up timers for scheduled tasks based on their type (absolute time, relative delay, or recurring interval).
    async function scheduleTask(task: ScheduledTask) { switch (task.type) { case 'once_absolute': const targetTime = new Date(task.time); const delay = targetTime.getTime() - Date.now(); if (delay > 0) { task.timerId = setTimeout(async () => { await executeTask(task); }, delay); } break; case 'once_relative': const delaySeconds = task.delaySeconds; const delayMs = delaySeconds * 1000; task.timerId = setTimeout(async () => { await executeTask(task); }, delayMs); break; case 'recurring': const intervalStr = task.interval; const num = parseInt(intervalStr.substring(6)); const unit = intervalStr.slice(String(num).length + 6); let intervalMs = 0; if (unit === 's') { intervalMs = num * 1000; } else if (unit === 'm') { intervalMs = num * 60 * 1000; } else if (unit === 'h') { intervalMs = num * 60 * 60 * 1000; } else if (unit === 'd') { intervalMs = num * 24 * 60 * 60 * 1000; } if (intervalMs <= 0) { console.error(`Invalid interval for task ${task.id}: ${task.interval}`); return; } const scheduleRecurring = async () => { await executeTask(task); // Schedule next execution task.timerId = setTimeout(scheduleRecurring, intervalMs); }; let initialDelay = 0; if (task.startTime) { const startTime = new Date(task.startTime); initialDelay = startTime.getTime() - Date.now(); if (initialDelay < 0) { initialDelay = 0; } } task.timerId = setTimeout(scheduleRecurring, initialDelay); break; } }
  • Helper function that executes the scheduled tool call and updates task status.
    async function executeTask(task: ScheduledTask) { await callToolHandler({ params: { name: task.toolName, arguments: task.toolArgs } }, 'schedule_tool_' + task.id); task.executed = true; task.lastExecutionTime = new Date().toISOString(); saveTasks(); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/xiaoguomeiyitian/ToolBox'

If you have feedback or need assistance with the MCP directory API, please join our Discord server