"""Scheduler and background job tools.""" import json from mcp.types import Tool from frappe_mcp.client.frappe_api import FrappeClient def tools() -> list[Tool]: return [ Tool( name="frappe_list_scheduled_jobs", description="List all Scheduled Job Types (cron definitions).", inputSchema={ "type": "object", "properties": { "stopped": {"type": "integer", "description": "1 = stopped only, 0 = running only"}, "limit": {"type": "integer", "default": 30}, }, }, ), Tool( name="frappe_get_scheduled_job", description="Get details of a Scheduled Job Type.", inputSchema={ "type": "object", "required": ["name"], "properties": {"name": {"type": "string"}}, }, ), Tool( name="frappe_create_scheduled_job", description=( "Create a new Scheduled Job Type — a Frappe cron task " "that calls a whitelisted Python method on a schedule." ), inputSchema={ "type": "object", "required": ["method", "frequency"], "properties": { "method": {"type": "string", "description": "Dotted Python method path e.g. myapp.tasks.daily_sync"}, "frequency": { "type": "string", "enum": [ "All", "Hourly", "Daily", "Weekly", "Monthly", "Yearly", "Hourly Long", "Daily Long", "Weekly Long", "Monthly Long", "Cron", ], }, "cron_format": {"type": "string", "description": "Required if frequency is 'Cron' e.g. '0 2 * * *'"}, "stopped": {"type": "integer", "default": 0}, }, }, ), Tool( name="frappe_toggle_scheduled_job", description="Start or stop a Scheduled Job Type.", inputSchema={ "type": "object", "required": ["name", "stopped"], "properties": { "name": {"type": "string"}, "stopped": {"type": "integer", "description": "1 to stop, 0 to start"}, }, }, ), Tool( name="frappe_trigger_scheduled_job", description="Manually trigger a scheduled job to run immediately.", inputSchema={ "type": "object", "required": ["job_name"], "properties": { "job_name": {"type": "string", "description": "Scheduled Job Type name"}, }, }, ), Tool( name="frappe_list_background_jobs", description="Get the current background job queue status.", inputSchema={ "type": "object", "properties": { "status": { "type": "string", "enum": ["queued", "started", "finished", "failed"], "description": "Filter by job status", }, "limit": {"type": "integer", "default": 20}, }, }, ), Tool( name="frappe_get_scheduler_status", description="Check if the Frappe scheduler is active or paused.", inputSchema={"type": "object", "properties": {}}, ), Tool( name="frappe_enable_scheduler", description="Enable or disable the Frappe background job scheduler.", inputSchema={ "type": "object", "required": ["enable"], "properties": { "enable": {"type": "boolean", "description": "true to enable, false to disable"}, }, }, ), ] def handlers() -> dict: return { "frappe_list_scheduled_jobs": _list_scheduled_jobs, "frappe_get_scheduled_job": _get_scheduled_job, "frappe_create_scheduled_job": _create_scheduled_job, "frappe_toggle_scheduled_job": _toggle_scheduled_job, "frappe_trigger_scheduled_job": _trigger_scheduled_job, "frappe_list_background_jobs": _list_background_jobs, "frappe_get_scheduler_status": _get_scheduler_status, "frappe_enable_scheduler": _enable_scheduler, } async def _list_scheduled_jobs(args: dict) -> str: client = FrappeClient() filters = [] if "stopped" in args: filters.append(["stopped", "=", args["stopped"]]) result = await client.get_list( "Scheduled Job Type", fields=["name", "method", "frequency", "cron_format", "stopped", "last_execution"], filters=filters if filters else None, limit=args.get("limit", 30), ) return json.dumps(result, indent=2) async def _get_scheduled_job(args: dict) -> str: client = FrappeClient() result = await client.get_doc("Scheduled Job Type", args["name"]) return json.dumps(result, indent=2) async def _create_scheduled_job(args: dict) -> str: client = FrappeClient() result = await client.create_doc("Scheduled Job Type", args) return json.dumps(result, indent=2) async def _toggle_scheduled_job(args: dict) -> str: client = FrappeClient() result = await client.update_doc("Scheduled Job Type", args["name"], {"stopped": args["stopped"]}) return json.dumps(result, indent=2) async def _trigger_scheduled_job(args: dict) -> str: client = FrappeClient() result = await client.call_method( "frappe.core.doctype.scheduled_job_type.scheduled_job_type.run_scheduled_job", job_type=args["job_name"], ) return json.dumps(result, indent=2) async def _list_background_jobs(args: dict) -> str: client = FrappeClient() result = await client.call_method( "frappe.utils.background_jobs.get_jobs", status=args.get("status", ""), ) return json.dumps(result, indent=2) async def _get_scheduler_status(args: dict) -> str: client = FrappeClient() result = await client.call_method("frappe.core.doctype.scheduled_job_type.scheduled_job_type.get_enabled_scheduler_events") return json.dumps(result, indent=2) async def _enable_scheduler(args: dict) -> str: client = FrappeClient() method = "frappe.desk.doctype.event.event.get_events" if args["enable"] else "frappe.handler.ping" method = "frappe.core.doctype.system_settings.system_settings.enable_scheduler" if args["enable"] else \ "frappe.core.doctype.system_settings.system_settings.disable_scheduler" result = await client.call_method(method) return json.dumps(result, indent=2)