@sargonpiraev/hh-mcp-server 1.1.0
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.
- package/LICENSE +21 -0
- package/README.md +133 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +226 -0
- package/package.json +74 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Sargon Piraev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# HeadHunter MCP Server
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
MCP Server for HeadHunter API - job search and vacancy management
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 🔍 User Profile Management - View and manage your HeadHunter profile
|
|
11
|
+
- 📄 Resume Management - View detailed resume information
|
|
12
|
+
- 💼 Job Application Management - Manage negotiations and communications with employers
|
|
13
|
+
- ⭐ Vacancy Search & Favorites - Search for jobs and manage your favorites
|
|
14
|
+
|
|
15
|
+
## Get Your Credentials
|
|
16
|
+
|
|
17
|
+
Before installation, you'll need to obtain your API credentials:
|
|
18
|
+
|
|
19
|
+
1. **HH_USER_AGENT**: User-Agent header for HeadHunter API requests (required by HH API)
|
|
20
|
+
|
|
21
|
+
Save these credentials for the installation steps below.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
<details>
|
|
26
|
+
<summary><b>Installing via Smithery</b></summary>
|
|
27
|
+
|
|
28
|
+
To install HeadHunter MCP Server for any client automatically via [Smithery](https://smithery.ai):
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx -y @smithery/cli@latest install @sargonpiraev/hh-mcp-server --client <CLIENT_NAME>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
</details>
|
|
35
|
+
|
|
36
|
+
<details>
|
|
37
|
+
<summary><b>Install in Cursor</b></summary>
|
|
38
|
+
|
|
39
|
+
#### Cursor One-Click Installation
|
|
40
|
+
|
|
41
|
+
[](https://cursor.com/install-mcp?name=@sargonpiraev/hh-mcp-server&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBzYXJnb25waXJhZXYvaGFiaXRpZnktbWNwLXNlcnZlciJdLCJlbnYiOnsiSEFCSVRJRllfQVBJX0tFWSI6InlvdXItaGFiaXRpZnktYXBpLWtleSJ9fQo=)
|
|
42
|
+
|
|
43
|
+
#### Manual Configuration
|
|
44
|
+
|
|
45
|
+
Add to your Cursor `~/.cursor/mcp.json` file:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"mcpServers": {
|
|
50
|
+
"hh-mcp-server": {
|
|
51
|
+
"command": "npx",
|
|
52
|
+
"args": ["-y", "@sargonpiraev/hh-mcp-server"],
|
|
53
|
+
"env": {
|
|
54
|
+
"HH_USER_AGENT": "your-HH_USER_AGENT-here"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
</details>
|
|
62
|
+
|
|
63
|
+
<details>
|
|
64
|
+
<summary><b>Install in VS Code</b></summary>
|
|
65
|
+
|
|
66
|
+
[](vscode:mcp/install?%7B%22name%22%3A%22hh-mcp-server%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22@sargonpiraev/hh-mcp-server%22%5D%7D)
|
|
67
|
+
|
|
68
|
+
Or add manually to your VS Code settings:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
"mcp": {
|
|
72
|
+
"servers": {
|
|
73
|
+
"hh-mcp-server": {
|
|
74
|
+
"type": "stdio",
|
|
75
|
+
"command": "npx",
|
|
76
|
+
"args": ["-y", "@sargonpiraev/hh-mcp-server"],
|
|
77
|
+
"env": {
|
|
78
|
+
"HH_USER_AGENT": "your-HH_USER_AGENT-here"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
</details>
|
|
86
|
+
|
|
87
|
+
<details>
|
|
88
|
+
<summary><b>Install in Claude Desktop</b></summary>
|
|
89
|
+
|
|
90
|
+
Add to your `claude_desktop_config.json`:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"mcpServers": {
|
|
95
|
+
"hh-mcp-server": {
|
|
96
|
+
"command": "npx",
|
|
97
|
+
"args": ["-y", "@sargonpiraev/hh-mcp-server"],
|
|
98
|
+
"env": {
|
|
99
|
+
"HH_USER_AGENT": "your-HH_USER_AGENT-here"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
</details>
|
|
107
|
+
|
|
108
|
+
## Available Tools
|
|
109
|
+
|
|
110
|
+
- **`get-vacancies`**: Execute get-vacancies operation
|
|
111
|
+
- **`get-dictionaries`**: Execute get-dictionaries operation
|
|
112
|
+
- **`get-areas`**: Execute get-areas operation
|
|
113
|
+
- **`get-languages`**: Execute get-languages operation
|
|
114
|
+
- **`get-industries`**: Execute get-industries operation
|
|
115
|
+
- **`get-metro`**: Execute get-metro operation
|
|
116
|
+
- **`get-professional-roles`**: Execute get-professional-roles operation
|
|
117
|
+
- **`get-employers`**: Execute get-employers operation
|
|
118
|
+
|
|
119
|
+
**Total: 8 tools available** 🎯
|
|
120
|
+
|
|
121
|
+
## Support This Project
|
|
122
|
+
|
|
123
|
+
Hi! I'm Sargon, a software engineer passionate about AI tools and automation. I create open-source MCP servers to help developers integrate AI assistants with their favorite services.
|
|
124
|
+
|
|
125
|
+
Your support helps me continue developing and maintaining these tools, and motivates me to create new integrations that make AI assistants even more powerful! 🚀
|
|
126
|
+
|
|
127
|
+
[](https://boosty.to/sargonpiraev)
|
|
128
|
+
|
|
129
|
+
## Connect with Author
|
|
130
|
+
|
|
131
|
+
- 🌐 Visit [sargonpiraev.com](https://sargonpiraev.com)
|
|
132
|
+
- 📧 Email: [sargonpiraev@gmail.com](mailto:sargonpiraev@gmail.com)
|
|
133
|
+
- 💬 Join [Discord](https://discord.gg/ZsWGxRGj)
|
package/build/index.d.ts
ADDED
package/build/index.js
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import axios from 'axios';
|
|
6
|
+
import dotenv from 'dotenv';
|
|
7
|
+
// Load environment variables
|
|
8
|
+
dotenv.config();
|
|
9
|
+
// Environment configuration schema
|
|
10
|
+
const envSchema = z.object({
|
|
11
|
+
HH_USER_AGENT: z.string().min(1),
|
|
12
|
+
// TOOL_GLOB_PATTERNS: z.string().optional(),
|
|
13
|
+
// LOG_LEVEL: z.enum(['debug', 'info', 'notice', 'warning', 'error']).default('info').optional(),
|
|
14
|
+
});
|
|
15
|
+
// Parse and validate environment variables
|
|
16
|
+
const env = envSchema.parse(process.env);
|
|
17
|
+
const mcpServer = new McpServer({
|
|
18
|
+
name: '@sargonpiraev/hh-mcp-server',
|
|
19
|
+
version: '',
|
|
20
|
+
}, {
|
|
21
|
+
capabilities: {
|
|
22
|
+
tools: {},
|
|
23
|
+
logging: {},
|
|
24
|
+
},
|
|
25
|
+
instructions: `MCP Server for HeadHunter API - job search and vacancy management`,
|
|
26
|
+
});
|
|
27
|
+
const logger = {
|
|
28
|
+
log: (...message) => mcpServer.server.sendLoggingMessage({
|
|
29
|
+
level: 'info',
|
|
30
|
+
data: message.join(' '),
|
|
31
|
+
}),
|
|
32
|
+
error: (...message) => mcpServer.server.sendLoggingMessage({
|
|
33
|
+
level: 'error',
|
|
34
|
+
data: message.join(' '),
|
|
35
|
+
}),
|
|
36
|
+
debug: (...message) => mcpServer.server.sendLoggingMessage({
|
|
37
|
+
level: 'debug',
|
|
38
|
+
data: message.join(' '),
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
41
|
+
// Axios client setup
|
|
42
|
+
const apiClient = axios.create({
|
|
43
|
+
baseURL: 'https://api.hh.ru',
|
|
44
|
+
headers: {
|
|
45
|
+
Accept: 'application/json',
|
|
46
|
+
},
|
|
47
|
+
timeout: 30000,
|
|
48
|
+
});
|
|
49
|
+
// Add request interceptor for environment variables
|
|
50
|
+
apiClient.interceptors.request.use((config) => {
|
|
51
|
+
if (env.HH_USER_AGENT) {
|
|
52
|
+
config.headers['User-Agent'] = env.HH_USER_AGENT;
|
|
53
|
+
}
|
|
54
|
+
return config;
|
|
55
|
+
}, (error) => {
|
|
56
|
+
return Promise.reject(error);
|
|
57
|
+
});
|
|
58
|
+
function handleError(error) {
|
|
59
|
+
console.error(error);
|
|
60
|
+
logger.error('Error occurred:', JSON.stringify(error));
|
|
61
|
+
if (axios.isAxiosError(error)) {
|
|
62
|
+
const message = error.response?.data?.description || error.message;
|
|
63
|
+
return {
|
|
64
|
+
isError: true,
|
|
65
|
+
content: [{ type: 'text', text: `API Error: ${message}` }],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
isError: true,
|
|
70
|
+
content: [{ type: 'text', text: `Error: ${error}` }],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// Tools
|
|
74
|
+
mcpServer.tool('get-vacancies', `Search for vacancies`, {}, async (args) => {
|
|
75
|
+
try {
|
|
76
|
+
const response = await apiClient.get('/vacancies', {
|
|
77
|
+
params: args,
|
|
78
|
+
});
|
|
79
|
+
return {
|
|
80
|
+
content: [
|
|
81
|
+
{
|
|
82
|
+
type: 'text',
|
|
83
|
+
text: JSON.stringify(response.data, null, 2),
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
return handleError(error);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
mcpServer.tool('get-dictionaries', `Directories of fields`, {}, async (args) => {
|
|
93
|
+
try {
|
|
94
|
+
const response = await apiClient.get('/dictionaries', {
|
|
95
|
+
params: args,
|
|
96
|
+
});
|
|
97
|
+
return {
|
|
98
|
+
content: [
|
|
99
|
+
{
|
|
100
|
+
type: 'text',
|
|
101
|
+
text: JSON.stringify(response.data, null, 2),
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
return handleError(error);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
mcpServer.tool('get-areas', `Tree view of all regions`, {}, async (args) => {
|
|
111
|
+
try {
|
|
112
|
+
const response = await apiClient.get('/areas', {
|
|
113
|
+
params: args,
|
|
114
|
+
});
|
|
115
|
+
return {
|
|
116
|
+
content: [
|
|
117
|
+
{
|
|
118
|
+
type: 'text',
|
|
119
|
+
text: JSON.stringify(response.data, null, 2),
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
return handleError(error);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
mcpServer.tool('get-languages', `The list of all languages`, {}, async (args) => {
|
|
129
|
+
try {
|
|
130
|
+
const response = await apiClient.get('/languages', {
|
|
131
|
+
params: args,
|
|
132
|
+
});
|
|
133
|
+
return {
|
|
134
|
+
content: [
|
|
135
|
+
{
|
|
136
|
+
type: 'text',
|
|
137
|
+
text: JSON.stringify(response.data, null, 2),
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
return handleError(error);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
mcpServer.tool('get-industries', `Industries`, {}, async (args) => {
|
|
147
|
+
try {
|
|
148
|
+
const response = await apiClient.get('/industries', {
|
|
149
|
+
params: args,
|
|
150
|
+
});
|
|
151
|
+
return {
|
|
152
|
+
content: [
|
|
153
|
+
{
|
|
154
|
+
type: 'text',
|
|
155
|
+
text: JSON.stringify(response.data, null, 2),
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
return handleError(error);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
mcpServer.tool('get-metro', `The list of metro stations in all cities`, {}, async (args) => {
|
|
165
|
+
try {
|
|
166
|
+
const response = await apiClient.get('/metro', {
|
|
167
|
+
params: args,
|
|
168
|
+
});
|
|
169
|
+
return {
|
|
170
|
+
content: [
|
|
171
|
+
{
|
|
172
|
+
type: 'text',
|
|
173
|
+
text: JSON.stringify(response.data, null, 2),
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
return handleError(error);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
mcpServer.tool('get-professional-roles', `Professional role directory`, {}, async (args) => {
|
|
183
|
+
try {
|
|
184
|
+
const response = await apiClient.get('/professional_roles', {
|
|
185
|
+
params: args,
|
|
186
|
+
});
|
|
187
|
+
return {
|
|
188
|
+
content: [
|
|
189
|
+
{
|
|
190
|
+
type: 'text',
|
|
191
|
+
text: JSON.stringify(response.data, null, 2),
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
return handleError(error);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
mcpServer.tool('get-employers', `Employer search`, {}, async (args) => {
|
|
201
|
+
try {
|
|
202
|
+
const response = await apiClient.get('/employers', {
|
|
203
|
+
params: args,
|
|
204
|
+
});
|
|
205
|
+
return {
|
|
206
|
+
content: [
|
|
207
|
+
{
|
|
208
|
+
type: 'text',
|
|
209
|
+
text: JSON.stringify(response.data, null, 2),
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
return handleError(error);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
async function main() {
|
|
219
|
+
const transport = new StdioServerTransport();
|
|
220
|
+
await mcpServer.server.connect(transport);
|
|
221
|
+
logger.log('HeadHunter MCP Server started');
|
|
222
|
+
}
|
|
223
|
+
main().catch((error) => {
|
|
224
|
+
console.error('Server error:', error);
|
|
225
|
+
process.exit(1);
|
|
226
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sargonpiraev/hh-mcp-server",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "MCP Server for HeadHunter API - job search and vacancy management",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"claude",
|
|
8
|
+
"ai",
|
|
9
|
+
"assistant"
|
|
10
|
+
],
|
|
11
|
+
"main": "./build/main.js",
|
|
12
|
+
"types": "./build/main.d.ts",
|
|
13
|
+
"type": "module",
|
|
14
|
+
"files": [
|
|
15
|
+
"build/",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"test": "jest --passWithNoTests --coverage",
|
|
21
|
+
"dev": "tsx watch ./src/main.ts",
|
|
22
|
+
"build": "tsc -p tsconfig.json",
|
|
23
|
+
"lint": "eslint ./src --ext .ts",
|
|
24
|
+
"format": "prettier --write .",
|
|
25
|
+
"format:check": "prettier --check .",
|
|
26
|
+
"prepare": "husky",
|
|
27
|
+
"commitlint": "commitlint --edit",
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
29
|
+
"audit": "npm audit --omit=dev",
|
|
30
|
+
"inspect": "npx @modelcontextprotocol/inspector node ./build/main.js"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18.0.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@commitlint/cli": "^19.8.0",
|
|
37
|
+
"@commitlint/config-conventional": "^19.8.0",
|
|
38
|
+
"@eslint/js": "^9.26.0",
|
|
39
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
40
|
+
"@semantic-release/github": "^11.0.0",
|
|
41
|
+
"@semantic-release/npm": "^12.0.2",
|
|
42
|
+
"@semantic-release/release-notes-generator": "^14.0.3",
|
|
43
|
+
"@types/debug": "^4.1.12",
|
|
44
|
+
"@types/node": "^22.15.3",
|
|
45
|
+
"eslint": "^9.26.0",
|
|
46
|
+
"globals": "^16.0.0",
|
|
47
|
+
"husky": "^9.1.7",
|
|
48
|
+
"jest": "^29.7.0",
|
|
49
|
+
"jest-junit": "^16.0.0",
|
|
50
|
+
"prettier": "^3.5.3",
|
|
51
|
+
"semantic-release": "^24.2.3",
|
|
52
|
+
"ts-jest": "^29.3.2",
|
|
53
|
+
"ts-node": "^10.9.2",
|
|
54
|
+
"tsx": "^4.19.4",
|
|
55
|
+
"typescript": "^5.8.3",
|
|
56
|
+
"typescript-eslint": "^8.31.1",
|
|
57
|
+
"@types/minimatch": "^5.1.2"
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@modelcontextprotocol/sdk": "^1.11.0",
|
|
61
|
+
"dotenv": "^16.5.0",
|
|
62
|
+
"zod": "^3.24.3",
|
|
63
|
+
"axios": "^1.7.7"
|
|
64
|
+
},
|
|
65
|
+
"publishConfig": {
|
|
66
|
+
"access": "public"
|
|
67
|
+
},
|
|
68
|
+
"author": {
|
|
69
|
+
"name": "Sargon Piraev",
|
|
70
|
+
"email": "sargonpiraev@gmail.com",
|
|
71
|
+
"url": "https://sargonpiraev.com"
|
|
72
|
+
},
|
|
73
|
+
"license": "MIT"
|
|
74
|
+
}
|