workspace-mcp 1.1.10__tar.gz → 1.1.12__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.
- {workspace_mcp-1.1.10/workspace_mcp.egg-info → workspace_mcp-1.1.12}/PKG-INFO +14 -6
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/README.md +12 -4
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/google_auth.py +3 -15
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/oauth_callback_server.py +4 -9
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/scopes.py +0 -5
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/core/server.py +6 -15
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gcalendar/calendar_tools.py +19 -10
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/pyproject.toml +2 -2
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12/workspace_mcp.egg-info}/PKG-INFO +14 -6
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/LICENSE +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/__init__.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/oauth21/__init__.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/oauth21/compat.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/oauth21/config.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/oauth21/discovery.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/oauth21/example_config.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/oauth21/handler.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/oauth21/http.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/oauth21/jwt.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/oauth21/middleware.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/oauth21/oauth2.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/oauth21/sessions.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/oauth21/tokens.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/oauth_responses.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/auth/service_decorator.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/core/__init__.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/core/comments.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/core/context.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/core/utils.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gTasks/__init__.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gTasks/tasks_tools.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gcalendar/__init__.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gchat/__init__.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gchat/chat_tools.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gdocs/__init__.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gdocs/docs_tools.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gdrive/__init__.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gdrive/drive_tools.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gforms/__init__.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gforms/forms_tools.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gmail/__init__.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gmail/gmail_tools.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gsheets/__init__.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gsheets/sheets_tools.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gslides/__init__.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/gslides/slides_tools.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/main.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/setup.cfg +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/tests/test_auth.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/tests/test_oauth_callback_server.py +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/workspace_mcp.egg-info/SOURCES.txt +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/workspace_mcp.egg-info/dependency_links.txt +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/workspace_mcp.egg-info/entry_points.txt +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/workspace_mcp.egg-info/requires.txt +0 -0
- {workspace_mcp-1.1.10 → workspace_mcp-1.1.12}/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.
|
3
|
+
Version: 1.1.12
|
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
|
@@ -27,7 +27,7 @@ Classifier: Topic :: Communications :: Chat
|
|
27
27
|
Classifier: Topic :: Office/Business
|
28
28
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
29
29
|
Classifier: Typing :: Typed
|
30
|
-
Requires-Python: >=3.
|
30
|
+
Requires-Python: >=3.10
|
31
31
|
Description-Content-Type: text/markdown
|
32
32
|
License-File: LICENSE
|
33
33
|
Requires-Dist: fastapi>=0.115.12
|
@@ -46,7 +46,7 @@ Dynamic: license-file
|
|
46
46
|
# Google Workspace MCP Server <img src="https://github.com/user-attachments/assets/b89524e4-6e6e-49e6-ba77-00d6df0c6e5c" width="80" align="right" />
|
47
47
|
|
48
48
|
[](https://opensource.org/licenses/MIT)
|
49
|
-
[](https://www.python.org/downloads/)
|
50
50
|
[](https://pypi.org/project/workspace-mcp/)
|
51
51
|
[](https://pepy.tech/projects/workspace-mcp)
|
52
52
|
[](https://workspacemcp.com)
|
@@ -151,7 +151,7 @@ If you’re developing, deploying to servers, or using another MCP-capable clien
|
|
151
151
|
#### Instant CLI (uvx)
|
152
152
|
|
153
153
|
```bash
|
154
|
-
# Requires Python 3.
|
154
|
+
# Requires Python 3.10+ and uvx
|
155
155
|
export GOOGLE_OAUTH_CLIENT_ID="xxx"
|
156
156
|
export GOOGLE_OAUTH_CLIENT_SECRET="yyy"
|
157
157
|
uvx workspace-mcp --tools gmail drive calendar
|
@@ -174,7 +174,7 @@ uvx workspace-mcp --tools gmail drive calendar tasks
|
|
174
174
|
uvx workspace-mcp --transport streamable-http
|
175
175
|
```
|
176
176
|
|
177
|
-
*Requires Python 3.
|
177
|
+
*Requires Python 3.10+ and [uvx](https://github.com/astral-sh/uv). The package is available on [PyPI](https://pypi.org/project/workspace-mcp).*
|
178
178
|
|
179
179
|
### Development Installation
|
180
180
|
|
@@ -188,7 +188,7 @@ uv run main.py
|
|
188
188
|
|
189
189
|
### Prerequisites
|
190
190
|
|
191
|
-
- **Python 3.
|
191
|
+
- **Python 3.10+**
|
192
192
|
- **[uvx](https://github.com/astral-sh/uv)** (for instant installation) or [uv](https://github.com/astral-sh/uv) (for development)
|
193
193
|
- **Google Cloud Project** with OAuth 2.0 credentials
|
194
194
|
|
@@ -524,6 +524,14 @@ async def your_new_tool(service, param1: str, param2: int = 10):
|
|
524
524
|
|
525
525
|
To use this server as a tool provider within Open WebUI:
|
526
526
|
|
527
|
+
### Instant Start (No Config Needed)
|
528
|
+
Just copy and paste the below, set your values and you're off!
|
529
|
+
```bash
|
530
|
+
GOOGLE_OAUTH_CLIENT_ID="your_client_id" GOOGLE_OAUTH_CLIENT_SECRET="your_client_secret" uvx mcpo --port 8000 --api-key "top-secret" -- uvx workspace-mcp
|
531
|
+
```
|
532
|
+
|
533
|
+
Otherwise:
|
534
|
+
|
527
535
|
### 1. Create MCPO Configuration
|
528
536
|
|
529
537
|
Create a file named `config.json` with the following structure to have `mcpo` make the streamable HTTP endpoint available as an OpenAPI spec tool:
|
@@ -3,7 +3,7 @@
|
|
3
3
|
# Google Workspace MCP Server <img src="https://github.com/user-attachments/assets/b89524e4-6e6e-49e6-ba77-00d6df0c6e5c" width="80" align="right" />
|
4
4
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
6
|
-
[](https://www.python.org/downloads/)
|
7
7
|
[](https://pypi.org/project/workspace-mcp/)
|
8
8
|
[](https://pepy.tech/projects/workspace-mcp)
|
9
9
|
[](https://workspacemcp.com)
|
@@ -108,7 +108,7 @@ If you’re developing, deploying to servers, or using another MCP-capable clien
|
|
108
108
|
#### Instant CLI (uvx)
|
109
109
|
|
110
110
|
```bash
|
111
|
-
# Requires Python 3.
|
111
|
+
# Requires Python 3.10+ and uvx
|
112
112
|
export GOOGLE_OAUTH_CLIENT_ID="xxx"
|
113
113
|
export GOOGLE_OAUTH_CLIENT_SECRET="yyy"
|
114
114
|
uvx workspace-mcp --tools gmail drive calendar
|
@@ -131,7 +131,7 @@ uvx workspace-mcp --tools gmail drive calendar tasks
|
|
131
131
|
uvx workspace-mcp --transport streamable-http
|
132
132
|
```
|
133
133
|
|
134
|
-
*Requires Python 3.
|
134
|
+
*Requires Python 3.10+ and [uvx](https://github.com/astral-sh/uv). The package is available on [PyPI](https://pypi.org/project/workspace-mcp).*
|
135
135
|
|
136
136
|
### Development Installation
|
137
137
|
|
@@ -145,7 +145,7 @@ uv run main.py
|
|
145
145
|
|
146
146
|
### Prerequisites
|
147
147
|
|
148
|
-
- **Python 3.
|
148
|
+
- **Python 3.10+**
|
149
149
|
- **[uvx](https://github.com/astral-sh/uv)** (for instant installation) or [uv](https://github.com/astral-sh/uv) (for development)
|
150
150
|
- **Google Cloud Project** with OAuth 2.0 credentials
|
151
151
|
|
@@ -481,6 +481,14 @@ async def your_new_tool(service, param1: str, param2: int = 10):
|
|
481
481
|
|
482
482
|
To use this server as a tool provider within Open WebUI:
|
483
483
|
|
484
|
+
### Instant Start (No Config Needed)
|
485
|
+
Just copy and paste the below, set your values and you're off!
|
486
|
+
```bash
|
487
|
+
GOOGLE_OAUTH_CLIENT_ID="your_client_id" GOOGLE_OAUTH_CLIENT_SECRET="your_client_secret" uvx mcpo --port 8000 --api-key "top-secret" -- uvx workspace-mcp
|
488
|
+
```
|
489
|
+
|
490
|
+
Otherwise:
|
491
|
+
|
484
492
|
### 1. Create MCPO Configuration
|
485
493
|
|
486
494
|
Create a file named `config.json` with the following structure to have `mcpo` make the streamable HTTP endpoint available as an OpenAPI spec tool:
|
@@ -15,7 +15,7 @@ from google.auth.transport.requests import Request
|
|
15
15
|
from google.auth.exceptions import RefreshError
|
16
16
|
from googleapiclient.discovery import build
|
17
17
|
from googleapiclient.errors import HttpError
|
18
|
-
from auth.scopes import
|
18
|
+
from auth.scopes import SCOPES
|
19
19
|
|
20
20
|
# Configure logging
|
21
21
|
logging.basicConfig(level=logging.INFO)
|
@@ -346,7 +346,6 @@ def create_oauth_flow(
|
|
346
346
|
|
347
347
|
|
348
348
|
async def start_auth_flow(
|
349
|
-
mcp_session_id: Optional[str],
|
350
349
|
user_google_email: Optional[str],
|
351
350
|
service_name: str, # e.g., "Google Calendar", "Gmail" for user messages
|
352
351
|
redirect_uri: str, # Added redirect_uri as a required parameter
|
@@ -355,7 +354,6 @@ async def start_auth_flow(
|
|
355
354
|
Initiates the Google OAuth flow and returns an actionable message for the user.
|
356
355
|
|
357
356
|
Args:
|
358
|
-
mcp_session_id: The active MCP session ID.
|
359
357
|
user_google_email: The user's specified Google email, if provided.
|
360
358
|
service_name: The name of the Google service requiring auth (for user messages).
|
361
359
|
redirect_uri: The URI Google will redirect to after authorization.
|
@@ -378,7 +376,7 @@ async def start_auth_flow(
|
|
378
376
|
)
|
379
377
|
|
380
378
|
logger.info(
|
381
|
-
f"[start_auth_flow] Initiating auth for {user_display_name}
|
379
|
+
f"[start_auth_flow] Initiating auth for {user_display_name} with global SCOPES."
|
382
380
|
)
|
383
381
|
|
384
382
|
try:
|
@@ -391,11 +389,6 @@ async def start_auth_flow(
|
|
391
389
|
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
|
392
390
|
|
393
391
|
oauth_state = os.urandom(16).hex()
|
394
|
-
if mcp_session_id:
|
395
|
-
OAUTH_STATE_TO_SESSION_ID_MAP[oauth_state] = mcp_session_id
|
396
|
-
logger.info(
|
397
|
-
f"[start_auth_flow] Stored mcp_session_id '{mcp_session_id}' for oauth_state '{oauth_state}'."
|
398
|
-
)
|
399
392
|
|
400
393
|
flow = create_oauth_flow(
|
401
394
|
scopes=SCOPES, # Use global SCOPES
|
@@ -417,11 +410,7 @@ async def start_auth_flow(
|
|
417
410
|
"**LLM, after presenting the link, instruct the user as follows:**",
|
418
411
|
"1. Click the link and complete the authorization in their browser.",
|
419
412
|
]
|
420
|
-
session_info_for_llm =
|
421
|
-
f" (this will link to your current session {mcp_session_id})"
|
422
|
-
if mcp_session_id
|
423
|
-
else ""
|
424
|
-
)
|
413
|
+
session_info_for_llm = ""
|
425
414
|
|
426
415
|
if not initial_email_provided:
|
427
416
|
message_lines.extend(
|
@@ -773,7 +762,6 @@ async def get_authenticated_google_service(
|
|
773
762
|
|
774
763
|
# Generate auth URL and raise exception with it
|
775
764
|
auth_response = await start_auth_flow(
|
776
|
-
mcp_session_id=None, # Session ID not available in service layer
|
777
765
|
user_google_email=user_google_email,
|
778
766
|
service_name=f"Google {service_name.title()}",
|
779
767
|
redirect_uri=redirect_uri,
|
@@ -18,7 +18,7 @@ from typing import Optional
|
|
18
18
|
from urllib.parse import urlparse
|
19
19
|
|
20
20
|
from auth.google_auth import handle_auth_callback, check_client_secrets
|
21
|
-
from auth.scopes import
|
21
|
+
from auth.scopes import SCOPES
|
22
22
|
from auth.oauth_responses import create_error_response, create_success_response, create_server_error_response
|
23
23
|
|
24
24
|
logger = logging.getLogger(__name__)
|
@@ -68,11 +68,7 @@ class MinimalOAuthServer:
|
|
68
68
|
|
69
69
|
logger.info(f"OAuth callback: Received code (state: {state}). Attempting to exchange for tokens.")
|
70
70
|
|
71
|
-
|
72
|
-
if mcp_session_id:
|
73
|
-
logger.info(f"OAuth callback: Retrieved MCP session ID '{mcp_session_id}' for state '{state}'.")
|
74
|
-
else:
|
75
|
-
logger.warning(f"OAuth callback: No MCP session ID found for state '{state}'. Auth will not be tied to a specific session.")
|
71
|
+
# Session ID tracking removed - not needed
|
76
72
|
|
77
73
|
# Exchange code for credentials
|
78
74
|
redirect_uri = get_oauth_redirect_uri(port=self.port, base_uri=self.base_uri)
|
@@ -80,11 +76,10 @@ class MinimalOAuthServer:
|
|
80
76
|
scopes=SCOPES,
|
81
77
|
authorization_response=str(request.url),
|
82
78
|
redirect_uri=redirect_uri,
|
83
|
-
session_id=
|
79
|
+
session_id=None
|
84
80
|
)
|
85
81
|
|
86
|
-
|
87
|
-
logger.info(f"OAuth callback: Successfully authenticated user: {verified_user_id} (state: {state}){log_session_part}.")
|
82
|
+
logger.info(f"OAuth callback: Successfully authenticated user: {verified_user_id} (state: {state}).")
|
88
83
|
|
89
84
|
# Return success page using shared template
|
90
85
|
return create_success_response(verified_user_id)
|
@@ -5,14 +5,9 @@ This module centralizes OAuth scope definitions for Google Workspace integration
|
|
5
5
|
Separated from service_decorator.py to avoid circular imports.
|
6
6
|
"""
|
7
7
|
import logging
|
8
|
-
from typing import Dict
|
9
8
|
|
10
9
|
logger = logging.getLogger(__name__)
|
11
10
|
|
12
|
-
# Temporary map to associate OAuth state with MCP session ID
|
13
|
-
# This should ideally be a more robust cache in a production system (e.g., Redis)
|
14
|
-
OAUTH_STATE_TO_SESSION_ID_MAP: Dict[str, str] = {}
|
15
|
-
|
16
11
|
# Individual OAuth Scope Constants
|
17
12
|
USERINFO_EMAIL_SCOPE = 'https://www.googleapis.com/auth/userinfo.email'
|
18
13
|
OPENID_SCOPE = 'openid'
|
@@ -16,7 +16,6 @@ from auth.oauth_responses import create_error_response, create_success_response,
|
|
16
16
|
|
17
17
|
# Import shared configuration
|
18
18
|
from auth.scopes import (
|
19
|
-
OAUTH_STATE_TO_SESSION_ID_MAP,
|
20
19
|
SCOPES,
|
21
20
|
USERINFO_EMAIL_SCOPE, # noqa: F401
|
22
21
|
OPENID_SCOPE, # noqa: F401
|
@@ -129,11 +128,7 @@ async def oauth2_callback(request: Request) -> HTMLResponse:
|
|
129
128
|
|
130
129
|
logger.info(f"OAuth callback: Received code (state: {state}). Attempting to exchange for tokens.")
|
131
130
|
|
132
|
-
|
133
|
-
if mcp_session_id:
|
134
|
-
logger.info(f"OAuth callback: Retrieved MCP session ID '{mcp_session_id}' for state '{state}'.")
|
135
|
-
else:
|
136
|
-
logger.warning(f"OAuth callback: No MCP session ID found for state '{state}'. Auth will not be tied to a specific session directly via this callback.")
|
131
|
+
# Session ID tracking removed - not needed
|
137
132
|
|
138
133
|
# Exchange code for credentials. handle_auth_callback will save them.
|
139
134
|
# The user_id returned here is the Google-verified email.
|
@@ -141,11 +136,10 @@ async def oauth2_callback(request: Request) -> HTMLResponse:
|
|
141
136
|
scopes=SCOPES, # Ensure all necessary scopes are requested
|
142
137
|
authorization_response=str(request.url),
|
143
138
|
redirect_uri=get_oauth_redirect_uri_for_current_mode(),
|
144
|
-
session_id=
|
139
|
+
session_id=None # Session ID tracking removed
|
145
140
|
)
|
146
141
|
|
147
|
-
|
148
|
-
logger.info(f"OAuth callback: Successfully authenticated user: {verified_user_id} (state: {state}){log_session_part}.")
|
142
|
+
logger.info(f"OAuth callback: Successfully authenticated user: {verified_user_id} (state: {state}).")
|
149
143
|
|
150
144
|
# Return success page using shared template
|
151
145
|
return create_success_response(verified_user_id)
|
@@ -159,14 +153,13 @@ async def oauth2_callback(request: Request) -> HTMLResponse:
|
|
159
153
|
@server.tool()
|
160
154
|
async def start_google_auth(
|
161
155
|
service_name: str,
|
162
|
-
user_google_email: str = USER_GOOGLE_EMAIL
|
163
|
-
mcp_session_id: Optional[str] = Header(None, alias="mcp-session-id")
|
156
|
+
user_google_email: str = USER_GOOGLE_EMAIL
|
164
157
|
) -> str:
|
165
158
|
"""
|
166
159
|
Initiates the Google OAuth 2.0 authentication flow for the specified user email and service.
|
167
160
|
This is the primary method to establish credentials when no valid session exists or when targeting a specific account for a particular service.
|
168
161
|
It generates an authorization URL that the LLM must present to the user.
|
169
|
-
|
162
|
+
This initiates a new authentication flow for the specified user and service.
|
170
163
|
|
171
164
|
LLM Guidance:
|
172
165
|
- Use this tool when you need to authenticate a user for a specific Google service (e.g., "Google Calendar", "Google Docs", "Gmail", "Google Drive")
|
@@ -182,7 +175,6 @@ async def start_google_auth(
|
|
182
175
|
Args:
|
183
176
|
user_google_email (str): The user's full Google email address (e.g., 'example@gmail.com'). This is REQUIRED.
|
184
177
|
service_name (str): The name of the Google service for which authentication is being requested (e.g., "Google Calendar", "Google Docs"). This is REQUIRED.
|
185
|
-
mcp_session_id (Optional[str]): The active MCP session ID (automatically injected by FastMCP from the mcp-session-id header). Links the OAuth flow state to the session.
|
186
178
|
|
187
179
|
Returns:
|
188
180
|
str: A detailed message for the LLM with the authorization URL and instructions to guide the user through the authentication process.
|
@@ -197,7 +189,7 @@ async def start_google_auth(
|
|
197
189
|
logger.error(f"[start_google_auth] {error_msg}")
|
198
190
|
raise Exception(error_msg)
|
199
191
|
|
200
|
-
logger.info(f"Tool 'start_google_auth' invoked for user_google_email: '{user_google_email}', service: '{service_name}'
|
192
|
+
logger.info(f"Tool 'start_google_auth' invoked for user_google_email: '{user_google_email}', service: '{service_name}'.")
|
201
193
|
|
202
194
|
# Ensure OAuth callback is available for current transport mode
|
203
195
|
redirect_uri = get_oauth_redirect_uri_for_current_mode()
|
@@ -205,7 +197,6 @@ async def start_google_auth(
|
|
205
197
|
raise Exception("Failed to start OAuth callback server. Please try again.")
|
206
198
|
|
207
199
|
auth_result = await start_auth_flow(
|
208
|
-
mcp_session_id=mcp_session_id,
|
209
200
|
user_google_email=user_google_email,
|
210
201
|
service_name=service_name,
|
211
202
|
redirect_uri=redirect_uri
|
@@ -122,9 +122,11 @@ async def get_events(
|
|
122
122
|
time_min: Optional[str] = None,
|
123
123
|
time_max: Optional[str] = None,
|
124
124
|
max_results: int = 25,
|
125
|
+
query: Optional[str] = None,
|
125
126
|
) -> str:
|
126
127
|
"""
|
127
128
|
Retrieves a list of events from a specified Google Calendar within a given time range.
|
129
|
+
You can also search for events by keyword by supplying the optional "query" param.
|
128
130
|
|
129
131
|
Args:
|
130
132
|
user_google_email (str): The user's Google email address. Required.
|
@@ -132,12 +134,13 @@ async def get_events(
|
|
132
134
|
time_min (Optional[str]): The start of the time range (inclusive) in RFC3339 format (e.g., '2024-05-12T10:00:00Z' or '2024-05-12'). If omitted, defaults to the current time.
|
133
135
|
time_max (Optional[str]): The end of the time range (exclusive) in RFC3339 format. If omitted, events starting from `time_min` onwards are considered (up to `max_results`).
|
134
136
|
max_results (int): The maximum number of events to return. Defaults to 25.
|
137
|
+
query (Optional[str]): A keyword to search for within event fields (summary, description, location).
|
135
138
|
|
136
139
|
Returns:
|
137
140
|
str: A formatted list of events (summary, start and end times, link) within the specified range.
|
138
141
|
"""
|
139
142
|
logger.info(
|
140
|
-
f"[get_events] Raw time parameters - time_min: '{time_min}', time_max: '{time_max}'"
|
143
|
+
f"[get_events] Raw time parameters - time_min: '{time_min}', time_max: '{time_max}', query: '{query}'"
|
141
144
|
)
|
142
145
|
|
143
146
|
# Ensure time_min and time_max are correctly formatted for the API
|
@@ -161,19 +164,25 @@ async def get_events(
|
|
161
164
|
)
|
162
165
|
|
163
166
|
logger.info(
|
164
|
-
f"[get_events] Final API parameters - calendarId: '{calendar_id}', timeMin: '{effective_time_min}', timeMax: '{effective_time_max}', maxResults: {max_results}"
|
167
|
+
f"[get_events] Final API parameters - calendarId: '{calendar_id}', timeMin: '{effective_time_min}', timeMax: '{effective_time_max}', maxResults: {max_results}, query: '{query}'"
|
165
168
|
)
|
166
169
|
|
170
|
+
# Build the request parameters dynamically
|
171
|
+
request_params = {
|
172
|
+
"calendarId": calendar_id,
|
173
|
+
"timeMin": effective_time_min,
|
174
|
+
"timeMax": effective_time_max,
|
175
|
+
"maxResults": max_results,
|
176
|
+
"singleEvents": True,
|
177
|
+
"orderBy": "startTime",
|
178
|
+
}
|
179
|
+
|
180
|
+
if query:
|
181
|
+
request_params["q"] = query
|
182
|
+
|
167
183
|
events_result = await asyncio.to_thread(
|
168
184
|
lambda: service.events()
|
169
|
-
.list(
|
170
|
-
calendarId=calendar_id,
|
171
|
-
timeMin=effective_time_min,
|
172
|
-
timeMax=effective_time_max,
|
173
|
-
maxResults=max_results,
|
174
|
-
singleEvents=True,
|
175
|
-
orderBy="startTime",
|
176
|
-
)
|
185
|
+
.list(**request_params)
|
177
186
|
.execute()
|
178
187
|
)
|
179
188
|
items = events_result.get("items", [])
|
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "workspace-mcp"
|
7
|
-
version = "1.1.
|
7
|
+
version = "1.1.12"
|
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"]
|
11
|
-
requires-python = ">=3.
|
11
|
+
requires-python = ">=3.10"
|
12
12
|
dependencies = [
|
13
13
|
"fastapi>=0.115.12",
|
14
14
|
"fastmcp>=2.3.3",
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: workspace-mcp
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.12
|
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
|
@@ -27,7 +27,7 @@ Classifier: Topic :: Communications :: Chat
|
|
27
27
|
Classifier: Topic :: Office/Business
|
28
28
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
29
29
|
Classifier: Typing :: Typed
|
30
|
-
Requires-Python: >=3.
|
30
|
+
Requires-Python: >=3.10
|
31
31
|
Description-Content-Type: text/markdown
|
32
32
|
License-File: LICENSE
|
33
33
|
Requires-Dist: fastapi>=0.115.12
|
@@ -46,7 +46,7 @@ Dynamic: license-file
|
|
46
46
|
# Google Workspace MCP Server <img src="https://github.com/user-attachments/assets/b89524e4-6e6e-49e6-ba77-00d6df0c6e5c" width="80" align="right" />
|
47
47
|
|
48
48
|
[](https://opensource.org/licenses/MIT)
|
49
|
-
[](https://www.python.org/downloads/)
|
50
50
|
[](https://pypi.org/project/workspace-mcp/)
|
51
51
|
[](https://pepy.tech/projects/workspace-mcp)
|
52
52
|
[](https://workspacemcp.com)
|
@@ -151,7 +151,7 @@ If you’re developing, deploying to servers, or using another MCP-capable clien
|
|
151
151
|
#### Instant CLI (uvx)
|
152
152
|
|
153
153
|
```bash
|
154
|
-
# Requires Python 3.
|
154
|
+
# Requires Python 3.10+ and uvx
|
155
155
|
export GOOGLE_OAUTH_CLIENT_ID="xxx"
|
156
156
|
export GOOGLE_OAUTH_CLIENT_SECRET="yyy"
|
157
157
|
uvx workspace-mcp --tools gmail drive calendar
|
@@ -174,7 +174,7 @@ uvx workspace-mcp --tools gmail drive calendar tasks
|
|
174
174
|
uvx workspace-mcp --transport streamable-http
|
175
175
|
```
|
176
176
|
|
177
|
-
*Requires Python 3.
|
177
|
+
*Requires Python 3.10+ and [uvx](https://github.com/astral-sh/uv). The package is available on [PyPI](https://pypi.org/project/workspace-mcp).*
|
178
178
|
|
179
179
|
### Development Installation
|
180
180
|
|
@@ -188,7 +188,7 @@ uv run main.py
|
|
188
188
|
|
189
189
|
### Prerequisites
|
190
190
|
|
191
|
-
- **Python 3.
|
191
|
+
- **Python 3.10+**
|
192
192
|
- **[uvx](https://github.com/astral-sh/uv)** (for instant installation) or [uv](https://github.com/astral-sh/uv) (for development)
|
193
193
|
- **Google Cloud Project** with OAuth 2.0 credentials
|
194
194
|
|
@@ -524,6 +524,14 @@ async def your_new_tool(service, param1: str, param2: int = 10):
|
|
524
524
|
|
525
525
|
To use this server as a tool provider within Open WebUI:
|
526
526
|
|
527
|
+
### Instant Start (No Config Needed)
|
528
|
+
Just copy and paste the below, set your values and you're off!
|
529
|
+
```bash
|
530
|
+
GOOGLE_OAUTH_CLIENT_ID="your_client_id" GOOGLE_OAUTH_CLIENT_SECRET="your_client_secret" uvx mcpo --port 8000 --api-key "top-secret" -- uvx workspace-mcp
|
531
|
+
```
|
532
|
+
|
533
|
+
Otherwise:
|
534
|
+
|
527
535
|
### 1. Create MCPO Configuration
|
528
536
|
|
529
537
|
Create a file named `config.json` with the following structure to have `mcpo` make the streamable HTTP endpoint available as an OpenAPI spec tool:
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|