workspace-mcp 1.1.12__py3-none-any.whl → 1.1.13__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.
- auth/google_auth.py +10 -0
- auth/oauth_callback_server.py +23 -18
- core/server.py +6 -2
- main.py +6 -2
- {workspace_mcp-1.1.12.dist-info → workspace_mcp-1.1.13.dist-info}/METADATA +1 -1
- {workspace_mcp-1.1.12.dist-info → workspace_mcp-1.1.13.dist-info}/RECORD +10 -10
- {workspace_mcp-1.1.12.dist-info → workspace_mcp-1.1.13.dist-info}/WHEEL +0 -0
- {workspace_mcp-1.1.12.dist-info → workspace_mcp-1.1.13.dist-info}/entry_points.txt +0 -0
- {workspace_mcp-1.1.12.dist-info → workspace_mcp-1.1.13.dist-info}/licenses/LICENSE +0 -0
- {workspace_mcp-1.1.12.dist-info → workspace_mcp-1.1.13.dist-info}/top_level.txt +0 -0
auth/google_auth.py
CHANGED
@@ -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
|
auth/oauth_callback_server.py
CHANGED
@@ -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
|
-
|
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
|
-
|
116
|
-
|
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
|
-
|
154
|
-
|
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
|
-
|
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
|
-
|
236
|
-
if
|
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
|
-
|
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
|
-
|
247
|
-
|
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."""
|
core/server.py
CHANGED
@@ -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
|
-
|
197
|
-
|
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,
|
main.py
CHANGED
@@ -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
|
-
|
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
|
-
|
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("")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: workspace-mcp
|
3
|
-
Version: 1.1.
|
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
|
@@ -1,7 +1,7 @@
|
|
1
|
-
main.py,sha256=
|
1
|
+
main.py,sha256=QnpxBnYTqrLaEkO5sqkIeVjiJsvQ9PqnIPk9HiaCs0Y,7765
|
2
2
|
auth/__init__.py,sha256=gPCU3GE-SLy91S3D3CbX-XfKBm6hteK_VSPKx7yjT5s,42
|
3
|
-
auth/google_auth.py,sha256=
|
4
|
-
auth/oauth_callback_server.py,sha256=
|
3
|
+
auth/google_auth.py,sha256=KJjwEgeysKTiqymf_zkx6Z4YIWo94gdSG7aFsZ_G2JQ,32942
|
4
|
+
auth/oauth_callback_server.py,sha256=mUgfE4OqftTbXfWvKJmrJ3PjCxz8HZ5nvJW3Emk7_20,9630
|
5
5
|
auth/oauth_responses.py,sha256=qbirSB4d7mBRKcJKqGLrJxRAPaLHqObf9t-VMAq6UKA,7020
|
6
6
|
auth/scopes.py,sha256=QdeoTq7MtWRcf5G9CqbpEUI5yVbu7JriCtY7zupGVeY,3331
|
7
7
|
auth/service_decorator.py,sha256=crHax8t3EL4DXLPg4i3h9YHyfdpegRex880yNBTNqqI,15795
|
@@ -20,7 +20,7 @@ auth/oauth21/tokens.py,sha256=0BzYU0vdSXq8LiUpVQ8nncZ8UnvjAhXEVw0iY8NYIhs,14745
|
|
20
20
|
core/__init__.py,sha256=AHVKdPl6v4lUFm2R-KuGuAgEmCyfxseMeLGtntMcqCs,43
|
21
21
|
core/comments.py,sha256=ZiPxdZOsQYhxFwkClCDlcefP0iyLvO23qvN7OPLGSPk,11119
|
22
22
|
core/context.py,sha256=zNgPXf9EO2EMs9sQkfKiywoy6sEOksVNgOrJMA_c30Y,768
|
23
|
-
core/server.py,sha256=
|
23
|
+
core/server.py,sha256=GslrWM4P6bK5vOrcmT8qZtwQe5JnpSjA3xC1X7c41J4,9075
|
24
24
|
core/utils.py,sha256=sebbgJtzgmtoj-5PNgAvKEjmPtIKmtMY6b-faVf4Oec,13101
|
25
25
|
gcalendar/__init__.py,sha256=D5fSdAwbeomoaj7XAdxSnIy-NVKNkpExs67175bOtfc,46
|
26
26
|
gcalendar/calendar_tools.py,sha256=44RLehBqiCnuSWM50T0ZPnx06Xmbsu2bbUot-2WJ_qc,22562
|
@@ -40,9 +40,9 @@ gslides/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
40
|
gslides/slides_tools.py,sha256=vbhdzqHtNHfkNXN3h2_E9j_rMc747OzUaXH5XBu6XQY,10017
|
41
41
|
gtasks/__init__.py,sha256=qwOWUzQbkYLSBrdhCqEkAWPH2lEOljk1mLtrlab9YZc,107
|
42
42
|
gtasks/tasks_tools.py,sha256=s95fEMI7-TxyP8K2JoDMiRWftnVE9Fkrrr4j6jVgxAE,26469
|
43
|
-
workspace_mcp-1.1.
|
44
|
-
workspace_mcp-1.1.
|
45
|
-
workspace_mcp-1.1.
|
46
|
-
workspace_mcp-1.1.
|
47
|
-
workspace_mcp-1.1.
|
48
|
-
workspace_mcp-1.1.
|
43
|
+
workspace_mcp-1.1.13.dist-info/licenses/LICENSE,sha256=bB8L7rIyRy5o-WHxGgvRuY8hUTzNu4h3DTkvyV8XFJo,1070
|
44
|
+
workspace_mcp-1.1.13.dist-info/METADATA,sha256=HbbexOvBqcxjgOzfqWA0Rj8rfWKzKbQRl0mnHcdRQD0,23846
|
45
|
+
workspace_mcp-1.1.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
46
|
+
workspace_mcp-1.1.13.dist-info/entry_points.txt,sha256=kPiEfOTuf-ptDM0Rf2OlyrFudGW7hCZGg4MCn2Foxs4,44
|
47
|
+
workspace_mcp-1.1.13.dist-info/top_level.txt,sha256=uAg7uV2mETWYRw5g80XtO1lhxVO1sY6_IihNdG_4n24,80
|
48
|
+
workspace_mcp-1.1.13.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|