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