Schedule MCP Server
Manages Google Calendar events, including creating, updating, deleting events, listing calendars, and finding free time slots.
Syncs appointments and tasks with Notion databases, allowing querying, creating, updating appointments and tasks, and linking them with Google Calendar events.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Schedule MCP Server what does my week look like?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
schedule-mcp
Personal schedule management MCP server. Connects Google Calendar, Notion Appointments, and Notion Tasks so Claude can help you plan your week, detect conflicts, schedule task work blocks, and keep your calendar and Notion in sync.
Architecture
Google Calendar ←→ Claude (sync layer) ←→ Notion Appointments
↓
Notion Tasks
(linked via GCal event description)Key design decisions:
Google Calendar is the source of truth for time
Notion Appointments is the source of truth for context (type, notes, rich metadata)
Notion Tasks are linked to calendar events via Notion URLs in the event description (no bidirectional sync needed)
A
GCal Event IDfield on each Notion Appointment prevents duplicate syncA
GCal Series IDfield for linking Notion Appointments with recurring GCal events
Related MCP server: Google Calendar MCP Server
Tools
Tool | Source | What it does |
| GCal | List all your calendars |
| GCal | Fetch events in a date range |
| GCal | Create a calendar event |
| GCal | Update an existing event |
| GCal | Delete an event |
| GCal | Find available time blocks |
| Notion | Query appointments with filters |
| Notion | Add an appointment to Notion |
| Notion | Update an appointment |
| Notion | Check if a GCal event is already in Notion |
| Notion | Query tasks with filters |
| Notion | Get all overdue tasks |
| Notion | Add a new task |
| Notion | Update a task |
| All | Unified week view: events, appointments, tasks due, overdue tasks |
| GCal + Notion | Schedule a work block for a task |
| GCal | Detect overlaps and tight transitions |
Notion Database Schema
Appointments database — expected fields:
Field | Type | Notes |
Appointment | Title | Appointment name |
Start | Date | Start datetime |
End | Date | End datetime |
Type | Select | Medical, Personal, Work, Other |
Status | Status | Scheduled, In progress, Completed |
Canceled | Select | Canceled, Not canceled |
Recurring | Select | One-Time, Limited Recurring, Recurring |
Notes | Rich text | Free-form notes |
GCal Event ID | Rich text | Linked GCal event ID (prevents duplicate sync) |
GCal Series ID | Rich text | Linked GCal series ID (for recurring events) |
Tasks database — expected fields:
Field | Type | Notes |
Task name | Title | Task name |
Task Status | Select | Not started, In progress, Done, Archived, Overdue |
Due | Date | Due date |
Setup
1. Prerequisites
Python 3.11+
uv (recommended) or pip
A Google Cloud project with the Calendar API enabled
A Notion integration with access to your Appointments and Tasks databases
2. Google Calendar API
Go to Google Cloud Console
Create a project (or use an existing one)
Enable the Google Calendar API
Go to APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client ID
Application type: Desktop app
Download the JSON file → save as
~/.schedule_mcp/google_credentials.json(Windows:%USERPROFILE%\.schedule_mcp\google_credentials.json)
3. Notion Integration
Create a new integration (Internal, Read + Write content)
Copy the Internal Integration Token
In Notion, open your Appointments database →
...menu → Connections → add your integrationDo the same for your Tasks database
4. Configure Environment
# Linux/macOS
cp .env.example .env
# Windows (PowerShell)
Copy-Item .env.example .envThen edit .env with your credentials.
5. Install and Run
# Using uv (recommended)
uv sync
uv run schedule-mcp
# Or with pip
pip install -e .
schedule-mcpThe first run will open a browser window for Google OAuth consent. After that, the token is saved and auto-refreshed.
6. Add to Claude MCP Config
Add this to %APPDATA%\Claude\claude_desktop_config.json (Windows) or ~/Library/Application Support/Claude/claude_desktop_config.json (macOS), merged into the top-level JSON object alongside any existing keys:
{
"mcpServers": {
"schedule": {
"command": "uv",
"args": ["run", "--project", "C:/Users/YOU/source/repos/schedule_mcp", "schedule-mcp"],
"env": {
"GOOGLE_TOKEN_FILE": "C:/Users/YOU/.schedule_mcp/google_token.json",
"GOOGLE_CREDENTIALS_FILE": "C:/Users/YOU/.schedule_mcp/google_credentials.json",
"NOTION_TOKEN": "your_token_here",
"NOTION_APPOINTMENTS_DB_ID": "your_notion_appointments_db_id_here",
"NOTION_TASKS_DB_ID": "your_notion_tasks_db_id_here",
"LOCAL_TIMEZONE": "America/Los_Angeles"
}
}
}
}Replace YOU with your Windows username. On macOS, use ~ paths instead.
Example Claude Prompts
What does my week look like?
Do I have any conflicts or back-to-backs this week?
Find me 90 minutes of free time tomorrow morning for SeattleCouncilmatic work.
Schedule 2 hours for "Add transit data support to SeattleCouncilmatic"
on Thursday afternoon.
I have a dentist appointment Tuesday at 2pm — add it to both my calendar and Notion.
Show me all my medical appointments this month.
What tasks do I have due this week?Development
# Verify syntax
python -m py_compile schedule_mcp/server.py
# Run with MCP Inspector for interactive testing
npx @modelcontextprotocol/inspector uv run schedule-mcpProject Structure
schedule_mcp/
├── pyproject.toml
├── uv.lock
├── .env.example
├── README.md
└── schedule_mcp/
├── __init__.py
├── server.py # MCP server entry point
├── auth/
│ ├── __init__.py
│ └── google_auth.py # Google OAuth2 flow
├── clients/
│ ├── __init__.py
│ ├── gcal.py # Google Calendar API client
│ └── notion.py # Notion API client
└── tools/
├── __init__.py # Exports register_* functions
├── calendar.py # gcal_* MCP tools
├── appointments.py # notion_*appointment* MCP tools
├── tasks.py # notion_*task* MCP tools
└── schedule.py # schedule_* cross-source toolsAvailable Tools
17 toolsgcal_create_eventA
Create a new Google Calendar event.
When creating work blocks for Notion tasks, include the task's Notion URL in the description so there's a direct link from the calendar event to the task.
Args: params.title: Event title. params.start: ISO datetime string for start time. params.end: ISO datetime string for end time. params.description: Optional description (include Notion task URL here for task blocks). params.location: Optional location. params.calendar_id: Target calendar (default: primary).
Returns: str: JSON dict of the created event including its 'id'.
Inputs: params (required). Returns: result
gcal_delete_eventADestructiveIdempotent
Permanently delete a Google Calendar event.
This action cannot be undone. Confirm the event ID with gcal_get_events before deleting.
Args: params.event_id: ID of the event to delete. params.calendar_id: Calendar containing the event.
Returns: str: Confirmation message.
Inputs: params (required). Returns: result
gcal_find_free_slotsARead-only
Find available time slots of a given duration on a specific date.
Useful for scheduling work blocks, appointments, or any time-bound task. Returns all slots with at least the requested duration available.
Args: params.date: The date to check (ISO date string). params.duration_minutes: How long the slot needs to be (in minutes). params.earliest_hour: Don't suggest slots starting before this hour. params.latest_hour: Don't suggest slots ending after this hour. params.calendar_id: Calendar to check for conflicts.
Returns: str: JSON array of available slots with 'start' and 'end' ISO datetimes.
Inputs: params (required). Returns: result
gcal_get_eventsARead-only
Fetch Google Calendar events within a date range.
Returns a list of events with their IDs, titles, start/end times, descriptions, and locations. Use the event ID with other tools to update or delete specific events.
Args: params.start_date: Start of the date range (ISO date string). params.end_date: End of the date range (ISO date string). params.calendar_id: Calendar to query (default: primary). params.max_results: Max events to return (default: 50).
Returns: str: JSON array of event dicts.
Inputs: params (required). Returns: result
gcal_list_calendarsARead-only
List all Google Calendars the user has access to.
Returns: str: JSON array of calendars with id, summary, and primary flag.
Inputs: no named parameters. Returns: result
gcal_update_eventAIdempotent
Update one or more fields on an existing Google Calendar event. Only provided fields are changed; omitted fields remain as-is.
Args: params.event_id: ID of the event to update. params.calendar_id: Calendar containing the event. params.title/start/end/description/location: Fields to update.
Returns: str: JSON dict of the updated event.
Inputs: params (required). Returns: result
notion_create_appointmentA
Create a new appointment in the Notion Appointments database.
When syncing from Google Calendar, always pass the gcal_event_id to prevent duplicates. When creating a new appointment from scratch, omit gcal_event_id and use gcal_create_event separately to sync it to Google Calendar.
Args: params.title: Appointment name. params.start/end: ISO datetime strings. params.appointment_type: Medical, Personal, Work, or Other. params.notes: Optional notes. params.gcal_event_id: Google Calendar event ID (if syncing from GCal). params.gcal_series_id: Google Calendar series ID (for recurring appointments). params.recurring: One-Time, Limited Recurring, or Recurring.
Returns: str: JSON dict of the created appointment including Notion ID.
Inputs: params (required). Returns: result
notion_create_taskA
Create a new task in the Notion Tasks database.
Args: params.name: Task name. params.due_date: Optional due date (ISO date string). params.status: Initial status (default: Not started).
Returns: str: JSON dict of the created task including its Notion ID and URL.
Inputs: params (required). Returns: result
notion_get_appointment_by_gcal_idARead-only
Find a Notion appointment by its linked Google Calendar event ID.
Use this before syncing to check whether a calendar event already has a corresponding Notion record, preventing duplicate entries.
Args: params.gcal_event_id: Google Calendar event ID to search for.
Returns: str: JSON dict of the appointment if found, or a not-found message.
Inputs: params (required). Returns: result
notion_get_appointmentsARead-only
Query the Notion Appointments database with optional filters.
Returns appointments with Notion ID, title, start/end times, type, status, notes, and linked Google Calendar event ID (if synced).
Args: params.start_date: Only return appointments from this date onwards. params.end_date: Only return appointments up to this date. params.appointment_type: Filter by Medical, Personal, Work, or Other. params.status: Filter by Scheduled, In progress, or Completed.
Returns: str: JSON array of appointment dicts.
Inputs: params (required). Returns: result
notion_get_overdue_tasksARead-only
Return all overdue tasks — either explicitly marked Overdue or with a due date in the past that isn't marked Done, Archived, or Overdue.
Returns: str: JSON array of overdue task dicts.
Inputs: no named parameters. Returns: result
notion_get_tasksARead-only
Query the Notion Tasks database with optional filters.
Returns tasks with their Notion IDs, names, statuses, due dates, and Notion URLs (for linking in calendar event descriptions).
Args: params.status: Filter by Not started, In progress, Done, Archived, or Overdue. params.due_before: Only return tasks due on or before this date. params.due_after: Only return tasks due on or after this date.
Returns: str: JSON array of task dicts.
Inputs: params (required). Returns: result
notion_update_appointmentAIdempotent
Update fields on an existing Notion appointment. Only provided fields change.
Args: params.notion_id: The Notion page ID (from notion_get_appointments). params.*: Any fields to update.
Returns: str: JSON dict of the updated appointment.
Inputs: params (required). Returns: result
notion_update_taskAIdempotent
Update fields on an existing Notion task. Only provided fields change.
Args: params.notion_id: Notion page ID (from notion_get_tasks). params.name/status/due_date: Fields to update.
Returns: str: JSON dict of the updated task.
Inputs: params (required). Returns: result
schedule_find_conflictsARead-only
Detect overlapping events or tight transitions in a date range.
Checks Google Calendar events for: exact overlaps, events with fewer than 10 minutes between them (tight transitions), and events longer than 4 hours (marathon sessions worth flagging).
Args: params.start_date: Start of the range to scan. params.end_date: End of the range to scan. params.calendar_id: Calendar to check.
Returns: str: JSON with lists of overlaps, tight transitions, and long events.
Inputs: params (required). Returns: result
schedule_task_blockA
Schedule a focused work block for a Notion task on Google Calendar.
Creates a Google Calendar event with the task name as the title and a link to the Notion task in the description. The task itself is NOT modified — this just blocks time and creates a visible pointer.
Typical workflow: 1. notion_get_tasks → find the task and get its ID and URL 2. gcal_find_free_slots → find available time 3. schedule_task_block → create the calendar event with Notion link
Args: params.task_notion_id: Notion page ID of the task. params.task_name: Task name (used as event title). params.task_url: Notion URL (embedded in event description). params.start/end: ISO datetime strings for the work block. params.calendar_id: Target calendar.
Returns: str: JSON with the created calendar event and a confirmation.
Inputs: params (required). Returns: result
schedule_week_overviewARead-only
Get a unified overview of a week: calendar events, Notion appointments, and tasks due that week.
This is the primary 'how does my week look?' tool. It pulls from all three sources and returns a combined view so you can see everything in context — scheduled appointments, work blocks, and upcoming deadlines.
Args: params.date: Any date in the target week (defaults to current week).
Returns: str: JSON with 'week_range', 'calendar_events', 'appointments', 'tasks_due', and 'overdue_tasks' keys.
Inputs: params (required). Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 17 tools
Tools are grouped by clear domain prefixes and resource/action pairs, making most purposes obvious. The main overlaps are notion_get_overdue_tasks versus notion_get_tasks with a status filter, and schedule_task_block acting as a convenience wrapper around gcal_create_event, but the descriptions explain these well enough to prevent serious misselection.
Most tools follow a consistent verb_noun pattern with domain prefixes like gcal_create_event and notion_update_task. The schedule_* tools break the pattern, using noun phrases like schedule_week_overview and schedule_task_block rather than verb_noun names, and gcal_find_free_slots adds an adjective into the mix.
17 tools is on the higher end, but the count is reasonably justified by covering two external systems plus cross-service scheduling helpers. The set could be slightly tighter by removing redundant conveniences like notion_get_overdue_tasks, but no tool feels entirely out of place.
The server covers calendar CRUD, Notion task query/create/update, Notion appointment query/create/update, and useful cross-service views. However, there are no delete operations for Notion tasks or appointments, so cleaning up a Notion record after deleting its linked calendar event is impossible, leaving a notable lifecycle gap.
Maintenance
Related MCP Connectors
AI-native scheduler that lives in Claude. Describe meetings in plain English; Heldly does the rest.
Multiple Google accounts (Gmail, Calendar, Drive, Contacts, Tasks) in one Claude connector.
Multiple Google accounts (Gmail, Calendar, Drive, Contacts, Tasks) in one Claude connector.
Notes, tasks, habits, journal and 6 more tools Claude can read and change, with undo. Free.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceConnects Claude Desktop to Google Calendar for local calendar management including adding, updating, and deleting events, checking schedules, and calculating travel time between meetings.1ISC
- AlicenseNot gradedqualityDmaintenanceEnables Claude to interact with Google Calendar through natural language, providing the ability to view, create, update, and delete calendar events with persistent OAuth2 authentication.7 npmMIT
- AlicenseNot gradedqualityDmaintenanceEnables Claude to interact with Google Calendar through OAuth authentication, allowing users to list events, create and manage meetings, update or delete calendar entries, and find available time slots using natural language.72MIT
- AlicenseAqualityDmaintenanceIntegrates Google Calendar with the Model Context Protocol to manage events, search agendas, and check availability. It features Home Assistant integration and SSE support for remote access through Claude Desktop.11MIT