7
7
8
8
import os
9
9
import sys
10
- import json
11
- import requests
10
+ from typing import Any
11
+
12
+ import requests # type: ignore
12
13
from dotenv import load_dotenv
13
14
14
- def print_auth_url (client_id ):
15
- """Print the authorization URL for the user to visit."""
15
+
16
+ def print_auth_url (client_id : str ) -> None :
17
+ """
18
+ Print the authorization URL for the user to visit.
19
+
20
+ Args:
21
+ client_id: The Strava API client ID
22
+ """
16
23
auth_url = (
17
24
f"https://www.strava.com/oauth/authorize"
18
25
f"?client_id={ client_id } "
19
26
f"&redirect_uri=http://localhost"
20
27
f"&response_type=code"
21
28
f"&scope=read,activity:read,activity:read_all,profile:read_all"
22
29
)
23
-
30
+
24
31
print ("\n === Step 1: Visit the following URL in your browser ===" )
25
32
print (auth_url )
26
33
print ("\n Authorize the application when prompted." )
27
34
print ("You'll be redirected to a URL like: http://localhost/?state=&code=AUTHORIZATION_CODE&scope=..." )
28
35
print ("Copy the 'code' parameter value from the URL.\n " )
29
36
30
- def exchange_code_for_token (client_id , client_secret , auth_code ):
31
- """Exchange the authorization code for tokens."""
37
+
38
+ def exchange_code_for_token (client_id : str , client_secret : str , auth_code : str ) -> dict [str , Any ]:
39
+ """
40
+ Exchange the authorization code for tokens.
41
+
42
+ Args:
43
+ client_id: The Strava API client ID
44
+ client_secret: The Strava API client secret
45
+ auth_code: The authorization code from the redirect URL
46
+
47
+ Returns:
48
+ dictionary containing token data (access_token, refresh_token, expires_at)
49
+
50
+ Raises:
51
+ SystemExit: If the token exchange fails
52
+ """
32
53
token_url = "https://www.strava.com/oauth/token"
33
54
payload = {
34
55
'client_id' : client_id ,
35
56
'client_secret' : client_secret ,
36
57
'code' : auth_code ,
37
58
'grant_type' : 'authorization_code'
38
59
}
39
-
60
+
40
61
try :
41
62
response = requests .post (token_url , data = payload )
42
63
response .raise_for_status ()
43
- return response .json ()
64
+ return dict ( response .json () )
44
65
except requests .exceptions .RequestException as e :
45
66
print (f"Error exchanging code for token: { e } " )
46
67
if hasattr (e , 'response' ) and e .response :
47
68
print (f"Response: { e .response .text } " )
48
69
sys .exit (1 )
49
70
50
- def update_env_file (token_data ):
51
- """Update the .env file with the token data."""
71
+
72
+ def update_env_file (token_data : dict [str , Any ]) -> None :
73
+ """
74
+ Update the .env file with the token data.
75
+
76
+ Args:
77
+ token_data: dictionary containing token data (access_token, refresh_token, expires_at)
78
+ """
52
79
env_file = ".env"
53
-
80
+
54
81
# Read existing .env file if it exists
55
- env_vars = {}
82
+ env_vars : dict [ str , str ] = {}
56
83
if os .path .exists (env_file ):
57
84
with open (env_file , 'r' ) as f :
58
85
for line in f :
59
86
line = line .strip ()
60
87
if line and not line .startswith ('#' ) and '=' in line :
61
88
key , value = line .split ('=' , 1 )
62
89
env_vars [key ] = value
63
-
90
+
64
91
# Update with new token data
65
92
env_vars ['STRAVA_REFRESH_TOKEN' ] = token_data ['refresh_token' ]
66
93
env_vars ['STRAVA_ACCESS_TOKEN' ] = token_data ['access_token' ]
67
94
env_vars ['STRAVA_EXPIRES_AT' ] = str (token_data ['expires_at' ])
68
-
95
+
69
96
# Write back to .env file
70
97
with open (env_file , 'w' ) as f :
71
98
for key , value in env_vars .items ():
72
99
f .write (f"{ key } ={ value } \n " )
73
-
100
+
74
101
print (f"Updated { env_file } with new token data" )
75
102
76
- def main ():
103
+
104
+ def main () -> None :
77
105
"""Main function to guide the user through the token acquisition process."""
78
106
load_dotenv ()
79
-
107
+
80
108
print ("=== Strava API Token Helper ===" )
81
-
109
+
82
110
# Get client ID and secret
83
111
client_id = os .environ .get ('STRAVA_CLIENT_ID' )
84
112
client_secret = os .environ .get ('STRAVA_CLIENT_SECRET' )
85
-
113
+
86
114
if not client_id or not client_secret :
87
115
print ("Please provide your Strava API credentials:" )
88
116
client_id = input ("Client ID: " ).strip ()
89
117
client_secret = input ("Client Secret: " ).strip ()
90
-
118
+
91
119
# Save to .env file
92
120
with open (".env" , 'w' ) as f :
93
121
f .write (f"STRAVA_CLIENT_ID={ client_id } \n " )
94
122
f .write (f"STRAVA_CLIENT_SECRET={ client_secret } \n " )
95
-
123
+
96
124
print ("Saved credentials to .env file" )
97
-
125
+
98
126
# Print authorization URL
99
127
print_auth_url (client_id )
100
-
128
+
101
129
# Get authorization code from user
102
130
auth_code = input ("Enter the authorization code from the URL: " ).strip ()
103
-
131
+
104
132
# Exchange code for token
105
133
print ("\n === Step 2: Exchanging code for token ===" )
106
134
token_data = exchange_code_for_token (client_id , client_secret , auth_code )
107
-
135
+
108
136
# Print token information
109
137
print ("\n === Token Information ===" )
110
138
print (f"Access Token: { token_data ['access_token' ][:10 ]} ..." )
111
139
print (f"Refresh Token: { token_data ['refresh_token' ][:10 ]} ..." )
112
140
print (f"Expires At: { token_data ['expires_at' ]} (Unix timestamp)" )
113
-
141
+
114
142
# Update .env file
115
143
update_env_file (token_data )
116
-
144
+
117
145
print ("\n === Success! ===" )
118
- print ("You can now run the strava_api.py script to fetch your data." )
146
+ print ("You can now run the strava-mcp-server to access your Strava data." )
147
+
119
148
120
149
if __name__ == "__main__" :
121
- main ()
150
+ main ()
0 commit comments