Skip to main content
Glama
firyomaefx

Job Application MCP

by firyomaefx

Job Application MCP

A local-first, open-source job application assistant built on the Model Context Protocol.

Analyse jobs · Match against your CV · Tailor documents · Preview forms · Track applications — all on your machine, nothing uploaded, submission stays in your hands.

License: AGPL-3.0-or-later Node TypeScript Status: Alpha


Table of contents


Related MCP server: jobjourney-claude-plugin

Why

Job hunting is repetitive: read a posting, check it against your CV, tweak a cover letter, fill the same fields on yet another form, and remember where you applied.

Job Application MCP turns that into a set of tools any MCP-compatible AI client (Claude Desktop, Claude Code, others) can drive for you — while keeping you in control:

  • Your CV and applications never leave your machine in the free core.

  • The assistant prepares and previews; you review and submit.

  • It's open source under AGPL-3.0, so you can audit exactly what it does.

ℹ️ This repository is the free community core described in BUSINESS_PROPOSAL.md. Paid AI/cloud/business services are intentionally out of scope here.


What it does (free core)

Capability

Description

🧩 Local MCP server

A stdio server you connect from any MCP client.

👤 Candidate profile

One local profile: skills, headline, contact, summary.

📄 CV parsing

Parse PDF / DOCX / TXT locally — no upload, no network.

🔍 Job analysis

Paste a job description; get extracted key skills + a short summary.

🎯 Match scoring

Heuristic 0–100 score with matched / missing skills.

✂️ Tailoring suggestions

Structural advice on which skills to surface or add.

✍️ Answer drafting

A template starter for screening questions (you rewrite it).

📝 Form autofill preview

Maps your profile onto form fields — preview only, never submits.

📊 Application tracking

Local SQLite store with a status pipeline (draft → submitted → offer…).

What it deliberately does NOT do

  • No automated submission. You submit manually on the employer's site.

  • No automation of LinkedIn or Indeed — their Terms of Service prohibit it. Paste the description and complete those by hand.

  • No CAPTCHA solving, 2FA bypass, or login recovery — it pauses for manual action.

  • No AI rewriting, cloud sync, or premium adapters — those are future Pro/cloud services.

These aren't missing features; they're the design.


How it works

┌─────────────────┐      stdio (JSON-RPC)      ┌──────────────────────┐
│  MCP client     │  ◀────────────────────────▶│  job-application-mcp │
│  (Claude, etc.) │                             │  (this server)       │
└─────────────────┘                             └──────────┬───────────┘
                                                           │ reads / writes
                                                           ▼
                                                ┌──────────────────────┐
                                                │  local SQLite DB     │
                                                │  + parsed CV text    │
                                                │  (JOB_MCP_DATA_DIR)  │
                                                └──────────────────────┘

You (or an AI client) call tools. Each tool does a small, auditable thing and returns structured JSON. Tools that touch external sites do not exist; everything operates on data you provide and store locally.


Quick start

Requirements

  • Node.js ≥ 22 (uses the built-in node:sqlite — no native compilation needed)

  • npm

Install & build

git clone https://github.com/<your-user>/job-application-mcp.git
cd job-application-mcp
npm install
npm run build      # -> dist/

Verify it works

npm test           # full unit/integration test suite
node dist/cli/cli.js --help

Connect an MCP client

Build the project, then add the server to your MCP client's config.

Claude Desktop / Claude Code

{
  "mcpServers": {
    "job-application-mcp": {
      "command": "node",
      "args": ["/ABSOLUTE/path/to/job-application-mcp/dist/src/index.js"]
    }
  }
}

⚠️ Use an absolute path — MCP clients launch the server from their own working directory, not yours.

Run directly (no client)

node dist/cli/cli.js serve      # equivalent to: node dist/src/index.js

The server speaks JSON-RPC over stdio. See A full example flow for raw request examples.


Tools reference

All 23 tools are local and synchronous-ish (CV parsing and AI calls are async). Arguments are validated with zod; the MCP client receives a JSON Schema for each. The 13 free-core tools (profile → autofill) are the everyday workflow. The credits/Pro and admin/business tools are wire-ready seams for the hosted Pro service (see Business model); they run locally today and do not require any subscription.

Profile

Tool

Args

Returns

get_profile

The local candidate profile (auto-created on first call).

update_profile

full_name?, email?, phone?, location?, headline?, summary?, skills?, experience_years?

Updated profile. skills replaces the list.

CVs

Tool

Args

Returns

parse_cv

file_path? or text, label?

Parsed CV stored locally; detected skills + a short preview.

list_cvs

All stored CVs.

parse_cv supports .pdf (pdf-parse), .docx (mammoth), and plain text. If you pass text, it's stored as-is. file_path must be inside the data dir (or a folder listed in JOB_MCP_CV_DIRS) — paths outside the allow-list are rejected, so an MCP client can't read arbitrary files.

Jobs

Tool

Args

Returns

analyze_job

description (≥20 chars), title?, company?, url?, store?=true

Extracted keywords + summary; stored as a job (unless store: false).

get_job

job_id

A stored job with its keywords.

Matching & prep

Tool

Args

Returns

match_cv

job_id, cv_id, save?=false

0–100 score, matched/missing/extra skills; optionally creates a draft application.

tailor_cv

job_id, cv_id

Tailored CV draft. With your own AI API key (AI_API_KEY): AI-rewritten prose; without: heuristic local draft.

cover_letter

job_id, cv_id

Cover-letter draft (AI with your own key, else heuristic).

draft_answer

question, cv_id?, job_id?

Screening-answer draft (AI with your own key, else heuristic template). Always review.

AI tools and your own key. tailor_cv, cover_letter, and draft_answer use a real AI provider when you set AI_PROVIDER (openai or anthropic) and AI_API_KEY — on the Free or Pro plan. Without a key they fall back to a local heuristic. The Pro hosted path additionally debits an AI credit; using your own key is never debited. See Business model.

Applications & forms

Tool

Args

Returns

save_application

job_id, cv_id?, match_score?, tailored_cv_text?, cover_letter?, answers?, notes?

A draft application record. Does not submit.

list_applications

status?

Application records (optionally filtered by status).

update_application_status

application_id, status, notes?

Updates status; sets submitted_at when status is submitted.

autofill_form

application_id, form_fields?

A preview mapping of profile data onto form fields. Nothing is submitted.

Status pipeline: draft → ready → submitted → interview → offer → rejected → closed.

Analytics & status

Tool

Args

Returns

application_analytics

Counts by status, average match score, recent activity. Pro entitlement adds an advanced breakdown.

status

Server/plan/credits snapshot (plan label, AI credit balance, active features).

Credits & Pro (wire-ready seams)

Tool

Args

Returns

credits

Current AI credit balance + recent ledger entries.

topup_credits

code, amount

Apply an AI-credit top-up code (idempotent per code). Admin/test.

grant_monthly_credits

amount?

Grant the monthly AI allowance (idempotent per calendar month). Admin/test.

Admin / business (wire-ready seams)

Tool

Args

Returns

admin_create_account

email, name, plan?

Create a business account.

admin_add_candidate

account_id, profile_id, role?

Add a candidate/coach to an account.

admin_list_team

account_id

List an account's team members.

admin_usage_report

account_id

Usage summary for an account.


A full example flow

Here's a complete session using the stdio JSON-RPC interface directly. (An MCP client like Claude does this for you in natural language.)

node dist/src/index.js

Send these lines (one JSON-RPC object per line):

// 1. handshake
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"demo","version":"0"}}}
{"jsonrpc":"2.0","method":"notifications/initialized"}

// 2. set up your profile
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"update_profile","arguments":{"full_name":"Ada Lovelace","headline":"Backend Engineer","skills":["python","sql","aws","docker"]}}}

// 3. analyse + store a job (paste the description text)
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"analyze_job","arguments":{"title":"Backend Engineer","company":"Acme Co","description":"We need a backend engineer with Python, SQL, and AWS to build data pipelines. PostgreSQL and Docker are a plus."}}}

// 4. parse a CV (file path or pasted text)
{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"parse_cv","arguments":{"label":"main-cv","text":"Ada Lovelace — Backend Engineer. Python, SQL, AWS, PostgreSQL. Built ETL pipelines..."}}}

// 5. score the CV against the job (save=true creates a draft application)
{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"match_cv","arguments":{"job_id":1,"cv_id":1,"save":true}}}

// 6. preview autofill for a form (no submission)
{"jsonrpc":"2.0","id":6,"method":"tools/call","params":{"name":"autofill_form","arguments":{"application_id":1,"form_fields":[{"name":"name","label":"Full name"},{"name":"email","label":"Email"},{"name":"salary","label":"Salary expectation"}]}}}

// 7. after you submit on the employer's site, mark it submitted
{"jsonrpc":"2.0","id":7,"method":"tools/call","params":{"name":"update_application_status","arguments":{"application_id":1,"status":"submitted"}}}

Step 6 returns a mapping where the salary field is flagged requires_user_review: true — sensitive fields always need your eyes.


Configuration

All config is via environment variables. The free core needs none of them.

Variable

Default

Purpose

JOB_MCP_DATA_DIR

./data

Where the SQLite DB and parsed data live.

JOB_MCP_CV_DIRS

Extra folders parse_cv may read from (OS path separator: ; on Windows, : elsewhere).

JOB_MCP_HTTP_PORT

8787

Port for the local HTTP bridge (loopback only).

JOB_MCP_HTTP_TOKEN

Optional bearer token the bridge requires on /call.

The following enable your own AI key (works on Free or Pro) and are placeholders for future hosted Pro/cloud services (see .env.example):

Variable

Purpose

AI_PROVIDER / AI_API_KEY

openai or anthropic + your own key → real AI drafts for tailor_cv / cover_letter / draft_answer. Keys entered in the desktop UI are session-only; use the environment for restart persistence.

AI_MODEL / AI_BASE_URL

Optional model + base URL override (e.g. an OpenAI-compatible endpoint).

JOB_MCP_LICENCE_SERVER

Pro licence activation endpoint (hosted service).

SUPABASE_URL / SUPABASE_ANON_KEY

Cloud sync & auth (Pro, hosted).


Project layout

job-application-mcp/
├── src/
│   ├── index.ts           # stdio MCP server entrypoint
│   ├── http.ts            # local HTTP bridge entrypoint (127.0.0.1)
│   ├── server.ts          # server factory + tool registry
│   ├── tools/             # task and compatibility MCP tools
│   │   ├── types.ts       # ToolDef / AnyTool / result helpers
│   │   ├── profile.ts     # get/update_profile
│   │   ├── cv.ts          # parse_cv, list_cvs
│   │   ├── job.ts         # analyze_job, get_job
│   │   ├── matching.ts    # match_cv, tailor_cv, cover_letter, draft_answer
│   │   ├── application.ts # save/list/update_application, autofill_form
│   │   ├── analytics.ts   # application_analytics, status
│   │   ├── pro.ts         # credits, topup_credits, grant_monthly_credits
│   │   └── admin.ts       # admin_create_account / add_candidate / list_team / usage_report
│   ├── store/             # SQLite layer (node:sqlite)
│   │   ├── db.ts          # open / migrate / close / reset
│   │   ├── profile.ts     # profile CRUD
│   │   └── applications.ts# cv / job / application CRUD
│   ├── cv/parser.ts       # PDF / DOCX / TXT parsing (path allow-listed)
│   ├── ai/                # provider abstraction (mock / openai / anthropic)
│   ├── licence/           # entitlement tokens + credits + referrals
│   ├── payments/          # payment-webhook seam (server-side, not in clients)
│   ├── sync/              # cloud-sync seam (local no-op until Pro)
│   ├── features.ts        # feature gating (plan + credits + AI mode)
│   └── lib/
│       ├── types.ts       # domain types
│       ├── crypto.ts      # HMAC-SHA256 + constant-time compare
│       ├── entitlement.ts # Entitlement value type + plan limits
│       └── scoring.ts     # keyword extraction + match scoring (pure)
├── cli/cli.ts             # human CLI: job-mcp serve | serve:http | --help
├── extension/             # Chrome MV3 extension (form capture → preview)
├── desktop/               # Electron wrapper UI (launches the bridge)
├── .github/workflows/ci.yml  # build + typecheck + test + stdio smoke
├── .github/workflows/daily-effectiveness.yml # scheduled regression gate
├── evals/                 # synthetic effectiveness fixtures + thresholds
├── tests/                 # node:test suite
├── BUSINESS_PROPOSAL.md   # open-core + paid-service model
├── CLAUDE.md              # guide for Claude Code working in this repo
└── LICENSE                # AGPL-3.0-or-later

Companion apps

The free core is the stdio MCP server above. Two optional companions live in this repo and talk to a local HTTP bridge (same tools, loopback only):

HTTP bridge

npm run serve:http      # 127.0.0.1:8787 by default

Endpoints: GET /health, POST /call with {"name","arguments"}. Optional bearer auth via JOB_MCP_HTTP_TOKEN. Source: src/http.ts.

Chrome extension — extension/

Captures form fields on a career page and asks the bridge to preview an autofill mapping. Never submits. Load it unpacked from extension/. See extension/README.md.

Desktop app — desktop/

An Electron wrapper that launches the bridge and shows a dashboard (status, profile, applications). Run with cd desktop && npm install && npm start. See desktop/README.md.

Both companions are read/preview only and reach only 127.0.0.1. They inherit the project's no-submission, no-LinkedIn/Indeed-automation rules.


Develop

npm run build       # tsc -> dist/
npm run typecheck   # tsc --noEmit
npm test            # node --test (scoring + store)
npm run eval:effectiveness # synthetic safety/effectiveness report
npm run dev         # tsc --watch

GitHub also runs the deterministic effectiveness gate daily at 01:17 UTC (09:17 Malaysia time). It uses synthetic fixtures, makes no model calls, and never changes code or user data automatically. See docs/EFFECTIVENESS.md for metrics and limits.

Adding a tool

  1. Create src/tools/<name>.ts exporting a ToolDef<z.ZodObject<…>>.

  2. Register it in src/tools/index.ts (add to the tools array).

  3. Add a test in tests/ if it has pure logic worth covering.

Tools receive parsed, typed input and return a ToolResult ({ summary, data?, notes? }). The server handles JSON Schema generation, validation, and error wrapping for you.


How matching works

Matching is a pure, heuristic function in src/lib/scoring.ts — no AI, no network.

  1. Extract keywords from the job description: tokenize, drop stopwords and filler verbs, weight tech hints and frequent terms.

  2. Score: for each job keyword, check the candidate's curated profile skills plus skills detected in the CV text. Stem-ish matches count (e.g. reactreactjs).

  3. Result: score (0–100), matched, missing, extra, and notes (e.g. "Below 50% — consider tailoring or skipping").

Formula: score = matched/total × 100 plus a small, capped breadth bonus for extra skills (only when there are job keywords). It's intentionally simple and auditable — a baseline you can replace with the Pro AI scorer later.


Privacy & data

  • Local-first by default. CVs, profile, and applications live in JOB_MCP_DATA_DIR (default ./data), which is gitignored. Ollama and the heuristic stay local; configuring OpenAI, Anthropic, an update feed, or a licence endpoint enables the corresponding outbound request.

  • Provider keys are not stored in SQLite. Desktop-entered keys last only for the bridge process; environment variables can provide restart persistence.

  • No PII in logs. CV text and personal fields aren't logged at info level.

  • Sensitive fields are flagged. autofill_form marks salary, authorization, gender, disability, and consent fields as requires_user_review: true.

Windows alpha installer

GitHub prereleases provide a standalone x64 one-click Setup executable. The installer bundles the local bridge, so a separate Node.js installation is not required. Version 0.4.2 is intentionally unsigned alpha software: Windows SmartScreen may display a warning. Verify the downloaded file against SHA256SUMS.txt from the same GitHub prerelease before running it. This is not a production-ready hosted or paid release.

  • You can wipe everything by deleting the data directory.


Roadmap / Pro upgrade

The free core is the foundation. BUSINESS_PROPOSAL.md describes the open-core model. Likely next steps:

  • Free core: match_cv + tailor_cv integration test through the MCP layer; richer keyword extraction (skill taxonomy).

  • Distribution: Windows installer via GitHub Releases; Chrome Web Store extension for form-field capture.

  • Pro (separate hosted services): AI CV tailoring & cover letters, encrypted cloud backup, multi-device sync, maintained site adapters, application analytics.

  • Business: multi-candidate accounts, team dashboards, white-label.

Tool handlers are written so a Pro upgrade can slot in without changing the public tool surface — e.g. tailor_cv returns heuristic suggestions today and could call an AI service tomorrow.


Limitations

  • Keyword extraction is heuristic and will miss or mis-rank some skills. Confirm against the source posting before relying on a match score.

  • No browser automation. Form fields must be supplied to autofill_form (manually or, later, via the extension). The tool previews; it doesn't fill.

  • LinkedIn / Indeed: analysis-only, paste the description, submit manually.

  • Alpha status: APIs and stored schemas may change before 1.0.


License

Copyright © 2026 Job Application MCP contributors.

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. See LICENSE.

A separate commercial licence is available for embedding without AGPL obligations — see BUSINESS_PROPOSAL.md §8.


Contributing

Issues and PRs welcome. By contributing you agree your contributions will be licensed under the same AGPL-3.0-or-later terms.

Please keep the free core fully local and free — no feature in this repo may gate a free-core capability behind a paid/network service. See CLAUDE.md for the conventions used in this codebase.

Related MCP Connectors

Related MCP Servers