11#!/usr/bin/env python3
22"""
33Auto-installer for Google Workspace MCP in Claude Desktop
4+ Enhanced version with OAuth configuration and installation options
45"""
56
67import json
78import os
89import platform
910import sys
1011from pathlib import Path
12+ from typing import Dict , Optional , Tuple
1113
1214
13- def get_claude_config_path ():
15+ def get_claude_config_path () -> Path :
1416 """Get the Claude Desktop config file path for the current platform."""
1517 system = platform .system ()
1618 if system == "Darwin" : # macOS
@@ -24,44 +26,227 @@ def get_claude_config_path():
2426 raise RuntimeError (f"Unsupported platform: { system } " )
2527
2628
29+ def prompt_yes_no (question : str , default : bool = True ) -> bool :
30+ """Prompt user for yes/no question."""
31+ default_str = "Y/n" if default else "y/N"
32+ while True :
33+ response = input (f"{ question } [{ default_str } ]: " ).strip ().lower ()
34+ if not response :
35+ return default
36+ if response in ['y' , 'yes' ]:
37+ return True
38+ if response in ['n' , 'no' ]:
39+ return False
40+ print ("Please answer 'y' or 'n'" )
41+
42+
43+ def get_oauth_credentials () -> Tuple [Optional [Dict [str , str ]], Optional [str ]]:
44+ """Get OAuth credentials from user."""
45+ print ("\n 🔑 OAuth Credentials Setup" )
46+ print ("You need Google OAuth 2.0 credentials to use this server." )
47+ print ("\n You can provide credentials in two ways:" )
48+ print ("1. Environment variables (recommended for production)" )
49+ print ("2. Client secrets JSON file" )
50+
51+ use_env = prompt_yes_no ("\n Do you want to use environment variables?" , default = True )
52+
53+ env_vars = {}
54+ client_secret_path = None
55+
56+ if use_env :
57+ print ("\n 📝 Enter your OAuth credentials:" )
58+ client_id = input ("Client ID (ends with .apps.googleusercontent.com): " ).strip ()
59+ client_secret = input ("Client Secret: " ).strip ()
60+
61+ if not client_id or not client_secret :
62+ print ("❌ Both Client ID and Client Secret are required!" )
63+ return None , None
64+
65+ env_vars ["GOOGLE_OAUTH_CLIENT_ID" ] = client_id
66+ env_vars ["GOOGLE_OAUTH_CLIENT_SECRET" ] = client_secret
67+
68+ # Optional redirect URI
69+ custom_redirect = input ("Redirect URI (press Enter for default http://localhost:8000/oauth2callback): " ).strip ()
70+ if custom_redirect :
71+ env_vars ["GOOGLE_OAUTH_REDIRECT_URI" ] = custom_redirect
72+
73+ else :
74+ print ("\n 📁 Client secrets file setup:" )
75+ default_path = "client_secret.json"
76+ file_path = input (f"Path to client_secret.json file [{ default_path } ]: " ).strip ()
77+
78+ if not file_path :
79+ file_path = default_path
80+
81+ # Check if file exists
82+ if not Path (file_path ).exists ():
83+ print (f"❌ File not found: { file_path } " )
84+ return None , None
85+
86+ client_secret_path = file_path
87+
88+ # Optional: Default user email
89+ print ("\n 📧 Optional: Default user email (for single-user setups)" )
90+ user_email = input ("Your Google email (press Enter to skip): " ).strip ()
91+ if user_email :
92+ env_vars ["USER_GOOGLE_EMAIL" ] = user_email
93+
94+ # Development mode
95+ if prompt_yes_no ("\n 🔧 Enable development mode (OAUTHLIB_INSECURE_TRANSPORT)?" , default = False ):
96+ env_vars ["OAUTHLIB_INSECURE_TRANSPORT" ] = "1"
97+
98+ return env_vars , client_secret_path
99+
100+
101+ def get_installation_options () -> Dict [str , any ]:
102+ """Get installation options from user."""
103+ options = {}
104+
105+ print ("\n ⚙️ Installation Options" )
106+
107+ # Installation method
108+ print ("\n Choose installation method:" )
109+ print ("1. uvx (recommended - auto-installs from PyPI)" )
110+ print ("2. Development mode (requires local repository)" )
111+
112+ method = input ("Select method [1]: " ).strip ()
113+ if method == "2" :
114+ options ["dev_mode" ] = True
115+ cwd = input ("Path to google_workspace_mcp repository [current directory]: " ).strip ()
116+ options ["cwd" ] = cwd if cwd else os .getcwd ()
117+ else :
118+ options ["dev_mode" ] = False
119+
120+ # Single-user mode
121+ if prompt_yes_no ("\n 👤 Enable single-user mode (simplified authentication)?" , default = False ):
122+ options ["single_user" ] = True
123+
124+ # Tool selection
125+ print ("\n 🛠️ Tool Selection" )
126+ print ("Available tools: gmail, drive, calendar, docs, sheets, forms, chat" )
127+ print ("Leave empty to enable all tools" )
128+ tools = input ("Enter tools to enable (comma-separated): " ).strip ()
129+ if tools :
130+ options ["tools" ] = [t .strip () for t in tools .split ("," )]
131+
132+ # Transport mode
133+ if prompt_yes_no ("\n 🌐 Use HTTP transport mode (for debugging)?" , default = False ):
134+ options ["http_mode" ] = True
135+
136+ return options
137+
138+
139+ def create_server_config (options : Dict , env_vars : Dict , client_secret_path : Optional [str ]) -> Dict :
140+ """Create the server configuration."""
141+ config = {}
142+
143+ if options .get ("dev_mode" ):
144+ config ["command" ] = "uv"
145+ config ["args" ] = ["run" , "main.py" ]
146+ config ["cwd" ] = options ["cwd" ]
147+ else :
148+ config ["command" ] = "uvx"
149+ config ["args" ] = ["workspace-mcp" ]
150+
151+ # Add command line arguments
152+ if options .get ("single_user" ):
153+ config ["args" ].append ("--single-user" )
154+
155+ if options .get ("tools" ):
156+ config ["args" ].extend (["--tools" ] + options ["tools" ])
157+
158+ if options .get ("http_mode" ):
159+ config ["args" ].extend (["--transport" , "streamable-http" ])
160+
161+ # Add environment variables
162+ if env_vars or client_secret_path :
163+ config ["env" ] = {}
164+
165+ if env_vars :
166+ config ["env" ].update (env_vars )
167+
168+ if client_secret_path :
169+ config ["env" ]["GOOGLE_CLIENT_SECRET_PATH" ] = client_secret_path
170+
171+ return config
172+
173+
27174def main ():
175+ print ("🚀 Google Workspace MCP Installer for Claude Desktop" )
176+ print ("=" * 50 )
177+
28178 try :
29179 config_path = get_claude_config_path ()
30-
31- # Create directory if it doesn't exist
32- config_path .parent .mkdir (parents = True , exist_ok = True )
33-
34- # Load existing config or create new one
180+
181+ # Check if config already exists
182+ existing_config = {}
35183 if config_path .exists ():
36184 with open (config_path , 'r' ) as f :
37- config = json .load (f )
38- else :
39- config = {}
40-
41- # Ensure mcpServers section exists
42- if "mcpServers" not in config :
43- config ["mcpServers" ] = {}
44-
45- # Add Google Workspace MCP server
46- config ["mcpServers" ]["google_workspace" ] = {
47- "command" : "uvx" ,
48- "args" : ["workspace-mcp" ]
49- }
50-
51- # Write updated config
185+ existing_config = json .load (f )
186+
187+ if "mcpServers" in existing_config and "google_workspace" in existing_config ["mcpServers" ]:
188+ print (f"\n ⚠️ Google Workspace MCP is already configured in { config_path } " )
189+ if not prompt_yes_no ("Do you want to reconfigure it?" , default = True ):
190+ print ("Installation cancelled." )
191+ return
192+
193+ # Get OAuth credentials
194+ env_vars , client_secret_path = get_oauth_credentials ()
195+ if env_vars is None and client_secret_path is None :
196+ print ("\n ❌ OAuth credentials are required. Installation cancelled." )
197+ sys .exit (1 )
198+
199+ # Get installation options
200+ options = get_installation_options ()
201+
202+ # Create server configuration
203+ server_config = create_server_config (options , env_vars , client_secret_path )
204+
205+ # Prepare final config
206+ if "mcpServers" not in existing_config :
207+ existing_config ["mcpServers" ] = {}
208+
209+ existing_config ["mcpServers" ]["google_workspace" ] = server_config
210+
211+ # Create directory if needed
212+ config_path .parent .mkdir (parents = True , exist_ok = True )
213+
214+ # Write configuration
52215 with open (config_path , 'w' ) as f :
53- json .dump (config , f , indent = 2 )
54-
55- print (f"✅ Successfully added Google Workspace MCP to Claude Desktop config !" )
216+ json .dump (existing_config , f , indent = 2 )
217+
218+ print (f"\n ✅ Successfully configured Google Workspace MCP!" )
56219 print (f"📁 Config file: { config_path } " )
220+
221+ print ("\n 📋 Configuration Summary:" )
222+ print (f" • Installation method: { 'Development' if options .get ('dev_mode' ) else 'uvx (PyPI)' } " )
223+ print (f" • Authentication: { 'Environment variables' if env_vars else 'Client secrets file' } " )
224+ if options .get ("single_user" ):
225+ print (" • Single-user mode: Enabled" )
226+ if options .get ("tools" ):
227+ print (f" • Tools: { ', ' .join (options ['tools' ])} " )
228+ else :
229+ print (" • Tools: All enabled" )
230+ if options .get ("http_mode" ):
231+ print (" • Transport: HTTP mode" )
232+ else :
233+ print (" • Transport: stdio (default)" )
234+
57235 print ("\n 🚀 Next steps:" )
58236 print ("1. Restart Claude Desktop" )
59237 print ("2. The Google Workspace tools will be available in your chats!" )
60238 print ("\n 💡 The server will start automatically when Claude Desktop needs it." )
61- print (" No need to manually start the server - uvx handles everything!" )
62-
239+
240+ if options .get ("http_mode" ):
241+ print ("\n ⚠️ Note: HTTP mode requires additional setup." )
242+ print (" You may need to install and configure mcp-remote." )
243+ print (" See the README for details." )
244+
245+ except KeyboardInterrupt :
246+ print ("\n \n Installation cancelled by user." )
247+ sys .exit (0 )
63248 except Exception as e :
64- print (f"❌ Error: { e } " )
249+ print (f"\n ❌ Error: { e } " )
65250 print ("\n 📋 Manual installation:" )
66251 print ("1. Open Claude Desktop Settings → Developer → Edit Config" )
67252 print ("2. Add the server configuration shown in the README" )
0 commit comments