CareerPilot

CareerPilot

An AI job-hunt copilot that enables searching live job boards, shortlisting openings, tracking application pipelines, and generating tailored resumes and cover letters from any MCP client.

Category
Visit Server

README

CareerPilot ๐Ÿงญ

tests

An AI job-hunt copilot built on the Model Context Protocol โ€” search live job boards, shortlist openings, track your application pipeline, and generate tailored resumes/cover letters, all from any MCP client (Claude Desktop, Claude Code, MCP Inspector).

Built as a learning project that deliberately exercises every major MCP concept in a real product.

Real data, no API keys

Source What it is
Remotive Remote job board, free public API
RemoteOK Remote job board, free public API
Hacker News "Who is hiring?" Monthly hiring thread, via the free Algolia API

Your shortlist, applications, and profile live in a local SQLite DB (~/.careerpilot/careerpilot.db).

MCP feature map

MCP concept Where it lives in this project What it teaches
Tools search_jobs, save_job, track_application, update_application, schedule_follow_up, set_profile Model-callable actions with typed schemas
Resources careerpilot://pipeline, careerpilot://saved-jobs, careerpilot://profile App data exposed as readable context
Resource templates careerpilot://applications/{app_id} Parameterized URIs
Prompts tailor_resume, cover_letter, interview_prep Reusable, server-defined prompt workflows
Sampling score_job_fit โ€” the server asks the client's LLM to judge fit Server โ†” LLM inversion; server needs no API key
Elicitation delete_application asks the user to confirm Mid-tool-call user input
Roots find_resume scans client-granted folders Filesystem boundaries negotiated with the client
Subscriptions pipeline & watches emit resources/updated on every change Push notifications to subscribed clients
Logging & progress ctx.info() / ctx.report_progress() in search_jobs Server โ†’ client observability
Background notifications watch_search + lifespan poller push updates with no request in flight Server-initiated protocol traffic
Streamable HTTP careerpilot --http The production transport
Authorization Bearer-token resource server (auth.py, 401 + WWW-Authenticate) The MCP auth spec's resource-server side
The client side careerpilot-chat (host.py) โ€” a full MCP host on the Anthropic API Handshake, tool loop, sampling/elicitation/roots handlers

Quickstart

uv sync

# Interactive protocol playground (best way to learn):
uv run mcp dev src/careerpilot/server.py
# โ†’ opens MCP Inspector in the browser; poke every tool/resource/prompt,
#   and test sampling + elicitation from the Inspector UI

Claude Code: this repo ships a .mcp.json, so just open the project and approve the server.

Claude Desktop: claude_desktop_config.json โ†’

{
  "mcpServers": {
    "careerpilot": {
      "command": "uv",
      "args": ["run", "--directory", "/Users/shwetarani/Developer/MCP_Project", "careerpilot"]
    }
  }
}

Then try, in plain language:

"Search for remote python jobs, save the best three, and track that I applied to the first one." "Read my pipeline and tell me who I should follow up with." "Use the cover letter prompt for job 2."

Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   MCP (stdio โ†’ later Streamable HTTP)
โ”‚  MCP client + LLM   โ”‚โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ (Claude Code, etc.) โ”‚                                     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                     โ”‚
           โ”‚ tools / resources / prompts          sampling / elicitation / roots
           โ–ผ                                     (server โ†’ client callbacks)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  CareerPilot server โ”‚  src/careerpilot/server.py   (FastMCP)
โ”‚  โ”œโ”€โ”€ sources.py     โ”‚  Remotive ยท RemoteOK ยท HN (httpx, concurrent)
โ”‚  โ””โ”€โ”€ db.py          โ”‚  SQLite: saved_jobs ยท applications ยท profile
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Watched searches (stage 2)

you> watch this search: "python backend", remotive only
     -> Watch #1 created ... baseline: 10 current listings

A background poller re-runs every watch (default: every 15 min, tune with CAREERPILOT_POLL_SECONDS) and pushes resources/updated notifications to any client subscribed to careerpilot://watches โ€” the server talks first, with no request in flight. Review new finds in careerpilot://watches/{id}, then mark_watch_reviewed.

Production transport: HTTP + auth (stage 3)

# Serve over Streamable HTTP with bearer-token auth
CAREERPILOT_TOKEN=$(openssl rand -hex 24) uv run careerpilot --http --port 8848
# MCP endpoint: http://127.0.0.1:8848/mcp   (requests without the token get 401)

auth.py implements the SDK's TokenVerifier โ€” the resource server role in the MCP authorization spec (401 + WWW-Authenticate, protected-resource metadata, scope checks). Swap StaticTokenVerifier for a JWT verifier against a real OAuth 2.1 IdP without touching the rest of the server.

docker build -t careerpilot .
docker run -p 8848:8848 -v careerpilot-data:/data -e CAREERPILOT_TOKEN=... careerpilot

Web dashboard

CareerPilot dashboard โ€” the hiring file

careerpilot --http also serves a dashboard at / โ€” a "hiring file" view of your pipeline styled as stamped paperwork: an action tray (follow-ups due, unreviewed watch finds), the application drawer grouped in triage order, watch index cards, and one-click "I applied" / "mark reviewed" / status changes. Same process, same SQLite, two front doors: humans at /, LLMs at /mcp โ€” and edits made in the browser push resources/updated notifications to connected MCP clients.

uv run careerpilot --http    # dashboard: http://127.0.0.1:8848/

When CAREERPILOT_TOKEN is set, the dashboard locks too: open /?token=<your token> once and that browser stays unlocked (cookie); the JSON API also accepts the same Authorization: Bearer header as /mcp.

The client side: your own MCP host (stage 4)

careerpilot-chat is a complete MCP host in ~250 lines (src/careerpilot/host.py) โ€” what Claude Desktop does, made visible:

export ANTHROPIC_API_KEY=sk-ant-...
uv run careerpilot-chat                                   # spawn local server (stdio)
uv run careerpilot-chat --url http://host:8848/mcp --token ...  # remote server
uv run careerpilot-chat --list                            # capability dump (no API key needed)

It negotiates capabilities, exposes the server's tools to Claude, runs the agentic tool-call loop, answers the server's sampling requests by calling the Anthropic API, surfaces elicitation at the terminal, grants roots (cwd), and prints server logs and push notifications. /tools, /read <uri>, /prompt <name> k=v, /quit inside the REPL.

Learning roadmap โ€” complete โœ…

  • [x] Stage 1 โ€” Server fundamentals: tools, resources, templates, prompts, sampling, elicitation, roots, subscriptions, logging/progress over stdio
  • [x] Stage 2 โ€” Watched searches: background poller pushes resources/updated notifications when new matching jobs appear
  • [x] Stage 3 โ€” Production transport: Streamable HTTP, bearer-token auth (MCP resource-server pattern), Dockerfile
  • [x] Stage 4 โ€” The client: careerpilot-chat, a minimal MCP host on the Anthropic API โ€” handshake, tool-call loop, sampling/elicitation/roots handlers

Development

uv sync                                  # install
uv run mcp dev src/careerpilot/server.py # inspector
uv run careerpilot                       # run over stdio directly
CAREERPILOT_DB=/tmp/test.db uv run careerpilot  # throwaway database

# End-to-end protocol tests (spawn the real server, no mocks on the MCP layer)
uv run python tests/e2e_stdio_test.py     # stage 1: every MCP feature over stdio
uv run python tests/stage2_watches_test.py  # stage 2: poller + notifications
uv run python tests/stage3_http_test.py     # stage 3: HTTP transport + 401/auth

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured