From 795e8066734d1383ffe271ccea4aa59ee76fcabd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lago=20=28via=20Crotolamo=20=F0=9F=A6=8E=29?= Date: Wed, 18 Feb 2026 20:19:33 +0100 Subject: [PATCH] feat: add alarm/reminder support to create_event tool --- src/__pycache__/caldav_client.cpython-314.pyc | Bin 8983 -> 10288 bytes src/caldav_client.py | 46 ++++++++++++++---- src/server.py | 5 +- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/__pycache__/caldav_client.cpython-314.pyc b/src/__pycache__/caldav_client.cpython-314.pyc index eea7ef1b7b26e22f16b47c94d750073cfd2e9669..c5ea334fc0e39f60027f44108f0657afe0b0aca4 100644 GIT binary patch delta 2085 zcmaJ?O>7fK6rSC+y=(8+fl3TaQN)B~soQgNty;m}i255&aC(YBRxpyFDfh^pey8UJ8IlRnAc&b;@{ z_nv2F-`@COAz};ItQLUnGy813$^E@8WeDvJok=IvP(m3`hqk0MYATvgE`%-RVXeJm{5;0{Wl!ejIoms}HL3u}{-7rFZYU*Rx_J9!A z4g6;G*sf&SQ|C1`3%fDT&%z%3fMxi&~Feq_pzd(HPQ7EYe}`SQc?>9V76HeJYEEKFWr%v^qWHdppN z0pKVt(Y3KkCu!_T(U5))fJ$dyMTVIX21kxD$C>BgZ7|H7sAR#u7&DGTI5G6#ilQ8b znvtsUAK{+44d`W)&%%w;)eyQuH|M;dzdFsBWpjkE-!KVCRDX3%Cs>0+OH7^fDg%f# zR#Me%$Y_y2v8X#s3&ID^wb62hiKTt>iGVD(j2S?~gx^#jSalLBBpsj4BBCE`GDxg8?kkAuX@ zcd6pDH2AnkGvQHY^u*ePL@Vd01vA!Hf1g}kI^rTk#u{;>--TAjCfm?CTN}FD%!Wl- zjC54eG@>N#Isw2qejVDtuoHk$Z!L=XTXXAh%UG|QGB6#B$0j!fL!rY1 z5zl~<7(5_*MpQVV!cb`Fh|c0cHl9vRGTXLng?q3V+)H2|f&CbCBZTJ@s%}!E8s_Qj zV0a|*(Sehb7D>fjD5k=9J$_0zYw@HSQxlq^vl@(x*A8#J7rwvtTX0mbKXC9yvX@#v*3JdkqbWJoAYPC?Jey@m-==W z`gSjgd+uCn`HG^nJ1wqW1Erw-?K}3sI5`k}-GOeN7*sTsTrAyK9_pqENsXR|FiFA& za*Tc}Y$FS{6VTAz_Ajv9u8vu(itcxAroKl1bpGJJK=>wnJylKh8(&-Ti)RRv)_G5| z3>?I?BPioN#-Af{mk3-%_q|7`VbsyJmB$~er{s(E;uwWabX}#sM89?g#Sxlnc?JlU HzhwUcaCyBq delta 714 zcmX|7cD6vt*dy_*W;poMqZKr`*6>*rMAFWZr@aF2JYIO- zpXAXAUO_<<*c}mGS4b_$!L-8#j~xEGPSW2iXdj8j&<@2LWt+-Jwj-O)&80?i>Pv0w z>U76w%$6GErN(mYYq_>HTkm)~2u(5x=HOjp<``lX8J+oskj7O0SL)1VwzG&nLYB?( z2swy$!$gGa+tfaeA@23Eyvjpdb~;(rpfaja)^mxf;o-5`GGDlGE$Hkxln>7f5;Ft>SLrszesVO z;sQa-sOt*_4gMSs*aiJ0b%aW0QA=x!TCobtZrS3Yz1InX7I-OnV@>$R{0D8djz0a5e2x(=pT>RGRkTZ40t_+K96WtHwPmJWz%ZrR-8tEF^4mnpy}cR$X;Yv~B=x>ID-q_T#&EZs*K zM2i=%fX(|s(umRGX0(D<)yQ`b)A|{TEPVG~Ax!~al4JC7V!^8Kwk1t#a}+xK@ZH4M iAmR@T>#{!r^Zv*9A?*1>efKdQXd}wbIsXM0HLZvM diff --git a/src/caldav_client.py b/src/caldav_client.py index 11202cc..2c23075 100644 --- a/src/caldav_client.py +++ b/src/caldav_client.py @@ -71,17 +71,43 @@ class CalDAVClient: }) return results - def create_event(self, calendar_name: str, summary: str, start_time: Union[datetime, date], end_time: Union[datetime, date], description: str = "", recurrence: Optional[Dict] = None) -> str: + def create_event(self, calendar_name: str, summary: str, start_time: Union[datetime, date], end_time: Union[datetime, date], description: str = "", recurrence: Optional[Dict] = None, alarm_minutes: Optional[int] = None) -> str: calendar = self._get_calendar(calendar_name) - event = calendar.save_event( - dtstart=start_time, - dtend=end_time, - summary=summary, - description=description, - rrule=recurrence - ) - # Re-parse to get the UID, though library might provide it - ical = icalendar.Calendar.from_ical(event.data) + + # Build raw ical for better control + cal = icalendar.Calendar() + cal.add('prodid', '-//MCP CalDAV Server//EN') + cal.add('version', '2.0') + + event = icalendar.Event() + event.add('summary', summary) + event.add('description', description) + + if isinstance(start_time, datetime): + event.add('dtstart', start_time) + event.add('dtend', end_time) + else: + event.add('dtstart', start_time) + event.add('dtend', end_time) + + if recurrence: + event.add('rrule', recurrence) + + if alarm_minutes is not None: + alarm = icalendar.Alarm() + alarm.add('action', 'DISPLAY') + alarm.add('description', f'Reminder: {summary}') + # Use a proper timedelta or iCalendar DURATION string + from datetime import timedelta + alarm.add('trigger', timedelta(minutes=-alarm_minutes)) + event.add_component(alarm) + + cal.add_component(event) + + saved_event = calendar.save_event(cal.to_ical()) + + # Re-parse to get the UID + ical = icalendar.Calendar.from_ical(saved_event.data) for component in ical.walk(): if component.name == "VEVENT": return str(component.get("uid")) diff --git a/src/server.py b/src/server.py index c9745b5..77ca134 100644 --- a/src/server.py +++ b/src/server.py @@ -72,7 +72,7 @@ def parse_rrule(rrule_str: str) -> dict: return rrule @mcp.tool() -def create_event(calendar_name: str, summary: str, start_time: str, end_time: str, description: str = "", all_day: bool = False, recurrence: Optional[str] = None) -> str: +def create_event(calendar_name: str, summary: str, start_time: str, end_time: str, description: str = "", all_day: bool = False, recurrence: Optional[str] = None, alarm_minutes: Optional[int] = None) -> str: """ Creates a new event. @@ -84,6 +84,7 @@ def create_event(calendar_name: str, summary: str, start_time: str, end_time: st description: Event description. all_day: Set to True for all-day events (start/end time will be treated as dates). recurrence: RRULE string, e.g., "FREQ=DAILY;COUNT=10". + alarm_minutes: Minutes before the event to trigger an alarm/reminder. """ if not client: return "Error: CalDAV client not initialized" @@ -98,7 +99,7 @@ def create_event(calendar_name: str, summary: str, start_time: str, end_time: st rrule_dict = parse_rrule(recurrence) if recurrence else None - result = client.create_event(calendar_name, summary, dt_start, dt_end, description, rrule_dict) + result = client.create_event(calendar_name, summary, dt_start, dt_end, description, rrule_dict, alarm_minutes) return f"Event created: {result}" except Exception as e: return f"Error creating event: {str(e)}"