jobseek-mcp 0.5.1 → 0.8.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 CHANGED
@@ -1,24 +1,58 @@
1
1
  # JobSeek MCP Server
2
2
 
3
- AI-powered job search automation for Claude Code.
3
+ AI-powered job search automation for Claude. Works with Claude for macOS + Claude for Chrome for fully automated job searching and application assistance.
4
+
5
+ [![npm version](https://badge.fury.io/js/jobseek-mcp.svg)](https://www.npmjs.com/package/jobseek-mcp)
6
+
7
+ ## Features
8
+
9
+ - **🚀 Automated Job Search** - Claude navigates job boards, finds matching roles, and helps you apply
10
+ - **📋 Smart Form Filling** - Get your profile data ready for any application form
11
+ - **🎯 Job Matching** - AI-powered scoring to find the best fit roles
12
+ - **📄 Resume Optimization** - ATS-friendly resume enhancements
4
13
 
5
14
  ## Quick Start
6
15
 
7
- ### 1. Build the MCP Server
16
+ ### Install from npm
17
+
8
18
  ```bash
9
- cd jobseek-mcp
10
- npm install
11
- npm run build
19
+ npx jobseek-mcp
20
+ ```
21
+
22
+ Or install globally:
23
+
24
+ ```bash
25
+ npm install -g jobseek-mcp
12
26
  ```
13
27
 
14
- ### 2. Generate an API Key
28
+ ### 1. Generate an API Key
15
29
  - Go to https://getjobseek.com/dashboard/api-keys
16
30
  - Click "Generate Key"
17
31
  - Copy the key (you won't be able to see it again!)
18
32
 
19
- ### 3. Configure Claude Code
33
+ ### 2. Configure Claude
34
+
35
+ #### For Claude for macOS / Claude Desktop
36
+
37
+ Add to your Claude config (`~/Library/Application Support/Claude/claude_desktop_config.json` on Mac):
38
+
39
+ ```json
40
+ {
41
+ "mcpServers": {
42
+ "jobseek": {
43
+ "command": "npx",
44
+ "args": ["jobseek-mcp"],
45
+ "env": {
46
+ "JOBSEEK_API_KEY": "sk_live_your_key_here"
47
+ }
48
+ }
49
+ }
50
+ }
51
+ ```
52
+
53
+ #### For Claude Code
20
54
 
21
- Open `~/.claude.json` in your editor and find your project's `mcpServers` section. Add the `jobseek` entry:
55
+ Add to `~/.claude.json`:
22
56
 
23
57
  ```json
24
58
  {
@@ -27,10 +61,9 @@ Open `~/.claude.json` in your editor and find your project's `mcpServers` sectio
27
61
  "mcpServers": {
28
62
  "jobseek": {
29
63
  "type": "stdio",
30
- "command": "node",
31
- "args": ["/path/to/jobseek-mcp/dist/index.js"],
64
+ "command": "npx",
65
+ "args": ["jobseek-mcp"],
32
66
  "env": {
33
- "JOBSEEK_API_URL": "https://getjobseek.com",
34
67
  "JOBSEEK_API_KEY": "sk_live_your_key_here"
35
68
  }
36
69
  }
@@ -40,81 +73,143 @@ Open `~/.claude.json` in your editor and find your project's `mcpServers` sectio
40
73
  }
41
74
  ```
42
75
 
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
76
+ ### 3. Restart Claude
49
77
 
50
- After saving the config, restart Claude Code. Type `/mcp` to verify the server is connected.
78
+ After saving the config, restart Claude. Type `/mcp` to verify the server is connected.
51
79
 
52
80
  ## Available Tools
53
81
 
54
- ### `upload_resume`
55
- Upload a PDF resume to JobSeek.
82
+ ### `my_profile`
83
+ Get your profile information including resume summary, skills, and experience.
84
+
85
+ ### `get_form_data`
86
+ Get structured profile data optimized for filling job application forms. Returns:
87
+ - Personal info (name, email, phone, location)
88
+ - Professional summary and headline
89
+ - Skills (as array and comma-separated text)
90
+ - Work history formatted for forms
91
+ - Education details
92
+ - Default cover letter text
56
93
 
57
- **Example prompts:**
58
- - "Upload my resume from ~/Documents/resume.pdf"
59
- - "Upload /Users/me/Downloads/Resume_2025.pdf to JobSeek"
94
+ **Example:** "Get my form data for applying to jobs"
60
95
 
61
- **What it does:**
62
- - Reads PDF from your local filesystem
63
- - Extracts text and parses with AI
64
- - Stores the parsed resume in JobSeek
96
+ ### `evaluate_job`
97
+ Score a job against your profile. Provide the job title, company, and description to get:
98
+ - Match score (0-100%)
99
+ - Recommendation (strongly_recommend, recommend, consider, skip)
100
+ - Strengths and gaps analysis
101
+ - Application strategy
102
+
103
+ **Example:** "Evaluate this job for me: [paste job description]"
104
+
105
+ ### `launch_pad`
106
+ Open job search tabs across major job boards (LinkedIn, Indeed, Glassdoor, etc.) using your resume to determine search terms.
65
107
 
66
108
  ### `optimize_resume`
67
109
  Optimize your resume for ATS (Applicant Tracking Systems).
68
110
 
69
- **Example prompts:**
70
- - "Optimize my resume for ATS"
71
- - "Regenerate my resume with a more technical summary"
72
- - "Make my resume more concise"
111
+ ### `upload_resume`
112
+ Upload a PDF resume to JobSeek.
113
+
114
+ ### `analyze_matches`
115
+ Review your recent job matches from the Chrome extension.
73
116
 
74
- **What it does:**
75
- - Rewrites with stronger action verbs
76
- - Adds measurable impact statements
77
- - Optimizes keywords for ATS scanning
78
- - Returns the optimized content + rationale
117
+ ### `my_applications`
118
+ Get a list of your job applications with their current status, match scores, and status history with dates.
79
119
 
80
- ### `download_resume_pdf`
81
- Download your resume as a file.
120
+ **Example:** "Show me my recent applications"
82
121
 
83
- **Example prompts:**
84
- - "Download my resume"
85
- - "Save my optimized resume to a file"
86
- - "Download my ATS-optimized resume to ~/Documents/resume.txt"
122
+ ### `update_application_status`
123
+ Update the status of a job application. Perfect for tracking application progress from email updates (Gmail parsing).
87
124
 
88
125
  **Parameters:**
89
- - `filePath` (optional): Custom path for the file
90
- - `optimized` (optional): If true, downloads the ATS-optimized version
126
+ - `company` (required) - Company name to find the application
127
+ - `jobTitle` (optional) - Job title to match (useful if you applied to multiple roles at same company)
128
+ - `status` (required) - One of: `received`, `interviewing`, `rejected`, `offer`, `accepted`, `declined`
129
+ - `date` (optional) - Date of the status change (YYYY-MM-DD format, defaults to today)
130
+ - `notes` (optional) - Additional context (e.g., "Interview with Sarah scheduled")
131
+
132
+ **Example:** "Update my Interplay application to interviewing status - interview scheduled for January 13th with Stacy Greco"
133
+
134
+ ## Automated Job Search (with Claude for Chrome)
135
+
136
+ The most powerful feature! Use the `/auto_job_search` prompt to have Claude:
137
+
138
+ 1. **Prepare** - Fetch your profile and form data
139
+ 2. **Search** - Navigate to job sites and search for matching roles
140
+ 3. **Evaluate** - Score each job against your profile
141
+ 4. **Present** - Show you good matches (65%+ score) and ask for approval
142
+ 5. **Apply** - Fill out application forms with your data
143
+ 6. **Track** - Keep count of applied/skipped jobs
144
+
145
+ ### Usage
146
+
147
+ In Claude for macOS with Claude for Chrome installed:
148
+
149
+ ```
150
+ /auto_job_search site:linkedin query:"Senior Software Engineer" location:"Remote"
151
+ ```
152
+
153
+ Or simply ask:
154
+ > "Help me search for jobs on LinkedIn and apply to good matches"
155
+
156
+ ### Requirements
157
+ - Claude for macOS
158
+ - Claude for Chrome extension (for browser control)
159
+ - JobSeek MCP configured with your API key
91
160
 
92
161
  ## Full Workflow Example
93
162
 
94
163
  ```
95
- You: "Optimize my resume for ATS"
96
- Claude: [calls optimize_resume] "Here's your optimized resume..."
164
+ You: "Start an automated job search on LinkedIn for product manager roles"
165
+
166
+ Claude: [fetches your profile]
167
+ "I found your profile. You're a Product Manager with 8 years of experience..."
168
+
169
+ Claude: [navigates to LinkedIn, searches, finds a job]
170
+ "Found: Senior Product Manager at Stripe
171
+ Match Score: 87%
172
+ Strengths: Product strategy, data analysis, cross-functional leadership
173
+ Would you like me to apply to this role?"
97
174
 
98
- You: "That looks great! Download it as a file"
99
- Claude: [calls download_resume_pdf] "Saved to ~/Downloads/resume_optimized.txt"
175
+ You: "Yes, apply"
176
+
177
+ Claude: [fills out application form]
178
+ "I've filled out the application:
179
+ - Name: John Doe
180
+ - Email: john@example.com
181
+ - Resume: [attached]
182
+ - Why interested: [drafted response]
183
+
184
+ Ready to submit?"
185
+
186
+ You: "Looks good, submit it"
187
+
188
+ Claude: [submits] "Application submitted! Moving to next job..."
100
189
  ```
101
190
 
102
191
  ## Troubleshooting
103
192
 
104
193
  ### "1 MCP server failed" error
105
194
  - Check `/mcp` in Claude Code for details
106
- - Verify the path to `dist/index.js` is correct
107
- - Make sure you ran `npm run build`
195
+ - Make sure you have a valid API key
196
+ - Try running `npx jobseek-mcp` directly to test
108
197
 
109
198
  ### "Authentication Required" error
110
- - Verify your API key is correct in `~/.claude.json`
199
+ - Verify your API key is correct
111
200
  - Make sure you have a resume uploaded at https://getjobseek.com/dashboard/profile
112
- - Check that JOBSEEK_API_URL is set to `https://getjobseek.com`
113
201
 
114
202
  ## Development
115
203
 
116
204
  ```bash
205
+ git clone https://github.com/shawnmitchell/jobseek.git
206
+ cd jobseek/jobseek-mcp
207
+ npm install
117
208
  npm run dev # Run with tsx (hot reload)
118
209
  npm run build # Build for production
119
210
  npm start # Run production build
120
211
  ```
212
+
213
+ ## License
214
+
215
+ MIT © Shawn Mitchell
package/dist/index.js CHANGED
@@ -1,78 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
2
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
- import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } 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
- import { uploadResumeTool, handleUploadResume } from "./tools/upload-resume.js";
8
- import { launchPadTool, handleLaunchPad } from "./tools/launch-pad.js";
9
- import { allResources, handleReadResource } from "./resources.js";
10
- import { allPrompts, getPromptMessages } from "./prompts.js";
11
- // Configuration
12
- const JOBSEEK_API_URL = process.env.JOBSEEK_API_URL || "https://jobseek-iota.vercel.app";
13
- const JOBSEEK_API_KEY = process.env.JOBSEEK_API_KEY;
14
- // Create the MCP server
15
- const server = new Server({
16
- name: "jobseek-mcp",
17
- version: "0.5.0",
18
- }, {
19
- capabilities: {
20
- tools: {},
21
- resources: {},
22
- prompts: {},
23
- },
24
- });
25
- // List available tools
26
- server.setRequestHandler(ListToolsRequestSchema, async () => {
27
- return {
28
- tools: [
29
- optimizeResumeTool,
30
- downloadResumePdfTool,
31
- uploadResumeTool,
32
- launchPadTool,
33
- ],
34
- };
35
- });
36
- // Handle tool calls
37
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
38
- const { name, arguments: args } = request.params;
39
- switch (name) {
40
- case "optimize_resume":
41
- return handleOptimizeResume(args, JOBSEEK_API_URL, JOBSEEK_API_KEY);
42
- case "download_resume_pdf":
43
- return handleDownloadResumePdf(args, JOBSEEK_API_URL, JOBSEEK_API_KEY);
44
- case "upload_resume":
45
- return handleUploadResume(args, JOBSEEK_API_URL, JOBSEEK_API_KEY);
46
- case "launch_pad":
47
- return handleLaunchPad(args, JOBSEEK_API_URL, JOBSEEK_API_KEY);
48
- default:
49
- throw new Error(`Unknown tool: ${name}`);
50
- }
51
- });
52
- // List available resources
53
- server.setRequestHandler(ListResourcesRequestSchema, async () => {
54
- return {
55
- resources: allResources,
56
- };
57
- });
58
- // Handle resource reads
59
- server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
60
- const { uri } = request.params;
61
- return handleReadResource(uri);
62
- });
63
- // List available prompts
64
- server.setRequestHandler(ListPromptsRequestSchema, async () => {
65
- return {
66
- prompts: allPrompts,
67
- };
68
- });
69
- // Handle prompt requests
70
- server.setRequestHandler(GetPromptRequestSchema, async (request) => {
71
- const { name, arguments: args } = request.params;
72
- return getPromptMessages(name, args || {});
73
- });
74
- // Start the server
3
+ import { createServer } from "./server.js";
75
4
  async function main() {
5
+ const apiKey = process.env.JOBSEEK_API_KEY;
6
+ if (!apiKey) {
7
+ throw new Error("JOBSEEK_API_KEY environment variable is required");
8
+ }
9
+ const server = createServer(apiKey);
76
10
  const transport = new StdioServerTransport();
77
11
  await server.connect(transport);
78
12
  console.error("JobSeek MCP Server running on stdio");
package/dist/prompts.d.ts CHANGED
@@ -30,6 +30,15 @@ export declare const uploadResumePrompt: {
30
30
  required: boolean;
31
31
  }[];
32
32
  };
33
+ export declare const autoJobSearchPrompt: {
34
+ name: string;
35
+ description: string;
36
+ arguments: {
37
+ name: string;
38
+ description: string;
39
+ required: boolean;
40
+ }[];
41
+ };
33
42
  export declare const allPrompts: {
34
43
  name: string;
35
44
  description: string;
package/dist/prompts.js CHANGED
@@ -38,12 +38,34 @@ export const uploadResumePrompt = {
38
38
  }
39
39
  ]
40
40
  };
41
+ export const autoJobSearchPrompt = {
42
+ name: "auto_job_search",
43
+ description: "Automated job search: Navigate job sites, find matching jobs, and help apply. Requires Claude for Chrome browser control.",
44
+ arguments: [
45
+ {
46
+ name: "site",
47
+ description: "Which job site to search: linkedin, indeed, glassdoor, or all",
48
+ required: false
49
+ },
50
+ {
51
+ name: "query",
52
+ description: "Optional: specific job title or keywords to search for",
53
+ required: false
54
+ },
55
+ {
56
+ name: "location",
57
+ description: "Optional: location to search in (e.g., 'Remote', 'New York, NY')",
58
+ required: false
59
+ }
60
+ ]
61
+ };
41
62
  // All prompts
42
63
  export const allPrompts = [
43
64
  launchPadPrompt,
44
65
  optimizeResumePrompt,
45
66
  reviewMatchesPrompt,
46
67
  uploadResumePrompt,
68
+ autoJobSearchPrompt,
47
69
  ];
48
70
  // Generate prompt messages
49
71
  export function getPromptMessages(name, args) {
@@ -94,6 +116,71 @@ export function getPromptMessages(name, args) {
94
116
  }
95
117
  }]
96
118
  };
119
+ case "auto_job_search":
120
+ const site = args.site || "linkedin";
121
+ const searchQuery = args.query || "";
122
+ const location = args.location || "Remote";
123
+ return {
124
+ messages: [{
125
+ role: "user",
126
+ content: {
127
+ type: "text",
128
+ text: `# Automated Job Search Session
129
+
130
+ You are my job search assistant. Using browser control (Claude for Chrome) and the JobSeek MCP tools, help me find and apply to jobs.
131
+
132
+ ## Your Workflow:
133
+
134
+ ### Phase 1: Preparation
135
+ 1. First, use the \`my_profile\` tool to understand my background, skills, and experience
136
+ 2. Use the \`get_form_data\` tool to have my application data ready for form filling
137
+
138
+ ### Phase 2: Search
139
+ 3. Navigate to ${site === 'all' ? 'LinkedIn first, then Indeed' : site} job search
140
+ 4. Search for: ${searchQuery ? `"${searchQuery}"` : 'roles matching my most recent job title from my profile'}
141
+ 5. Filter by location: ${location}
142
+ 6. Filter for jobs posted in the last week if possible
143
+
144
+ ### Phase 3: Evaluate & Present
145
+ For each promising job listing:
146
+ 7. Click to view the full job description
147
+ 8. Read the job details (title, company, requirements, salary if shown)
148
+ 9. Use the \`evaluate_job\` tool to score the match against my profile
149
+ 10. If match score is 65% or higher, present it to me with:
150
+ - Job title and company
151
+ - Match score and key strengths
152
+ - Any concerns or gaps
153
+ - Ask: "Would you like me to apply to this role?"
154
+
155
+ ### Phase 4: Apply (if I approve)
156
+ If I say yes to applying:
157
+ 11. Look for "Apply" or "Easy Apply" button
158
+ 12. Click to start the application
159
+ 13. Use \`get_form_data\` to fill in form fields:
160
+ - Name, email, phone → from my profile
161
+ - Work history → from my experience
162
+ - Education → from my education
163
+ - For text questions, draft thoughtful responses based on my profile
164
+ 14. Before final submission, show me a summary and ask for confirmation
165
+ 15. If I confirm, submit. If not, make any edits I request.
166
+
167
+ ### Phase 5: Track
168
+ 16. After each application (or skip), move to the next job listing
169
+ 17. Keep a running count: "Applied: X, Skipped: Y, Remaining to review: Z"
170
+
171
+ ## Important Rules:
172
+ - ALWAYS ask before submitting an application
173
+ - ALWAYS show me what you're about to submit
174
+ - If you encounter a CAPTCHA or login wall, pause and ask for help
175
+ - If an application requires a resume upload, let me know
176
+ - Skip jobs requiring skills I clearly don't have (score < 50%)
177
+ - Take your time - accuracy is more important than speed
178
+
179
+ ## Ready?
180
+ Let's start! First, fetch my profile, then navigate to the job site.`
181
+ }
182
+ }]
183
+ };
97
184
  default:
98
185
  throw new Error(`Unknown prompt: ${name}`);
99
186
  }
@@ -4,6 +4,12 @@ export declare const resumeResource: {
4
4
  description: string;
5
5
  mimeType: string;
6
6
  };
7
+ export declare const resumeTextResource: {
8
+ uri: string;
9
+ name: string;
10
+ description: string;
11
+ mimeType: string;
12
+ };
7
13
  export declare const applicationsResource: {
8
14
  uri: string;
9
15
  name: string;
package/dist/resources.js CHANGED
@@ -5,10 +5,16 @@ const getApiKey = () => process.env.JOBSEEK_API_KEY;
5
5
  // Resource definitions
6
6
  export const resumeResource = {
7
7
  uri: "jobseek://resume",
8
- name: "Current Resume",
9
- description: "Your resume data stored in JobSeek including skills, experience, education, and summary",
8
+ name: "Current Resume (JSON)",
9
+ description: "Your resume data stored in JobSeek as structured JSON including skills, experience, education, and summary",
10
10
  mimeType: "application/json"
11
11
  };
12
+ export const resumeTextResource = {
13
+ uri: "jobseek://resume/text",
14
+ name: "Current Resume (Text)",
15
+ description: "Your resume formatted as readable plain text - use this to understand the user's background",
16
+ mimeType: "text/plain"
17
+ };
12
18
  export const applicationsResource = {
13
19
  uri: "jobseek://applications",
14
20
  name: "Job Applications",
@@ -18,6 +24,7 @@ export const applicationsResource = {
18
24
  // All resources
19
25
  export const allResources = [
20
26
  resumeResource,
27
+ resumeTextResource,
21
28
  applicationsResource,
22
29
  ];
23
30
  // Fetch resume data
@@ -62,6 +69,91 @@ async function fetchResume() {
62
69
  }, null, 2);
63
70
  }
64
71
  }
72
+ // Format resume data as readable text
73
+ function formatResumeAsText(resume) {
74
+ let text = '';
75
+ // Header
76
+ text += `# ${resume.name || 'Resume'}\n`;
77
+ if (resume.email)
78
+ text += `Email: ${resume.email}\n`;
79
+ if (resume.linkedinUrl)
80
+ text += `LinkedIn: ${resume.linkedinUrl}\n`;
81
+ text += '\n';
82
+ // Summary
83
+ if (resume.summary) {
84
+ text += `## Professional Summary\n${resume.summary}\n\n`;
85
+ }
86
+ // Skills
87
+ if (resume.skills && resume.skills.length > 0) {
88
+ text += `## Skills\n`;
89
+ text += resume.skills.map((skill) => `• ${skill}`).join('\n');
90
+ text += '\n\n';
91
+ }
92
+ // Experience
93
+ if (resume.experience && resume.experience.length > 0) {
94
+ text += `## Work Experience\n`;
95
+ for (const exp of resume.experience) {
96
+ text += `### ${exp.title || 'Position'} at ${exp.company || 'Company'}\n`;
97
+ if (exp.location)
98
+ text += `Location: ${exp.location}\n`;
99
+ if (exp.startDate || exp.endDate || exp.duration) {
100
+ const duration = exp.duration || `${exp.startDate || ''} - ${exp.endDate || 'Present'}`;
101
+ text += `Duration: ${duration}\n`;
102
+ }
103
+ if (exp.description)
104
+ text += `\n${exp.description}\n`;
105
+ if (exp.bullets && exp.bullets.length > 0) {
106
+ text += exp.bullets.map((b) => `• ${b}`).join('\n') + '\n';
107
+ }
108
+ text += '\n';
109
+ }
110
+ }
111
+ // Education
112
+ if (resume.education && resume.education.length > 0) {
113
+ text += `## Education\n`;
114
+ for (const edu of resume.education) {
115
+ text += `### ${edu.degree || 'Degree'}`;
116
+ if (edu.field)
117
+ text += ` in ${edu.field}`;
118
+ text += '\n';
119
+ if (edu.institution || edu.school)
120
+ text += `Institution: ${edu.institution || edu.school}\n`;
121
+ if (edu.year || edu.graduationDate)
122
+ text += `Year: ${edu.year || edu.graduationDate}\n`;
123
+ text += '\n';
124
+ }
125
+ }
126
+ return text;
127
+ }
128
+ // Fetch resume as formatted text
129
+ async function fetchResumeText() {
130
+ const apiKey = getApiKey();
131
+ const apiUrl = getApiUrl();
132
+ if (!apiKey) {
133
+ return "Error: No API key configured. Get your API key at " + apiUrl + "/dashboard/api-keys";
134
+ }
135
+ try {
136
+ const response = await fetch(`${apiUrl}/api/resumes/current`, {
137
+ headers: {
138
+ "Authorization": `Bearer ${apiKey}`,
139
+ },
140
+ });
141
+ if (!response.ok) {
142
+ if (response.status === 401) {
143
+ return "Error: Invalid API key. Generate a new key at " + apiUrl + "/dashboard/api-keys";
144
+ }
145
+ if (response.status === 404) {
146
+ return "Error: No resume found. Upload a resume first using the upload_resume tool.";
147
+ }
148
+ return `Error: Failed to fetch resume (status ${response.status})`;
149
+ }
150
+ const data = await response.json();
151
+ return formatResumeAsText(data);
152
+ }
153
+ catch (error) {
154
+ return `Error: Network error - ${error.message}`;
155
+ }
156
+ }
65
157
  // Fetch applications data
66
158
  async function fetchApplications() {
67
159
  const apiKey = getApiKey();
@@ -108,6 +200,14 @@ export async function handleReadResource(uri) {
108
200
  text: await fetchResume()
109
201
  }]
110
202
  };
203
+ case "jobseek://resume/text":
204
+ return {
205
+ contents: [{
206
+ uri,
207
+ mimeType: "text/plain",
208
+ text: await fetchResumeText()
209
+ }]
210
+ };
111
211
  case "jobseek://applications":
112
212
  return {
113
213
  contents: [{
@@ -0,0 +1,20 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ export declare function createServer(apiKey: string): Server<{
3
+ method: string;
4
+ params?: import("zod").objectOutputType<{
5
+ _meta: import("zod").ZodOptional<import("zod").ZodObject<{
6
+ progressToken: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodString, import("zod").ZodNumber]>>;
7
+ }, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
8
+ progressToken: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodString, import("zod").ZodNumber]>>;
9
+ }, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
10
+ progressToken: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodString, import("zod").ZodNumber]>>;
11
+ }, import("zod").ZodTypeAny, "passthrough">>>;
12
+ }, import("zod").ZodTypeAny, "passthrough"> | undefined;
13
+ }, {
14
+ method: string;
15
+ params?: import("zod").objectOutputType<{
16
+ _meta: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
17
+ }, import("zod").ZodTypeAny, "passthrough"> | undefined;
18
+ }, import("zod").objectOutputType<{
19
+ _meta: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
20
+ }, import("zod").ZodTypeAny, "passthrough">>;