iflow-mcp_gmen1057-headhunter-mcp-server 0.1.0__py3-none-any.whl
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.
- .env.example +12 -0
- .gitignore +30 -0
- 3090_process.log +4 -0
- CONTRIBUTING.md +86 -0
- LICENSE +21 -0
- PKG-INFO +326 -0
- README.md +314 -0
- docs/vacancy-hunter.md +150 -0
- examples/README.md +90 -0
- examples/oauth_flow.py +177 -0
- hh_client.py +573 -0
- iflow_mcp_gmen1057_headhunter_mcp_server-0.1.0.dist-info/METADATA +326 -0
- iflow_mcp_gmen1057_headhunter_mcp_server-0.1.0.dist-info/RECORD +23 -0
- iflow_mcp_gmen1057_headhunter_mcp_server-0.1.0.dist-info/WHEEL +4 -0
- iflow_mcp_gmen1057_headhunter_mcp_server-0.1.0.dist-info/entry_points.txt +2 -0
- iflow_mcp_gmen1057_headhunter_mcp_server-0.1.0.dist-info/licenses/LICENSE +21 -0
- language.json +1 -0
- oauth_flow.py +69 -0
- package_name +1 -0
- push_info.json +5 -0
- pyproject.toml +22 -0
- requirements.txt +4 -0
- server.py +496 -0
examples/oauth_flow.py
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""HeadHunter OAuth Authorization Flow Example.
|
|
3
|
+
|
|
4
|
+
This script demonstrates the complete OAuth 2.0 authorization flow for HeadHunter API.
|
|
5
|
+
It guides the user through the process of obtaining access and refresh tokens required
|
|
6
|
+
for authenticated API calls to HeadHunter services.
|
|
7
|
+
|
|
8
|
+
The OAuth flow consists of the following steps:
|
|
9
|
+
1. Generate authorization URL with required parameters
|
|
10
|
+
2. User opens the URL, authorizes the application, and gets authorization code
|
|
11
|
+
3. Exchange the authorization code for access and refresh tokens
|
|
12
|
+
4. Save tokens to .env file for use by the MCP server
|
|
13
|
+
|
|
14
|
+
This script is intended to be run once to set up authentication. The obtained
|
|
15
|
+
tokens can then be used by the HeadHunter MCP server for authenticated operations
|
|
16
|
+
such as job applications and resume management.
|
|
17
|
+
|
|
18
|
+
Required environment variables:
|
|
19
|
+
HH_CLIENT_ID: OAuth client ID from HeadHunter developer account
|
|
20
|
+
HH_CLIENT_SECRET: OAuth client secret from HeadHunter developer account
|
|
21
|
+
HH_REDIRECT_URI: Redirect URI registered in HeadHunter application settings
|
|
22
|
+
|
|
23
|
+
Usage:
|
|
24
|
+
python examples/oauth_flow.py
|
|
25
|
+
|
|
26
|
+
The script will:
|
|
27
|
+
- Display authorization URL for user to open in browser
|
|
28
|
+
- Prompt for authorization code from the redirect URL
|
|
29
|
+
- Exchange code for tokens
|
|
30
|
+
- Save tokens to .env file automatically
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
import os
|
|
34
|
+
import asyncio
|
|
35
|
+
import httpx
|
|
36
|
+
from dotenv import load_dotenv
|
|
37
|
+
from urllib.parse import urlencode
|
|
38
|
+
|
|
39
|
+
load_dotenv()
|
|
40
|
+
|
|
41
|
+
CLIENT_ID = os.getenv("HH_CLIENT_ID")
|
|
42
|
+
CLIENT_SECRET = os.getenv("HH_CLIENT_SECRET")
|
|
43
|
+
REDIRECT_URI = os.getenv("HH_REDIRECT_URI")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_auth_url():
|
|
47
|
+
"""Generate HeadHunter OAuth authorization URL.
|
|
48
|
+
|
|
49
|
+
Constructs the authorization URL that users need to visit to grant
|
|
50
|
+
permission to the application. The URL includes the client ID and
|
|
51
|
+
redirect URI, and uses the authorization code grant type.
|
|
52
|
+
|
|
53
|
+
The user should open this URL in a browser, log in to their HeadHunter
|
|
54
|
+
account, and authorize the application. After authorization, they will
|
|
55
|
+
be redirected to the specified redirect URI with an authorization code.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
str: Complete authorization URL with query parameters including:
|
|
59
|
+
- response_type: Set to "code" for authorization code flow
|
|
60
|
+
- client_id: OAuth client ID from environment variables
|
|
61
|
+
- redirect_uri: Registered redirect URI from environment variables
|
|
62
|
+
|
|
63
|
+
Note:
|
|
64
|
+
Requires HH_CLIENT_ID and HH_REDIRECT_URI environment variables to be set.
|
|
65
|
+
"""
|
|
66
|
+
params = {
|
|
67
|
+
"response_type": "code",
|
|
68
|
+
"client_id": CLIENT_ID,
|
|
69
|
+
"redirect_uri": REDIRECT_URI,
|
|
70
|
+
}
|
|
71
|
+
return f"https://hh.ru/oauth/authorize?{urlencode(params)}"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
async def exchange_code(code: str):
|
|
75
|
+
"""Exchange authorization code for OAuth tokens.
|
|
76
|
+
|
|
77
|
+
Makes a POST request to HeadHunter's token endpoint to exchange
|
|
78
|
+
the authorization code (received from the authorization step) for
|
|
79
|
+
access and refresh tokens.
|
|
80
|
+
|
|
81
|
+
This is the second step of the OAuth 2.0 authorization code flow.
|
|
82
|
+
The authorization code has a short lifetime and can only be used once.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
code (str): Authorization code received from the HeadHunter
|
|
86
|
+
authorization redirect. This code is typically found in the
|
|
87
|
+
URL query parameter after user authorization.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Dict[str, Any]: Token response containing:
|
|
91
|
+
- access_token (str): OAuth access token for authenticated API calls
|
|
92
|
+
- refresh_token (str): Token for refreshing expired access tokens
|
|
93
|
+
- expires_in (int): Access token lifetime in seconds
|
|
94
|
+
- token_type (str): Token type (typically "Bearer")
|
|
95
|
+
|
|
96
|
+
Raises:
|
|
97
|
+
httpx.HTTPError: If the token exchange fails due to invalid code,
|
|
98
|
+
client credentials, or other OAuth errors.
|
|
99
|
+
|
|
100
|
+
Note:
|
|
101
|
+
Requires HH_CLIENT_ID, HH_CLIENT_SECRET, and HH_REDIRECT_URI
|
|
102
|
+
environment variables to be set.
|
|
103
|
+
"""
|
|
104
|
+
async with httpx.AsyncClient() as client:
|
|
105
|
+
response = await client.post(
|
|
106
|
+
"https://hh.ru/oauth/token",
|
|
107
|
+
data={
|
|
108
|
+
"grant_type": "authorization_code",
|
|
109
|
+
"client_id": CLIENT_ID,
|
|
110
|
+
"client_secret": CLIENT_SECRET,
|
|
111
|
+
"code": code,
|
|
112
|
+
"redirect_uri": REDIRECT_URI,
|
|
113
|
+
},
|
|
114
|
+
)
|
|
115
|
+
response.raise_for_status()
|
|
116
|
+
return response.json()
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
async def main():
|
|
120
|
+
"""Main function that orchestrates the complete OAuth flow.
|
|
121
|
+
|
|
122
|
+
This function guides the user through the entire OAuth 2.0 authorization
|
|
123
|
+
process for HeadHunter API access. It provides a step-by-step interactive
|
|
124
|
+
experience to obtain and save authentication tokens.
|
|
125
|
+
|
|
126
|
+
The function performs the following steps:
|
|
127
|
+
1. Display formatted instructions and authorization URL
|
|
128
|
+
2. Wait for user to complete browser authorization and enter code
|
|
129
|
+
3. Exchange the authorization code for tokens
|
|
130
|
+
4. Display token information (partially masked for security)
|
|
131
|
+
5. Automatically append tokens to .env file for future use
|
|
132
|
+
|
|
133
|
+
The saved tokens can then be used by the HeadHunter MCP server to make
|
|
134
|
+
authenticated API calls for user-specific operations like job applications
|
|
135
|
+
and resume management.
|
|
136
|
+
|
|
137
|
+
Raises:
|
|
138
|
+
Exception: If required environment variables are missing or if the
|
|
139
|
+
OAuth flow fails at any step.
|
|
140
|
+
|
|
141
|
+
Note:
|
|
142
|
+
This function modifies the .env file by appending the obtained tokens.
|
|
143
|
+
Existing content is preserved, and tokens are added with comments
|
|
144
|
+
indicating their expiration time.
|
|
145
|
+
"""
|
|
146
|
+
print("=" * 60)
|
|
147
|
+
print("HeadHunter OAuth Authorization")
|
|
148
|
+
print("=" * 60)
|
|
149
|
+
print("\n1. Откройте эту ссылку в браузере:\n")
|
|
150
|
+
print(get_auth_url())
|
|
151
|
+
print("\n2. Авторизуйтесь и разрешите доступ")
|
|
152
|
+
print("3. Скопируйте код из URL (после ?code=)\n")
|
|
153
|
+
|
|
154
|
+
code = input("Введите код авторизации: ").strip()
|
|
155
|
+
|
|
156
|
+
print("\nОбмен кода на токены...")
|
|
157
|
+
tokens = await exchange_code(code)
|
|
158
|
+
|
|
159
|
+
print("\n✅ Успешно получены токены!")
|
|
160
|
+
print(f"Access Token: {tokens['access_token'][:50]}...")
|
|
161
|
+
print(f"Refresh Token: {tokens['refresh_token'][:50]}...")
|
|
162
|
+
print(f"Expires in: {tokens['expires_in']} seconds")
|
|
163
|
+
|
|
164
|
+
print("\n📝 Сохраните эти токены в .env файл:")
|
|
165
|
+
print(f"\nHH_ACCESS_TOKEN={tokens['access_token']}")
|
|
166
|
+
print(f"HH_REFRESH_TOKEN={tokens['refresh_token']}")
|
|
167
|
+
|
|
168
|
+
with open(".env", "a") as f:
|
|
169
|
+
f.write(f"\n\n# OAuth tokens (expires at {tokens['expires_in']} seconds)\n")
|
|
170
|
+
f.write(f"HH_ACCESS_TOKEN={tokens['access_token']}\n")
|
|
171
|
+
f.write(f"HH_REFRESH_TOKEN={tokens['refresh_token']}\n")
|
|
172
|
+
|
|
173
|
+
print("\n✅ Токены сохранены в .env файл")
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
if __name__ == "__main__":
|
|
177
|
+
asyncio.run(main())
|