Calendar Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Calendar Mcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
MCP server for accessing and analyzing Google Calendar events through the Model Context Protocol.
# Install in development mode
pip install -e .Calendar MCP (or your choice)Important: Do this BEFORE creating credentials
.../auth/calendar (full access for read/write operations)calendar-mcp-clientclient_secret.json in /Users/feamster/src/calendar-mcp/Note: The Google Cloud Console interface uses "OAuth Platform" with Audience/Data Access/Clients, not the old consent screen wizard.
Run the authentication setup:
python -m calendar_mcp.authThis will:
~/.mcp-auth/calendar/tokens/Important: Google will show a warning "Google hasn't verified this app" because this is your personal project. This is normal and safe:
To use multiple Google accounts (e.g., personal + work), add each account:
# Add your first account
python -m calendar_mcp.auth add [email protected]
# Add your work account and set as default
python -m calendar_mcp.auth add [email protected] --default
# List configured accounts
python -m calendar_mcp.auth list
# Change default account
python -m calendar_mcp.auth default [email protected]How multi-account works:
calendarIdcalendarId="[email protected]", invites come FROM that accountcalendarId="[email protected]", invites come FROM that accountaccount parameter to overrideExample usage after setup:
# Creates event on UChicago calendar, invite FROM [email protected]
create_event(summary="Meeting", calendarId="[email protected]", attendees=["[email protected]"])
# Creates event on Gmail calendar, invite FROM [email protected]
create_event(summary="Personal", calendarId="[email protected]", attendees=["[email protected]"])Calendar display names: calendarId accepts a calendar's display name in addition to its raw id. create_event(calendarId="Chemster Events") resolves to the underlying [email protected] id by matching against the summary/summaryOverride fields returned by list_all_calendars (case- insensitive, trimmed). If a name is shared across accounts pass account=... to disambiguate; an unknown name returns a structured error listing the available calendars. primary and raw ids are passed through unchanged.
Create ~/.mcp-config/calendar/config.json to customize your scheduling preferences:
{
"preferences": {
"timezone": "America/New_York",
"meetingPreferences": {
"preferAdjacentToMeetings": true,
"preferredMeetingDuration": 30,
"avoidDeepWorkBlocks": true,
"deepWorkBlockUsage": "end",
"neverAvailablePatterns": ["kids"],
"preferredDays": {
"Wednesday-PM": 100,
"Thursday": 100,
"Monday-PM": 70,
"Tuesday": 40,
"Friday": 40
},
"afternoonStartHour": 12,
"notes": "SCHEDULING PRIORITY: 1. BEST (100): Wed PM & Thu. 2. GOOD (70): Mon PM. 3. LAST RESORT (40): Tue & Fri. Prefer 30-min slots adjacent to meetings. Avoid deep work blocks. Never schedule over 'kids' blocks."
},
"flexibleBlockPatterns": ["flexible", "optional", "buffer", "hold"],
"deepWorkPatterns": ["deep work", "focus time", "writing", "research", "reading"]
}
}Meeting Preference Options:
preferAdjacentToMeetings: Suggest times next to existing meetingspreferredMeetingDuration: Default meeting length in minutesavoidDeepWorkBlocks: Try not to suggest deep work timedeepWorkBlockUsage: "end" = use end of block if needed, "start" = use start, "avoid" = never useneverAvailablePatterns: Keywords for completely unavailable blocks"Monday", "Tuesday", "Wednesday", "Thursday", "Friday""Monday-PM", "Wednesday-PM", etc."Wednesday-PM": 100 and "Thursday": 100 = BEST days (strongly prefer)"Monday-PM": 70 = GOOD day (acceptable)"Tuesday": 40 and "Friday": 40 = LAST RESORT (avoid if better options exist)afternoonStartHour: Hour when afternoon starts (default: 12 = noon)notes: Human-readable description explaining your preferences for Claude to understandAdd to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"calendar": {
"command": "python",
"args": ["-m", "calendar_mcp.server"],
"cwd": "/Users/feamster/src/calendar-mcp"
}
}
}If you have other MCP servers (like spark-mcp), add the "calendar" section to your existing "mcpServers" object.
Before configuring Claude Desktop, verify everything works:
python test_calendar.pyYou should see:
Restart Claude Desktop to load the new MCP server.
Once configured, ask Claude questions like:
Meeting Queries:
Relationship Tracking:
Time Analysis:
Finding Meeting Times (with preferences):
When finding meeting times, the MCP will:
Managing Calendar Events:
Integration with spark-mcp: If you have both calendar-mcp and spark-mcp installed:
list_accountsList all configured Google accounts for multi-account calendar access. Shows which accounts are set up and which is the default.
list_all_calendarsList all calendars you have access to (primary, work, shared, etc.)
list_calendar_eventsList calendar events from ALL your calendars with filtering by time range, search query, etc. Each event shows which calendar it's from.
get_upcoming_meetingsGet upcoming meetings for preparation, includes time until meeting and attendee info.
find_meetings_with_personFind when you last met with someone (by email or name).
get_meeting_by_idGet full details of a specific calendar event.
analyze_time_blocksAnalyze calendar blocks and distinguish between deep work and flexible time.
summarize_meetingsGet summaries of meetings grouped by day, week, or person.
check_availabilityCheck if you're available at a proposed time.
find_meeting_timesFind best available meeting times based on your preferences (day ranking, adjacent to meetings, avoid deep work).
create_eventCreate a new calendar event with optional attendees and automatic invitation emails. Multi-account: Automatically selects the correct Google account based on calendarId. Recurring events: Pass recurrence (structured) or recurrenceRrule (raw RFC 5545) to create a series:
# MWF for 3 weeks
recurrence = {"freq": "WEEKLY", "by_day": ["MO", "WE", "FR"], "until": "2026-07-24"}
# First Monday of every month, for a year
recurrence = {"freq": "MONTHLY", "by_day": ["MO"], "by_set_pos": [1], "count": 12}
# MWF for 3 weeks, skipping July 13
recurrence = {"freq": "WEEKLY", "by_day": ["MO", "WE", "FR"], "until": "2026-07-24", "exceptions": ["2026-07-13"]}Supported keys: freq (DAILY/WEEKLY/MONTHLY/YEARLY), interval, by_day, by_month_day, by_month, by_set_pos, count (mutually exclusive with until), until (ISO date or datetime — bare dates interpreted as end-of-day in start's timezone), exceptions (list of ISO dates to skip via EXDATE). The response includes an occurrence_count so you can verify the series size without listing instances.
update_event_recurrenceModify the recurrence rule of an existing event without deleting and recreating:
scope="series" (default): replace the RRULE on the master event (pass recurrence=null to clear).scope="this_and_following": split the series at splitAt — shortens the original's UNTIL to just before splitAt and inserts a new event with the new rule starting at splitAt.scope="single": apply the change to a single instance (pass the instance event id, not the master id).delete_eventDelete a calendar event with optional cancellation notifications to attendees.
respond_to_eventAccept, decline, or tentatively accept a calendar invitation.
The server can distinguish between different types of calendar blocks:
Configure patterns in ~/.mcp-config/calendar/config.json:
{
"preferences": {
"flexibleBlockPatterns": ["flexible", "optional", "buffer"],
"deepWorkPatterns": ["deep work", "focus time", "writing", "research"]
}
}If you have spark-mcp installed, the calendar MCP can cross-reference calendar events with meeting transcripts to provide unified context.
ls ~/.mcp-auth/calendar/credentials.json python -m calendar_mcp.auth tail -f ~/Library/Logs/Claude/mcp-server-calendar.logclaude_desktop_config.json cd /Users/feamster/src/calendar-mcp
python -m calendar_mcp.server
# Should start without errors (Ctrl+C to exit)This is normal for personal projects. Your app is safe because you created it.
Solution:
Google Calendar API has rate limits (1M queries/day). If you hit limits:
# Test authentication status
python -m calendar_mcp.auth --test
# Run full test suite
python test_calendar.py# Install in development mode
pip install -e .
# Make changes to calendar_mcp/*.py files
# Restart Claude Desktop to reload changescalendar-mcp/
├── calendar_mcp/
│ ├── __init__.py
│ ├── auth.py # OAuth2 authentication (multi-account support)
│ ├── calendar_client.py # Google Calendar API wrapper
│ └── server.py # MCP server implementation
├── test_calendar.py # Test script
├── setup.py # Package installer
├── README.md # This file
├── SETUP.md # Detailed setup instructions
├── QUICKSTART.md # Quick start guide
└── SPEC.md # Technical specification
~/.mcp-config/calendar/
├── accounts.json # Multi-account configuration
└── config.json # User preferences (ignored calendars, meeting prefs)
~/.mcp-auth/calendar/
├── credentials.json # OAuth client credentials
└── tokens/ # Per-account OAuth tokens
├── feamster_at_gmail_com.json
└── feamster_at_uchicago_edu.jsoncalendar scope for read and write operations~/.mcp-auth/calendar/See SPEC.md for detailed roadmap, including:
MIT
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.