A robust task scheduler server built with Model Context Protocol (MCP) for scheduling and managing various types of automated tasks.
MCP Scheduler is a versatile task automation system that allows you to schedule and run different types of tasks:
- Shell Commands: Execute system commands on a schedule
- API Calls: Make HTTP requests to external services
- AI Tasks: Generate content through OpenAI models
- Reminders: Display desktop notifications with sound
The scheduler uses cron expressions for flexible timing and provides a complete history of task executions. It's built on the Model Context Protocol (MCP), making it easy to integrate with AI assistants and other MCP-compatible clients.
- Multiple Task Types: Support for shell commands, API calls, AI content generation, and desktop notifications
- Cron Scheduling: Familiar cron syntax for precise scheduling control
- Run Once or Recurring: Option to run tasks just once or repeatedly on schedule
- Execution History: Track successful and failed task executions
- Cross-Platform: Works on Windows, macOS, and Linux
- Interactive Notifications: Desktop alerts with sound for reminder tasks
- MCP Integration: Seamless connection with AI assistants and tools
- Robust Error Handling: Comprehensive logging and error recovery
- Python 3.10 or higher
- uv (recommended package manager)
# For Mac/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# For Windows (PowerShell)
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
After installing uv, restart your terminal to ensure the command is available.
# Clone the repository
git clone https://github.com/yourusername/mcp-scheduler.git
cd mcp-scheduler
# Create and activate a virtual environment with uv
uv venv
source .venv/bin/activate # On Unix/MacOS
# or
.venv\Scripts\activate # On Windows
# Install dependencies with uv
uv pip install -r requirements.txt
If you prefer using standard pip:
# Clone the repository
git clone https://github.com/yourusername/mcp-scheduler.git
cd mcp-scheduler
# Create and activate a virtual environment
python -m venv .venv
source .venv/bin/activate # On Unix/MacOS
# or
.venv\Scripts\activate # On Windows
# Install dependencies
pip install -r requirements.txt
# Run with default settings (stdio transport)
python main.py
# Run with server transport on specific port
python main.py --transport sse --port 8080
# Run with debug mode for detailed logging
python main.py --debug
SSE (Server-Sent Events) is an HTTP-based protocol that allows the server to push
events to the client over a single long-lived connection. When running the
scheduler with --transport sse
, FastMCP exposes an HTTP endpoint that streams
JSON-RPC responses using SSE. This mode is suitable when integrating with tools
that expect an HTTP interface rather than standard input/output.
To use your MCP Scheduler with Claude Desktop:
- Make sure you have Claude Desktop installed
- Open your Claude Desktop App configuration at:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
- Windows:
%APPDATA%\Claude\claude_desktop_config.json
- macOS:
- Create the file if it doesn't exist, and add your server:
{
"mcpServers": [
{
"type": "stdio",
"name": "MCP Scheduler",
"command": "python",
"args": ["/path/to/your/mcp-scheduler/main.py"]
}
]
}
Alternatively, use the fastmcp
utility if you're using the FastMCP library:
# Install your server in Claude Desktop
fastmcp install main.py --name "Task Scheduler"
--address Server address (default: localhost)
--port Server port (default: 8080)
--transport Transport mode (sse or stdio) (default: stdio)
--log-level Logging level (default: INFO)
--log-file Log file path (default: mcp_scheduler.log)
--db-path SQLite database path (default: scheduler.db)
--config Path to JSON configuration file
--ai-model AI model to use for AI tasks (default: gpt-4o)
--version Show version and exit
--debug Enable debug mode with full traceback
--fix-json Enable JSON fixing for malformed messages
You can use a JSON configuration file instead of command-line arguments:
{
"server": {
"name": "mcp-scheduler",
"version": "0.1.0",
"address": "localhost",
"port": 8080,
"transport": "sse"
},
"database": {
"path": "scheduler.db"
},
"logging": {
"level": "INFO",
"file": "mcp_scheduler.log"
},
"scheduler": {
"check_interval": 5,
"execution_timeout": 300
},
"ai": {
"model": "gpt-4o",
"openai_api_key": "your-api-key"
}
}
The MCP Scheduler provides the following tools:
list_tasks
: Get all scheduled tasksget_task
: Get details of a specific taskadd_command_task
: Add a new shell command taskadd_api_task
: Add a new API call taskadd_ai_task
: Add a new AI taskadd_reminder_task
: Add a new reminder task with desktop notificationupdate_task
: Update an existing taskremove_task
: Delete a taskenable_task
: Enable a disabled taskdisable_task
: Disable an active taskrun_task_now
: Run a task immediately
get_task_executions
: Get execution history for a taskget_server_info
: Get server information
MCP Scheduler uses standard cron expressions for scheduling. Here are some examples:
0 0 * * *
- Daily at midnight0 */2 * * *
- Every 2 hours0 9-17 * * 1-5
- Every hour from 9 AM to 5 PM, Monday to Friday0 0 1 * *
- At midnight on the first day of each month0 0 * * 0
- At midnight every Sunday
The scheduler can be configured using environment variables:
MCP_SCHEDULER_NAME
: Server name (default: mcp-scheduler)MCP_SCHEDULER_VERSION
: Server version (default: 0.1.0)MCP_SCHEDULER_ADDRESS
: Server address (default: localhost)MCP_SCHEDULER_PORT
: Server port (default: 8080)MCP_SCHEDULER_TRANSPORT
: Transport mode (default: stdio)MCP_SCHEDULER_LOG_LEVEL
: Logging level (default: INFO)MCP_SCHEDULER_LOG_FILE
: Log file pathMCP_SCHEDULER_DB_PATH
: Database path (default: scheduler.db)MCP_SCHEDULER_CHECK_INTERVAL
: How often to check for tasks (default: 5 seconds)MCP_SCHEDULER_EXECUTION_TIMEOUT
: Task execution timeout (default: 300 seconds)MCP_SCHEDULER_AI_MODEL
: OpenAI model for AI tasks (default: gpt-4o)OPENAI_API_KEY
: API key for OpenAI tasks
The MCP Scheduler exposes its API and the auto-discovery endpoint on a single port.
- MCP Server Port:
The server listens on the port defined by the environment variable
MCP_SCHEDULER_PORT
(default:8080
). The well-known schema is available athttp://<address>:<MCP_SCHEDULER_PORT>/.well-known/mcp-schema.json
.
await scheduler.add_command_task(
name="Backup Database",
schedule="0 0 * * *", # Midnight every day
command="pg_dump -U postgres mydb > /backups/mydb_$(date +%Y%m%d).sql",
description="Daily database backup",
do_only_once=False # Recurring task
)
await scheduler.add_api_task(
name="Fetch Weather Data",
schedule="0 */6 * * *", # Every 6 hours
api_url="https://api.weather.gov/stations/KJFK/observations/latest",
api_method="GET",
description="Get latest weather observations",
do_only_once=False
)
await scheduler.add_ai_task(
name="Generate Weekly Report",
schedule="0 9 * * 1", # 9 AM every Monday
prompt="Generate a summary of the previous week's sales data.",
description="Weekly sales report generation",
do_only_once=False
)
await scheduler.add_reminder_task(
name="Team Meeting",
schedule="30 9 * * 2,4", # 9:30 AM every Tuesday and Thursday
message="Don't forget the team standup meeting!",
title="Meeting Reminder",
do_only_once=False
)
When running in SSE (HTTP) mode, MCP Scheduler exposes a well-known endpoint for tool/schema auto-discovery:
- Endpoint:
/.well-known/mcp-schema.json
on the same port as the MCP API. - Purpose: Allows clients and AI assistants to discover all available MCP tools and their parameters automatically.
If you run:
python main.py --transport sse --port 8080
You can access the schema at:
http://localhost:8080/.well-known/mcp-schema.json
{
"tools": [
{
"name": "list_tasks",
"description": "List all scheduled tasks.",
"endpoint": "list_tasks",
"method": "POST",
"parameters": {
"type": "object",
"properties": {},
"required": [],
"additionalProperties": false
}
},
{
"name": "add_command_task",
"description": "Add a new shell command task.",
"endpoint": "add_command_task",
"method": "POST",
"parameters": {
"type": "object",
"properties": {
"name": {"type": "string"},
"schedule": {"type": "string"},
"command": {"type": "string"},
"description": {"type": "string"},
"enabled": {"type": "boolean"},
"do_only_once": {"type": "boolean"}
},
"required": ["name", "schedule", "command"],
"additionalProperties": false
}
}
// ... more tools ...
]
}
This schema is generated automatically from the registered MCP tools and always reflects the current server capabilities.
To use the scheduler through SSE, you need to ensure that:
- The server is running in SSE mode:
python main.py --transport sse --port 8080
- The client has access to the following endpoints:
http://<host>:<port>/.well-known/mcp-schema.json
- To discover available toolshttp://<host>:<port>/mcp/sse
- For SSE connectionhttp://<host>:<port>/mcp/messages
- To send messages to the server
# 1. First, get the schema
curl http://localhost:8080/.well-known/mcp-schema.json
# 2. Create a reminder task using the messages endpoint
curl -X POST http://localhost:8080/mcp/messages \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "add_reminder_task",
"params": {
"name": "Important Reminder",
"schedule": "*/1 * * * *",
"message": "Time for your reminder!",
"title": "Reminder",
"do_only_once": true
}
}'
import asyncio
import aiohttp
import json
async def schedule_reminder():
# Server base URL
base_url = "http://localhost:8080"
# 1. Create the task using the messages endpoint
async with aiohttp.ClientSession() as session:
# Prepare JSON-RPC message
message = {
"jsonrpc": "2.0",
"id": "1",
"method": "add_reminder_task",
"params": {
"name": "Reminder in 1 minute",
"schedule": "*/1 * * * *", # Every minute
"message": "Time for your reminder!",
"title": "Important Reminder",
"do_only_once": true
}
}
# Send the request
async with session.post(
f"{base_url}/mcp/messages",
json=message,
headers={"Content-Type": "application/json"}
) as response:
result = await response.json()
print(f"Server response: {result}")
# Run the example
asyncio.run(schedule_reminder())
-
SSE Connection Error
- Ensure the server is running and accessible
- Verify the port is open and not blocked by a firewall
- Check that the server URL is correct
- If using Docker, ensure containers are on the same network and ports are properly mapped
-
Schedule Format
- Use valid cron expressions (e.g.,
*/1 * * * *
for every minute) - For one-time tasks, use
do_only_once: true
- Common schedule examples:
*/1 * * * *
- Every minute0 */1 * * *
- Every hour0 0 * * *
- Once a day at midnight
- Use valid cron expressions (e.g.,
-
Docker Configuration If using Docker, ensure your
docker-compose.yml
includes:
services:
scheduler:
image: mcp-scheduler
ports:
- "8080:8080"
environment:
- MCP_SCHEDULER_TRANSPORT=sse
- MCP_SCHEDULER_PORT=8080
- MCP_SCHEDULER_ADDRESS=0.0.0.0
networks:
- mcp_network
networks:
mcp_network:
driver: bridge
- Status Verification To verify the server is working correctly:
# Verify server response
curl http://localhost:8080/.well-known/mcp-schema.json
# Verify existing tasks
curl -X POST http://localhost:8080/mcp/messages \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "list_tasks",
"params": {}
}'
-
Security:
- By default, the server listens on
0.0.0.0
when running in Docker - In production, consider using HTTPS and authentication
- Limit access to necessary ports
- By default, the server listens on
-
Performance:
- The SSE server maintains an open connection
- Consider the maximum number of simultaneous connections
- Monitor resource usage
-
Error Handling:
- Implement automatic reconnection in the client
- Handle timeouts appropriately
- Verify server responses
-
Debugging:
- Use
--debug
when starting the server for detailed logs - Check server logs for specific errors
- Verify network connectivity between client and server
- Use
If you want to contribute or develop the MCP Scheduler further, here are some additional commands:
# Install the MCP SDK for development
uv pip install "mcp[cli]>=1.4.0"
# Or for FastMCP (alternative implementation)
uv pip install fastmcp
# Testing your MCP server
# With the MCP Inspector tool
mcp inspect --stdio -- python main.py
# Or with a simple MCP client
python -m mcp.client.stdio python main.py
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Built on the Model Context Protocol
- Uses croniter for cron parsing
- Uses OpenAI API for AI tasks
- Uses FastMCP for enhanced MCP functionality
When using the scheduler in a Docker environment, special attention must be paid to the client configuration. Based on the server implementation and test cases, here's the correct setup:
- Server Configuration (docker-compose.yml)
services:
scheduler_mcp:
image: ghcr.io/mnofresno/scheduler-mcp:0.0.1
restart: unless-stopped
environment:
- MCP_SCHEDULER_PORT=8085
- MCP_SCHEDULER_ADDRESS=0.0.0.0
- MCP_SCHEDULER_TRANSPORT=sse
networks:
- mcp_network
networks:
mcp_network:
driver: bridge
- MCP Client Configuration
{
"id": "scheduler",
"server_url": "http://scheduler_mcp:8085",
"transport": "sse"
}
- Available Endpoints
Based on the server implementation (
server.py
) and test cases (test_well_known.py
), these are the ONLY valid endpoints:
- Schema Discovery:
http://scheduler_mcp:8085/.well-known/mcp-schema.json
- SSE Connection:
http://scheduler_mcp:8085/mcp/sse
- Message Endpoint:
http://scheduler_mcp:8085/mcp/messages
- Important Notes for Docker Setup
-
Network Configuration:
- Both client and server containers MUST be on the same Docker network
- Use the container name (
scheduler_mcp
) as the hostname in URLs - The port (8085) must match the
MCP_SCHEDULER_PORT
environment variable
-
Schema Validation:
- The server implements schema validation through
test_well_known.py
- Only tools registered in
server.py
are available - The schema endpoint (
/.well-known/mcp-schema.json
) is the source of truth for available tools
- The server implements schema validation through
-
Common Mistakes to Avoid:
- Don't use
localhost
in Docker - use the container name - Don't assume additional endpoints - only use the documented ones
- Don't modify the base paths (
/mcp/
and/.well-known/
) - they are hardcoded in the server - Don't use different ports than configured in the environment variables
- Don't use
- Verification Steps
# 1. Verify the schema endpoint is accessible
curl http://scheduler_mcp:8085/.well-known/mcp-schema.json
# 2. Verify the server is running and accessible
curl -X POST http://scheduler_mcp:8085/mcp/messages \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "get_server_info",
"params": {}
}'
# 3. Check network connectivity
docker exec your_client_container ping scheduler_mcp
- Troubleshooting Docker Issues
If you encounter connection issues:
- Verify Network:
# Check if containers are on the same network
docker network inspect mcp_network
# Check container logs
docker logs scheduler_mcp
- Verify Port Mapping:
# Check if the port is actually listening
docker exec scheduler_mcp netstat -tulpn | grep 8085
- Check Environment Variables:
# Verify environment variables in the container
docker exec scheduler_mcp env | grep MCP_SCHEDULER
- Common Error Messages and Solutions:
Error: "Connection refused"
Solution: Verify container name and port in server_url
Error: "SSE connection error"
Solution: Check if MCP_SCHEDULER_TRANSPORT=sse is set
Error: "Schema not found"
Solution: Verify the /.well-known/mcp-schema.json endpoint is accessible
- Security Considerations
- The server listens on
0.0.0.0
by default in Docker - Use Docker networks to isolate the communication
- Consider using Docker secrets for sensitive configuration
- In production, consider adding authentication to the MCP endpoints