MCP-Frappe/frappe_mcp/tools/scheduler.py
MOHAN 2ee93048e1 feat: Add tools for managing server scripts, client scripts, translations, assignment rules, user permissions, webhooks, API keys, and workflows
- Implemented server and client script management tools in `frappe_mcp/tools/scripts.py`
- Added translation and user permission management tools in `frappe_mcp/tools/translations.py`
- Created user and role management tools in `frappe_mcp/tools/users.py`
- Developed webhook and API key management tools in `frappe_mcp/tools/webhooks.py`
- Introduced workflow management tools in `frappe_mcp/tools/workflow_tools.py`
- Added `pyproject.toml` for project metadata and dependencies
2026-04-21 20:26:45 +05:30

180 lines
6.8 KiB
Python

"""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)