11# server.py
22import logging
33from typing import Optional
4+ from datetime import datetime , timedelta
45from nextcloud_mcp_server .config import setup_logging
56from contextlib import asynccontextmanager
67from dataclasses import dataclass
@@ -351,31 +352,52 @@ async def nc_calendar_list_calendars(ctx: Context):
351352async def nc_calendar_create_event (
352353 calendar_name : str ,
353354 title : str ,
354- start_datetime : str , # ISO format: "2025-01-15T14:00:00" or "2025-01-15" for all-day
355+ start_datetime : str ,
355356 ctx : Context ,
356- end_datetime : str = "" , # Empty for all-day events
357+ end_datetime : str = "" ,
357358 all_day : bool = False ,
358359 description : str = "" ,
359360 location : str = "" ,
360- categories : str = "" , # "work,meeting" - comma separated
361- # Recurrence
361+ categories : str = "" ,
362362 recurring : bool = False ,
363- recurrence_rule : str = "" , # "FREQ=WEEKLY;BYDAY=MO,WE,FR" (RFC5545 RRULE)
364- recurrence_end_date : str = "" , # When to stop recurring
365- # Notifications/Alarms
366- reminder_minutes : int = 15 , # Minutes before event to remind
367- reminder_email : bool = False , # Email notification
368- # Event properties
369- status : str = "CONFIRMED" , # CONFIRMED, TENTATIVE, CANCELLED
370- priority : int = 5 , # 1-9 (1=highest, 9=lowest, 5=normal)
371- privacy : str = "PUBLIC" , # PUBLIC, PRIVATE, CONFIDENTIAL
372- # Attendees
373- 374- # Additional
375- url : str = "" , # Related URL
376- color : str = "" , # Event color (hex or name)
363+ recurrence_rule : str = "" ,
364+ recurrence_end_date : str = "" ,
365+ reminder_minutes : int = 15 ,
366+ reminder_email : bool = False ,
367+ status : str = "CONFIRMED" ,
368+ priority : int = 5 ,
369+ privacy : str = "PUBLIC" ,
370+ attendees : str = "" ,
371+ url : str = "" ,
372+ color : str = "" ,
377373):
378- """Create a comprehensive calendar event with full feature support"""
374+ """Create a comprehensive calendar event with full feature support
375+
376+ Args:
377+ calendar_name: Name of the calendar to create the event in
378+ title: Event title
379+ start_datetime: ISO format: "2025-01-15T14:00:00" or "2025-01-15" for all-day
380+ ctx: MCP context
381+ end_datetime: ISO format end time, empty for all-day events
382+ all_day: Whether this is an all-day event
383+ description: Event description/details
384+ location: Event location
385+ categories: Comma-separated categories (e.g., "work,meeting")
386+ recurring: Whether this is a recurring event
387+ recurrence_rule: RFC5545 RRULE (e.g., "FREQ=WEEKLY;BYDAY=MO,WE,FR")
388+ recurrence_end_date: When to stop recurring
389+ reminder_minutes: Minutes before event to send reminder
390+ reminder_email: Whether to send email notification
391+ status: Event status: CONFIRMED, TENTATIVE, or CANCELLED
392+ priority: Priority level 1-9 (1=highest, 9=lowest, 5=normal)
393+ privacy: Privacy level: PUBLIC, PRIVATE, or CONFIDENTIAL
394+ attendees: Comma-separated email addresses
395+ url: Related URL for the event
396+ color: Event color (hex or name)
397+
398+ Returns:
399+ Dict with event creation result
400+ """
379401 client : NextcloudClient = ctx .request_context .lifespan_context .client
380402
381403 event_data = {
@@ -406,13 +428,13 @@ async def nc_calendar_create_event(
406428async def nc_calendar_list_events (
407429 calendar_name : str ,
408430 ctx : Context ,
409- start_date : str = "" , # "2025-01-01"
410- end_date : str = "" , # "2025-01-31"
431+ start_date : str = "" ,
432+ end_date : str = "" ,
411433 limit : int = 50 ,
412434 min_attendees : Optional [int ] = None ,
413435 min_duration_minutes : Optional [int ] = None ,
414- categories : Optional [str ] = None , # Comma-separated: "work,meeting"
415- status : Optional [str ] = None , # "CONFIRMED", "TENTATIVE", "CANCELLED"
436+ categories : Optional [str ] = None ,
437+ status : Optional [str ] = None ,
416438 title_contains : Optional [str ] = None ,
417439 location_contains : Optional [str ] = None ,
418440 search_all_calendars : bool = False ,
@@ -421,16 +443,20 @@ async def nc_calendar_list_events(
421443
422444 Args:
423445 calendar_name: Name of the calendar to search. Ignored if search_all_calendars=True.
424- start_date: Start date for search (YYYY-MM-DD format)
425- end_date: End date for search (YYYY-MM-DD format)
446+ ctx: MCP context
447+ start_date: Start date for search (YYYY-MM-DD format, e.g., "2025-01-01")
448+ end_date: End date for search (YYYY-MM-DD format, e.g., "2025-01-31")
426449 limit: Maximum number of events to return
427450 min_attendees: Filter events with at least this many attendees
428451 min_duration_minutes: Filter events with at least this duration
429- categories: Filter events containing any of these categories (comma-separated)
430- status: Filter events by status (CONFIRMED, TENTATIVE, CANCELLED)
452+ categories: Filter events containing any of these categories (comma-separated, e.g., "work,meeting" )
453+ status: Filter events by status (CONFIRMED, TENTATIVE, or CANCELLED)
431454 title_contains: Filter events where title contains this text
432455 location_contains: Filter events where location contains this text
433456 search_all_calendars: If True, search across all calendars instead of just one
457+
458+ Returns:
459+ List of events matching the filters
434460 """
435461 client : NextcloudClient = ctx .request_context .lifespan_context .client
436462
@@ -572,8 +598,8 @@ async def nc_calendar_delete_event(
572598@mcp .tool ()
573599async def nc_calendar_create_meeting (
574600 title : str ,
575- date : str , # "2025-01-15"
576- time : str , # "14:00"
601+ date : str ,
602+ time : str ,
577603 ctx : Context ,
578604 duration_minutes : int = 60 ,
579605 calendar_name : str = "personal" ,
@@ -582,14 +608,38 @@ async def nc_calendar_create_meeting(
582608 description : str = "" ,
583609 reminder_minutes : int = 15 ,
584610):
585- """Quick meeting creation with smart defaults"""
611+ """Quick meeting creation with smart defaults
612+
613+ This is a convenience function for creating events with common meeting defaults.
614+ It automatically:
615+ - Calculates end time based on duration
616+ - Sets status to CONFIRMED
617+ - Adds a reminder
618+ - Uses simpler date/time inputs instead of full ISO format
619+
620+ For full control over all event properties, use nc_calendar_create_event instead.
621+
622+ Args:
623+ title: Meeting title
624+ date: Meeting date (YYYY-MM-DD format, e.g., "2025-01-15")
625+ time: Meeting start time (HH:MM format, e.g., "14:00")
626+ ctx: MCP context
627+ duration_minutes: Meeting duration in minutes (default: 60)
628+ calendar_name: Calendar to create the meeting in (default: "personal")
629+ attendees: Comma-separated email addresses of attendees
630+ location: Meeting location
631+ description: Meeting description/agenda
632+ reminder_minutes: Minutes before meeting to send reminder (default: 15)
633+
634+ Returns:
635+ Dict with meeting creation result
636+ """
586637 client : NextcloudClient = ctx .request_context .lifespan_context .client
587638
588639 # Combine date and time for start_datetime
589640 start_datetime = f"{ date } T{ time } :00"
590641
591642 # Calculate end_datetime
592- from datetime import datetime , timedelta
593643
594644 start_dt = datetime .fromisoformat (start_datetime )
595645 end_dt = start_dt + timedelta (minutes = duration_minutes )
@@ -622,8 +672,6 @@ async def nc_calendar_get_upcoming_events(
622672 """Get upcoming events in next N days"""
623673 client : NextcloudClient = ctx .request_context .lifespan_context .client
624674
625- from datetime import datetime , timedelta
626-
627675 now = datetime .now ()
628676 end_date = now + timedelta (days = days_ahead )
629677
0 commit comments