readme changes

#11
README.md CHANGED
@@ -11,9 +11,8 @@ pinned: false
11
  short_description: Answer any questions you have about the content of your mail
12
  ---
13
 
 
14
 
15
- Our Google authentication verification is currently pending. If you would like to proceed with testing, we can add you as a test user. To facilitate this, please complete the Google Form provided below.
16
 
17
- https://forms.gle/FRWwhhMeKaiXDAJQ9
18
 
19
- Link to the vide demo: https://www.youtube.com/watch?v=Ie8kdGU6bjY
 
11
  short_description: Answer any questions you have about the content of your mail
12
  ---
13
 
14
+ An example chatbot using [Gradio](https://gradio.app), [`huggingface_hub`](https://huggingface.co/docs/huggingface_hub/v0.22.2/en/index), and the [Hugging Face Inference API](https://huggingface.co/docs/api-inference/index).
15
 
 
16
 
 
17
 
18
+ uvicorn main:app --reload
agentic_implementation/email_mcp_server_oauth.py CHANGED
@@ -12,9 +12,7 @@ import os
12
  from typing import Dict, List
13
  from datetime import datetime, timedelta
14
  from dotenv import load_dotenv
15
- from fastapi.responses import HTMLResponse
16
- from fastapi import FastAPI,Request
17
- from fastapi.routing import APIRoute
18
  # Import OAuth-enabled modules
19
  # from tools import extract_query_info, analyze_emails
20
  from gmail_api_scraper import GmailAPIScraper
@@ -23,13 +21,6 @@ from logger import logger
23
 
24
  load_dotenv()
25
 
26
- if not oauth_manager.client_secrets_file.exists():
27
- print("Setupy")
28
- oauth_manager.setup_client_secrets(
29
- os.environ["GOOGLE_CLIENT_ID"],
30
- os.environ["GOOGLE_CLIENT_SECRET"]
31
- )
32
-
33
  # Initialize Gmail API scraper
34
  gmail_scraper = GmailAPIScraper()
35
 
@@ -123,17 +114,6 @@ def authenticate_user() -> str:
123
  try:
124
  logger.info("Starting OAuth authentication flow...")
125
 
126
- if oauth_manager.is_authenticated():
127
- user_email = oauth_manager.get_current_account()
128
- return json.dumps({
129
- "success": True,
130
- "message": "Already authenticated!",
131
- "user_email": user_email,
132
- "instructions": [
133
- "You are already authenticated and ready to use email tools",
134
- f"Currently authenticated as: {user_email}"
135
- ]
136
- }, indent=2)
137
  # Check if OAuth is configured
138
  if not oauth_manager.client_secrets_file.exists():
139
  return json.dumps({
@@ -158,34 +138,17 @@ def authenticate_user() -> str:
158
  ]
159
  }
160
  else:
161
- # Authentication not completed, provide manual instructions
162
- auth_url = oauth_manager.get_pending_auth_url()
163
- callback_url = oauth_manager.get_hf_redirect_uri()
164
-
165
- if auth_url:
166
- result = {
167
- "success": False,
168
- "message": "Manual authentication required",
169
- "auth_url": auth_url,
170
- "callback_url": callback_url,
171
- "instructions": [
172
- "Authentication URL has been generated",
173
- "Please click the link below to authenticate:",
174
- "1. Open the authentication URL(auth_url) in a new browser tab",
175
- "2. Sign in with your Google account",
176
- "3. Grant Gmail access permissions",
177
- "4. You'll be redirected back automatically",
178
- "5. Try clicking 'Submit' again after completing authentication"
179
- ],
180
- "note": "After completing authentication in the popup, click Submit again to verify"
181
- }
182
- else:
183
- result = {
184
- "success": False,
185
- "error": "Failed to generate authentication URL",
186
- "message": "Could not start authentication process. Check your OAuth configuration."
187
- }
188
-
189
  return json.dumps(result, indent=2)
190
 
191
  except Exception as e:
@@ -196,79 +159,6 @@ def authenticate_user() -> str:
196
  "message": "Authentication failed due to an error."
197
  }
198
  return json.dumps(error_result, indent=2)
199
-
200
-
201
- def handle_oauth_callback(auth_code: str) -> str:
202
- """Handle OAuth callback for Hugging Face Spaces
203
-
204
- Args:
205
- auth_code: Authorization code from OAuth callback
206
-
207
- Returns:
208
- HTML response string
209
- """
210
- try:
211
- if not auth_code:
212
- return """
213
- <html>
214
- <head><title>OAuth Error</title></head>
215
- <body style="font-family: Arial, sans-serif; text-align: center; padding: 50px;">
216
- <h1 style="color: #d32f2f;">Authentication Error</h1>
217
- <p>No authorization code received.</p>
218
- <button onclick="window.close()" style="padding: 10px 20px; margin: 20px; background: #1976d2; color: white; border: none; border-radius: 4px; cursor: pointer;">Close Window</button>
219
- </body>
220
- </html>
221
- """
222
- print(f"Received OAuth callback with code: {auth_code}")
223
- success = oauth_manager.complete_hf_spaces_auth(auth_code)
224
-
225
- if success:
226
- user_email = oauth_manager.get_current_account()
227
- return f"""
228
- <html>
229
- <head><title>OAuth Success</title></head>
230
- <body style="font-family: Arial, sans-serif; text-align: center; padding: 50px;">
231
- <h1 style="color: #2e7d32;">πŸŽ‰ Authentication Successful!</h1>
232
- <p>You are now authenticated as:</p>
233
- <p style="font-weight: bold; font-size: 18px; color: #1976d2;">{user_email}</p>
234
- <p>You can now close this window and return to the main application.</p>
235
- <p style="color: #666; font-size: 14px;">This window will close automatically in 5 seconds...</p>
236
- <button onclick="window.close()" style="padding: 10px 20px; margin: 20px; background: #2e7d32; color: white; border: none; border-radius: 4px; cursor: pointer;">Close Window</button>
237
- <script>
238
- setTimeout(function() {{
239
- window.close();
240
- }}, 5000);
241
- </script>
242
- </body>
243
- </html>
244
- """
245
- else:
246
- return """
247
- <html>
248
- <head><title>OAuth Error</title></head>
249
- <body style="font-family: Arial, sans-serif; text-align: center; padding: 50px;">
250
- <h1 style="color: #d32f2f;">Authentication Failed</h1>
251
- <p>Unable to complete authentication. Please try again.</p>
252
- <p>Make sure you granted all required permissions.</p>
253
- <button onclick="window.close()" style="padding: 10px 20px; margin: 20px; background: #d32f2f; color: white; border: none; border-radius: 4px; cursor: pointer;">Close Window</button>
254
- </body>
255
- </html>
256
- """
257
-
258
- except Exception as e:
259
- logger.error(f"Error handling OAuth callback: {e}")
260
- return f"""
261
- <html>
262
- <head><title>OAuth Error</title></head>
263
- <body style="font-family: Arial, sans-serif; text-align: center; padding: 50px;">
264
- <h1 style="color: #d32f2f;">Authentication Error</h1>
265
- <p>An error occurred during authentication:</p>
266
- <pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; text-align: left; max-width: 500px; margin: 0 auto;">{str(e)}</pre>
267
- <button onclick="window.close()" style="padding: 10px 20px; margin: 20px; background: #d32f2f; color: white; border: none; border-radius: 4px; cursor: pointer;">Close Window</button>
268
- </body>
269
- </html>
270
- """
271
-
272
 
273
  def switch_account(target_email: str) -> str:
274
  """
@@ -771,16 +661,31 @@ demo = gr.TabbedInterface(
771
  title="πŸ“§ Gmail Assistant MCP Server (Multi-Account OAuth)"
772
  )
773
 
774
- app = FastAPI()
775
- # Add your OAuth callback route
776
- @app.get("/oauth2callback")
777
- async def google_oauth_cb(request: Request):
778
- code = request.query_params.get("code")
779
- print("code:", code)
780
- return HTMLResponse(handle_oauth_callback(code))
781
-
782
- app = gr.mount_gradio_app(app, demo, path="/")
783
-
784
  if __name__ == "__main__":
785
- import uvicorn
786
- uvicorn.run(app, host="0.0.0.0", port=7860)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  from typing import Dict, List
13
  from datetime import datetime, timedelta
14
  from dotenv import load_dotenv
15
+
 
 
16
  # Import OAuth-enabled modules
17
  # from tools import extract_query_info, analyze_emails
18
  from gmail_api_scraper import GmailAPIScraper
 
21
 
22
  load_dotenv()
23
 
 
 
 
 
 
 
 
24
  # Initialize Gmail API scraper
25
  gmail_scraper = GmailAPIScraper()
26
 
 
114
  try:
115
  logger.info("Starting OAuth authentication flow...")
116
 
 
 
 
 
 
 
 
 
 
 
 
117
  # Check if OAuth is configured
118
  if not oauth_manager.client_secrets_file.exists():
119
  return json.dumps({
 
138
  ]
139
  }
140
  else:
141
+ result = {
142
+ "success": False,
143
+ "error": "Authentication failed",
144
+ "message": "Please try again or check your internet connection.",
145
+ "instructions": [
146
+ "Make sure you have internet connection",
147
+ "Ensure you complete the authentication in the browser",
148
+ "Try running 'python setup_oauth.py' if problems persist"
149
+ ]
150
+ }
151
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  return json.dumps(result, indent=2)
153
 
154
  except Exception as e:
 
159
  "message": "Authentication failed due to an error."
160
  }
161
  return json.dumps(error_result, indent=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
 
163
  def switch_account(target_email: str) -> str:
164
  """
 
661
  title="πŸ“§ Gmail Assistant MCP Server (Multi-Account OAuth)"
662
  )
663
 
 
 
 
 
 
 
 
 
 
 
664
  if __name__ == "__main__":
665
+ # Set environment variable to enable MCP server
666
+ import os
667
+ os.environ["GRADIO_MCP_SERVER"] = "True"
668
+
669
+ # Check authentication status on startup
670
+ current_account = oauth_manager.get_current_account()
671
+ all_accounts = oauth_manager.list_accounts()
672
+
673
+ if current_account and oauth_manager.is_authenticated():
674
+ print(f"βœ… Currently authenticated as: {current_account}")
675
+ if len(all_accounts) > 1:
676
+ print(f"πŸ“± {len(all_accounts)} total accounts available: {list(all_accounts.keys())}")
677
+ elif all_accounts:
678
+ print(f"πŸ“± {len(all_accounts)} stored accounts found: {list(all_accounts.keys())}")
679
+ print("⚠️ No current account selected. Use the web interface or Claude to switch accounts.")
680
+ else:
681
+ print("❌ No authenticated accounts. Users will need to authenticate through the web interface.")
682
+ print("πŸ’‘ Or run 'python setup_oauth.py' for initial setup.")
683
+
684
+ # Launch the server
685
+ demo.launch(share=False)
686
+
687
+ print("\nπŸš€ MCP Server is running!")
688
+ print("πŸ“ MCP Endpoint: http://localhost:7860/gradio_api/mcp/sse")
689
+ print("πŸ“– Copy this URL to your Claude Desktop MCP configuration")
690
+ print("\nπŸ”— Web Interface: http://localhost:7860")
691
+ print("πŸ“ Use the web interface to authenticate and test the tools")
agentic_implementation/oauth_manager.py CHANGED
@@ -14,13 +14,8 @@ import webbrowser
14
  import threading
15
  import time
16
  from http.server import HTTPServer, BaseHTTPRequestHandler
17
- from urllib.parse import urlparse,parse_qs
18
  from logger import logger
19
- from dotenv import load_dotenv
20
- load_dotenv()
21
-
22
-
23
- redirect_uri=os.getenv("GOOGLE_REDIRECT_URI")
24
 
25
  class OAuthCallbackHandler(BaseHTTPRequestHandler):
26
  """HTTP request handler for OAuth callback"""
@@ -109,7 +104,7 @@ class GmailOAuthManager:
109
  self._init_encryption()
110
 
111
  # OAuth flow settings
112
- self.redirect_uri = redirect_uri
113
 
114
  # Current account
115
  self.current_account_email = self._load_current_account()
@@ -195,7 +190,7 @@ class GmailOAuthManager:
195
  scopes=self.SCOPES
196
  )
197
  flow.redirect_uri = self.redirect_uri
198
- print("πŸ‘‰ redirect_uri being sent to Google:", self.redirect_uri, flush=True)
199
  auth_url, _ = flow.authorization_url(
200
  access_type='offline',
201
  include_granted_scopes='true',
@@ -205,95 +200,41 @@ class GmailOAuthManager:
205
  return auth_url
206
 
207
  def authenticate_interactive(self) -> bool:
208
- """Interactive authentication flow for Hugging Face Spaces
209
 
210
  Returns:
211
  True if authentication successful, False otherwise
212
  """
213
  try:
214
- # Check if already authenticated
215
- if self.is_authenticated():
216
- logger.info("Already authenticated")
217
- return True
218
-
219
 
220
  # Get authorization URL
221
  auth_url = self.get_authorization_url()
222
 
223
- logger.info("Running on Hugging Face Spaces")
224
- logger.info(f"Authentication URL generated: {auth_url}")
225
- logger.info("User must visit the URL manually to complete authentication")
226
 
227
- # Store the auth URL for the Gradio interface to use
228
- self._pending_auth_url = auth_url
229
- self._auth_completed = False
230
 
231
- # For setup_oauth.py and testing contexts, we'll print the URL
232
- # and wait briefly to see if authentication completes
233
- print(f"\n🌐 Please visit this URL to authenticate:")
234
- print(f" {auth_url}")
235
- print("\n⏳ Waiting for authentication completion...")
236
 
237
- # Wait for a reasonable time to see if auth completes
238
- # This allows the callback to potentially complete the auth
239
- timeout = 10 # 1 minute for manual completion
240
  start_time = time.time()
241
 
242
- while (time.time() - start_time) < timeout:
243
- # Check if authentication was completed via callback
244
- if getattr(self, '_auth_completed', False):
245
- logger.info("Authentication completed successfully!")
246
- return True
247
-
248
- # Check if user is now authenticated (credentials were saved)
249
- if self.is_authenticated():
250
- self._auth_completed = True
251
- logger.info("Authentication verified successful!")
252
- return True
253
-
254
- time.sleep(2) # Check every 2 seconds
255
-
256
- # Timeout reached - authentication not completed
257
- logger.info("Authentication timeout. Please complete authentication via the provided URL.")
258
- return False
259
-
260
- except Exception as e:
261
- logger.error(f"Authentication failed: {e}")
262
- return False
263
-
264
- def complete_hf_spaces_auth(self, auth_code: str) -> bool:
265
- """Complete authentication for HF Spaces with received auth code
266
-
267
- Args:
268
- auth_code: Authorization code received from OAuth callback
269
-
270
- Returns:
271
- True if authentication successful, False otherwise
272
- """
273
- try:
274
- success = self._exchange_code_for_credentials(auth_code)
275
-
276
- if success:
277
- # Mark authentication as completed
278
- self._auth_completed = True
279
- logger.info("HF Spaces authentication marked as completed")
280
-
281
- return success
282
 
283
- except Exception as e:
284
- logger.error(f"Failed to complete HF Spaces authentication: {e}")
285
- return False
286
-
287
- def _exchange_code_for_credentials(self, auth_code: str) -> bool:
288
- """Exchange authorization code for credentials
289
-
290
- Args:
291
- auth_code: Authorization code from OAuth flow
292
 
293
- Returns:
294
- True if successful, False otherwise
295
- """
296
- try:
297
  # Exchange authorization code for credentials
298
  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
299
  str(self.client_secrets_file),
@@ -301,7 +242,7 @@ class GmailOAuthManager:
301
  )
302
  flow.redirect_uri = self.redirect_uri
303
 
304
- flow.fetch_token(code=auth_code)
305
  credentials = flow.credentials
306
 
307
  # Get user email from credentials
@@ -320,93 +261,8 @@ class GmailOAuthManager:
320
  return True
321
 
322
  except Exception as e:
323
- logger.error(f"Failed to exchange code for credentials: {e}")
324
  return False
325
-
326
- def get_pending_auth_url(self) -> str:
327
- """Get the pending authentication URL for manual completion
328
-
329
- Returns:
330
- Authentication URL string or None if not available
331
- """
332
- return getattr(self, '_pending_auth_url', None)
333
-
334
- def get_hf_redirect_uri(self) -> str:
335
- """Get the Hugging Face Spaces redirect URI
336
-
337
- Returns:
338
- Redirect URI string
339
- # """
340
- # space_id = os.getenv('SPACE_ID')
341
- # space_author = os.getenv('SPACE_AUTHOR', 'username')
342
- return redirect_uri
343
-
344
- # For running in a local machine, use this method instead
345
-
346
- # def authenticate_interactive(self) -> bool:
347
- # """Interactive authentication flow that opens browser
348
-
349
- # Returns:
350
- # True if authentication successful, False otherwise
351
- # """
352
- # try:
353
- # # Start local HTTP server for OAuth callback
354
- # server = HTTPServer(('localhost', 8080), OAuthCallbackHandler)
355
- # server.auth_code = None
356
-
357
- # # Get authorization URL
358
- # auth_url = self.get_authorization_url()
359
-
360
- # logger.info("Opening browser for authentication...")
361
- # logger.info(f"If browser doesn't open, visit: {auth_url}")
362
-
363
- # # Open browser
364
- # webbrowser.open(auth_url)
365
-
366
- # # Start server in background thread
367
- # server_thread = threading.Thread(target=server.handle_request)
368
- # server_thread.daemon = True
369
- # server_thread.start()
370
-
371
- # # Wait for callback (max 5 minutes)
372
- # timeout = 300 # 5 minutes
373
- # start_time = time.time()
374
-
375
- # while server.auth_code is None and (time.time() - start_time) < timeout:
376
- # time.sleep(1)
377
-
378
- # if server.auth_code is None:
379
- # logger.error("Authentication timed out")
380
- # return False
381
-
382
- # # Exchange authorization code for credentials
383
- # flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
384
- # str(self.client_secrets_file),
385
- # scopes=self.SCOPES
386
- # )
387
- # flow.redirect_uri = self.redirect_uri
388
-
389
- # flow.fetch_token(code=server.auth_code)
390
- # credentials = flow.credentials
391
-
392
- # # Get user email from credentials
393
- # user_email = self._get_email_from_credentials(credentials)
394
- # if not user_email:
395
- # logger.error("Failed to get user email from credentials")
396
- # return False
397
-
398
- # # Save encrypted credentials for this account
399
- # self._save_credentials(user_email, credentials)
400
-
401
- # # Set as current account
402
- # self._save_current_account(user_email)
403
-
404
- # logger.info("Authentication successful!")
405
- # return True
406
-
407
- # except Exception as e:
408
- # logger.error(f"Authentication failed: {e}")
409
- # return False
410
 
411
  def _get_email_from_credentials(self, credentials: Credentials) -> Optional[str]:
412
  """Get email address from credentials"""
@@ -628,4 +484,4 @@ class GmailOAuthManager:
628
  return self.current_account_email
629
 
630
  # Global OAuth manager instance
631
- oauth_manager = GmailOAuthManager(credentials_dir="secure_data")
 
14
  import threading
15
  import time
16
  from http.server import HTTPServer, BaseHTTPRequestHandler
17
+ import urllib.parse as urlparse
18
  from logger import logger
 
 
 
 
 
19
 
20
  class OAuthCallbackHandler(BaseHTTPRequestHandler):
21
  """HTTP request handler for OAuth callback"""
 
104
  self._init_encryption()
105
 
106
  # OAuth flow settings
107
+ self.redirect_uri = "http://localhost:8080/oauth2callback"
108
 
109
  # Current account
110
  self.current_account_email = self._load_current_account()
 
190
  scopes=self.SCOPES
191
  )
192
  flow.redirect_uri = self.redirect_uri
193
+
194
  auth_url, _ = flow.authorization_url(
195
  access_type='offline',
196
  include_granted_scopes='true',
 
200
  return auth_url
201
 
202
  def authenticate_interactive(self) -> bool:
203
+ """Interactive authentication flow that opens browser
204
 
205
  Returns:
206
  True if authentication successful, False otherwise
207
  """
208
  try:
209
+ # Start local HTTP server for OAuth callback
210
+ server = HTTPServer(('localhost', 8080), OAuthCallbackHandler)
211
+ server.auth_code = None
 
 
212
 
213
  # Get authorization URL
214
  auth_url = self.get_authorization_url()
215
 
216
+ logger.info("Opening browser for authentication...")
217
+ logger.info(f"If browser doesn't open, visit: {auth_url}")
 
218
 
219
+ # Open browser
220
+ webbrowser.open(auth_url)
 
221
 
222
+ # Start server in background thread
223
+ server_thread = threading.Thread(target=server.handle_request)
224
+ server_thread.daemon = True
225
+ server_thread.start()
 
226
 
227
+ # Wait for callback (max 5 minutes)
228
+ timeout = 300 # 5 minutes
 
229
  start_time = time.time()
230
 
231
+ while server.auth_code is None and (time.time() - start_time) < timeout:
232
+ time.sleep(1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
 
234
+ if server.auth_code is None:
235
+ logger.error("Authentication timed out")
236
+ return False
 
 
 
 
 
 
237
 
 
 
 
 
238
  # Exchange authorization code for credentials
239
  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
240
  str(self.client_secrets_file),
 
242
  )
243
  flow.redirect_uri = self.redirect_uri
244
 
245
+ flow.fetch_token(code=server.auth_code)
246
  credentials = flow.credentials
247
 
248
  # Get user email from credentials
 
261
  return True
262
 
263
  except Exception as e:
264
+ logger.error(f"Authentication failed: {e}")
265
  return False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
 
267
  def _get_email_from_credentials(self, credentials: Credentials) -> Optional[str]:
268
  """Get email address from credentials"""
 
484
  return self.current_account_email
485
 
486
  # Global OAuth manager instance
487
+ oauth_manager = GmailOAuthManager()
agentic_implementation/setup_oauth.py CHANGED
@@ -11,10 +11,6 @@ import json
11
  from pathlib import Path
12
  from oauth_manager import oauth_manager
13
  from logger import logger
14
- from dotenv import load_dotenv
15
- load_dotenv()
16
- import os
17
-
18
 
19
  def print_banner():
20
  """Print setup banner"""
@@ -82,16 +78,31 @@ def setup_oauth_credentials():
82
  """Guide user through OAuth credentials setup"""
83
  print_step(3, "OAuth Client Credentials Setup")
84
 
85
- client_id = os.getenv("GOOGLE_CLIENT_ID")
86
- client_secret = os.getenv("GOOGLE_CLIENT_SECRET")
87
-
88
- if not client_id or not client_secret:
89
- print("❌ Missing GOOGLE_CLIENT_ID or GOOGLE_CLIENT_SECRET in your .env")
90
- print(" Please add:")
91
- print(" GOOGLE_CLIENT_ID=your-client-id")
92
- print(" GOOGLE_CLIENT_SECRET=your-client-secret")
93
- return False
94
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  try:
96
  oauth_manager.setup_client_secrets(client_id, client_secret)
97
  print("βœ… OAuth credentials saved successfully")
 
11
  from pathlib import Path
12
  from oauth_manager import oauth_manager
13
  from logger import logger
 
 
 
 
14
 
15
  def print_banner():
16
  """Print setup banner"""
 
78
  """Guide user through OAuth credentials setup"""
79
  print_step(3, "OAuth Client Credentials Setup")
80
 
81
+ print("Now you need to create OAuth 2.0 client credentials.")
82
+ print("\nπŸ“‹ Follow these steps:")
83
+ print("1. Go to: https://console.cloud.google.com/apis/credentials")
84
+ print("2. Click 'Create Credentials' > 'OAuth client ID'")
85
+ print("3. Choose 'Web application' as the application type")
86
+ print("4. Set the name to 'Gmail MCP Server'")
87
+ print("5. Add this redirect URI:")
88
+ print(" http://localhost:8080/oauth2callback")
89
+ print("6. Click 'Create'")
90
+ print("7. Copy the Client ID and Client Secret")
91
+
92
+ print("\nπŸ”‘ Enter your OAuth credentials:")
93
+
94
+ while True:
95
+ client_id = input("Client ID: ").strip()
96
+ if client_id:
97
+ break
98
+ print("❌ Client ID cannot be empty")
99
+
100
+ while True:
101
+ client_secret = input("Client Secret: ").strip()
102
+ if client_secret:
103
+ break
104
+ print("❌ Client Secret cannot be empty")
105
+
106
  try:
107
  oauth_manager.setup_client_secrets(client_id, client_secret)
108
  print("βœ… OAuth credentials saved successfully")
requirements.txt CHANGED
@@ -9,8 +9,6 @@ requests
9
  loguru
10
  python-dateutil
11
 
12
- uvicorn
13
-
14
  # MCP server support
15
  mcp
16
 
 
9
  loguru
10
  python-dateutil
11
 
 
 
12
  # MCP server support
13
  mcp
14