Serveur MCP

jobctl

io.github.DmytroRybka/jobctl
Productivité Public et accessible MCP 2025-11-25

Ce que fait ce MCP

Tracks job applications, interviews, deadlines, notes, analyses, resumes, cover letters, and interview materials.

add_application
Add application
Track a new job application. Pass either a single `raw` line — `add_application({raw: "Bosch, Tech Lead, prio A, due friday, remote, via LinkedIn"})` — or structured fields (`company` and `role` required then). Returns the created application and possible-duplicate warnings; if duplicates are listed, tell the user instead of creating again.
Schéma d’entrée
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'properties': {'raw': {'type': 'string', 'description': 'Free-form line: "Company, Role, prio A|B|C, due <date>, remote|hybrid|onsite, via <source>, https://…, in <location>, applied <date>"'}, 'url': {'type': 'string', 'description': 'Link to the job posting'}, 'role': {'type': 'string'}, 'remote': {'enum': ['remote', 'hybrid', 'onsite', 'unknown'], 'type': 'string'}, 'source': {'type': 'string', 'description': 'LinkedIn, referral, recruiter, Easy Apply…'}, 'status': {'enum': ['started_apply', 'waiting_referral', 'applied', 'waiting', 'interview', 'offer', 'accepted', 'rejected', 'no_response', 'on_hold', 'withdrawn', 'archived'], 'type': 'string'}, 'company': {'type': 'string'}, 'location': {'type': 'string'}, 'priority': {'enum': ['A', 'B', 'C'], 'type': 'string', 'description': 'A = top priority'}, 'applied_at': {'type': 'string', 'description': 'ISO date YYYY-MM-DD'}, 'cv_variant': {'type': 'string', 'description': 'Which CV was sent: DE, EN, AI-focused…'}, 'match_notes': {'type': 'string', 'description': 'Markdown match assessment: why the candidate fits this role — strengths vs requirements, gaps, level/salary advice, process notes. Save your vacancy analysis here so it is not lost; shown as an expandable section in the dashboard.'}, 'next_action': {'type': 'string', 'description': 'e.g. "follow-up", "thank-you email"'}, 'remote_note': {'type': 'string', 'description': 'e.g. "2 days office"'}, 'salary_asked': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': -9007199254740991, 'description': 'What the candidate asked for — yearly gross EUR as a plain number, e.g. 110000'}, 'salary_range': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': -9007199254740991, 'description': 'Posting salary range upper bound — yearly gross EUR, plain number'}, 'next_action_due': {'type': 'string', 'description': 'ISO date YYYY-MM-DD'}, 'salary_range_min': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': -9007199254740991, 'description': 'Posting salary range lower bound — yearly gross EUR, plain number'}, 'next_interview_at': {'type': 'string', 'description': 'ISO datetime, e.g. 2026-07-20T14:00:00+02:00'}}}
add_note
Add note
Append a free-text note to an application timeline — recruiter call summaries, interview instructions, pasted messages. Multiline markdown is fine. Example: `add_note({application_id: "…", text: "Recruiter: team of 5, on-call rotation, offer range 85-95k"})`.
Schéma d’entrée
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['application_id', 'text'], 'properties': {'text': {'type': 'string', 'minLength': 1}, 'application_id': {'type': 'string', 'format': 'uuid', 'pattern': '^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$'}}}
attach_analysis
Attach company analysis
Attach a markdown company analysis (research you produced) to an application. Single document per application — a new call REPLACES the previous one. Max 100000 bytes (~100 KB) of utf-8. The user reads it in the dashboard, e.g. before an interview. Example: `attach_analysis({application_id: "…", markdown: "# Bosch\n\n## Culture…"})`.
Destructif
Schéma d’entrée
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['application_id', 'markdown'], 'properties': {'markdown': {'type': 'string', 'minLength': 1, 'description': 'The analysis as markdown'}, 'application_id': {'type': 'string', 'format': 'uuid', 'pattern': '^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$'}}}
attach_file
Attach CV or cover letter
Attach or replace a file on an application so the user sees it in the dashboard: a CV/resume (kind: 'cv') or a cover letter (kind: 'cover_letter'). Pass the file bytes as base64 in data_base64. One file per (application, kind) - a new call REPLACES the previous one. Max ~5 MB; pdf/doc/docx/txt/md (MIME is inferred from the filename if you omit it). Call this whenever you generate a tailored CV or cover letter for an application. Example: `attach_file({application_id: "…", kind: "cv", filename: "CV_Cursor.pdf", data_base64: "JVBERi0…"})`.
Destructif
Schéma d’entrée
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['application_id', 'kind', 'filename', 'data_base64'], 'properties': {'kind': {'enum': ['cv', 'cover_letter'], 'type': 'string'}, 'mime': {'type': 'string', 'description': 'Optional; inferred from the filename extension when omitted'}, 'filename': {'type': 'string', 'maxLength': 300, 'minLength': 1}, 'data_base64': {'type': 'string', 'minLength': 1, 'description': 'Base64-encoded file bytes'}, 'application_id': {'type': 'string', 'format': 'uuid', 'pattern': '^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$'}}}
attach_interview_file
Attach interview prep file
Attach prep material to a specific interview so the user sees it next to that round in the dashboard: the prep document you wrote, the job description, a deck, notes the company sent. Max 3 files per interview, 20000000 bytes (20 MB) each; pass the bytes as base64. Get interview ids from get_application. Example: `attach_interview_file({application_id: "…", interview_id: "…", filename: "prep-round2.md", data_base64: "IyBQcmVw…"})`.
Schéma d’entrée
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['application_id', 'interview_id', 'filename', 'data_base64'], 'properties': {'mime': {'type': 'string', 'description': 'Optional; inferred from the filename extension when omitted'}, 'filename': {'type': 'string', 'maxLength': 300, 'minLength': 1}, 'data_base64': {'type': 'string', 'minLength': 1, 'description': 'Base64-encoded file bytes'}, 'interview_id': {'type': 'string', 'format': 'uuid', 'pattern': '^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$'}, 'application_id': {'type': 'string', 'format': 'uuid', 'pattern': '^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$'}}}
get_application
Get application
Full detail of one application: all fields, contacts, recent timeline events, and whether a company analysis is attached (fetch it via the dashboard or attach_analysis to replace).
Lecture seule
Schéma d’entrée
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['id'], 'properties': {'id': {'type': 'string', 'format': 'uuid', 'pattern': '^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$'}}}
get_due
Due actions
What is burning today: applications with next_action_due today or overdue. Call this when the user asks "what should I do today?" about their job search.
Lecture seule
Schéma d’entrée
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'properties': {}}
get_planned
Planned schedule
What is actually SCHEDULED: interviews with their time, attendees and meeting links, plus the actions falling due, for today, tomorrow, or the next seven days. Use this whenever the user asks what is planned, what the day or week looks like, or before proposing a time to anyone — get_due only knows action deadlines and is blind to booked interviews. Example: `get_planned({range: "tomorrow"})`.
Lecture seule
Schéma d’entrée
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'properties': {'range': {'enum': ['today', 'tomorrow', 'week'], 'type': 'string', 'description': 'today (default), tomorrow, or week (today plus the next 6 days)'}}}
list_applications
List applications
List job applications. Filter by view (active = default working set, archive = rejected/withdrawn/no-response), status list, priority, or free-text search in company/role. Example: `list_applications({view: "active"})`, `list_applications({q: "bosch"})`.
Lecture seule
Schéma d’entrée
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'properties': {'q': {'type': 'string', 'description': 'Search in company/role'}, 'view': {'enum': ['active', 'interviewing', 'waiting', 'archive', 'all'], 'type': 'string'}, 'limit': {'type': 'integer', 'maximum': 500, 'minimum': 1}, 'status': {'type': 'string', 'description': 'Comma-separated: started_apply, waiting_referral, applied, waiting, interview, offer, accepted, rejected, no_response, on_hold, withdrawn, archived'}, 'priority': {'enum': ['A', 'B', 'C'], 'type': 'string'}}}
log_interview
Log interview
Log an interview for an application (max 10 per application): when it takes place, its status (planned or done), who attends (each with an optional profile link), related links (prep materials the company sent, meeting URL), and a short recap of what was discussed. Also keeps the application's next-interview date in sync. Example: `log_interview({application_id: "…", scheduled_at: "2026-07-20T14:00:00+02:00", status: "planned", attendees: [{name: "Anna Weber (HR)", url: "https://linkedin.com/in/annaweber"}], links: [{label: "Prep materials", url: "https://company.com/interview-prep"}], recap: "System design round"})`.
Schéma d’entrée
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['application_id', 'scheduled_at'], 'properties': {'links': {'type': 'array', 'items': {'type': 'object', 'required': ['url'], 'properties': {'url': {'type': 'string'}, 'label': {'type': 'string', 'description': 'e.g. "Prep materials", "Meeting link"'}}}, 'description': 'Related links: prep materials, meeting URL, docs'}, 'recap': {'type': 'string', 'description': 'Short recap of what was discussed'}, 'status': {'enum': ['planned', 'done'], 'type': 'string', 'description': 'planned (default) or done'}, 'attendees': {'type': 'array', 'items': {'type': 'object', 'required': ['name'], 'properties': {'url': {'type': 'string', 'description': 'Profile link, e.g. LinkedIn'}, 'name': {'type': 'string'}}}, 'description': 'Who attends, each with an optional profile link'}, 'scheduled_at': {'type': 'string', 'description': 'ISO datetime with offset, e.g. 2026-07-20T14:00:00+02:00'}, 'application_id': {'type': 'string', 'format': 'uuid', 'pattern': '^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$'}}}
update_application
Update application
Update fields of an application (get the id from list_applications). Status changes are logged to the timeline automatically. Example: `update_application({id: "…", status: "interview", next_action: "prepare system design", next_action_due: "2026-07-20"})`.
Schéma d’entrée
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['id'], 'properties': {'id': {'type': 'string', 'format': 'uuid', 'pattern': '^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$'}, 'url': {'type': 'string', 'description': 'Link to the job posting'}, 'role': {'type': 'string'}, 'remote': {'enum': ['remote', 'hybrid', 'onsite', 'unknown'], 'type': 'string'}, 'source': {'type': 'string', 'description': 'LinkedIn, referral, recruiter, Easy Apply…'}, 'status': {'enum': ['started_apply', 'waiting_referral', 'applied', 'waiting', 'interview', 'offer', 'accepted', 'rejected', 'no_response', 'on_hold', 'withdrawn', 'archived'], 'type': 'string'}, 'company': {'type': 'string'}, 'location': {'type': 'string'}, 'priority': {'enum': ['A', 'B', 'C'], 'type': 'string', 'description': 'A = top priority'}, 'applied_at': {'type': 'string', 'description': 'ISO date YYYY-MM-DD'}, 'cv_variant': {'type': 'string', 'description': 'Which CV was sent: DE, EN, AI-focused…'}, 'match_notes': {'type': 'string', 'description': 'Markdown match assessment: why the candidate fits this role — strengths vs requirements, gaps, level/salary advice, process notes. Save your vacancy analysis here so it is not lost; shown as an expandable section in the dashboard.'}, 'next_action': {'type': 'string', 'description': 'e.g. "follow-up", "thank-you email"'}, 'remote_note': {'type': 'string', 'description': 'e.g. "2 days office"'}, 'salary_asked': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': -9007199254740991, 'description': 'What the candidate asked for — yearly gross EUR as a plain number, e.g. 110000'}, 'salary_range': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': -9007199254740991, 'description': 'Posting salary range upper bound — yearly gross EUR, plain number'}, 'next_action_due': {'type': 'string', 'description': 'ISO date YYYY-MM-DD'}, 'salary_range_min': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': -9007199254740991, 'description': 'Posting salary range lower bound — yearly gross EUR, plain number'}, 'next_interview_at': {'type': 'string', 'description': 'ISO datetime, e.g. 2026-07-20T14:00:00+02:00'}}}
Ajouté
get_application
17 September 2026 12:41
Ajouté
attach_interview_file
17 September 2026 12:41
Ajouté
attach_file
17 September 2026 12:41
Ajouté
attach_analysis
17 September 2026 12:41
Ajouté
get_planned
17 September 2026 12:41
Ajouté
get_due
17 September 2026 12:41
Ajouté
log_interview
17 September 2026 12:41
Ajouté
add_note
17 September 2026 12:41
Ajouté
update_application
17 September 2026 12:41
Ajouté
list_applications
17 September 2026 12:41
Ajouté
add_application
17 September 2026 12:41