Skip to main content
Glama
Mzaq1559

Job Application MCP

by Mzaq1559

License: Commercial Python 3.12+ Version: 1.0.0

Job Application MCP

A remote MCP server that turns an AI assistant into a structured job-application workspace. It manages your profile, resumes, job analysis, application tracking, and interview history, with Claude Web as the primary documented client.

The project is designed as a serious, extensible platform rather than a one-off personal script. The core repository is source-available for learning and contribution, while commercial use, hosted use, and use inside paid products require a separate commercial license. See LICENSE.

It does not scrape or automate any job platform — job descriptions are supplied by the user (pasted or typed), and the final submission is always done by the user, manually.

v1.0.0: the core server is implemented and deployed to Azure Container Apps with 21 MCP tools, Streamable HTTP, OAuth 2.1 resource-server authentication, Docker, GitHub Actions CI/CD, and Auth0 integration. The public deployment is configured for Claude Web custom connectors.

Table of contents

Related MCP server: resume-tailor-mcp-server

Why no scraping or automation

Platforms like LinkedIn explicitly prohibit automated scraping and bot-driven activity in their Terms of Service, and have pursued account suspensions and legal action over it. This project deliberately stays on the right side of that line: it only ever works from information you provide directly (pasted job descriptions, uploaded resumes), and it never logs into, scrapes, or automates form submission on a third-party site. You stay in control of every application you actually send.

Features

  • Profile management — one structured profile (education, skills, projects, experience, research interests, certifications, achievements) that every other tool reads from. Nothing about you is hard-coded into the source.

  • Resume/CV management — upload multiple resumes (PDF, DOCX, TXT, MD), keep multiple versions of each, and get a transparent, keyword-based recommendation for which resume fits a given job description.

  • Job tracking — save jobs with full description/requirements text, automatic duplicate detection (by URL, then by company+title), and a status workflow (saved → analyzing → ready_to_apply → applied → screening → interview → offer, with rejected/withdrawn reachable from most states).

  • Transparent job analysis — literal keyword comparison between a job's text and your stored skills. No fabricated "hireability score" — matches and gaps are reported plainly so you can judge fit yourself.

  • Application tracking — persistent records per job, full event history, and duplicate-application prevention. Nothing is ever marked applied except in response to you telling Claude you submitted it — the tools never submit anything themselves.

  • Interview tracking — scheduled interviews, prep/post-interview notes, linked to the application they belong to.

Architecture

The system is split into transport/authentication, MCP tools, business services, persistence, and external identity infrastructure so new clients and features can be added without rewriting the core domain logic.

flowchart TB
    CLIENT["AI Client<br/>Claude Web / MCP Client"]
    CLIENT -->|"Streamable HTTP + OAuth 2.1"| SERVER["Remote MCP Server<br/>Starlette + MCP SDK"]

    SERVER --> AUTH["OAuth 2.1 Resource Server<br/>JWT/JWKS validation"]
    AUTH --> AUTH0["Auth0"]

    SERVER --> TOOLS["MCP Tool Layer<br/>21 tools"]
    TOOLS --> SERVICES["Application Services"]

    SERVICES --> PROFILE["Profile Service"]
    SERVICES --> RESUME["Resume / CV Service"]
    SERVICES --> JOB["Job Service<br/>duplicate detection + analysis"]
    SERVICES --> APP["Application Service<br/>pipeline + event history"]
    SERVICES --> INTERVIEW["Interview Service"]

    PROFILE --> DB["SQLAlchemy Async"]
    RESUME --> DB
    JOB --> DB
    APP --> DB
    INTERVIEW --> DB

    DB --> SQLITE["SQLite<br/>development"]
    DB --> POSTGRES["PostgreSQL<br/>production"]

    SERVER --> FILES["Resume File Storage"]

Design principles

  • AI-client agnostic: MCP is the interface; Claude Web is the first documented client, not a hard dependency of the domain layer.

  • User-controlled applications: the server prepares and tracks applications but never submits them to third-party job platforms.

  • Transparent analysis: current job/resume matching is deliberately inspectable keyword-based logic rather than an opaque hiring score.

  • Authentication at the edge: OAuth 2.1 protects the remote MCP endpoint while application services remain focused on business logic.

  • Extensible domain services: contributors can add deeper AI analysis, cover-letter generation, integrations, migrations, durable storage, and other capabilities without replacing the existing architecture.

MCP tools

Domain

Tools

Profile

profile_get, profile_update, profile_summary

Resume

resume_list, resume_get, resume_upload, resume_update, resume_delete, resume_select_for_job

Job

job_create, job_get, job_list, job_analyze, job_update_status

Application

application_create, application_get, application_list, application_update_status, application_history, application_delete

Interview

interview_create, interview_list, interview_update, interview_notes

Every tool's description is explicit about what it does and doesn't do. For example: job_create states it never fetches or scrapes a URL itself — the job description must come from you; application_update_status states that moving an application to applied only records what you report, it never submits anything on your behalf; destructive tools (resume_delete, application_delete) require an explicit confirm=true flag.

Tech stack

  • Python 3.12+, official mcp SDK v2.x (MCPServer, Streamable HTTP transport)

  • Starlette for the ASGI app, Pydantic for validation, SQLAlchemy (async) + Alembic for the database

  • SQLite in development, PostgreSQL in production — swap by changing DATABASE_URL only, no code changes

  • pypdf / python-docx for resume text extraction

  • Docker for packaging; pytest + ruff for tests and linting

Project structure

job-application-mcp/
├── src/job_application_mcp/
│   ├── server.py              # ASGI app: health/ready routes, OAuth auth, uvicorn entrypoint
│   ├── mcp_app.py             # shared MCPServer instance
│   ├── config/settings.py     # env-driven configuration
│   ├── database/              # SQLAlchemy engine/session + models
│   ├── models/                # Pydantic schemas at the MCP tool boundary
│   ├── services/               # business logic (profile, resume, job, application, interview)
│   ├── mcp/tools/               # MCP tool definitions, one module per domain
│   └── utils/                  # document text extraction, upload validation
├── tests/unit/                 # service-layer unit tests
├── Dockerfile, docker-compose.yml
├── pyproject.toml
└── .env.example

Getting started

Requires Python 3.12+.

git clone https://github.com/Mzaq1559/job-application-mcp.git
cd job-application-mcp
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

cp .env.example .env
# edit .env: at minimum, set MCP_AUTH_TOKENS to a random secret
python -c "import secrets; print(secrets.token_urlsafe(32))"

# For local development, configure the OAuth variables in .env
python -m job_application_mcp.server

The server starts on http://0.0.0.0:8000 by default. Check it's alive:

curl http://localhost:8000/health
# {"status": "ok"}

Environment variables

See .env.example for the full, current list. The essentials for the deployed OAuth configuration are:

Variable

Purpose

Default

DATABASE_URL

SQLAlchemy async connection string

sqlite+aiosqlite:///./data/app.db

OAUTH_ISSUER_URL

Auth0 issuer URL

(required)

OAUTH_AUDIENCE

Auth0 API Identifier / JWT audience

(required)

OAUTH_RESOURCE_URL

Exact public /mcp URL used for RFC 9728 metadata

(required)

OAUTH_JWKS_URL

Optional Auth0 JWKS URL

derived from issuer

OAUTH_REQUIRED_SCOPE

Scope required on MCP access tokens

mcp:access

MCP_HOST / MCP_PORT

Bind address

0.0.0.0 / 8000

UPLOAD_DIR

Where resume files are stored on disk

./uploads

AI_PROVIDER / AI_API_KEY / AI_MODEL

Reserved for the AI-assisted analysis layer (not yet implemented)

—

Database

Development uses SQLite and creates tables automatically on server startup — nothing to run manually. Production should point DATABASE_URL at PostgreSQL; Alembic migrations for that path are on the roadmap but not yet implemented (the auto-create-on-startup behavior works against Postgres too in the meantime).

Running tests

pip install -e ".[dev]"
pytest -q          # 16 tests, run against an isolated per-test SQLite database
ruff check .        # lint

Docker

docker compose up --build

This starts the app plus a PostgreSQL container. The compose file is intended for local development; configure the OAuth variables in your local .env when testing authenticated MCP requests.

To build and run standalone (SQLite, no Postgres container):

docker build -t job-application-mcp .
docker run -p 8000:8000 job-application-mcp

Deployment

Any platform that runs a long-lived container works — the server just needs a public HTTPS URL and a couple of environment variables. Options that fit a personal, single-user deployment like this one:

  • Render or Railway — connect the GitHub repo, they build the Dockerfile automatically, set env vars in their dashboard, get a public HTTPS URL.

  • Azure Container Apps — a good fit if you have Azure for Students credit; deploy the same Dockerfile via az containerapp up or the portal's "deploy from GitHub" flow.

  • Fly.io — fly launch against this repo's Dockerfile.

For the current Azure deployment, configure the OAuth environment variables shown above. Do not add an Auth0 client secret to the repository or GitHub Actions. Azure stores deployment configuration separately from source control.

The production deployment currently runs on Azure Container Apps. GitHub Actions builds the Docker image, pushes it to Azure Container Registry, updates the Container App to the exact Git SHA image, and verifies /health after deployment.

Connecting to Claude Web

Once deployed, add it in Claude Web as a custom remote MCP connector, pointing at the public /mcp endpoint:

https://<your-deployed-domain>/mcp

Authentication is OAuth 2.1 through Auth0; Claude signs in through the OAuth authorization flow rather than receiving a shared bearer secret. The Auth0 API requires the mcp:access scope. The Claude Web application uses the callback https://claude.ai/api/mcp/auth_callback. See docs/claude-web.md for the setup details.

Example prompts

Once connected, things like:

  • "Here's a job description I found — [paste text]. Save it and tell me how well I match it."

  • "Which of my resumes fits this job best?"

  • "I just submitted the ML intern application at Example Co — mark it as applied."

  • "What applications do I have in the interview stage?"

Security

  • The /mcp endpoint is protected by OAuth 2.1 bearer access tokens issued by Auth0. JWT signatures, issuer, audience, expiry, and required scope are verified before MCP requests are served.

  • No secrets, .env files, or database files are committed — see .gitignore / .dockerignore.

  • File uploads are validated by extension and size, and filenames are checked for path traversal before being written to disk.

  • The Docker image runs as a non-root user.

  • This is a single-user server by design — see Limitations for what that means for auth.

Limitations

  • Personal deployment. Authentication is delegated to one Auth0 tenant and the MCP tools operate on the database attached to this deployment. Add application-level authorization rules before turning this into a multi-user service.

  • No AI-assisted analysis yet. Resume selection and job analysis are transparent keyword-matching heuristics, not LLM-based reasoning — by design, so there's nothing to audit for fabrication yet. A proper AI-assisted layer (with explicit no-fabrication prompt rules) is on the roadmap.

  • No migrations yet. Schema changes currently mean dropping and recreating tables in development; Alembic migrations for safe production upgrades aren't wired up yet.

  • Never submits anything. By design, not a bug — this project prepares and tracks applications; you always click submit yourself.

Roadmap

  • Repo scaffold, license, .gitignore, pyproject.toml

  • Settings (env-driven config)

  • Database models (Profile, Resume, ResumeVersion, Job, Application, ApplicationDocument, ScreeningQuestion, Interview, InterviewNote, ApplicationEvent)

  • Service layer (profile, resume, job, application, interview)

  • MCP server + tools, verified end-to-end over HTTP (health check, bearer auth, initialize, tools/list)

  • Unit tests (16 passing) + clean ruff lint

  • Docker + docker-compose, verified with a production-equivalent install and boot

  • CI/CD (GitHub Actions for lint + tests + Docker build/push + Azure deployment)

  • Public Azure Container Apps deployment

  • Alembic migrations

  • AI provider abstraction + prompts (no-fabrication rules) for deeper job analysis and cover-letter generation

  • Integration tests against the running HTTP server

  • Azure Container Apps deployment documentation

  • Public Azure deployment

  • OAuth 2.1 resource-server authentication for Claude Web

  • Durable resume-file storage

Contributing

Community development happens on the community branch. Contributors should fork the repository, create a focused branch from community, and open pull requests back into community. The main branch is reserved for reviewed, release-ready changes.

Before contributing, read:

Contributions are especially useful around the AI-assisted analysis layer, Alembic migrations, integrations, durable storage, testing, observability, authentication/authorization, multi-user support, and deployment.

If you want to build on this project commercially, host it for customers, or include it in a paid product, contact the maintainer for commercial licensing.

This started as a personal project, but issues and PRs are welcome. Contributions are especially useful around the AI-assisted analysis layer, Alembic migrations, integrations, durable storage, testing, observability, and additional ATS-adjacent tooling that does not involve scraping or unauthorized automation.

If you want to build on this project commercially, host it for customers, or include it in a paid product, contact the maintainer for commercial licensing.

License

This project is source-available, not open-source under an OSI-approved license. Personal evaluation, learning, and non-commercial contribution are permitted under the project license. Commercial use, hosted/SaaS use, and inclusion in paid products require a separate commercial license.

See LICENSE for the full terms.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    F
    maintenance
    Enables users to search for jobs, prefill applications using AI, and automate submissions across major platforms like Lever and Ashby directly from Claude or Cursor. It provides a full suite of tools for managing job queues, profile data, and resumes within a chat interface.
    37
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables Claude to parse CVs, search job boards (Remotive, Arbeitnow, Adzuna, Greenhouse/Lever), tailor resumes and cover letters, and prepare application packages with direct apply links—without ever auto-submitting. It runs 100% locally and free, storing jobs and applications as JSON files.
    -
  • F
    license
    A
    quality
    B
    maintenance
    Enables managing a job search through natural language: tracking applications, discovery leads, interview prep, and resume generation. Connects to Claude via MCP to read and update local Excel files and documents.
    35
    -