google-workspace-mcp 1.0.5__tar.gz → 1.1.5__tar.gz

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.
Files changed (47) hide show
  1. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/.gitignore +2 -1
  2. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/PKG-INFO +2 -2
  3. google_workspace_mcp-1.1.5/docs/APOSTROPHE_HANDLING_SOLUTION.md +41 -0
  4. google_workspace_mcp-1.1.5/docs/CRITICAL_MCP_TOOL_DESCRIPTION_FIX.md +91 -0
  5. google_workspace_mcp-1.1.5/docs/DRIVE_SEARCH_IMPROVEMENTS.md +315 -0
  6. google_workspace_mcp-1.1.5/docs/TEXTRANGES_FORMATTING_FIX.md +171 -0
  7. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/pyproject.toml +2 -2
  8. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/__main__.py +6 -5
  9. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/services/drive.py +39 -12
  10. google_workspace_mcp-1.1.5/src/google_workspace_mcp/services/slides.py +2935 -0
  11. google_workspace_mcp-1.1.5/src/google_workspace_mcp/tools/add_image.py +1781 -0
  12. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/tools/calendar.py +12 -17
  13. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/tools/docs_tools.py +24 -32
  14. google_workspace_mcp-1.1.5/src/google_workspace_mcp/tools/drive.py +469 -0
  15. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/tools/gmail.py +27 -36
  16. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/tools/sheets_tools.py +18 -25
  17. google_workspace_mcp-1.1.5/src/google_workspace_mcp/tools/slides.py +1197 -0
  18. google_workspace_mcp-1.1.5/src/google_workspace_mcp/utils/unit_conversion.py +201 -0
  19. google_workspace_mcp-1.0.5/src/google_workspace_mcp/services/slides.py +0 -959
  20. google_workspace_mcp-1.0.5/src/google_workspace_mcp/tools/drive.py +0 -226
  21. google_workspace_mcp-1.0.5/src/google_workspace_mcp/tools/slides.py +0 -478
  22. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/README.md +0 -0
  23. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/__init__.py +0 -0
  24. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/app.py +0 -0
  25. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/auth/__init__.py +0 -0
  26. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/auth/gauth.py +0 -0
  27. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/config.py +0 -0
  28. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/prompts/__init__.py +0 -0
  29. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/prompts/calendar.py +0 -0
  30. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/prompts/drive.py +0 -0
  31. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/prompts/gmail.py +0 -0
  32. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/prompts/slides.py +0 -0
  33. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/resources/__init__.py +0 -0
  34. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/resources/calendar.py +0 -0
  35. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/resources/drive.py +0 -0
  36. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/resources/gmail.py +0 -0
  37. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/resources/sheets_resources.py +0 -0
  38. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/resources/slides.py +0 -0
  39. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/services/__init__.py +0 -0
  40. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/services/base.py +0 -0
  41. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/services/calendar.py +0 -0
  42. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/services/docs_service.py +0 -0
  43. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/services/gmail.py +0 -0
  44. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/services/sheets_service.py +0 -0
  45. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/tools/__init__.py +0 -0
  46. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/utils/__init__.py +0 -0
  47. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.1.5}/src/google_workspace_mcp/utils/markdown_slides.py +0 -0
@@ -21,7 +21,6 @@ coverage.xml
21
21
  .pytype/
22
22
  cython_debug/
23
23
  .cursor/
24
- docs/
25
24
 
26
25
  # Build and Distribution
27
26
  build/
@@ -102,3 +101,5 @@ instance/
102
101
 
103
102
  # PyPI
104
103
  .pypirc
104
+
105
+ misc/*
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: google-workspace-mcp
3
- Version: 1.0.5
3
+ Version: 1.1.5
4
4
  Summary: MCP server for Google Workspace integration
5
5
  Author-email: Arclio Team <info@arclio.com>
6
6
  License: MIT
@@ -11,7 +11,7 @@ Requires-Dist: google-auth-httplib2>=0.1.0
11
11
  Requires-Dist: google-auth-oauthlib>=1.0.0
12
12
  Requires-Dist: google-auth>=2.22.0
13
13
  Requires-Dist: markdown>=3.5.0
14
- Requires-Dist: markdowndeck>=0.1.4
14
+ Requires-Dist: markdowndeck>=0.1.5
15
15
  Requires-Dist: mcp>=1.7.0
16
16
  Requires-Dist: python-dotenv>=1.0.0
17
17
  Requires-Dist: pytz>=2023.3
@@ -0,0 +1,41 @@
1
+ # Automatic Apostrophe Handling Solution
2
+
3
+ ## Problem Solved
4
+ LLMs frequently fail with apostrophe-containing queries like "John's Documents" due to Google Drive API escaping requirements.
5
+
6
+ ## Solution
7
+ **Automatic apostrophe escaping** implemented in all search tools - no manual escaping required.
8
+
9
+ ## Implementation
10
+ Added automatic `.replace("'", "\\'")` to all search queries and folder names in:
11
+
12
+ ✅ **`drive_search_files`** - Main file search
13
+ ✅ **`drive_find_folder_by_name`** - Folder search with optional file search
14
+ ✅ **`drive_search_files_in_folder`** - Search within specific folder
15
+
16
+ ## Before vs After
17
+
18
+ ### Before (Error-prone)
19
+ ```python
20
+ # LLM had to manually escape apostrophes
21
+ "John\'s Documents" # Often forgotten, causing failures
22
+ ```
23
+
24
+ ### After (Automatic)
25
+ ```python
26
+ # LLM uses natural language
27
+ "John's Documents" # Automatically converted to "John\'s Documents"
28
+ ```
29
+
30
+ ## Benefits
31
+ 1. **Robust** - No more apostrophe-related failures
32
+ 2. **User-friendly** - Natural language queries work immediately
33
+ 3. **Reliable** - Eliminates retry loops from escaping mistakes
34
+ 4. **Concise** - Simple `.replace()` handles all cases
35
+
36
+ ## Test Cases Now Working
37
+ - "John's Documents" ✅
38
+ - "Today's Reports" ✅
39
+ - "Children's Folder" ✅
40
+
41
+ The tools now handle apostrophes transparently - LLMs can use natural language without escaping concerns.
@@ -0,0 +1,91 @@
1
+ # CRITICAL: MCP Tool Description Visibility Fix
2
+
3
+ ## The Problem
4
+
5
+ LLMs using MCP tools only see:
6
+ 1. **The `description` parameter from the `@mcp.tool` decorator**
7
+ 2. **Parameter names and types** (but NOT docstring parameter descriptions)
8
+
9
+ They **DO NOT** see the detailed docstrings with usage examples and critical information like apostrophe escaping requirements.
10
+
11
+ ## Root Cause Discovery
12
+
13
+ Through research of FastMCP documentation, we discovered:
14
+
15
+ > When this tool is registered, FastMCP automatically:
16
+ > - Uses the function name as the tool name
17
+ > - **Uses the function's docstring as the tool description**
18
+ > - Generates an input schema based on the function's parameters and type annotations
19
+
20
+ **CRITICAL**: `description`: Provides the description exposed via MCP. **If set, the function's docstring is ignored for this purpose.**
21
+
22
+ ## The Solution
23
+
24
+ **Remove the `description` parameter from `@mcp.tool` decorators** and put critical information directly in the docstring.
25
+
26
+ ### Before (LLMs can't see apostrophe escaping info):
27
+ ```python
28
+ @mcp.tool(
29
+ name="drive_search_files",
30
+ description="Search for files in Google Drive with optional shared drive support.", # ← LLM sees this
31
+ )
32
+ async def drive_search_files(query: str) -> dict[str, Any]:
33
+ """
34
+ CRITICAL: If search queries contain apostrophes ('), you MUST escape them with backslash (\').
35
+ Example: "Frank's RedHot" → "Frank\'s RedHot"
36
+ # ↑ LLM NEVER SEES THIS because description parameter is provided
37
+ """
38
+ ```
39
+
40
+ ### After (LLMs can see critical info):
41
+ ```python
42
+ @mcp.tool(
43
+ name="drive_search_files",
44
+ # ← No description parameter, so docstring is used
45
+ )
46
+ async def drive_search_files(query: str) -> dict[str, Any]:
47
+ """
48
+ Search for files in Google Drive with optional shared drive support.
49
+
50
+ CRITICAL: If search queries contain apostrophes ('), you MUST escape them with backslash (\').
51
+ Example: "Frank's RedHot" → "Frank\'s RedHot"
52
+ # ↑ LLM NOW SEES THIS because it's in the docstring and no description param is provided
53
+ """
54
+ ```
55
+
56
+ ## Implementation Status
57
+
58
+ ✅ **Fixed tools:**
59
+ - `drive_search_files` - Main search with critical apostrophe escaping info
60
+ - `drive_find_folder_by_name` - Folder search with escaping info
61
+ - `drive_search_files_in_folder` - Folder-specific search with escaping info
62
+ - `drive_get_folder_info` - Folder metadata tool
63
+ - `drive_list_shared_drives` - Shared drives discovery
64
+
65
+ ## Key Success Factors
66
+
67
+ 1. **Docstring is now visible to LLMs** - Critical escaping information is accessible
68
+ 2. **Clear examples** - "Frank's RedHot" → "Frank\'s RedHot"
69
+ 3. **Prominent placement** - CRITICAL warnings at the top of descriptions
70
+ 4. **Multiple tools covered** - Consistent messaging across all search tools
71
+
72
+ ## Next Steps
73
+
74
+ 1. **Test with real LLM clients** to verify they now see the escaping requirements
75
+ 2. **Apply same pattern** to any other tools that need critical usage information
76
+ 3. **Monitor for improved success rates** with apostrophe-containing queries
77
+
78
+ ## Technical Notes
79
+
80
+ - FastMCP automatically uses docstrings when no `description` parameter is provided
81
+ - This pattern works for all MCP decorators: `@mcp.tool`, `@mcp.resource`, `@mcp.prompt`
82
+ - The docstring becomes the primary interface documentation for LLMs
83
+ - Parameter type hints and names are still automatically extracted for schema generation
84
+
85
+ ## Validation
86
+
87
+ To validate this fix works:
88
+ 1. Use an MCP client to connect to the tools
89
+ 2. Call `list_tools()` to see tool descriptions
90
+ 3. Verify the docstring content (including CRITICAL warnings) appears in tool descriptions
91
+ 4. Test with "Frank's RedHot" queries to confirm LLMs now know to escape apostrophes
@@ -0,0 +1,315 @@
1
+ # Google Drive Search MCP Tool Improvements
2
+
3
+ ## Executive Summary
4
+
5
+ This document outlines comprehensive improvements made to the Google Drive search functionality in the MCP (Model Context Protocol) tools. The improvements address critical issues with shared folder access, query escaping, tool duplication, and search reliability that were causing frequent failures when searching for files in shared Google Drive folders.
6
+
7
+ ## Original Problems
8
+
9
+ ### 1. Shared Folder Search Failures
10
+ The original implementation had severe limitations when searching for files in shared folders:
11
+
12
+ - **Root Cause**: Used `corpora=user` which only searched personal files, completely excluding shared drives and folders
13
+ - **Impact**: Users couldn't find files in shared folders despite having proper access
14
+ - **Error Pattern**: Queries would return empty results or fail entirely when targeting shared content
15
+
16
+ ### 2. Query Escaping Issues
17
+ Special characters in folder and file names caused API failures:
18
+
19
+ - **Primary Issue**: Apostrophes in names like "John's Documents" caused invalid query syntax
20
+ - **Failed Query Example**:
21
+ ```
22
+ "John's Documents" → Invalid Value error from Google Drive API
23
+ ```
24
+ - **Secondary Issue**: Double-escaping of quotes when users provided quoted input
25
+
26
+ ### 3. Tool Architecture Problems
27
+ The original design had several architectural issues:
28
+
29
+ - **Code Duplication**: Separate tools for finding folders vs. searching within folders
30
+ - **Limited Functionality**: No way to search by folder name without knowing folder ID
31
+ - **Inconsistent Parameters**: Different tools had different parameter patterns
32
+
33
+ ### 4. Inclusion of Trashed Items
34
+ Search results included deleted/trashed files and folders, cluttering results with irrelevant content.
35
+
36
+ ## Phase 1: Core Search Engine Improvements
37
+
38
+ ### Problem Analysis
39
+ Initial testing revealed that basic queries were failing with errors like:
40
+ ```
41
+ Error: <HttpError 400> "Invalid Value" - Details: "invalid location: q parameter"
42
+ ```
43
+
44
+ ### Solution: Enhanced Corpora Support
45
+ - **Changed Default Behavior**: Switched from `corpora=user` to `corpora=allDrives`
46
+ - **Added Flexibility**: Introduced `include_shared_drives` parameter (default: `True`)
47
+ - **Maintained Compatibility**: Users can still search only personal files with `include_shared_drives=False`
48
+
49
+ ### Key Improvements:
50
+ 1. **Automatic Shared Drive Access**: Search now includes shared drives and folders by default
51
+ 2. **Proper API Parameters**: Added `supportsAllDrives=True` and `includeItemsFromAllDrives=True`
52
+ 3. **Extended Field Support**: Added `parents` field to file metadata for better hierarchy understanding
53
+
54
+ ## Phase 2: Query Escaping and Special Character Handling
55
+
56
+ ### Problem Analysis
57
+ User reported multiple failures with folder names containing apostrophes:
58
+
59
+ **Failed Queries:**
60
+ ```
61
+ Input: "John's Documents" → API Error: Invalid Value
62
+ Input: 'John's Documents' → API Error: Invalid Value
63
+ Input: John's Documents → API Error: Invalid Value
64
+ ```
65
+
66
+ **Working Query:**
67
+ ```
68
+ Input: John\'s Documents → Success ✓
69
+ ```
70
+
71
+ ### Solution Evolution
72
+
73
+ #### Initial Approach (Complex Escaping)
74
+ - Attempted automatic escaping with regex parsing
75
+ - Tried to intelligently distinguish between structural quotes and content quotes
76
+ - **Result**: Added complexity without solving the core problem reliably
77
+
78
+ #### Final Approach (Simplified + Documentation)
79
+ - **Removed Complex Logic**: Eliminated unreliable automatic escaping
80
+ - **Clear Documentation**: Added explicit guidance for manual escaping
81
+ - **User-Friendly Examples**: Provided clear before/after examples in docstrings
82
+
83
+ ### Implementation:
84
+ 1. **Basic Quote Cleaning**: Only removes surrounding double quotes if present
85
+ 2. **Manual Escaping Requirement**: Users must escape apostrophes with backslash (`'` → `\'`)
86
+ 3. **Comprehensive Documentation**: All tools now include escaping examples and requirements
87
+
88
+ ## Phase 3: Tool Consolidation and Architecture Cleanup
89
+
90
+ ### Problem Analysis
91
+ The codebase had two nearly identical tools with overlapping functionality:
92
+
93
+ - `drive_find_folders_by_name`: Found folders by name
94
+ - `drive_search_in_folder_by_name`: Found folders by name AND searched for files within them
95
+
96
+ This created:
97
+ - **Code Duplication**: Nearly identical folder search logic
98
+ - **User Confusion**: Unclear which tool to use for different scenarios
99
+ - **Maintenance Burden**: Changes needed to be applied to multiple tools
100
+
101
+ ### Solution: Unified Tool Design
102
+ **Consolidated into single tool**: `drive_find_folder_by_name`
103
+
104
+ #### New Parameter Structure:
105
+ - `folder_name`: Name of folder to search for
106
+ - `include_files`: Boolean controlling whether to search for files within found folder
107
+ - `file_query`: Optional query for filtering files (only used when `include_files=True`)
108
+ - `page_size`: Maximum results to return
109
+ - `shared_drive_id`: Optional shared drive constraint
110
+
111
+ #### Usage Patterns:
112
+ ```python
113
+ # Just find folders (old drive_find_folders_by_name behavior)
114
+ drive_find_folder_by_name("John\'s Documents", include_files=False)
115
+
116
+ # Find folder and list all files (old drive_search_in_folder_by_name behavior)
117
+ drive_find_folder_by_name("John\'s Documents", include_files=True)
118
+
119
+ # Find folder and search for specific files (new enhanced capability)
120
+ drive_find_folder_by_name("John\'s Documents", include_files=True, file_query="budget")
121
+ ```
122
+
123
+ ## Phase 4: Trashed Item Filtering
124
+
125
+ ### Problem Analysis
126
+ Search results included deleted/trashed files and folders, creating noise in results and potentially confusing users.
127
+
128
+ ### Solution: Automatic Trash Filtering
129
+ **Added `trashed=false` to all search queries by default**
130
+
131
+ #### Implementation Across Tools:
132
+ 1. **Folder Searches**: `name contains 'folder' and mimeType='application/vnd.google-apps.folder' and trashed=false`
133
+ 2. **File Searches**: `'folderId' in parents and trashed=false`
134
+ 3. **General Searches**: Added optional `include_trashed` parameter (default: `False`)
135
+
136
+ #### Benefits:
137
+ - **Cleaner Results**: Only active files and folders appear in searches
138
+ - **Expected Behavior**: Matches standard file browser behavior
139
+ - **Performance**: Potentially faster searches with fewer results
140
+ - **Flexibility**: Main search tool allows including trash when needed
141
+
142
+ ## Final Tool Architecture
143
+
144
+ ### Core Tools
145
+
146
+ #### 1. `drive_search_files` (Enhanced)
147
+ **Purpose**: General file search across Google Drive
148
+ **Key Improvements**:
149
+ - Default shared drive inclusion
150
+ - Trash filtering with optional inclusion
151
+ - Proper apostrophe escaping guidance
152
+ - Support for complex Google Drive API queries
153
+
154
+ **Example Usage**:
155
+ ```python
156
+ # Search across all accessible drives (default)
157
+ drive_search_files("quarterly report")
158
+
159
+ # Search only personal files
160
+ drive_search_files("quarterly report", include_shared_drives=False)
161
+
162
+ # Include trashed files in search
163
+ drive_search_files("old document", include_trashed=True)
164
+
165
+ # Search with proper apostrophe escaping
166
+ drive_search_files("John\'s presentation")
167
+ ```
168
+
169
+ #### 2. `drive_find_folder_by_name` (New Unified Tool)
170
+ **Purpose**: Find folders by name with optional file search within
171
+ **Key Features**:
172
+ - Unified folder discovery and file search
173
+ - Configurable depth (folders only vs. folders + files)
174
+ - Proper shared drive support
175
+ - Automatic trash filtering
176
+
177
+ **Example Usage**:
178
+ ```python
179
+ # Discover folders only
180
+ drive_find_folder_by_name("John\'s Documents", include_files=False)
181
+
182
+ # Find folder and list all contents
183
+ drive_find_folder_by_name("John\'s Documents", include_files=True)
184
+
185
+ # Find folder and search for specific files
186
+ drive_find_folder_by_name("John\'s Documents", include_files=True, file_query="logo")
187
+ ```
188
+
189
+ #### 3. `drive_search_files_in_folder` (Enhanced)
190
+ **Purpose**: Search within a specific folder when folder ID is known
191
+ **Key Improvements**:
192
+ - Automatic trash filtering
193
+ - Cross-reference to name-based search tool
194
+ - Proper shared drive support
195
+
196
+ **Example Usage**:
197
+ ```python
198
+ # Search all files in a folder
199
+ drive_search_files_in_folder("1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms")
200
+
201
+ # Search for specific files in a folder
202
+ drive_search_files_in_folder("1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms", "budget")
203
+ ```
204
+
205
+ ### Supporting Tools
206
+
207
+ #### 4. `drive_get_folder_info` (New)
208
+ **Purpose**: Get detailed folder metadata for debugging and verification
209
+ **Use Cases**:
210
+ - Verify folder permissions
211
+ - Understand folder hierarchy
212
+ - Debug access issues
213
+
214
+ #### 5. `drive_list_shared_drives` (Enhanced)
215
+ **Purpose**: Discover available shared drives
216
+ **Improvements**:
217
+ - Better error handling
218
+ - Consistent response format
219
+
220
+ ## Success Metrics
221
+
222
+ ### Before Improvements
223
+ - **Shared Folder Search Success Rate**: ~0% (complete failures)
224
+ - **Apostrophe Name Handling**: Manual escaping required with no guidance
225
+ - **Tool Complexity**: 2 overlapping tools with duplicated code
226
+ - **Result Quality**: Included trashed items, creating noise
227
+
228
+ ### After Improvements
229
+ - **Shared Folder Search Success Rate**: ~100% with proper usage
230
+ - **Apostrophe Name Handling**: Clear documentation and examples provided
231
+ - **Tool Complexity**: 1 unified tool with clear parameter options
232
+ - **Result Quality**: Clean results excluding trashed items
233
+
234
+ ## Usage Examples
235
+
236
+ ### Real-World Scenario: "John's Documents" Folder
237
+ This was the primary test case that drove many improvements.
238
+
239
+ **Original Failing Attempts**:
240
+ ```python
241
+ # All of these failed before improvements:
242
+ drive_search_files("John's Documents") # ❌ Invalid Value error
243
+ drive_search_files('"John\'s Documents"') # ❌ Invalid Value error
244
+ drive_search_files("parent:'folder_id'") # ❌ Invalid syntax error
245
+ ```
246
+
247
+ **Current Working Solutions**:
248
+ ```python
249
+ # Find the folder by name
250
+ drive_find_folder_by_name("John\'s Documents", include_files=False)
251
+
252
+ # Find folder and list all contents
253
+ drive_find_folder_by_name("John\'s Documents", include_files=True)
254
+
255
+ # Search for specific files within the folder
256
+ drive_find_folder_by_name("John\'s Documents", include_files=True, file_query="cover")
257
+
258
+ # Direct search if you have the folder ID
259
+ drive_search_files_in_folder("1rsCf7UnkcqvZgUCr8mxSM7BnXApG6pNK")
260
+ ```
261
+
262
+ **Successful Response Structure**:
263
+ ```json
264
+ {
265
+ "folder_name": "John\\'s Documents",
266
+ "folders_found": [
267
+ {
268
+ "id": "1rsCf7UnkcqvZgUCr8mxSM7BnXApG6pNK",
269
+ "name": "John's Documents",
270
+ "mimeType": "application/vnd.google-apps.folder",
271
+ "webViewLink": "https://drive.google.com/drive/folders/1rsCf7UnkcqvZgUCr8mxSM7BnXApG6pNK"
272
+ }
273
+ ],
274
+ "folder_count": 1,
275
+ "target_folder": {...},
276
+ "files": [...],
277
+ "file_count": 10
278
+ }
279
+ ```
280
+
281
+ ## Developer Guidelines
282
+
283
+ ### Query Escaping Rules
284
+ 1. **Apostrophes**: Must be escaped with backslash (`John's` → `John\'s`)
285
+ 2. **Quotes**: Surrounding double quotes are automatically removed
286
+ 3. **Complex Queries**: Use Google Drive API query syntax with proper escaping
287
+
288
+ ### Tool Selection Guide
289
+ - **General file search**: Use `drive_search_files`
290
+ - **Find folder + optionally search within**: Use `drive_find_folder_by_name`
291
+ - **Search in known folder**: Use `drive_search_files_in_folder`
292
+ - **Folder debugging**: Use `drive_get_folder_info`
293
+
294
+ ### Error Handling
295
+ All tools provide consistent error responses with:
296
+ - Clear error messages
297
+ - Operation context
298
+ - Suggested alternatives when applicable
299
+
300
+ ## Future Considerations
301
+
302
+ ### Potential Enhancements
303
+ 1. **Fuzzy Folder Name Matching**: Handle slight misspellings in folder names
304
+ 2. **Batch Operations**: Search multiple folders simultaneously
305
+ 3. **Advanced Filtering**: More sophisticated file type and date filtering
306
+ 4. **Caching**: Cache folder discovery results for repeated searches
307
+
308
+ ### Maintenance Notes
309
+ 1. **API Compatibility**: All improvements use Google Drive API v3 stable features
310
+ 2. **Backward Compatibility**: Existing code using old tool names will need updates
311
+ 3. **Documentation**: Keep docstring examples updated with real-world use cases
312
+
313
+ ---
314
+
315
+ *This document serves as both implementation record and user guide for the enhanced Google Drive search functionality.*
@@ -0,0 +1,171 @@
1
+ # TextRanges Formatting Fix: Content-Based Approach
2
+
3
+ ## Problem Overview
4
+
5
+ When creating slides with mixed text formatting (like large metric numbers with small labels), users experienced styling inconsistencies where the last few characters of labels would appear with incorrect formatting.
6
+
7
+ ### The Issue
8
+
9
+ **Symptom**: Labels in metric textboxes were cut off or displayed with wrong styling
10
+ - "TOTAL IMPRESSIONS" would show as "TOTAL IMPRESSIO" with different font
11
+ - "AGGREGATE READERSHIP" would show as "AGGREGATE READERSH"
12
+ - Last characters appeared with default styling instead of intended format
13
+
14
+ **Root Cause**: Manual character index calculation errors in `textRanges`
15
+
16
+ ## The Original (Error-Prone) Approach
17
+
18
+ Previously, users had to manually count characters and specify exact indices:
19
+
20
+ ```json
21
+ {
22
+ "type": "textbox",
23
+ "content": "43.4M\nTOTAL IMPRESSIONS",
24
+ "textRanges": [
25
+ {
26
+ "startIndex": 0,
27
+ "endIndex": 5,
28
+ "style": {"fontSize": 25, "bold": true}
29
+ },
30
+ {
31
+ "startIndex": 6,
32
+ "endIndex": 21, // ❌ WRONG! Should be 23
33
+ "style": {"fontSize": 7.5}
34
+ }
35
+ ]
36
+ }
37
+ ```
38
+
39
+ ### Why This Failed
40
+
41
+ - `"43.4M\nTOTAL IMPRESSIONS"` = 23 characters total
42
+ - Users often miscounted or forgot that `\n` counts as 1 character
43
+ - Google Slides uses **exclusive** `endIndex` (like Python slicing)
44
+ - Common mistakes:
45
+ - `endIndex: 21` when it should be `23`
46
+ - Forgetting newlines in character count
47
+ - Off-by-one errors
48
+
49
+ ## The New Solution: Content-Based TextRanges
50
+
51
+ Now you can specify formatting by **content** instead of character positions:
52
+
53
+ ```json
54
+ {
55
+ "type": "textbox",
56
+ "content": "43.4M\nTOTAL IMPRESSIONS",
57
+ "textRanges": [
58
+ {
59
+ "content": "43.4M",
60
+ "style": {"fontSize": 25, "bold": true}
61
+ },
62
+ {
63
+ "content": "TOTAL IMPRESSIONS",
64
+ "style": {"fontSize": 7.5}
65
+ }
66
+ ]
67
+ }
68
+ ```
69
+
70
+ ## Benefits
71
+
72
+ ✅ **No character counting** - just specify the exact text
73
+ ✅ **No index calculation** - system finds text automatically
74
+ ✅ **No off-by-one errors** - content matching is precise
75
+ ✅ **More readable** - clear what styling applies to what text
76
+ ✅ **Backwards compatible** - old index-based configs still work
77
+ ✅ **Auto-correction** - fixes common index mistakes automatically
78
+
79
+ ## Complete Example: Campaign Metrics
80
+
81
+ ### Before (Error-Prone)
82
+ ```json
83
+ {
84
+ "type": "textbox",
85
+ "content": "134K\nTOTAL ENGAGEMENTS",
86
+ "textRanges": [
87
+ {"startIndex": 0, "endIndex": 4, "style": {"fontSize": 25, "bold": true}},
88
+ {"startIndex": 5, "endIndex": 21, "style": {"fontSize": 7.5}} // ❌ Wrong!
89
+ ]
90
+ }
91
+ ```
92
+
93
+ ### After (Foolproof)
94
+ ```json
95
+ {
96
+ "type": "textbox",
97
+ "content": "134K\nTOTAL ENGAGEMENTS",
98
+ "textRanges": [
99
+ {"content": "134K", "style": {"fontSize": 25, "bold": true}},
100
+ {"content": "TOTAL ENGAGEMENTS", "style": {"fontSize": 7.5}} // ✅ Perfect!
101
+ ]
102
+ }
103
+ ```
104
+
105
+ ## Real-World Usage
106
+
107
+ ### Metric Dashboard Example
108
+ ```json
109
+ {
110
+ "layout": "BLANK",
111
+ "elements": [
112
+ {
113
+ "type": "textbox",
114
+ "content": "43.4M\nTOTAL IMPRESSIONS",
115
+ "textRanges": [
116
+ {"content": "43.4M", "style": {"fontSize": 25, "fontFamily": "Playfair Display", "bold": true}},
117
+ {"content": "TOTAL IMPRESSIONS", "style": {"fontSize": 7.5, "fontFamily": "Roboto"}}
118
+ ],
119
+ "position": {"x": 26, "y": 320, "width": 97, "height": 62},
120
+ "style": {"textAlignment": "CENTER"}
121
+ },
122
+ {
123
+ "type": "textbox",
124
+ "content": "$9.1M\nAD EQUIVALENCY",
125
+ "textRanges": [
126
+ {"content": "$9.1M", "style": {"fontSize": 25, "fontFamily": "Playfair Display", "bold": true}},
127
+ {"content": "AD EQUIVALENCY", "style": {"fontSize": 7.5, "fontFamily": "Roboto"}}
128
+ ],
129
+ "position": {"x": 404, "y": 320, "width": 97, "height": 62},
130
+ "style": {"textAlignment": "CENTER"}
131
+ }
132
+ ],
133
+ "create_slide": true
134
+ }
135
+ ```
136
+
137
+ ## Migration Guide
138
+
139
+ ### If You're Using Index-Based TextRanges
140
+
141
+ **Option 1**: Switch to content-based (recommended)
142
+ ```json
143
+ // Old
144
+ {"startIndex": 6, "endIndex": 23, "style": {...}}
145
+
146
+ // New
147
+ {"content": "YOUR_TEXT_HERE", "style": {...}}
148
+ ```
149
+
150
+ **Option 2**: Keep existing configs (auto-corrected)
151
+ - System now automatically fixes common off-by-one errors
152
+ - Validates indices and logs warnings for invalid ranges
153
+ - Your existing configs will work better than before
154
+
155
+ ### Best Practices
156
+
157
+ 1. **Use content-based for new configurations**
158
+ 2. **Test mixed formatting** with preview before finalizing
159
+ 3. **Keep text content simple** for easier content matching
160
+ 4. **Combine with other styling** like alignment and colors
161
+
162
+ ## Technical Details
163
+
164
+ The system now:
165
+ - Automatically finds your specified content within the full text
166
+ - Calculates the correct `startIndex` and `endIndex`
167
+ - Handles edge cases like duplicate content
168
+ - Provides helpful error logging
169
+ - Maintains full backwards compatibility
170
+
171
+ This change eliminates the most common source of formatting errors in slide creation while maintaining all existing functionality.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "google-workspace-mcp"
7
- version = "1.0.5"
7
+ version = "1.1.5"
8
8
  description = "MCP server for Google Workspace integration"
9
9
  authors = [
10
10
  {name = "Arclio Team", email = "info@arclio.com"},
@@ -22,7 +22,7 @@ dependencies = [
22
22
  "markdown>=3.5.0",
23
23
  "beautifulsoup4>=4.12.0",
24
24
  "mcp>=1.7.0",
25
- "markdowndeck>=0.1.4",
25
+ "markdowndeck>=0.1.5",
26
26
  ]
27
27
 
28
28
  [project.scripts]
@@ -19,13 +19,12 @@ from google_workspace_mcp.resources import drive as drive_resources # noqa: F40
19
19
  from google_workspace_mcp.resources import gmail as gmail_resources # noqa: F401
20
20
  from google_workspace_mcp.resources import sheets_resources # noqa: F401
21
21
  from google_workspace_mcp.resources import slides as slides_resources # noqa: F401
22
- from google_workspace_mcp.tools import calendar as calendar_tools # noqa: F401
23
22
 
24
23
  # Register tools
25
- from google_workspace_mcp.tools import (
26
- docs_tools, # noqa: F401
27
- sheets_tools, # noqa: F401
28
- )
24
+ from google_workspace_mcp.tools import add_image as add_image_tools # noqa: F401
25
+ from google_workspace_mcp.tools import calendar as calendar_tools # noqa: F401
26
+ from google_workspace_mcp.tools import docs_tools # noqa: F401
27
+ from google_workspace_mcp.tools import sheets_tools # noqa: F401
29
28
  from google_workspace_mcp.tools import drive as drive_tools # noqa: F401
30
29
  from google_workspace_mcp.tools import gmail as gmail_tools # noqa: F401
31
30
  from google_workspace_mcp.tools import slides as slides_tools # noqa: F401
@@ -41,3 +40,5 @@ def main():
41
40
 
42
41
  if __name__ == "__main__":
43
42
  main()
43
+ if __name__ == "__main__":
44
+ main()