iflow-mcp_rsc1102-google_calendar_mcp 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- calendar_mcp.py +131 -0
- iflow_mcp_rsc1102_google_calendar_mcp-0.1.0.dist-info/METADATA +107 -0
- iflow_mcp_rsc1102_google_calendar_mcp-0.1.0.dist-info/RECORD +6 -0
- iflow_mcp_rsc1102_google_calendar_mcp-0.1.0.dist-info/WHEEL +4 -0
- iflow_mcp_rsc1102_google_calendar_mcp-0.1.0.dist-info/entry_points.txt +2 -0
- services.py +309 -0
calendar_mcp.py
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
from mcp.server.fastmcp import FastMCP
|
|
2
|
+
import services
|
|
3
|
+
|
|
4
|
+
# Initialize FastMCP server
|
|
5
|
+
mcp = FastMCP("calendar")
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@mcp.tool()
|
|
9
|
+
async def list_events(
|
|
10
|
+
summary: str | None = None,
|
|
11
|
+
description: str | None = None,
|
|
12
|
+
location: str | None = None,
|
|
13
|
+
timeMin: str | None = None,
|
|
14
|
+
timeMax: str | None = None,
|
|
15
|
+
maxResults: int = 10,
|
|
16
|
+
) -> str:
|
|
17
|
+
"""
|
|
18
|
+
Retrieve a list of calendar events based on specified filters.
|
|
19
|
+
|
|
20
|
+
This function queries the calendar for events that match the given criteria.
|
|
21
|
+
All filter parameters are optional and can be used in combination to narrow
|
|
22
|
+
down the results.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
summary (str, optional): Filter events by their summary (title or subject).
|
|
26
|
+
description (str, optional): Filter events by text found in the event description.
|
|
27
|
+
location (str, optional): Filter events based on their location.
|
|
28
|
+
timeMin (str, optional): ISO 8601 formatted lower time bound (exclusive)
|
|
29
|
+
for filtering events by end time. Must be in local time and have timezone offset.
|
|
30
|
+
timeMax (str, optional): ISO 8601 formatted upper time bound (exclusive)
|
|
31
|
+
for filtering events by start time. Must be in local time and have timezone offset.
|
|
32
|
+
maxResults (int, optional): Maximum number of events to return.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
list: A list of event objects that match the provided filters.
|
|
36
|
+
"""
|
|
37
|
+
return await services.list_events(
|
|
38
|
+
summary=summary,
|
|
39
|
+
description=description,
|
|
40
|
+
location=location,
|
|
41
|
+
timeMin=timeMin,
|
|
42
|
+
timeMax=timeMax,
|
|
43
|
+
maxResults=maxResults,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@mcp.tool()
|
|
48
|
+
async def create_event(
|
|
49
|
+
start: str,
|
|
50
|
+
end: str,
|
|
51
|
+
timeZone: str,
|
|
52
|
+
summary: str,
|
|
53
|
+
description: str | None = None,
|
|
54
|
+
location: str | None = None,
|
|
55
|
+
) -> str:
|
|
56
|
+
"""
|
|
57
|
+
Creates a calendar event using the provided details.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
start (str): Event start time in ISO 8601 format (e.g., '2025-04-06T10:00:00-07:00').
|
|
61
|
+
end (str): Event end time in ISO 8601 format (e.g., '2025-04-06T11:00:00-07:00').
|
|
62
|
+
timeZone (str): User timezone formatted as an IANA Time Zone Database name (e.g. "Europe/Zurich").
|
|
63
|
+
summary (str): Short title or subject of the event.
|
|
64
|
+
description (str, optional): Detailed description or notes for the event. Defaults to None.
|
|
65
|
+
location (str, optional): Physical or virtual location of the event. Defaults to None.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
return await services.create_event(
|
|
69
|
+
start=start,
|
|
70
|
+
end=end,
|
|
71
|
+
timeZone=timeZone,
|
|
72
|
+
summary=summary,
|
|
73
|
+
description=description,
|
|
74
|
+
location=location,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@mcp.tool()
|
|
79
|
+
async def delete_event(event_id: str):
|
|
80
|
+
"""
|
|
81
|
+
Deletes an event from the calender.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
event_id: Event identifier.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
return await services.delete_event(event_id=event_id)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@mcp.tool()
|
|
91
|
+
async def update_event(
|
|
92
|
+
event_id: str,
|
|
93
|
+
start: str | None = None,
|
|
94
|
+
end: str | None = None,
|
|
95
|
+
timeZone: str | None = None,
|
|
96
|
+
summary: str | None = None,
|
|
97
|
+
description: str | None = None,
|
|
98
|
+
location: str | None = None,
|
|
99
|
+
):
|
|
100
|
+
"""
|
|
101
|
+
Updates an event by replacing specified fields with new values.
|
|
102
|
+
Any fields not included in the request will retain their existing values.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
event_id (str): Event identifier.
|
|
106
|
+
start (str, optional): Event start time in ISO 8601 format (e.g., '2025-04-06T10:00:00-04:00'). Defaults to None.
|
|
107
|
+
end (str, optional): Event end time in ISO 8601 format (e.g., '2025-04-06T11:00:00-04:00'). Defaults to None.
|
|
108
|
+
timeZone (str, optional): User timezone formatted as an IANA Time Zone Database name (e.g. "Europe/Zurich"). Defaults to None.
|
|
109
|
+
summary (str, optional): Short title or subject of the event. Defaults to None.
|
|
110
|
+
description (str, optional): Detailed description or notes for the event. Defaults to None.
|
|
111
|
+
location (str, optional): Physical or virtual location of the event. Defaults to None.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
return await services.update_event(
|
|
115
|
+
event_id=event_id,
|
|
116
|
+
start=start,
|
|
117
|
+
end=end,
|
|
118
|
+
timeZone=timeZone,
|
|
119
|
+
summary=summary,
|
|
120
|
+
description=description,
|
|
121
|
+
location=location,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
if __name__ == "__main__":
|
|
126
|
+
# Run MCP server
|
|
127
|
+
mcp.run(transport="stdio")
|
|
128
|
+
|
|
129
|
+
def main():
|
|
130
|
+
"""Entry point for the package"""
|
|
131
|
+
mcp.run(transport="stdio")
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: iflow-mcp_rsc1102-google_calendar_mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: An MCP server to interact with Google Calendar
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: google-api-python-client>=2.166.0
|
|
7
|
+
Requires-Dist: google-auth-oauthlib>=1.2.1
|
|
8
|
+
Requires-Dist: google-auth>=2.38.0
|
|
9
|
+
Requires-Dist: mcp[cli]>=1.6.0
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# Google Calendar MCP Server  
|
|
13
|
+
|
|
14
|
+
This repository provides a Model Context Protocol (MCP) server that integrates with the Google Calendar API. It allows users to list, create, delete, and update calendar events. The server is designed to work with Anthropic's Claude Desktop as an MCP client.
|
|
15
|
+
|
|
16
|
+
## 🚀 Features
|
|
17
|
+
- Interact with Google Calendar: list, add, delete, and update events
|
|
18
|
+
- Seamless integration with Claude Desktop via MCP
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 🧰 Prerequisites
|
|
23
|
+
- A Google Account
|
|
24
|
+
- [Anthropic Claude Desktop](https://claude.ai/download)
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 📦 Installation
|
|
29
|
+
|
|
30
|
+
1. **Install UV Package Manager:**
|
|
31
|
+
Follow the instructions on the [official UV installation guide](https://docs.astral.sh/uv/getting-started/installation/#installation-methods).
|
|
32
|
+
|
|
33
|
+
2. **Clone the Repository and Set Up Environment:**
|
|
34
|
+
```bash
|
|
35
|
+
git clone https://github.com/rsc1102/Google_Calendar_MCP.git
|
|
36
|
+
cd Google_Calendar_MCP
|
|
37
|
+
uv sync
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
3. **Create Google Cloud Credentials:**
|
|
41
|
+
- Visit [Google Cloud Console](https://console.cloud.google.com/).
|
|
42
|
+
- Create a new project or select an existing one.
|
|
43
|
+
- Enable the **Google Calendar API**.
|
|
44
|
+
- Navigate to **APIs & Services > Credentials**.
|
|
45
|
+
- Click **Create Credentials > OAuth Client ID**:
|
|
46
|
+
- Choose **Desktop app** as the application type.
|
|
47
|
+
- Download the generated `credentials.json` file.
|
|
48
|
+
- Place `credentials.json` inside the `Google_Calendar_MCP` directory.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 🔌 Integration with Claude Desktop
|
|
53
|
+
|
|
54
|
+
1. **Locate Configuration File:**
|
|
55
|
+
Open the `claude_desktop_config.json` file on your system:
|
|
56
|
+
|
|
57
|
+
**Linux/macOS:**
|
|
58
|
+
```bash
|
|
59
|
+
code ~/Library/Application\ Support/Claude/claude_desktop_config.json
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Windows (PowerShell):**
|
|
63
|
+
```bash
|
|
64
|
+
code $env:AppData\Claude\claude_desktop_config.json
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
2. **Add MCP Server Configuration:**
|
|
68
|
+
Add the following to the `mcpServers` section:
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"mcpServers": {
|
|
72
|
+
"calendar": {
|
|
73
|
+
"command": "uv",
|
|
74
|
+
"args": [
|
|
75
|
+
"--directory",
|
|
76
|
+
"/ABSOLUTE/PATH/TO/PARENT/FOLDER/Google_Calendar_MCP",
|
|
77
|
+
"run",
|
|
78
|
+
"calendar_mcp.py"
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
3. **Restart Claude Desktop.**
|
|
86
|
+
|
|
87
|
+
4. **Create a New Project in Claude Desktop.**
|
|
88
|
+
|
|
89
|
+
5. **Set Timezone:**
|
|
90
|
+
In the project's knowledge section, define your local timezone using the IANA Time Zone format (e.g., `timeZone="America/New_York"`).
|
|
91
|
+
|
|
92
|
+
6. **Start Chatting:**
|
|
93
|
+
Begin interacting with Claude to manage your Google Calendar events.
|
|
94
|
+
**Note:** When using the server for the first time, Google will prompt you to authenticate and grant permission to access your calendar.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
## 🎬 In Action
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
https://github.com/user-attachments/assets/75da4943-15c4-4ec2-bc5d-af4af3509031
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 📬 Support
|
|
107
|
+
For issues or questions, please open an issue in this repository.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
calendar_mcp.py,sha256=Gy0pXXMgBAGrBIFe9or2n73aB3dlOer_-BpKvPnrwMo,4331
|
|
2
|
+
services.py,sha256=gmGXVLeO9skWPe0ldJtpEjdSDHm-C_ojHXnjaUeeNEE,10540
|
|
3
|
+
iflow_mcp_rsc1102_google_calendar_mcp-0.1.0.dist-info/METADATA,sha256=QI-VAptLLE1mx0vXLl7eOuazv7A4io0tAJX3i77RtPw,3405
|
|
4
|
+
iflow_mcp_rsc1102_google_calendar_mcp-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
5
|
+
iflow_mcp_rsc1102_google_calendar_mcp-0.1.0.dist-info/entry_points.txt,sha256=hPYApG5HVY_rDtWuFtoMmXklKojxtdzUARenZaGzzFo,58
|
|
6
|
+
iflow_mcp_rsc1102_google_calendar_mcp-0.1.0.dist-info/RECORD,,
|
services.py
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from google.oauth2.credentials import Credentials
|
|
3
|
+
from google_auth_oauthlib.flow import InstalledAppFlow
|
|
4
|
+
from google.auth.transport.requests import Request
|
|
5
|
+
from googleapiclient.discovery import build
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CalenderService:
|
|
10
|
+
def __init__(self):
|
|
11
|
+
self.__calender_service = None
|
|
12
|
+
self.__scope = ["https://www.googleapis.com/auth/calendar"]
|
|
13
|
+
|
|
14
|
+
def __call__(self):
|
|
15
|
+
"""
|
|
16
|
+
Returns a Calendar API service object.
|
|
17
|
+
"""
|
|
18
|
+
if self.__calender_service is None:
|
|
19
|
+
try:
|
|
20
|
+
creds = None
|
|
21
|
+
# Check if token.json file exists with saved credentials
|
|
22
|
+
if os.path.exists("token.json"):
|
|
23
|
+
creds = Credentials.from_authorized_user_file(
|
|
24
|
+
"token.json", self.__scope
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# If credentials don't exist or are invalid, get new ones
|
|
28
|
+
if not creds or not creds.valid:
|
|
29
|
+
if creds and creds.expired and creds.refresh_token:
|
|
30
|
+
creds.refresh(Request())
|
|
31
|
+
else:
|
|
32
|
+
# flow instance using client secrets file from Google Cloud Console
|
|
33
|
+
flow = InstalledAppFlow.from_client_secrets_file(
|
|
34
|
+
"credentials.json", self.__scope
|
|
35
|
+
)
|
|
36
|
+
# Run the authorization flow in local server mode
|
|
37
|
+
creds = flow.run_local_server(port=0)
|
|
38
|
+
|
|
39
|
+
# Save the credentials for the next run
|
|
40
|
+
with open("token.json", "w") as token:
|
|
41
|
+
token.write(creds.to_json())
|
|
42
|
+
|
|
43
|
+
# Build and return the service object
|
|
44
|
+
self.__calender_service = build("calendar", "v3", credentials=creds)
|
|
45
|
+
except Exception:
|
|
46
|
+
print("Calendar service could not be initialized")
|
|
47
|
+
|
|
48
|
+
return self.__calender_service
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# singleton
|
|
52
|
+
calender_service = CalenderService()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
async def list_events(
|
|
56
|
+
summary: str | None = None,
|
|
57
|
+
description: str | None = None,
|
|
58
|
+
location: str | None = None,
|
|
59
|
+
timeMin: str | None = None,
|
|
60
|
+
timeMax: str | None = None,
|
|
61
|
+
maxResults: int = 10,
|
|
62
|
+
) -> str:
|
|
63
|
+
"""
|
|
64
|
+
Retrieve a list of calendar events based on specified filters.
|
|
65
|
+
|
|
66
|
+
This function queries the calendar for events that match the given criteria.
|
|
67
|
+
All filter parameters are optional and can be used in combination to narrow
|
|
68
|
+
down the results.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
summary (str, optional): Filter events by their summary (title or subject).
|
|
72
|
+
description (str, optional): Filter events by text found in the event description.
|
|
73
|
+
location (str, optional): Filter events based on their location.
|
|
74
|
+
timeMin (str, optional): ISO 8601 formatted lower time bound (exclusive)
|
|
75
|
+
for filtering events by end time. Must be in local time and have timezone offset.
|
|
76
|
+
timeMax (str, optional): ISO 8601 formatted upper time bound (exclusive)
|
|
77
|
+
for filtering events by start time. Must be in local time and have timezone offset.
|
|
78
|
+
maxResults (int, optional): Maximum number of events to return.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
list: A list of event objects that match the provided filters.
|
|
82
|
+
"""
|
|
83
|
+
service = calender_service()
|
|
84
|
+
if service is None:
|
|
85
|
+
return "Unable to communicate with the Google Calendar Service."
|
|
86
|
+
|
|
87
|
+
# datetime validation
|
|
88
|
+
try:
|
|
89
|
+
if timeMin is None:
|
|
90
|
+
timeMin = datetime.now().astimezone().isoformat()
|
|
91
|
+
timeMin = datetime.fromisoformat(timeMin).astimezone().isoformat()
|
|
92
|
+
except Exception:
|
|
93
|
+
return "timeMin in incorrect format. It should be in ISO format"
|
|
94
|
+
|
|
95
|
+
try:
|
|
96
|
+
timeMax = (
|
|
97
|
+
datetime.fromisoformat(timeMax).astimezone().isoformat()
|
|
98
|
+
if timeMax is not None
|
|
99
|
+
else None
|
|
100
|
+
)
|
|
101
|
+
except Exception:
|
|
102
|
+
return "timeMax in incorrect format. It should be in ISO format"
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
maxResults = int(maxResults)
|
|
106
|
+
except Exception:
|
|
107
|
+
maxResults = 10
|
|
108
|
+
|
|
109
|
+
search_parameters = [x for x in [summary, description, location] if x is not None]
|
|
110
|
+
search_query = " ".join(search_parameters)
|
|
111
|
+
|
|
112
|
+
events_result = (
|
|
113
|
+
service.events()
|
|
114
|
+
.list(
|
|
115
|
+
calendarId="primary",
|
|
116
|
+
timeMin=timeMin,
|
|
117
|
+
timeMax=timeMax,
|
|
118
|
+
maxResults=maxResults,
|
|
119
|
+
singleEvents=True,
|
|
120
|
+
orderBy="startTime",
|
|
121
|
+
q=search_query,
|
|
122
|
+
)
|
|
123
|
+
.execute()
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
events = events_result.get("items", [])
|
|
127
|
+
|
|
128
|
+
if not events:
|
|
129
|
+
return "No upcoming events found."
|
|
130
|
+
|
|
131
|
+
events_info = []
|
|
132
|
+
for i, event in enumerate(events):
|
|
133
|
+
start = event["start"].get("dateTime", event["start"].get("date"))
|
|
134
|
+
if start:
|
|
135
|
+
start = (
|
|
136
|
+
datetime.fromisoformat(start).astimezone().strftime("%Y-%m-%d %H:%M:%S")
|
|
137
|
+
)
|
|
138
|
+
end = event["end"].get("dateTime", event["end"].get("date"))
|
|
139
|
+
if end:
|
|
140
|
+
end = datetime.fromisoformat(end).astimezone().strftime("%Y-%m-%d %H:%M:%S")
|
|
141
|
+
summary = event.get("summary", "N/A")
|
|
142
|
+
description = event.get("description", "N/A")
|
|
143
|
+
location = event.get("location", "N/A")
|
|
144
|
+
event_id = event.get("id", "N/A")
|
|
145
|
+
|
|
146
|
+
event_info = f"""
|
|
147
|
+
index: {i + 1}
|
|
148
|
+
start: {start}
|
|
149
|
+
end: {end}
|
|
150
|
+
summary: {summary}
|
|
151
|
+
description: {description}
|
|
152
|
+
location: {location}
|
|
153
|
+
event_id: {event_id}
|
|
154
|
+
"""
|
|
155
|
+
|
|
156
|
+
events_info.append(event_info)
|
|
157
|
+
|
|
158
|
+
return "\n--\n".join(events_info)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
async def create_event(
|
|
162
|
+
start: str,
|
|
163
|
+
end: str,
|
|
164
|
+
timeZone: str,
|
|
165
|
+
summary: str | None = None,
|
|
166
|
+
description: str | None = None,
|
|
167
|
+
location: str | None = None,
|
|
168
|
+
) -> str:
|
|
169
|
+
"""
|
|
170
|
+
Creates a calendar event using the provided details.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
start (str): Event start time in ISO 8601 format (e.g., '2025-04-06T10:00:00-04:00').
|
|
174
|
+
end (str): Event end time in ISO 8601 format (e.g., '2025-04-06T11:00:00-04:00').
|
|
175
|
+
timeZone (str): User timezone formatted as an IANA Time Zone Database name (e.g. "Europe/Zurich").
|
|
176
|
+
summary (str, optional): Short title or subject of the event.
|
|
177
|
+
description (str, optional): Detailed description or notes for the event. Defaults to None.
|
|
178
|
+
location (str, optional): Physical or virtual location of the event. Defaults to None.
|
|
179
|
+
"""
|
|
180
|
+
|
|
181
|
+
service = calender_service()
|
|
182
|
+
if service is None:
|
|
183
|
+
return "Unable to communicate with the Google Calendar Service."
|
|
184
|
+
|
|
185
|
+
# datetime validation
|
|
186
|
+
try:
|
|
187
|
+
datetime.fromisoformat(start)
|
|
188
|
+
except Exception:
|
|
189
|
+
return "Event start time not in ISO format"
|
|
190
|
+
|
|
191
|
+
try:
|
|
192
|
+
datetime.fromisoformat(end)
|
|
193
|
+
except Exception:
|
|
194
|
+
return "Event end time not in ISO format"
|
|
195
|
+
|
|
196
|
+
event = {
|
|
197
|
+
"start": {"dateTime": start, "timeZone": timeZone},
|
|
198
|
+
"end": {"dateTime": end, "timeZone": timeZone},
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
for key, value in zip(
|
|
202
|
+
["summary", "description", "location"], [summary, description, location]
|
|
203
|
+
):
|
|
204
|
+
if value is not None:
|
|
205
|
+
event[key] = value
|
|
206
|
+
|
|
207
|
+
try:
|
|
208
|
+
event = service.events().insert(calendarId="primary", body=event).execute()
|
|
209
|
+
return f"Event created with id {event.get('id')}"
|
|
210
|
+
except Exception:
|
|
211
|
+
return "Event could not be created."
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
async def delete_event(event_id: str):
|
|
215
|
+
"""
|
|
216
|
+
Deletes an event from the calender.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
event_id: Event identifier.
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
service = calender_service()
|
|
223
|
+
if service is None:
|
|
224
|
+
return "Unable to communicate with the Google Calendar Service."
|
|
225
|
+
|
|
226
|
+
try:
|
|
227
|
+
service.events().delete(calendarId="primary", eventId=event_id).execute()
|
|
228
|
+
return f"Event with id {event_id} is deleted."
|
|
229
|
+
except Exception:
|
|
230
|
+
return "Event could not be deleted."
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
async def update_event(
|
|
234
|
+
event_id: str,
|
|
235
|
+
start: str | None = None,
|
|
236
|
+
end: str | None = None,
|
|
237
|
+
timeZone: str | None = None,
|
|
238
|
+
summary: str | None = None,
|
|
239
|
+
description: str | None = None,
|
|
240
|
+
location: str | None = None,
|
|
241
|
+
):
|
|
242
|
+
"""
|
|
243
|
+
Updates an event by replacing specified fields with new values.
|
|
244
|
+
Any fields not included in the request will retain their existing values.
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
event_id (str): Event identifier.
|
|
248
|
+
start (str, optional): Event start time in ISO 8601 format (e.g., '2025-04-06T10:00:00-04:00'). Defaults to None.
|
|
249
|
+
end (str, optional): Event end time in ISO 8601 format (e.g., '2025-04-06T11:00:00-04:00'). Defaults to None.
|
|
250
|
+
timeZone (str, optional): User timezone formatted as an IANA Time Zone Database name (e.g. "Europe/Zurich"). Defaults to None.
|
|
251
|
+
summary (str, optional): Short title or subject of the event. Defaults to None.
|
|
252
|
+
description (str, optional): Detailed description or notes for the event. Defaults to None.
|
|
253
|
+
location (str, optional): Physical or virtual location of the event. Defaults to None.
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
service = calender_service()
|
|
257
|
+
if service is None:
|
|
258
|
+
return "Unable to communicate with the Google Calendar Service."
|
|
259
|
+
|
|
260
|
+
updates = {}
|
|
261
|
+
updated_parameters = set()
|
|
262
|
+
|
|
263
|
+
if start is not None:
|
|
264
|
+
try:
|
|
265
|
+
datetime.fromisoformat(start)
|
|
266
|
+
except Exception:
|
|
267
|
+
return "Event start time not in ISO format"
|
|
268
|
+
updates['start'] = {}
|
|
269
|
+
updates['start']['dateTime'] = start
|
|
270
|
+
updated_parameters.add("start")
|
|
271
|
+
|
|
272
|
+
if end is not None:
|
|
273
|
+
try:
|
|
274
|
+
datetime.fromisoformat(end)
|
|
275
|
+
except Exception:
|
|
276
|
+
return "Event start time not in ISO format"
|
|
277
|
+
updates['end'] = {}
|
|
278
|
+
updates['end']['dateTime'] = end
|
|
279
|
+
updated_parameters.add("end")
|
|
280
|
+
|
|
281
|
+
if timeZone is not None:
|
|
282
|
+
if "start" not in updates:
|
|
283
|
+
updates["start"] = {}
|
|
284
|
+
updates['start']['timeZone'] = timeZone
|
|
285
|
+
updated_parameters.add("start")
|
|
286
|
+
|
|
287
|
+
if "end" not in updates:
|
|
288
|
+
updates["end"] = {}
|
|
289
|
+
updates['end']['timeZone'] = timeZone
|
|
290
|
+
updated_parameters.add("end")
|
|
291
|
+
|
|
292
|
+
for key, value in zip(
|
|
293
|
+
["summary", "description", "location"], [summary, description, location]
|
|
294
|
+
):
|
|
295
|
+
if value is not None:
|
|
296
|
+
updates[key] = value
|
|
297
|
+
updated_parameters.add(key)
|
|
298
|
+
|
|
299
|
+
updated_parameters = ",".join(updated_parameters)
|
|
300
|
+
try:
|
|
301
|
+
_ = service.events().patch(calendarId='primary', eventId=event_id, body=updates).execute()
|
|
302
|
+
return f"Event with id {event_id} updated with [{''.join(updated_parameters)}] "
|
|
303
|
+
except Exception:
|
|
304
|
+
return "Event could not be updated."
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
|