icebox-interview-mcp 1.0.0 → 1.0.3
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/index.js +48 -55
- package/package.json +19 -5
package/index.js
CHANGED
|
@@ -1,65 +1,47 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import EventSource from 'eventsource';
|
|
4
3
|
import { createInterface } from 'readline';
|
|
5
4
|
|
|
6
5
|
const token = process.env.ICEBOX_CANDIDATE_TOKEN;
|
|
7
6
|
const apiUrl = process.env.ICEBOX_API_URL || 'https://api.iceboxiq.com';
|
|
8
7
|
|
|
9
8
|
if (!token) {
|
|
10
|
-
|
|
9
|
+
const error = {
|
|
11
10
|
jsonrpc: '2.0',
|
|
12
11
|
error: { code: -32600, message: 'ICEBOX_CANDIDATE_TOKEN environment variable required' },
|
|
13
12
|
id: null
|
|
14
|
-
}
|
|
13
|
+
};
|
|
14
|
+
console.log(JSON.stringify(error));
|
|
15
15
|
process.exit(1);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const
|
|
19
|
-
const messagesUrl = `${apiUrl}/api/mcp/candidate/messages`;
|
|
18
|
+
const messagesUrl = `${apiUrl}/api/mcp/candidate/message`;
|
|
20
19
|
|
|
21
|
-
//
|
|
22
|
-
const es = new EventSource(sseUrl, {
|
|
23
|
-
headers: {
|
|
24
|
-
'Authorization': `Bearer ${token}`
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
es.onopen = () => {
|
|
29
|
-
// Connection established
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
es.onmessage = (event) => {
|
|
33
|
-
// Forward SSE messages to stdout for Claude Desktop
|
|
34
|
-
try {
|
|
35
|
-
const data = JSON.parse(event.data);
|
|
36
|
-
console.log(JSON.stringify(data));
|
|
37
|
-
} catch (e) {
|
|
38
|
-
// Raw message
|
|
39
|
-
console.log(event.data);
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
es.onerror = (err) => {
|
|
44
|
-
console.error(JSON.stringify({
|
|
45
|
-
jsonrpc: '2.0',
|
|
46
|
-
error: { code: -32603, message: 'SSE connection error' },
|
|
47
|
-
id: null
|
|
48
|
-
}));
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// Read from stdin (messages from Claude Desktop)
|
|
20
|
+
// Read JSON-RPC messages from stdin
|
|
52
21
|
const rl = createInterface({
|
|
53
22
|
input: process.stdin,
|
|
54
|
-
output: process.stdout,
|
|
55
23
|
terminal: false
|
|
56
24
|
});
|
|
57
25
|
|
|
26
|
+
// Process each line as a JSON-RPC message
|
|
58
27
|
rl.on('line', async (line) => {
|
|
28
|
+
if (!line.trim()) return;
|
|
29
|
+
|
|
30
|
+
let message;
|
|
59
31
|
try {
|
|
60
|
-
|
|
32
|
+
message = JSON.parse(line);
|
|
33
|
+
} catch (e) {
|
|
34
|
+
const error = {
|
|
35
|
+
jsonrpc: '2.0',
|
|
36
|
+
error: { code: -32700, message: 'Parse error: invalid JSON' },
|
|
37
|
+
id: null
|
|
38
|
+
};
|
|
39
|
+
console.log(JSON.stringify(error));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
61
42
|
|
|
62
|
-
|
|
43
|
+
try {
|
|
44
|
+
// Forward message to the API
|
|
63
45
|
const response = await fetch(messagesUrl, {
|
|
64
46
|
method: 'POST',
|
|
65
47
|
headers: {
|
|
@@ -70,30 +52,41 @@ rl.on('line', async (line) => {
|
|
|
70
52
|
});
|
|
71
53
|
|
|
72
54
|
if (!response.ok) {
|
|
73
|
-
|
|
74
|
-
|
|
55
|
+
let errorText;
|
|
56
|
+
try {
|
|
57
|
+
const errorJson = await response.json();
|
|
58
|
+
errorText = errorJson.error || JSON.stringify(errorJson);
|
|
59
|
+
} catch {
|
|
60
|
+
errorText = await response.text();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const error = {
|
|
75
64
|
jsonrpc: '2.0',
|
|
76
|
-
error: { code: -32603, message: error },
|
|
65
|
+
error: { code: -32603, message: `API error: ${errorText}` },
|
|
77
66
|
id: message.id || null
|
|
78
|
-
}
|
|
67
|
+
};
|
|
68
|
+
console.log(JSON.stringify(error));
|
|
69
|
+
return;
|
|
79
70
|
}
|
|
80
|
-
|
|
71
|
+
|
|
72
|
+
// Return the response
|
|
73
|
+
const result = await response.json();
|
|
74
|
+
console.log(JSON.stringify(result));
|
|
81
75
|
} catch (e) {
|
|
82
|
-
|
|
76
|
+
const error = {
|
|
83
77
|
jsonrpc: '2.0',
|
|
84
|
-
error: { code: -
|
|
85
|
-
id: null
|
|
86
|
-
}
|
|
78
|
+
error: { code: -32603, message: `Request failed: ${e.message}` },
|
|
79
|
+
id: message.id || null
|
|
80
|
+
};
|
|
81
|
+
console.log(JSON.stringify(error));
|
|
87
82
|
}
|
|
88
83
|
});
|
|
89
84
|
|
|
90
|
-
// Handle
|
|
91
|
-
|
|
92
|
-
es.close();
|
|
85
|
+
// Handle stdin close
|
|
86
|
+
rl.on('close', () => {
|
|
93
87
|
process.exit(0);
|
|
94
88
|
});
|
|
95
89
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
});
|
|
90
|
+
// Handle termination signals
|
|
91
|
+
process.on('SIGINT', () => process.exit(0));
|
|
92
|
+
process.on('SIGTERM', () => process.exit(0));
|
package/package.json
CHANGED
|
@@ -1,18 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "icebox-interview-mcp",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "MCP
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "MCP server for Icebox ATS candidate interviews",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"icebox-interview": "./index.js"
|
|
7
|
+
"icebox-interview-mcp": "./index.js"
|
|
8
8
|
},
|
|
9
9
|
"type": "module",
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=18"
|
|
12
|
+
},
|
|
10
13
|
"dependencies": {
|
|
11
14
|
"eventsource": "^2.0.2"
|
|
12
15
|
},
|
|
13
16
|
"files": [
|
|
14
17
|
"index.js"
|
|
15
18
|
],
|
|
16
|
-
"keywords": [
|
|
17
|
-
|
|
19
|
+
"keywords": [
|
|
20
|
+
"mcp",
|
|
21
|
+
"icebox",
|
|
22
|
+
"interview",
|
|
23
|
+
"ats",
|
|
24
|
+
"hiring"
|
|
25
|
+
],
|
|
26
|
+
"author": "Icebox",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/iceboxiq/icebox"
|
|
31
|
+
}
|
|
18
32
|
}
|