-
Notifications
You must be signed in to change notification settings - Fork 264
Added saving to disk support #255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Appreciate this @leftler couple of nits to pick but we can get this in if they're fixed! |
| Returns: | ||
| str: Success message with file details and saved location. | ||
| """ | ||
| import os |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imports go at the top
| if not os.path.isabs(local_file_path): | ||
| # Server runs from google-workspace-mcp-dev/google_workspace_mcp | ||
| # This file is in gdrive/drive_tools.py, so workspace root is ../../../ from here | ||
| workspace_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks specific to your environment - there is no established pattern around having google_workspace_mcp nested in some other folder, and this calculates workspace root incorrectly. The file is at gdrive/drive_tools.py, so:
- os.path.dirname(file) → gdrive/
- "..", "..", ".." → goes up 3 levels from gdrive/ to the workspace root - it's only 1 level deep in the actual repo structure
| # Server runs from google-workspace-mcp-dev/google_workspace_mcp | ||
| # This file is in gdrive/drive_tools.py, so workspace root is ../../../ from here | ||
| workspace_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..")) | ||
| local_file_path = os.path.join(workspace_root, local_file_path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably restrict / validate the resolved path somehow because as it stands, this introduces a major attack vector (a malicious payload could have it write files to /etc/passwd, firewall config or sudoers files etc)
|
Sure thing, will fix
…On Tue, Nov 4, 2025, 8:12 AM Taylor Wilsdon ***@***.***> wrote:
***@***.**** requested changes on this pull request.
------------------------------
In gdrive/drive_tools.py
<#255 (comment)>
:
> + file_id: str,
+ local_file_path: str,
+) -> str:
+ """
+ Downloads a Google Drive file and saves it directly to disk without streaming content to AI.
+ Perfect for large files, binary files, or any file you want to save locally.
+
+ Args:
+ user_google_email (str): The user's Google email address. Required.
+ file_id (str): The ID of the Google Drive file to download.
+ local_file_path (str): The local file path where the file should be saved.
+
+ Returns:
+ str: Success message with file details and saved location.
+ """
+ import os
imports go at the top
------------------------------
In gdrive/drive_tools.py
<#255 (comment)>
:
> + Args:
+ user_google_email (str): The user's Google email address. Required.
+ file_id (str): The ID of the Google Drive file to download.
+ local_file_path (str): The local file path where the file should be saved.
+
+ Returns:
+ str: Success message with file details and saved location.
+ """
+ import os
+ logger.info(f"[save_drive_file_to_disk] Downloading file {file_id} to {local_file_path} for user {user_google_email}")
+
+ # Convert relative paths to be relative from workspace root instead of server directory
+ if not os.path.isabs(local_file_path):
+ # Server runs from google-workspace-mcp-dev/google_workspace_mcp
+ # This file is in gdrive/drive_tools.py, so workspace root is ../../../ from here
+ workspace_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
This looks specific to your environment - there is no established pattern
around having google_workspace_mcp nested in some other folder, and this
calculates workspace root incorrectly. The file is at
gdrive/drive_tools.py, so:
- os.path.dirname(*file*) → gdrive/
- "..", "..", ".." → goes up 3 levels from gdrive/ to the workspace
root - it's only 1 level deep in the actual repo structure
------------------------------
In gdrive/drive_tools.py
<#255 (comment)>
:
> + user_google_email (str): The user's Google email address. Required.
+ file_id (str): The ID of the Google Drive file to download.
+ local_file_path (str): The local file path where the file should be saved.
+
+ Returns:
+ str: Success message with file details and saved location.
+ """
+ import os
+ logger.info(f"[save_drive_file_to_disk] Downloading file {file_id} to {local_file_path} for user {user_google_email}")
+
+ # Convert relative paths to be relative from workspace root instead of server directory
+ if not os.path.isabs(local_file_path):
+ # Server runs from google-workspace-mcp-dev/google_workspace_mcp
+ # This file is in gdrive/drive_tools.py, so workspace root is ../../../ from here
+ workspace_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
+ local_file_path = os.path.join(workspace_root, local_file_path)
We should probably restrict / validate the resolved path somehow because
as it stands, this introduces a major attack vector (a malicious payload
could have it write files to /etc/passwd, firewall config or sudoers files
etc)
—
Reply to this email directly, view it on GitHub
<#255 (review)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAK4AW6JLBHWJBKY7W5SPZL33DF5XAVCNFSM6AAAAACKPPMFEKVHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZTIMJXGMZTINJUGE>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Add save_drive_file_to_disk tool for downloading files directly to filesystem
Closes #254
Problem
The existing
get_drive_file_contenttool downloads Google Drive files to memory (io.BytesIO) and attempts to return content as text. This approach has several limitations:Solution
This PR adds a new
save_drive_file_to_diskMCP tool that downloads Google Drive files directly to the local filesystem without streaming content through the AI context.Features
✅ Direct disk download: Uses
MediaIoBaseDownloadwith file handles to write directly to disk✅ Smart path handling: Converts relative paths to workspace root automatically
✅ Native file support: Handles both Google native files (with export) and regular files
✅ Automatic directory creation: Creates necessary parent directories as needed
✅ Shared drive support: Full support for shared drives with
supportsAllDrives=True✅ Detailed feedback: Returns comprehensive success message with file metadata and location
✅ Export format mapping: Automatically exports Google Docs/Sheets/Slides to Office formats
Technical Implementation
New function:
save_drive_file_to_disk()gdrive/drive_tools.py(lines 412-509)user_google_email: User's Google email (required)file_id: Google Drive file ID (required)local_file_path: Local destination path (required)core/tool_tiers.yamlExport format mappings:
.docx(Word).xlsx(Excel).pptx(PowerPoint)Use Cases
This feature is particularly useful for:
Code Changes
Files modified:
gdrive/drive_tools.py: +97 lines (new function)core/tool_tiers.yaml: +1 line (tool tier registration)No conflicts: This PR adds new functionality without modifying existing tools. It complements recent upload improvements from PR #239.
Testing
Tested with:
Example Usage
Checklist
@handle_http_errors@require_google_serviceRelated