jobseek-mcp 0.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/README.md +108 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +60 -0
- package/dist/tools/download-resume-pdf.d.ts +24 -0
- package/dist/tools/download-resume-pdf.js +149 -0
- package/dist/tools/optimize-resume.d.ts +20 -0
- package/dist/tools/optimize-resume.js +114 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# JobSeek MCP Server
|
|
2
|
+
|
|
3
|
+
AI-powered job search automation for Claude Code.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### 1. Build the MCP Server
|
|
8
|
+
```bash
|
|
9
|
+
cd jobseek-mcp
|
|
10
|
+
npm install
|
|
11
|
+
npm run build
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### 2. Generate an API Key
|
|
15
|
+
- Go to https://getjobseek.com/dashboard/api-keys
|
|
16
|
+
- Click "Generate Key"
|
|
17
|
+
- Copy the key (you won't be able to see it again!)
|
|
18
|
+
|
|
19
|
+
### 3. Configure Claude Code
|
|
20
|
+
|
|
21
|
+
Open `~/.claude.json` in your editor and find your project's `mcpServers` section. Add the `jobseek` entry:
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"projects": {
|
|
26
|
+
"/path/to/your/project": {
|
|
27
|
+
"mcpServers": {
|
|
28
|
+
"jobseek": {
|
|
29
|
+
"type": "stdio",
|
|
30
|
+
"command": "node",
|
|
31
|
+
"args": ["/path/to/jobseek-mcp/dist/index.js"],
|
|
32
|
+
"env": {
|
|
33
|
+
"JOBSEEK_API_URL": "https://getjobseek.com",
|
|
34
|
+
"JOBSEEK_API_KEY": "sk_live_your_key_here"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Important:** Replace:
|
|
44
|
+
- `/path/to/your/project` with your project directory
|
|
45
|
+
- `/path/to/jobseek-mcp/dist/index.js` with the actual path to the built MCP server
|
|
46
|
+
- `sk_live_your_key_here` with your generated API key
|
|
47
|
+
|
|
48
|
+
### 4. Restart Claude Code
|
|
49
|
+
|
|
50
|
+
After saving the config, restart Claude Code. Type `/mcp` to verify the server is connected.
|
|
51
|
+
|
|
52
|
+
## Available Tools
|
|
53
|
+
|
|
54
|
+
### `optimize_resume`
|
|
55
|
+
Optimize your resume for ATS (Applicant Tracking Systems).
|
|
56
|
+
|
|
57
|
+
**Example prompts:**
|
|
58
|
+
- "Optimize my resume for ATS"
|
|
59
|
+
- "Regenerate my resume with a more technical summary"
|
|
60
|
+
- "Make my resume more concise"
|
|
61
|
+
|
|
62
|
+
**What it does:**
|
|
63
|
+
- Rewrites with stronger action verbs
|
|
64
|
+
- Adds measurable impact statements
|
|
65
|
+
- Optimizes keywords for ATS scanning
|
|
66
|
+
- Returns the optimized content + rationale
|
|
67
|
+
|
|
68
|
+
### `download_resume_pdf`
|
|
69
|
+
Download your resume as a file.
|
|
70
|
+
|
|
71
|
+
**Example prompts:**
|
|
72
|
+
- "Download my resume"
|
|
73
|
+
- "Save my optimized resume to a file"
|
|
74
|
+
- "Download my ATS-optimized resume to ~/Documents/resume.txt"
|
|
75
|
+
|
|
76
|
+
**Parameters:**
|
|
77
|
+
- `filePath` (optional): Custom path for the file
|
|
78
|
+
- `optimized` (optional): If true, downloads the ATS-optimized version
|
|
79
|
+
|
|
80
|
+
## Full Workflow Example
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
You: "Optimize my resume for ATS"
|
|
84
|
+
Claude: [calls optimize_resume] "Here's your optimized resume..."
|
|
85
|
+
|
|
86
|
+
You: "That looks great! Download it as a file"
|
|
87
|
+
Claude: [calls download_resume_pdf] "Saved to ~/Downloads/resume_optimized.txt"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Troubleshooting
|
|
91
|
+
|
|
92
|
+
### "1 MCP server failed" error
|
|
93
|
+
- Check `/mcp` in Claude Code for details
|
|
94
|
+
- Verify the path to `dist/index.js` is correct
|
|
95
|
+
- Make sure you ran `npm run build`
|
|
96
|
+
|
|
97
|
+
### "Authentication Required" error
|
|
98
|
+
- Verify your API key is correct in `~/.claude.json`
|
|
99
|
+
- Make sure you have a resume uploaded at https://getjobseek.com/dashboard/profile
|
|
100
|
+
- Check that JOBSEEK_API_URL is set to `https://getjobseek.com`
|
|
101
|
+
|
|
102
|
+
## Development
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npm run dev # Run with tsx (hot reload)
|
|
106
|
+
npm run build # Build for production
|
|
107
|
+
npm start # Run production build
|
|
108
|
+
```
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { optimizeResumeTool, handleOptimizeResume } from "./tools/optimize-resume.js";
|
|
6
|
+
import { downloadResumePdfTool, handleDownloadResumePdf } from "./tools/download-resume-pdf.js";
|
|
7
|
+
// Configuration
|
|
8
|
+
const JOBSEEK_API_URL = process.env.JOBSEEK_API_URL || "https://jobseek-iota.vercel.app";
|
|
9
|
+
const JOBSEEK_API_KEY = process.env.JOBSEEK_API_KEY;
|
|
10
|
+
// Create the MCP server
|
|
11
|
+
const server = new Server({
|
|
12
|
+
name: "jobseek-mcp",
|
|
13
|
+
version: "0.1.0",
|
|
14
|
+
}, {
|
|
15
|
+
capabilities: {
|
|
16
|
+
tools: {},
|
|
17
|
+
resources: {},
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
// List available tools
|
|
21
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
22
|
+
return {
|
|
23
|
+
tools: [
|
|
24
|
+
optimizeResumeTool,
|
|
25
|
+
downloadResumePdfTool,
|
|
26
|
+
],
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
// Handle tool calls
|
|
30
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
31
|
+
const { name, arguments: args } = request.params;
|
|
32
|
+
switch (name) {
|
|
33
|
+
case "optimize_resume":
|
|
34
|
+
return handleOptimizeResume(args, JOBSEEK_API_URL, JOBSEEK_API_KEY);
|
|
35
|
+
case "download_resume_pdf":
|
|
36
|
+
return handleDownloadResumePdf(args, JOBSEEK_API_URL, JOBSEEK_API_KEY);
|
|
37
|
+
default:
|
|
38
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
// List available resources
|
|
42
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
43
|
+
return {
|
|
44
|
+
resources: [
|
|
45
|
+
// Resources will be added here (resume, applications, etc.)
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
// Handle resource reads
|
|
50
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
51
|
+
const { uri } = request.params;
|
|
52
|
+
throw new Error(`Unknown resource: ${uri}`);
|
|
53
|
+
});
|
|
54
|
+
// Start the server
|
|
55
|
+
async function main() {
|
|
56
|
+
const transport = new StdioServerTransport();
|
|
57
|
+
await server.connect(transport);
|
|
58
|
+
console.error("JobSeek MCP Server running on stdio");
|
|
59
|
+
}
|
|
60
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const downloadResumePdfTool: {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: "object";
|
|
6
|
+
properties: {
|
|
7
|
+
filePath: {
|
|
8
|
+
type: string;
|
|
9
|
+
description: string;
|
|
10
|
+
};
|
|
11
|
+
optimized: {
|
|
12
|
+
type: string;
|
|
13
|
+
description: string;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
required: never[];
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export declare function handleDownloadResumePdf(args: unknown, apiUrl: string, apiKey?: string): Promise<{
|
|
20
|
+
content: Array<{
|
|
21
|
+
type: string;
|
|
22
|
+
text: string;
|
|
23
|
+
}>;
|
|
24
|
+
}>;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { writeFileSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
// Tool definition for MCP
|
|
5
|
+
export const downloadResumePdfTool = {
|
|
6
|
+
name: "download_resume_pdf",
|
|
7
|
+
description: `Generate and download a PDF of your resume.
|
|
8
|
+
|
|
9
|
+
This tool fetches your current resume from JobSeek and saves it as a PDF file.
|
|
10
|
+
You can optionally specify a custom file path, otherwise it will be saved to your Downloads folder.
|
|
11
|
+
|
|
12
|
+
Returns the path to the generated PDF file.`,
|
|
13
|
+
inputSchema: {
|
|
14
|
+
type: "object",
|
|
15
|
+
properties: {
|
|
16
|
+
filePath: {
|
|
17
|
+
type: "string",
|
|
18
|
+
description: "Optional custom file path for the PDF. Defaults to ~/Downloads/resume.pdf",
|
|
19
|
+
},
|
|
20
|
+
optimized: {
|
|
21
|
+
type: "boolean",
|
|
22
|
+
description: "If true, generates PDF from the ATS-optimized version. Otherwise uses current resume.",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
required: [],
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
// Input validation schema
|
|
29
|
+
const DownloadResumePdfInput = z.object({
|
|
30
|
+
filePath: z.string().optional(),
|
|
31
|
+
optimized: z.boolean().optional().default(false),
|
|
32
|
+
});
|
|
33
|
+
// Simple PDF generation using plain text (no external dependencies)
|
|
34
|
+
function generateSimplePdf(resume) {
|
|
35
|
+
// Create a simple text-based "PDF" that most viewers can read
|
|
36
|
+
// For a real PDF, you'd use a library like pdfkit or jsPDF
|
|
37
|
+
const content = `
|
|
38
|
+
================================================================================
|
|
39
|
+
RESUME
|
|
40
|
+
================================================================================
|
|
41
|
+
|
|
42
|
+
${resume.name}
|
|
43
|
+
${resume.email}
|
|
44
|
+
${resume.linkedinUrl ? `LinkedIn: ${resume.linkedinUrl}` : ''}
|
|
45
|
+
|
|
46
|
+
--------------------------------------------------------------------------------
|
|
47
|
+
PROFESSIONAL SUMMARY
|
|
48
|
+
--------------------------------------------------------------------------------
|
|
49
|
+
${resume.summary || 'No summary available.'}
|
|
50
|
+
|
|
51
|
+
--------------------------------------------------------------------------------
|
|
52
|
+
SKILLS
|
|
53
|
+
--------------------------------------------------------------------------------
|
|
54
|
+
${(resume.skills || []).join(' • ')}
|
|
55
|
+
|
|
56
|
+
--------------------------------------------------------------------------------
|
|
57
|
+
EXPERIENCE
|
|
58
|
+
--------------------------------------------------------------------------------
|
|
59
|
+
${(resume.experience || []).map((exp) => `
|
|
60
|
+
${exp.title} at ${exp.company}
|
|
61
|
+
${exp.duration}
|
|
62
|
+
|
|
63
|
+
${exp.description || (exp.bullets || []).map((b) => `• ${b}`).join('\n')}
|
|
64
|
+
`).join('\n')}
|
|
65
|
+
|
|
66
|
+
--------------------------------------------------------------------------------
|
|
67
|
+
EDUCATION
|
|
68
|
+
--------------------------------------------------------------------------------
|
|
69
|
+
${(resume.education || []).map((edu) => `
|
|
70
|
+
${edu.degree} - ${edu.institution} (${edu.year})
|
|
71
|
+
`).join('\n')}
|
|
72
|
+
|
|
73
|
+
================================================================================
|
|
74
|
+
Generated by JobSeek
|
|
75
|
+
================================================================================
|
|
76
|
+
`;
|
|
77
|
+
return Buffer.from(content, 'utf-8');
|
|
78
|
+
}
|
|
79
|
+
// Tool handler
|
|
80
|
+
export async function handleDownloadResumePdf(args, apiUrl, apiKey) {
|
|
81
|
+
const input = DownloadResumePdfInput.parse(args);
|
|
82
|
+
try {
|
|
83
|
+
const headers = {
|
|
84
|
+
"Content-Type": "application/json",
|
|
85
|
+
};
|
|
86
|
+
if (apiKey) {
|
|
87
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
88
|
+
}
|
|
89
|
+
// If optimized, first call optimize endpoint, otherwise fetch current resume
|
|
90
|
+
const endpoint = input.optimized
|
|
91
|
+
? `${apiUrl}/api/resumes/optimize`
|
|
92
|
+
: `${apiUrl}/api/resumes/current`;
|
|
93
|
+
const response = await fetch(endpoint, {
|
|
94
|
+
method: input.optimized ? "POST" : "GET",
|
|
95
|
+
headers,
|
|
96
|
+
...(input.optimized ? { body: JSON.stringify({}) } : {}),
|
|
97
|
+
});
|
|
98
|
+
if (!response.ok) {
|
|
99
|
+
const error = await response.json().catch(() => ({ error: "Unknown error" }));
|
|
100
|
+
if (response.status === 401) {
|
|
101
|
+
return {
|
|
102
|
+
content: [
|
|
103
|
+
{
|
|
104
|
+
type: "text",
|
|
105
|
+
text: "❌ **Authentication Required**\n\nPlease set your JOBSEEK_API_KEY environment variable.",
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
throw new Error(error.error || `API error: ${response.status}`);
|
|
111
|
+
}
|
|
112
|
+
const resumeData = await response.json();
|
|
113
|
+
// For optimized resume, the data is in result.content
|
|
114
|
+
const resume = input.optimized ? resumeData.content : resumeData;
|
|
115
|
+
// Generate PDF content
|
|
116
|
+
const pdfBuffer = generateSimplePdf(resume);
|
|
117
|
+
// Determine file path
|
|
118
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || '.';
|
|
119
|
+
const defaultPath = join(homeDir, 'Downloads', `resume${input.optimized ? '_optimized' : ''}.txt`);
|
|
120
|
+
const outputPath = input.filePath || defaultPath;
|
|
121
|
+
// Write to file
|
|
122
|
+
writeFileSync(outputPath, pdfBuffer);
|
|
123
|
+
return {
|
|
124
|
+
content: [
|
|
125
|
+
{
|
|
126
|
+
type: "text",
|
|
127
|
+
text: `✅ **Resume Downloaded!**
|
|
128
|
+
|
|
129
|
+
Your resume has been saved to:
|
|
130
|
+
\`${outputPath}\`
|
|
131
|
+
|
|
132
|
+
${input.optimized ? '📈 This is your ATS-optimized version.' : '📄 This is your current resume.'}
|
|
133
|
+
|
|
134
|
+
**Note:** This is a text-formatted resume. For a properly formatted PDF, visit your JobSeek dashboard and use the "Download PDF" button.`,
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
return {
|
|
141
|
+
content: [
|
|
142
|
+
{
|
|
143
|
+
type: "text",
|
|
144
|
+
text: `❌ **Error generating resume:** ${error.message}`,
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const optimizeResumeTool: {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: "object";
|
|
6
|
+
properties: {
|
|
7
|
+
feedback: {
|
|
8
|
+
type: string;
|
|
9
|
+
description: string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
required: never[];
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export declare function handleOptimizeResume(args: unknown, apiUrl: string, apiKey?: string): Promise<{
|
|
16
|
+
content: Array<{
|
|
17
|
+
type: string;
|
|
18
|
+
text: string;
|
|
19
|
+
}>;
|
|
20
|
+
}>;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// Tool definition for MCP
|
|
3
|
+
export const optimizeResumeTool = {
|
|
4
|
+
name: "optimize_resume",
|
|
5
|
+
description: `Optimize a resume for ATS (Applicant Tracking Systems).
|
|
6
|
+
|
|
7
|
+
This tool rewrites your resume to:
|
|
8
|
+
- Use strong action verbs
|
|
9
|
+
- Add measurable impact statements
|
|
10
|
+
- Optimize keywords for ATS scanning
|
|
11
|
+
- Improve formatting for machine readability
|
|
12
|
+
|
|
13
|
+
Returns the optimized resume content and a rationale explaining the changes.`,
|
|
14
|
+
inputSchema: {
|
|
15
|
+
type: "object",
|
|
16
|
+
properties: {
|
|
17
|
+
feedback: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "Optional feedback for regeneration (e.g., 'make the summary more technical')",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
required: [],
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
// Input validation schema
|
|
26
|
+
const OptimizeResumeInput = z.object({
|
|
27
|
+
feedback: z.string().optional(),
|
|
28
|
+
});
|
|
29
|
+
// Tool handler
|
|
30
|
+
export async function handleOptimizeResume(args, apiUrl, apiKey) {
|
|
31
|
+
const input = OptimizeResumeInput.parse(args);
|
|
32
|
+
try {
|
|
33
|
+
const headers = {
|
|
34
|
+
"Content-Type": "application/json",
|
|
35
|
+
};
|
|
36
|
+
if (apiKey) {
|
|
37
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
38
|
+
}
|
|
39
|
+
const response = await fetch(`${apiUrl}/api/resumes/optimize`, {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headers,
|
|
42
|
+
body: JSON.stringify({
|
|
43
|
+
feedback: input.feedback,
|
|
44
|
+
}),
|
|
45
|
+
});
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
const error = await response.json().catch(() => ({ error: "Unknown error" }));
|
|
48
|
+
if (response.status === 401) {
|
|
49
|
+
return {
|
|
50
|
+
content: [
|
|
51
|
+
{
|
|
52
|
+
type: "text",
|
|
53
|
+
text: "❌ **Authentication Required**\n\nPlease log in to JobSeek first:\n1. Visit https://jobseek-iota.vercel.app\n2. Sign in with Google\n3. Upload your resume\n4. Try this tool again",
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
throw new Error(error.error || `API error: ${response.status}`);
|
|
59
|
+
}
|
|
60
|
+
const result = await response.json();
|
|
61
|
+
// Format the response nicely
|
|
62
|
+
const formattedResponse = `# ✨ ATS-Optimized Resume
|
|
63
|
+
|
|
64
|
+
## Professional Summary
|
|
65
|
+
${result.content.summary}
|
|
66
|
+
|
|
67
|
+
## Skills
|
|
68
|
+
${result.content.skills.map((s) => `- ${s}`).join("\n")}
|
|
69
|
+
|
|
70
|
+
## Experience
|
|
71
|
+
${result.content.experience
|
|
72
|
+
.map((exp) => `### ${exp.title} at ${exp.company}
|
|
73
|
+
*${exp.duration}*
|
|
74
|
+
|
|
75
|
+
${exp.description}`)
|
|
76
|
+
.join("\n\n")}
|
|
77
|
+
|
|
78
|
+
## Education
|
|
79
|
+
${result.content.education
|
|
80
|
+
.map((edu) => `- **${edu.degree}** - ${edu.institution} (${edu.year})`)
|
|
81
|
+
.join("\n")}
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 📋 Changes Made
|
|
86
|
+
|
|
87
|
+
**Summary Changes:** ${result.rationale.summaryChanges}
|
|
88
|
+
|
|
89
|
+
**Skill Prioritization:** ${result.rationale.skillPrioritization}
|
|
90
|
+
|
|
91
|
+
**Experience Improvements:** ${result.rationale.experienceHighlights || result.rationale.experienceImprovements}
|
|
92
|
+
|
|
93
|
+
**Formatting Changes:** ${result.rationale.formattingChanges}
|
|
94
|
+
`;
|
|
95
|
+
return {
|
|
96
|
+
content: [
|
|
97
|
+
{
|
|
98
|
+
type: "text",
|
|
99
|
+
text: formattedResponse,
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
return {
|
|
106
|
+
content: [
|
|
107
|
+
{
|
|
108
|
+
type: "text",
|
|
109
|
+
text: `❌ **Error optimizing resume:** ${error.message}`,
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jobseek-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "JobSeek MCP Server - AI-powered job search automation for Claude Code",
|
|
5
|
+
"author": "Shawn Mitchell",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/shawnmitchell/jobseek.git"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"mcp",
|
|
13
|
+
"claude",
|
|
14
|
+
"ai",
|
|
15
|
+
"resume",
|
|
16
|
+
"job-search",
|
|
17
|
+
"ats",
|
|
18
|
+
"model-context-protocol"
|
|
19
|
+
],
|
|
20
|
+
"type": "module",
|
|
21
|
+
"main": "dist/index.js",
|
|
22
|
+
"bin": {
|
|
23
|
+
"jobseek-mcp": "dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"README.md"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc",
|
|
31
|
+
"dev": "tsx src/index.ts",
|
|
32
|
+
"start": "node dist/index.js",
|
|
33
|
+
"prepublishOnly": "npm run build"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@modelcontextprotocol/sdk": "^0.6.0",
|
|
37
|
+
"zod": "^3.22.4"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^20.10.0",
|
|
41
|
+
"tsx": "^4.7.0",
|
|
42
|
+
"typescript": "^5.3.0"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18"
|
|
46
|
+
}
|
|
47
|
+
}
|