workspace-mcp 1.1.12__tar.gz → 1.1.13__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 (55) hide show
  1. {workspace_mcp-1.1.12/workspace_mcp.egg-info → workspace_mcp-1.1.13}/PKG-INFO +1 -1
  2. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/google_auth.py +10 -0
  3. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/oauth_callback_server.py +23 -18
  4. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/core/server.py +6 -2
  5. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/main.py +6 -2
  6. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/pyproject.toml +1 -1
  7. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13/workspace_mcp.egg-info}/PKG-INFO +1 -1
  8. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/LICENSE +0 -0
  9. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/README.md +0 -0
  10. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/__init__.py +0 -0
  11. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/oauth21/__init__.py +0 -0
  12. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/oauth21/compat.py +0 -0
  13. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/oauth21/config.py +0 -0
  14. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/oauth21/discovery.py +0 -0
  15. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/oauth21/example_config.py +0 -0
  16. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/oauth21/handler.py +0 -0
  17. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/oauth21/http.py +0 -0
  18. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/oauth21/jwt.py +0 -0
  19. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/oauth21/middleware.py +0 -0
  20. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/oauth21/oauth2.py +0 -0
  21. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/oauth21/sessions.py +0 -0
  22. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/oauth21/tokens.py +0 -0
  23. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/oauth_responses.py +0 -0
  24. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/scopes.py +0 -0
  25. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/auth/service_decorator.py +0 -0
  26. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/core/__init__.py +0 -0
  27. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/core/comments.py +0 -0
  28. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/core/context.py +0 -0
  29. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/core/utils.py +0 -0
  30. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gTasks/__init__.py +0 -0
  31. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gTasks/tasks_tools.py +0 -0
  32. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gcalendar/__init__.py +0 -0
  33. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gcalendar/calendar_tools.py +0 -0
  34. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gchat/__init__.py +0 -0
  35. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gchat/chat_tools.py +0 -0
  36. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gdocs/__init__.py +0 -0
  37. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gdocs/docs_tools.py +0 -0
  38. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gdrive/__init__.py +0 -0
  39. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gdrive/drive_tools.py +0 -0
  40. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gforms/__init__.py +0 -0
  41. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gforms/forms_tools.py +0 -0
  42. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gmail/__init__.py +0 -0
  43. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gmail/gmail_tools.py +0 -0
  44. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gsheets/__init__.py +0 -0
  45. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gsheets/sheets_tools.py +0 -0
  46. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gslides/__init__.py +0 -0
  47. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/gslides/slides_tools.py +0 -0
  48. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/setup.cfg +0 -0
  49. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/tests/test_auth.py +0 -0
  50. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/tests/test_oauth_callback_server.py +0 -0
  51. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/workspace_mcp.egg-info/SOURCES.txt +0 -0
  52. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/workspace_mcp.egg-info/dependency_links.txt +0 -0
  53. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/workspace_mcp.egg-info/entry_points.txt +0 -0
  54. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/workspace_mcp.egg-info/requires.txt +0 -0
  55. {workspace_mcp-1.1.12 → workspace_mcp-1.1.13}/workspace_mcp.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: workspace-mcp
3
- Version: 1.1.12
3
+ Version: 1.1.13
4
4
  Summary: Comprehensive, highly performant Google Workspace Streamable HTTP & SSE MCP Server for Calendar, Gmail, Docs, Sheets, Slides & Drive
5
5
  Author-email: Taylor Wilsdon <taylor@taylorwilsdon.com>
6
6
  License: MIT
@@ -379,6 +379,16 @@ async def start_auth_flow(
379
379
  f"[start_auth_flow] Initiating auth for {user_display_name} with global SCOPES."
380
380
  )
381
381
 
382
+ # Import here to avoid circular imports
383
+ from auth.oauth_callback_server import ensure_oauth_callback_available
384
+ from core.server import _current_transport_mode, WORKSPACE_MCP_PORT, WORKSPACE_MCP_BASE_URI
385
+
386
+ # Ensure OAuth callback server is available before generating URLs
387
+ success, error_msg = ensure_oauth_callback_available(_current_transport_mode, WORKSPACE_MCP_PORT, WORKSPACE_MCP_BASE_URI)
388
+ if not success:
389
+ error_detail = f" ({error_msg})" if error_msg else ""
390
+ raise Exception(f"Cannot initiate OAuth flow - callback server unavailable{error_detail}. Please ensure the OAuth callback server can start before attempting authentication.")
391
+
382
392
  try:
383
393
  if "OAUTHLIB_INSECURE_TRANSPORT" not in os.environ and (
384
394
  "localhost" in redirect_uri or "127.0.0.1" in redirect_uri
@@ -89,16 +89,16 @@ class MinimalOAuthServer:
89
89
  logger.error(error_message_detail, exc_info=True)
90
90
  return create_server_error_response(str(e))
91
91
 
92
- def start(self) -> bool:
92
+ def start(self) -> tuple[bool, str]:
93
93
  """
94
94
  Start the minimal OAuth server.
95
95
 
96
96
  Returns:
97
- True if started successfully, False otherwise
97
+ Tuple of (success: bool, error_message: str)
98
98
  """
99
99
  if self.is_running:
100
100
  logger.info("Minimal OAuth server is already running")
101
- return True
101
+ return True, ""
102
102
 
103
103
  # Check if port is available
104
104
  # Extract hostname from base_uri (e.g., "http://localhost" -> "localhost")
@@ -112,8 +112,9 @@ class MinimalOAuthServer:
112
112
  with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
113
113
  s.bind((hostname, self.port))
114
114
  except OSError:
115
- logger.error(f"Port {self.port} is already in use on {hostname}. Cannot start minimal OAuth server.")
116
- return False
115
+ error_msg = f"Port {self.port} is already in use on {hostname}. Cannot start minimal OAuth server."
116
+ logger.error(error_msg)
117
+ return False, error_msg
117
118
 
118
119
  def run_server():
119
120
  """Run the server in a separate thread."""
@@ -130,6 +131,7 @@ class MinimalOAuthServer:
130
131
 
131
132
  except Exception as e:
132
133
  logger.error(f"Minimal OAuth server error: {e}", exc_info=True)
134
+ self.is_running = False
133
135
 
134
136
  # Start server in background thread
135
137
  self.server_thread = threading.Thread(target=run_server, daemon=True)
@@ -145,13 +147,14 @@ class MinimalOAuthServer:
145
147
  if result == 0:
146
148
  self.is_running = True
147
149
  logger.info(f"Minimal OAuth server started on {hostname}:{self.port}")
148
- return True
150
+ return True, ""
149
151
  except Exception:
150
152
  pass
151
153
  time.sleep(0.1)
152
154
 
153
- logger.error(f"Failed to start minimal OAuth server on {hostname}:{self.port}")
154
- return False
155
+ error_msg = f"Failed to start minimal OAuth server on {hostname}:{self.port} - server did not respond within {max_wait}s"
156
+ logger.error(error_msg)
157
+ return False, error_msg
155
158
 
156
159
  def stop(self):
157
160
  """Stop the minimal OAuth server."""
@@ -202,7 +205,7 @@ def get_oauth_redirect_uri(port: int = 8000, base_uri: str = "http://localhost")
202
205
  logger.info(f"Constructed redirect URI: {constructed_uri}")
203
206
  return constructed_uri
204
207
 
205
- def ensure_oauth_callback_available(transport_mode: str = "stdio", port: int = 8000, base_uri: str = "http://localhost") -> bool:
208
+ def ensure_oauth_callback_available(transport_mode: str = "stdio", port: int = 8000, base_uri: str = "http://localhost") -> tuple[bool, str]:
206
209
  """
207
210
  Ensure OAuth callback endpoint is available for the given transport mode.
208
211
 
@@ -215,14 +218,14 @@ def ensure_oauth_callback_available(transport_mode: str = "stdio", port: int = 8
215
218
  base_uri: Base URI (default "http://localhost")
216
219
 
217
220
  Returns:
218
- True if callback endpoint is available, False otherwise
221
+ Tuple of (success: bool, error_message: str)
219
222
  """
220
223
  global _minimal_oauth_server
221
224
 
222
225
  if transport_mode == "streamable-http":
223
226
  # In streamable-http mode, the main FastAPI server should handle callbacks
224
227
  logger.debug("Using existing FastAPI server for OAuth callbacks (streamable-http mode)")
225
- return True
228
+ return True, ""
226
229
 
227
230
  elif transport_mode == "stdio":
228
231
  # In stdio mode, start minimal server if not already running
@@ -232,19 +235,21 @@ def ensure_oauth_callback_available(transport_mode: str = "stdio", port: int = 8
232
235
 
233
236
  if not _minimal_oauth_server.is_running:
234
237
  logger.info("Starting minimal OAuth server for stdio mode")
235
- result = _minimal_oauth_server.start()
236
- if result:
238
+ success, error_msg = _minimal_oauth_server.start()
239
+ if success:
237
240
  logger.info(f"Minimal OAuth server successfully started on {base_uri}:{port}")
241
+ return True, ""
238
242
  else:
239
- logger.error(f"Failed to start minimal OAuth server on {base_uri}:{port}")
240
- return result
243
+ logger.error(f"Failed to start minimal OAuth server on {base_uri}:{port}: {error_msg}")
244
+ return False, error_msg
241
245
  else:
242
246
  logger.info("Minimal OAuth server is already running")
243
- return True
247
+ return True, ""
244
248
 
245
249
  else:
246
- logger.error(f"Unknown transport mode: {transport_mode}")
247
- return False
250
+ error_msg = f"Unknown transport mode: {transport_mode}"
251
+ logger.error(error_msg)
252
+ return False, error_msg
248
253
 
249
254
  def cleanup_oauth_callback_server():
250
255
  """Clean up the minimal OAuth server if it was started."""
@@ -193,8 +193,12 @@ async def start_google_auth(
193
193
 
194
194
  # Ensure OAuth callback is available for current transport mode
195
195
  redirect_uri = get_oauth_redirect_uri_for_current_mode()
196
- if not ensure_oauth_callback_available(_current_transport_mode, WORKSPACE_MCP_PORT, WORKSPACE_MCP_BASE_URI):
197
- raise Exception("Failed to start OAuth callback server. Please try again.")
196
+ success, error_msg = ensure_oauth_callback_available(_current_transport_mode, WORKSPACE_MCP_PORT, WORKSPACE_MCP_BASE_URI)
197
+ if not success:
198
+ if error_msg:
199
+ raise Exception(f"Failed to start OAuth callback server: {error_msg}")
200
+ else:
201
+ raise Exception("Failed to start OAuth callback server. Please try again.")
198
202
 
199
203
  auth_result = await start_auth_flow(
200
204
  user_google_email=user_google_email,
@@ -149,10 +149,14 @@ def main():
149
149
  safe_print("🚀 Starting server in stdio mode")
150
150
  # Start minimal OAuth callback server for stdio mode
151
151
  from auth.oauth_callback_server import ensure_oauth_callback_available
152
- if ensure_oauth_callback_available('stdio', port, base_uri):
152
+ success, error_msg = ensure_oauth_callback_available('stdio', port, base_uri)
153
+ if success:
153
154
  safe_print(f" OAuth callback server started on {base_uri}:{port}/oauth2callback")
154
155
  else:
155
- safe_print(" ⚠️ Warning: Failed to start OAuth callback server")
156
+ warning_msg = f" ⚠️ Warning: Failed to start OAuth callback server"
157
+ if error_msg:
158
+ warning_msg += f": {error_msg}"
159
+ safe_print(warning_msg)
156
160
 
157
161
  safe_print(" Ready for MCP connections!")
158
162
  safe_print("")
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "workspace-mcp"
7
- version = "1.1.12"
7
+ version = "1.1.13"
8
8
  description = "Comprehensive, highly performant Google Workspace Streamable HTTP & SSE MCP Server for Calendar, Gmail, Docs, Sheets, Slides & Drive"
9
9
  readme = "README.md"
10
10
  keywords = [ "mcp", "google", "workspace", "llm", "ai", "claude", "model", "context", "protocol", "server"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: workspace-mcp
3
- Version: 1.1.12
3
+ Version: 1.1.13
4
4
  Summary: Comprehensive, highly performant Google Workspace Streamable HTTP & SSE MCP Server for Calendar, Gmail, Docs, Sheets, Slides & Drive
5
5
  Author-email: Taylor Wilsdon <taylor@taylorwilsdon.com>
6
6
  License: MIT
File without changes
File without changes
File without changes