@thenextgennexus/hr-compensation-mcp-server 1.0.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/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # HR & Compensation MCP Server
2
+
3
+ Search H1B visa salaries, salary benchmarks, and job market data — powered by [nexgendata](https://apify.com/nexgendata) on Apify.
4
+
5
+ ## Quick Start
6
+
7
+ ### Using npx (recommended)
8
+
9
+ ```bash
10
+ npx @nexgendata/hr-compensation-mcp-server
11
+ ```
12
+
13
+ ### Install globally
14
+
15
+ ```bash
16
+ npm install -g @nexgendata/hr-compensation-mcp-server
17
+ ```
18
+
19
+ ## Configure with Claude Desktop
20
+
21
+ Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
22
+
23
+ ```json
24
+ {
25
+ "mcpServers": {
26
+ "hr-compensation-mcp-server": {
27
+ "command": "npx",
28
+ "args": [
29
+ "-y",
30
+ "@nexgendata/hr-compensation-mcp-server"
31
+ ],
32
+ "env": {
33
+ "APIFY_TOKEN": "your-apify-token-optional"
34
+ }
35
+ }
36
+ }
37
+ }
38
+ ```
39
+
40
+ ## Configure with Cline
41
+
42
+ Add the same configuration to your Cline MCP settings.
43
+
44
+ ## Available Tools
45
+
46
+ | Tool | Description |
47
+ |------|-------------|
48
+ | `search_h1b_salaries` | Search H1B visa salary data by employer, job title, or location |
49
+ | `get_salary_benchmarks` | Get salary benchmark data for roles and locations |
50
+ | `analyze_compensation` | Analyze compensation trends for a role or company |
51
+ | `search_job_market` | Search current job market data and trends |
52
+ | `get_company_salary_data` | Get salary data for a specific company |
53
+
54
+
55
+ ## Environment Variables
56
+
57
+ | Variable | Required | Description |
58
+ |----------|----------|-------------|
59
+ | `APIFY_TOKEN` | No | Your Apify API token for authenticated access. Without it, the server uses the public endpoint (rate-limited). |
60
+
61
+ ## How It Works
62
+
63
+ This MCP server acts as a local stdio bridge to the [nexgendata Apify MCP endpoint](https://nexgendata--hr-compensation-mcp-server.apify.actor/mcp). When you call a tool, it forwards the request to Apify and returns the results.
64
+
65
+ ## Links
66
+
67
+ - [Apify Store](https://apify.com/nexgendata/hr-compensation-mcp-server)
68
+ - [GitHub Repository](https://github.com/TheNextGenNexus/business-data-mcp-servers)
69
+ - [nexgendata Blog](https://thenextgennexus.com)
70
+
71
+ ## License
72
+
73
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,190 @@
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
+ const APIFY_ENDPOINT = "https://nexgendata--hr-compensation-mcp-server.apify.actor/mcp";
6
+ const APIFY_TOKEN = process.env.APIFY_TOKEN || "";
7
+ async function callApifyTool(toolName, args) {
8
+ const url = new URL(APIFY_ENDPOINT);
9
+ if (APIFY_TOKEN) {
10
+ url.searchParams.set("token", APIFY_TOKEN);
11
+ }
12
+ const body = {
13
+ jsonrpc: "2.0",
14
+ id: 1,
15
+ method: "tools/call",
16
+ params: {
17
+ name: toolName,
18
+ arguments: args
19
+ }
20
+ };
21
+ const response = await fetch(url.toString(), {
22
+ method: "POST",
23
+ headers: { "Content-Type": "application/json" },
24
+ body: JSON.stringify(body)
25
+ });
26
+ if (!response.ok) {
27
+ const errorText = await response.text();
28
+ throw new Error(`Apify API error (${response.status}): ${errorText}`);
29
+ }
30
+ const data = await response.json();
31
+ if (data.error) {
32
+ throw new Error(`Tool error: ${JSON.stringify(data.error)}`);
33
+ }
34
+ // Extract text content from MCP response
35
+ const result = data.result;
36
+ if (result?.content && Array.isArray(result.content)) {
37
+ return result.content
38
+ .filter((c) => c.type === "text")
39
+ .map((c) => c.text)
40
+ .join("\n");
41
+ }
42
+ return JSON.stringify(data.result, null, 2);
43
+ }
44
+ const server = new McpServer({
45
+ name: "hr-compensation-mcp-server",
46
+ version: "1.0.0"
47
+ });
48
+ server.registerTool("search_h1b_salaries", {
49
+ title: "Search H1B Salaries",
50
+ description: "Search H1B visa salary data",
51
+ inputSchema: {
52
+ query: z.string().describe('Employer, job title, or location'),
53
+ year: z.number().optional().describe('Filing year'),
54
+ maxItems: z.number().default(20).describe('Maximum results')
55
+ },
56
+ annotations: {
57
+ readOnlyHint: true,
58
+ destructiveHint: false,
59
+ openWorldHint: true
60
+ }
61
+ }, async (args) => {
62
+ try {
63
+ const result = await callApifyTool("search_h1b_salaries", args);
64
+ return {
65
+ content: [{ type: "text", text: result }]
66
+ };
67
+ }
68
+ catch (error) {
69
+ const message = error instanceof Error ? error.message : String(error);
70
+ return {
71
+ content: [{ type: "text", text: `Error: ${message}` }],
72
+ isError: true
73
+ };
74
+ }
75
+ });
76
+ server.registerTool("get_salary_benchmarks", {
77
+ title: "Get Salary Benchmarks",
78
+ description: "Get salary benchmarks for roles",
79
+ inputSchema: {
80
+ jobTitle: z.string().describe('Job title'),
81
+ location: z.string().optional().describe('City or region'),
82
+ maxItems: z.number().default(10).describe('Maximum results')
83
+ },
84
+ annotations: {
85
+ readOnlyHint: true,
86
+ destructiveHint: false,
87
+ openWorldHint: true
88
+ }
89
+ }, async (args) => {
90
+ try {
91
+ const result = await callApifyTool("get_salary_benchmarks", args);
92
+ return {
93
+ content: [{ type: "text", text: result }]
94
+ };
95
+ }
96
+ catch (error) {
97
+ const message = error instanceof Error ? error.message : String(error);
98
+ return {
99
+ content: [{ type: "text", text: `Error: ${message}` }],
100
+ isError: true
101
+ };
102
+ }
103
+ });
104
+ server.registerTool("analyze_compensation", {
105
+ title: "Analyze Compensation",
106
+ description: "Analyze compensation trends",
107
+ inputSchema: {
108
+ query: z.string().describe('Company or role'),
109
+ maxItems: z.number().default(20).describe('Maximum data points')
110
+ },
111
+ annotations: {
112
+ readOnlyHint: true,
113
+ destructiveHint: false,
114
+ openWorldHint: true
115
+ }
116
+ }, async (args) => {
117
+ try {
118
+ const result = await callApifyTool("analyze_compensation", args);
119
+ return {
120
+ content: [{ type: "text", text: result }]
121
+ };
122
+ }
123
+ catch (error) {
124
+ const message = error instanceof Error ? error.message : String(error);
125
+ return {
126
+ content: [{ type: "text", text: `Error: ${message}` }],
127
+ isError: true
128
+ };
129
+ }
130
+ });
131
+ server.registerTool("search_job_market", {
132
+ title: "Search Job Market",
133
+ description: "Search job market data and trends",
134
+ inputSchema: {
135
+ query: z.string().describe('Job market search query'),
136
+ maxItems: z.number().default(20).describe('Maximum results')
137
+ },
138
+ annotations: {
139
+ readOnlyHint: true,
140
+ destructiveHint: false,
141
+ openWorldHint: true
142
+ }
143
+ }, async (args) => {
144
+ try {
145
+ const result = await callApifyTool("search_job_market", args);
146
+ return {
147
+ content: [{ type: "text", text: result }]
148
+ };
149
+ }
150
+ catch (error) {
151
+ const message = error instanceof Error ? error.message : String(error);
152
+ return {
153
+ content: [{ type: "text", text: `Error: ${message}` }],
154
+ isError: true
155
+ };
156
+ }
157
+ });
158
+ server.registerTool("get_company_salary_data", {
159
+ title: "Get Company Salary Data",
160
+ description: "Get salary data for a company",
161
+ inputSchema: {
162
+ company: z.string().describe('Company name'),
163
+ maxItems: z.number().default(20).describe('Maximum results')
164
+ },
165
+ annotations: {
166
+ readOnlyHint: true,
167
+ destructiveHint: false,
168
+ openWorldHint: true
169
+ }
170
+ }, async (args) => {
171
+ try {
172
+ const result = await callApifyTool("get_company_salary_data", args);
173
+ return {
174
+ content: [{ type: "text", text: result }]
175
+ };
176
+ }
177
+ catch (error) {
178
+ const message = error instanceof Error ? error.message : String(error);
179
+ return {
180
+ content: [{ type: "text", text: `Error: ${message}` }],
181
+ isError: true
182
+ };
183
+ }
184
+ });
185
+ async function main() {
186
+ const transport = new StdioServerTransport();
187
+ await server.connect(transport);
188
+ console.error("HR & Compensation MCP Server running on stdio");
189
+ }
190
+ main().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@thenextgennexus/hr-compensation-mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "Search H1B visa salaries, salary benchmarks, and job market data",
5
+ "type": "module",
6
+ "bin": {
7
+ "hr-compensation-mcp-server": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "start": "node dist/index.js",
12
+ "dev": "tsx src/index.ts"
13
+ },
14
+ "dependencies": {
15
+ "@modelcontextprotocol/sdk": "^1.0.0",
16
+ "zod": "^3.22.0"
17
+ },
18
+ "devDependencies": {
19
+ "typescript": "^5.3.0",
20
+ "tsx": "^4.7.0",
21
+ "@types/node": "^20.11.0"
22
+ },
23
+ "engines": {
24
+ "node": ">=18.0.0"
25
+ },
26
+ "keywords": [
27
+ "mcp",
28
+ "model-context-protocol",
29
+ "ai",
30
+ "apify",
31
+ "nexgendata"
32
+ ],
33
+ "author": "nexgendata",
34
+ "license": "MIT",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/TheNextGenNexus/business-data-mcp-servers"
38
+ },
39
+ "mcpName": "io.github.thenextgennexus/hr-compensation-mcp-server"
40
+ }
package/smithery.yaml ADDED
@@ -0,0 +1,13 @@
1
+ startCommand:
2
+ type: stdio
3
+ configSchema:
4
+ type: object
5
+ required:
6
+ - apifyToken
7
+ properties:
8
+ apifyToken:
9
+ type: string
10
+ description: Your Apify API token. Get one free at https://apify.com
11
+ commandFunction:
12
+ |-
13
+ (config) => ({{ command: 'npx', args: ['tsx', 'src/index.ts'], env: {{ APIFY_TOKEN: config.apifyToken }} }})
package/src/index.ts ADDED
@@ -0,0 +1,223 @@
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
+
6
+ const APIFY_ENDPOINT = "https://nexgendata--hr-compensation-mcp-server.apify.actor/mcp";
7
+ const APIFY_TOKEN = process.env.APIFY_TOKEN || "";
8
+
9
+ async function callApifyTool(toolName: string, args: Record<string, unknown>): Promise<string> {
10
+ const url = new URL(APIFY_ENDPOINT);
11
+ if (APIFY_TOKEN) {
12
+ url.searchParams.set("token", APIFY_TOKEN);
13
+ }
14
+
15
+ const body = {
16
+ jsonrpc: "2.0",
17
+ id: 1,
18
+ method: "tools/call",
19
+ params: {
20
+ name: toolName,
21
+ arguments: args
22
+ }
23
+ };
24
+
25
+ const response = await fetch(url.toString(), {
26
+ method: "POST",
27
+ headers: { "Content-Type": "application/json" },
28
+ body: JSON.stringify(body)
29
+ });
30
+
31
+ if (!response.ok) {
32
+ const errorText = await response.text();
33
+ throw new Error(`Apify API error (${response.status}): ${errorText}`);
34
+ }
35
+
36
+ const data = await response.json();
37
+
38
+ if (data.error) {
39
+ throw new Error(`Tool error: ${JSON.stringify(data.error)}`);
40
+ }
41
+
42
+ // Extract text content from MCP response
43
+ const result = data.result;
44
+ if (result?.content && Array.isArray(result.content)) {
45
+ return result.content
46
+ .filter((c: { type: string }) => c.type === "text")
47
+ .map((c: { text: string }) => c.text)
48
+ .join("\n");
49
+ }
50
+
51
+ return JSON.stringify(data.result, null, 2);
52
+ }
53
+
54
+ const server = new McpServer({
55
+ name: "hr-compensation-mcp-server",
56
+ version: "1.0.0"
57
+ });
58
+
59
+ server.registerTool(
60
+ "search_h1b_salaries",
61
+ {
62
+ title: "Search H1B Salaries",
63
+ description: "Search H1B visa salary data",
64
+ inputSchema: {
65
+ query: z.string().describe('Employer, job title, or location'),
66
+ year: z.number().optional().describe('Filing year'),
67
+ maxItems: z.number().default(20).describe('Maximum results')
68
+ },
69
+ annotations: {
70
+ readOnlyHint: true,
71
+ destructiveHint: false,
72
+ openWorldHint: true
73
+ }
74
+ },
75
+ async (args) => {
76
+ try {
77
+ const result = await callApifyTool("search_h1b_salaries", args);
78
+ return {
79
+ content: [{ type: "text", text: result }]
80
+ };
81
+ } catch (error) {
82
+ const message = error instanceof Error ? error.message : String(error);
83
+ return {
84
+ content: [{ type: "text", text: `Error: ${message}` }],
85
+ isError: true
86
+ };
87
+ }
88
+ }
89
+ );
90
+
91
+ server.registerTool(
92
+ "get_salary_benchmarks",
93
+ {
94
+ title: "Get Salary Benchmarks",
95
+ description: "Get salary benchmarks for roles",
96
+ inputSchema: {
97
+ jobTitle: z.string().describe('Job title'),
98
+ location: z.string().optional().describe('City or region'),
99
+ maxItems: z.number().default(10).describe('Maximum results')
100
+ },
101
+ annotations: {
102
+ readOnlyHint: true,
103
+ destructiveHint: false,
104
+ openWorldHint: true
105
+ }
106
+ },
107
+ async (args) => {
108
+ try {
109
+ const result = await callApifyTool("get_salary_benchmarks", args);
110
+ return {
111
+ content: [{ type: "text", text: result }]
112
+ };
113
+ } catch (error) {
114
+ const message = error instanceof Error ? error.message : String(error);
115
+ return {
116
+ content: [{ type: "text", text: `Error: ${message}` }],
117
+ isError: true
118
+ };
119
+ }
120
+ }
121
+ );
122
+
123
+ server.registerTool(
124
+ "analyze_compensation",
125
+ {
126
+ title: "Analyze Compensation",
127
+ description: "Analyze compensation trends",
128
+ inputSchema: {
129
+ query: z.string().describe('Company or role'),
130
+ maxItems: z.number().default(20).describe('Maximum data points')
131
+ },
132
+ annotations: {
133
+ readOnlyHint: true,
134
+ destructiveHint: false,
135
+ openWorldHint: true
136
+ }
137
+ },
138
+ async (args) => {
139
+ try {
140
+ const result = await callApifyTool("analyze_compensation", args);
141
+ return {
142
+ content: [{ type: "text", text: result }]
143
+ };
144
+ } catch (error) {
145
+ const message = error instanceof Error ? error.message : String(error);
146
+ return {
147
+ content: [{ type: "text", text: `Error: ${message}` }],
148
+ isError: true
149
+ };
150
+ }
151
+ }
152
+ );
153
+
154
+ server.registerTool(
155
+ "search_job_market",
156
+ {
157
+ title: "Search Job Market",
158
+ description: "Search job market data and trends",
159
+ inputSchema: {
160
+ query: z.string().describe('Job market search query'),
161
+ maxItems: z.number().default(20).describe('Maximum results')
162
+ },
163
+ annotations: {
164
+ readOnlyHint: true,
165
+ destructiveHint: false,
166
+ openWorldHint: true
167
+ }
168
+ },
169
+ async (args) => {
170
+ try {
171
+ const result = await callApifyTool("search_job_market", args);
172
+ return {
173
+ content: [{ type: "text", text: result }]
174
+ };
175
+ } catch (error) {
176
+ const message = error instanceof Error ? error.message : String(error);
177
+ return {
178
+ content: [{ type: "text", text: `Error: ${message}` }],
179
+ isError: true
180
+ };
181
+ }
182
+ }
183
+ );
184
+
185
+ server.registerTool(
186
+ "get_company_salary_data",
187
+ {
188
+ title: "Get Company Salary Data",
189
+ description: "Get salary data for a company",
190
+ inputSchema: {
191
+ company: z.string().describe('Company name'),
192
+ maxItems: z.number().default(20).describe('Maximum results')
193
+ },
194
+ annotations: {
195
+ readOnlyHint: true,
196
+ destructiveHint: false,
197
+ openWorldHint: true
198
+ }
199
+ },
200
+ async (args) => {
201
+ try {
202
+ const result = await callApifyTool("get_company_salary_data", args);
203
+ return {
204
+ content: [{ type: "text", text: result }]
205
+ };
206
+ } catch (error) {
207
+ const message = error instanceof Error ? error.message : String(error);
208
+ return {
209
+ content: [{ type: "text", text: `Error: ${message}` }],
210
+ isError: true
211
+ };
212
+ }
213
+ }
214
+ );
215
+
216
+
217
+ async function main() {
218
+ const transport = new StdioServerTransport();
219
+ await server.connect(transport);
220
+ console.error("HR & Compensation MCP Server running on stdio");
221
+ }
222
+
223
+ main().catch(console.error);
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "declaration": true
12
+ },
13
+ "include": [
14
+ "src/**/*"
15
+ ]
16
+ }