Merge branch 'main' of github.com:taylorwilsdon/google_workspace_mcp into feature/googleCalendarAndDriveAttachment

This commit is contained in:
Taylor Wilsdon
2025-06-18 17:36:26 -04:00

View File

@@ -16,7 +16,7 @@ from fastapi import Body
from googleapiclient.errors import HttpError
from auth.service_decorator import require_google_service
from core.utils import handle_http_errors
from core.server import (
GMAIL_READONLY_SCOPE,
GMAIL_SEND_SCOPE,
@@ -133,6 +133,7 @@ def _format_gmail_results_plain(messages: list, query: str) -> str:
@server.tool()
@require_google_service("gmail", "gmail_read")
@handle_http_errors("search_gmail_messages")
async def search_gmail_messages(
service, query: str, user_google_email: str, page_size: int = 10
) -> str:
@@ -150,7 +151,6 @@ async def search_gmail_messages(
"""
logger.info(f"[search_gmail_messages] Email: '{user_google_email}', Query: '{query}'")
try:
response = await asyncio.to_thread(
service.users()
.messages()
@@ -163,18 +163,10 @@ async def search_gmail_messages(
logger.info(f"[search_gmail_messages] Found {len(messages)} messages")
return formatted_output
except HttpError as e:
error_msg = f"Gmail API error: {e.reason}" if e.resp.status != 400 else f"Invalid query: '{query}'"
logger.error(f"[search_gmail_messages] {error_msg}")
raise Exception(error_msg)
except Exception as e:
error_msg = f"Error searching Gmail: {str(e)}"
logger.error(f"[search_gmail_messages] {error_msg}")
raise Exception(error_msg)
@server.tool()
@require_google_service("gmail", "gmail_read")
@handle_http_errors("get_gmail_message_content")
async def get_gmail_message_content(
service, message_id: str, user_google_email: str
) -> str:
@@ -192,7 +184,6 @@ async def get_gmail_message_content(
f"[get_gmail_message_content] Invoked. Message ID: '{message_id}', Email: '{user_google_email}'"
)
try:
logger.info(f"[get_gmail_message_content] Using service for: {user_google_email}")
# Fetch message metadata first to get headers
@@ -240,20 +231,10 @@ async def get_gmail_message_content(
)
return content_text
except HttpError as e:
logger.error(
f"[get_gmail_message_content] Gmail API error getting message content: {e}", exc_info=True
)
raise Exception(f"Gmail API error: {e}")
except Exception as e:
logger.exception(
f"[get_gmail_message_content] Unexpected error getting Gmail message content: {e}"
)
raise Exception(f"Unexpected error: {e}")
@server.tool()
@require_google_service("gmail", "gmail_read")
@handle_http_errors("get_gmail_messages_content_batch")
async def get_gmail_messages_content_batch(
service,
message_ids: List[str],
@@ -279,7 +260,6 @@ async def get_gmail_messages_content_batch(
if not message_ids:
raise Exception("No message IDs provided")
try:
output_messages = []
# Process in chunks of 100 (Gmail batch limit)
@@ -404,20 +384,10 @@ async def get_gmail_messages_content_batch(
return final_output
except HttpError as e:
logger.error(
f"[get_gmail_messages_content_batch] Gmail API error in batch retrieval: {e}", exc_info=True
)
raise Exception(f"Gmail API error: {e}")
except Exception as e:
logger.exception(
f"[get_gmail_messages_content_batch] Unexpected error in batch retrieval: {e}"
)
raise Exception(f"Unexpected error: {e}")
@server.tool()
@require_google_service("gmail", GMAIL_SEND_SCOPE)
@handle_http_errors("send_gmail_message")
async def send_gmail_message(
service,
user_google_email: str,
@@ -437,7 +407,6 @@ async def send_gmail_message(
Returns:
str: Confirmation message with the sent email's message ID.
"""
try:
# Prepare the email
message = MIMEText(body)
message["to"] = to
@@ -452,18 +421,10 @@ async def send_gmail_message(
message_id = sent_message.get("id")
return f"Email sent! Message ID: {message_id}"
except HttpError as e:
logger.error(
f"[send_gmail_message] Gmail API error sending message: {e}", exc_info=True
)
raise Exception(f"Gmail API error: {e}")
except Exception as e:
logger.exception(f"[send_gmail_message] Unexpected error sending Gmail message: {e}")
raise Exception(f"Unexpected error: {e}")
@server.tool()
@require_google_service("gmail", GMAIL_COMPOSE_SCOPE)
@handle_http_errors("draft_gmail_message")
async def draft_gmail_message(
service,
user_google_email: str,
@@ -487,7 +448,6 @@ async def draft_gmail_message(
f"[draft_gmail_message] Invoked. Email: '{user_google_email}', Subject: '{subject}'"
)
try:
# Prepare the email
message = MIMEText(body)
message["subject"] = subject
@@ -508,18 +468,10 @@ async def draft_gmail_message(
draft_id = created_draft.get("id")
return f"Draft created! Draft ID: {draft_id}"
except HttpError as e:
logger.error(
f"[draft_gmail_message] Gmail API error creating draft: {e}", exc_info=True
)
raise Exception(f"Gmail API error: {e}")
except Exception as e:
logger.exception(f"[draft_gmail_message] Unexpected error creating Gmail draft: {e}")
raise Exception(f"Unexpected error: {e}")
@server.tool()
@require_google_service("gmail", "gmail_read")
@handle_http_errors("get_gmail_thread_content")
async def get_gmail_thread_content(
service, thread_id: str, user_google_email: str
) -> str:
@@ -537,7 +489,6 @@ async def get_gmail_thread_content(
f"[get_gmail_thread_content] Invoked. Thread ID: '{thread_id}', Email: '{user_google_email}'"
)
try:
# Fetch the complete thread with all messages
thread_response = await asyncio.to_thread(
service.users()
@@ -606,20 +557,10 @@ async def get_gmail_thread_content(
content_text = "\n".join(content_lines)
return content_text
except HttpError as e:
logger.error(
f"[get_gmail_thread_content] Gmail API error getting thread content: {e}", exc_info=True
)
raise Exception(f"Gmail API error: {e}")
except Exception as e:
logger.exception(
f"[get_gmail_thread_content] Unexpected error getting Gmail thread content: {e}"
)
raise Exception(f"Unexpected error: {e}")
@server.tool()
@require_google_service("gmail", "gmail_read")
@handle_http_errors("list_gmail_labels")
async def list_gmail_labels(service, user_google_email: str) -> str:
"""
Lists all labels in the user's Gmail account.
@@ -632,7 +573,6 @@ async def list_gmail_labels(service, user_google_email: str) -> str:
"""
logger.info(f"[list_gmail_labels] Invoked. Email: '{user_google_email}'")
try:
response = await asyncio.to_thread(
service.users().labels().list(userId="me").execute
)
@@ -665,16 +605,10 @@ async def list_gmail_labels(service, user_google_email: str) -> str:
return "\n".join(lines)
except HttpError as e:
logger.error(f"[list_gmail_labels] Gmail API error listing labels: {e}", exc_info=True)
raise Exception(f"Gmail API error: {e}")
except Exception as e:
logger.exception(f"[list_gmail_labels] Unexpected error listing Gmail labels: {e}")
raise Exception(f"Unexpected error: {e}")
@server.tool()
@require_google_service("gmail", GMAIL_LABELS_SCOPE)
@handle_http_errors("manage_gmail_label")
async def manage_gmail_label(
service,
user_google_email: str,
@@ -706,7 +640,6 @@ async def manage_gmail_label(
if action in ["update", "delete"] and not label_id:
raise Exception("Label ID is required for update and delete actions.")
try:
if action == "create":
label_object = {
"name": name,
@@ -746,16 +679,10 @@ async def manage_gmail_label(
)
return f"Label '{label_name}' (ID: {label_id}) deleted successfully!"
except HttpError as e:
logger.error(f"[manage_gmail_label] Gmail API error: {e}", exc_info=True)
raise Exception(f"Gmail API error: {e}")
except Exception as e:
logger.exception(f"[manage_gmail_label] Unexpected error: {e}")
raise Exception(f"Unexpected error: {e}")
@server.tool()
@require_google_service("gmail", GMAIL_MODIFY_SCOPE)
@handle_http_errors("modify_gmail_message_labels")
async def modify_gmail_message_labels(
service,
user_google_email: str,
@@ -780,7 +707,6 @@ async def modify_gmail_message_labels(
if not add_label_ids and not remove_label_ids:
raise Exception("At least one of add_label_ids or remove_label_ids must be provided.")
try:
body = {}
if add_label_ids:
body["addLabelIds"] = add_label_ids
@@ -798,10 +724,3 @@ async def modify_gmail_message_labels(
actions.append(f"Removed labels: {', '.join(remove_label_ids)}")
return f"Message labels updated successfully!\nMessage ID: {message_id}\n{'; '.join(actions)}"
except HttpError as e:
logger.error(f"[modify_gmail_message_labels] Gmail API error modifying message labels: {e}", exc_info=True)
raise Exception(f"Gmail API error: {e}")
except Exception as e:
logger.exception(f"[modify_gmail_message_labels] Unexpected error modifying Gmail message labels: {e}")
raise Exception(f"Unexpected error: {e}")