readme changes
#11
by
devanggg
- opened
- README.md +2 -3
- agentic_implementation/email_mcp_server_oauth.py +10 -128
- agentic_implementation/oauth_manager.py +23 -166
- agentic_implementation/setup_oauth.py +25 -14
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 |
-
|
|
|
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
@@ -21,12 +21,6 @@ from logger import logger
|
|
21 |
|
22 |
load_dotenv()
|
23 |
|
24 |
-
if not oauth_manager.client_secrets_file.exists():
|
25 |
-
oauth_manager.setup_client_secrets(
|
26 |
-
os.environ["GOOGLE_CLIENT_ID"],
|
27 |
-
os.environ["GOOGLE_CLIENT_SECRET"]
|
28 |
-
)
|
29 |
-
|
30 |
# Initialize Gmail API scraper
|
31 |
gmail_scraper = GmailAPIScraper()
|
32 |
|
@@ -120,17 +114,6 @@ def authenticate_user() -> str:
|
|
120 |
try:
|
121 |
logger.info("Starting OAuth authentication flow...")
|
122 |
|
123 |
-
if oauth_manager.is_authenticated():
|
124 |
-
user_email = oauth_manager.get_current_account()
|
125 |
-
return json.dumps({
|
126 |
-
"success": True,
|
127 |
-
"message": "Already authenticated!",
|
128 |
-
"user_email": user_email,
|
129 |
-
"instructions": [
|
130 |
-
"You are already authenticated and ready to use email tools",
|
131 |
-
f"Currently authenticated as: {user_email}"
|
132 |
-
]
|
133 |
-
}, indent=2)
|
134 |
# Check if OAuth is configured
|
135 |
if not oauth_manager.client_secrets_file.exists():
|
136 |
return json.dumps({
|
@@ -155,44 +138,16 @@ def authenticate_user() -> str:
|
|
155 |
]
|
156 |
}
|
157 |
else:
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
"
|
165 |
-
"
|
166 |
-
|
167 |
-
|
168 |
-
"instructions": [
|
169 |
-
"Authentication URL has been generated",
|
170 |
-
"Please click the link below to authenticate:",
|
171 |
-
"1. Click the authentication URL",
|
172 |
-
"2. Sign in with your Google account",
|
173 |
-
"3. Grant Gmail access permissions",
|
174 |
-
"4. You'll be redirected back automatically",
|
175 |
-
"5. Try clicking 'Submit' again after completing authentication"
|
176 |
-
],
|
177 |
-
"note": "After completing authentication in the popup, click Submit again to verify"
|
178 |
-
}
|
179 |
-
else:
|
180 |
-
result = {
|
181 |
-
"success": False,
|
182 |
-
"error": "Failed to generate authentication URL",
|
183 |
-
"message": "Could not start authentication process. Check your OAuth configuration."
|
184 |
-
}
|
185 |
-
|
186 |
-
# result = {
|
187 |
-
# "success": False,
|
188 |
-
# "error": "Authentication failed",
|
189 |
-
# "message": "Please try again or check your internet connection.",
|
190 |
-
# "instructions": [
|
191 |
-
# "Make sure you have internet connection",
|
192 |
-
# "Ensure you complete the authentication in the browser",
|
193 |
-
# "Try running 'python setup_oauth.py' if problems persist"
|
194 |
-
# ]
|
195 |
-
# }
|
196 |
|
197 |
return json.dumps(result, indent=2)
|
198 |
|
@@ -204,79 +159,6 @@ def authenticate_user() -> str:
|
|
204 |
"message": "Authentication failed due to an error."
|
205 |
}
|
206 |
return json.dumps(error_result, indent=2)
|
207 |
-
|
208 |
-
|
209 |
-
def handle_oauth_callback(auth_code: str) -> str:
|
210 |
-
"""Handle OAuth callback for Hugging Face Spaces
|
211 |
-
|
212 |
-
Args:
|
213 |
-
auth_code: Authorization code from OAuth callback
|
214 |
-
|
215 |
-
Returns:
|
216 |
-
HTML response string
|
217 |
-
"""
|
218 |
-
try:
|
219 |
-
if not auth_code:
|
220 |
-
return """
|
221 |
-
<html>
|
222 |
-
<head><title>OAuth Error</title></head>
|
223 |
-
<body style="font-family: Arial, sans-serif; text-align: center; padding: 50px;">
|
224 |
-
<h1 style="color: #d32f2f;">Authentication Error</h1>
|
225 |
-
<p>No authorization code received.</p>
|
226 |
-
<button onclick="window.close()" style="padding: 10px 20px; margin: 20px; background: #1976d2; color: white; border: none; border-radius: 4px; cursor: pointer;">Close Window</button>
|
227 |
-
</body>
|
228 |
-
</html>
|
229 |
-
"""
|
230 |
-
|
231 |
-
success = oauth_manager.complete_hf_spaces_auth(auth_code)
|
232 |
-
|
233 |
-
if success:
|
234 |
-
user_email = oauth_manager.get_current_account()
|
235 |
-
return f"""
|
236 |
-
<html>
|
237 |
-
<head><title>OAuth Success</title></head>
|
238 |
-
<body style="font-family: Arial, sans-serif; text-align: center; padding: 50px;">
|
239 |
-
<h1 style="color: #2e7d32;">π Authentication Successful!</h1>
|
240 |
-
<p>You are now authenticated as:</p>
|
241 |
-
<p style="font-weight: bold; font-size: 18px; color: #1976d2;">{user_email}</p>
|
242 |
-
<p>You can now close this window and return to the main application.</p>
|
243 |
-
<p style="color: #666; font-size: 14px;">This window will close automatically in 5 seconds...</p>
|
244 |
-
<button onclick="window.close()" style="padding: 10px 20px; margin: 20px; background: #2e7d32; color: white; border: none; border-radius: 4px; cursor: pointer;">Close Window</button>
|
245 |
-
<script>
|
246 |
-
setTimeout(function() {{
|
247 |
-
window.close();
|
248 |
-
}}, 5000);
|
249 |
-
</script>
|
250 |
-
</body>
|
251 |
-
</html>
|
252 |
-
"""
|
253 |
-
else:
|
254 |
-
return """
|
255 |
-
<html>
|
256 |
-
<head><title>OAuth Error</title></head>
|
257 |
-
<body style="font-family: Arial, sans-serif; text-align: center; padding: 50px;">
|
258 |
-
<h1 style="color: #d32f2f;">Authentication Failed</h1>
|
259 |
-
<p>Unable to complete authentication. Please try again.</p>
|
260 |
-
<p>Make sure you granted all required permissions.</p>
|
261 |
-
<button onclick="window.close()" style="padding: 10px 20px; margin: 20px; background: #d32f2f; color: white; border: none; border-radius: 4px; cursor: pointer;">Close Window</button>
|
262 |
-
</body>
|
263 |
-
</html>
|
264 |
-
"""
|
265 |
-
|
266 |
-
except Exception as e:
|
267 |
-
logger.error(f"Error handling OAuth callback: {e}")
|
268 |
-
return f"""
|
269 |
-
<html>
|
270 |
-
<head><title>OAuth Error</title></head>
|
271 |
-
<body style="font-family: Arial, sans-serif; text-align: center; padding: 50px;">
|
272 |
-
<h1 style="color: #d32f2f;">Authentication Error</h1>
|
273 |
-
<p>An error occurred during authentication:</p>
|
274 |
-
<pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; text-align: left; max-width: 500px; margin: 0 auto;">{str(e)}</pre>
|
275 |
-
<button onclick="window.close()" style="padding: 10px 20px; margin: 20px; background: #d32f2f; color: white; border: none; border-radius: 4px; cursor: pointer;">Close Window</button>
|
276 |
-
</body>
|
277 |
-
</html>
|
278 |
-
"""
|
279 |
-
|
280 |
|
281 |
def switch_account(target_email: str) -> str:
|
282 |
"""
|
|
|
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 |
|
|
|
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 |
"""
|
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 |
-
|
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 =
|
113 |
|
114 |
# Current account
|
115 |
self.current_account_email = self._load_current_account()
|
@@ -205,95 +200,41 @@ class GmailOAuthManager:
|
|
205 |
return auth_url
|
206 |
|
207 |
def authenticate_interactive(self) -> bool:
|
208 |
-
"""Interactive authentication flow
|
209 |
|
210 |
Returns:
|
211 |
True if authentication successful, False otherwise
|
212 |
"""
|
213 |
try:
|
214 |
-
#
|
215 |
-
|
216 |
-
|
217 |
-
return True
|
218 |
-
|
219 |
|
220 |
# Get authorization URL
|
221 |
auth_url = self.get_authorization_url()
|
222 |
|
223 |
-
logger.info("
|
224 |
-
logger.info(f"
|
225 |
-
logger.info("User must visit the URL manually to complete authentication")
|
226 |
|
227 |
-
#
|
228 |
-
|
229 |
-
self._auth_completed = False
|
230 |
|
231 |
-
#
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
print("\nβ³ Waiting for authentication completion...")
|
236 |
|
237 |
-
# Wait for
|
238 |
-
|
239 |
-
timeout = 60 # 1 minute for manual completion
|
240 |
start_time = time.time()
|
241 |
|
242 |
-
while (time.time() - start_time) < timeout:
|
243 |
-
|
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 |
-
|
271 |
-
|
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,92 +261,8 @@ class GmailOAuthManager:
|
|
320 |
return True
|
321 |
|
322 |
except Exception as e:
|
323 |
-
logger.error(f"
|
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 f"https://{space_author}-{space_id}.hf.space/oauth/callback"
|
343 |
-
|
344 |
-
|
345 |
-
# def authenticate_interactive(self) -> bool:
|
346 |
-
# """Interactive authentication flow that opens browser
|
347 |
-
|
348 |
-
# Returns:
|
349 |
-
# True if authentication successful, False otherwise
|
350 |
-
# """
|
351 |
-
# try:
|
352 |
-
# # Start local HTTP server for OAuth callback
|
353 |
-
# server = HTTPServer(('localhost', 8080), OAuthCallbackHandler)
|
354 |
-
# server.auth_code = None
|
355 |
-
|
356 |
-
# # Get authorization URL
|
357 |
-
# auth_url = self.get_authorization_url()
|
358 |
-
|
359 |
-
# logger.info("Opening browser for authentication...")
|
360 |
-
# logger.info(f"If browser doesn't open, visit: {auth_url}")
|
361 |
-
|
362 |
-
# # Open browser
|
363 |
-
# webbrowser.open(auth_url)
|
364 |
-
|
365 |
-
# # Start server in background thread
|
366 |
-
# server_thread = threading.Thread(target=server.handle_request)
|
367 |
-
# server_thread.daemon = True
|
368 |
-
# server_thread.start()
|
369 |
-
|
370 |
-
# # Wait for callback (max 5 minutes)
|
371 |
-
# timeout = 300 # 5 minutes
|
372 |
-
# start_time = time.time()
|
373 |
-
|
374 |
-
# while server.auth_code is None and (time.time() - start_time) < timeout:
|
375 |
-
# time.sleep(1)
|
376 |
-
|
377 |
-
# if server.auth_code is None:
|
378 |
-
# logger.error("Authentication timed out")
|
379 |
-
# return False
|
380 |
-
|
381 |
-
# # Exchange authorization code for credentials
|
382 |
-
# flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
|
383 |
-
# str(self.client_secrets_file),
|
384 |
-
# scopes=self.SCOPES
|
385 |
-
# )
|
386 |
-
# flow.redirect_uri = self.redirect_uri
|
387 |
-
|
388 |
-
# flow.fetch_token(code=server.auth_code)
|
389 |
-
# credentials = flow.credentials
|
390 |
-
|
391 |
-
# # Get user email from credentials
|
392 |
-
# user_email = self._get_email_from_credentials(credentials)
|
393 |
-
# if not user_email:
|
394 |
-
# logger.error("Failed to get user email from credentials")
|
395 |
-
# return False
|
396 |
-
|
397 |
-
# # Save encrypted credentials for this account
|
398 |
-
# self._save_credentials(user_email, credentials)
|
399 |
-
|
400 |
-
# # Set as current account
|
401 |
-
# self._save_current_account(user_email)
|
402 |
-
|
403 |
-
# logger.info("Authentication successful!")
|
404 |
-
# return True
|
405 |
-
|
406 |
-
# except Exception as e:
|
407 |
-
# logger.error(f"Authentication failed: {e}")
|
408 |
-
# return False
|
409 |
|
410 |
def _get_email_from_credentials(self, credentials: Credentials) -> Optional[str]:
|
411 |
"""Get email address from credentials"""
|
|
|
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()
|
|
|
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"""
|
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 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
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")
|