# Career Copilot

> AI hiring copilot built on Google ADK v2. Recruiter mode scores fit + drafts outreach. Candidate mode detects agency postings + generates full interview prep.

- **Type:** MCP server
- **Install:** `agentstack add mcp-naji-najari-career-copilot`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Naji-Najari](https://agentstack.voostack.com/s/naji-najari)
- **Installs:** 0
- **Category:** [Cloud & Infrastructure](https://agentstack.voostack.com/c/cloud-infrastructure)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Naji-Najari](https://github.com/Naji-Najari)
- **Source:** https://github.com/Naji-Najari/career-copilot
- **Website:** https://career-copilot.najinajari.com

## Install

```sh
agentstack add mcp-naji-najari-career-copilot
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

Career Copilot

  A multi-agent CV × JD pipeline on Google ADK v2.

  
  
  
  
  
  
  
  

  Live demo ·
  Project write-up

---

Career Copilot reads a CV against a job description and produces a different output depending on who is asking. Recruiters get a fit verdict and a LinkedIn outreach draft that quotes a real achievement from the CV. Candidates get a company brief researched live through Tavily MCP and a tailored interview-prep bundle.

The point of the project is the orchestration. Google ADK v2 shipped its graph workflow API recently, in the same spirit as LangGraph. This is an end-to-end test of it on a real use case.

## Why a graph

A single big-prompt agent works until you need any of: deterministic branching, parallel work, typed contracts at every step, or per-step tracing. Once you do, a graph stops being optional.

- **Explicit topology**: nodes, edges, parallel branches, conditional routing, and sync points are first-class.
- **Testable units**: each node can be tested, swapped, or traced in isolation.
- **Typed state**: contracts at every boundary instead of free-form prompt parsing.
- **Predictable cost**: you know upfront which steps run, in what order, and which model serves each.

## How it works

```mermaid
flowchart LR
    IN(["CV + JD+ mode"]):::io

    IN --> CV[CV Parser]:::agent
    IN --> JD[JD Parser]:::agent
    CV --> MR(["Mode Router"]):::router
    JD --> MR

    MR -- recruiter --> FA[Fit Analyzer]:::agent
    FA --> VR(["Verdict Router"]):::router
    VR -- fit / borderline --> OW["Outreach Writermedium"]:::agent
    VR -- no_fit --> GE[Gap Explainer]:::agent

    MR -- candidate --> CFORK((·)):::fork
    CFORK --> RA["Research Agent+ Tavily MCP"]:::agent
    CFORK --> CO[CV Optimizer]:::agent
    RA --> IP[Interview Prep]:::agent
    CO --> IP

    OW --> OUT1(["RecruiterFit"]):::io
    GE --> OUT2(["RecruiterNoFit"]):::io
    IP --> OUT3(["CandidateResp"]):::io

    classDef agent fill:#E3F2FD,stroke:#1565C0,stroke-width:2px,color:#0D47A1
    classDef router fill:#E8F5E9,stroke:#2E7D32,stroke-width:1.5px,color:#1B5E20
    classDef fork fill:#9E9E9E,stroke:#616161,stroke-width:1px,color:#9E9E9E
    classDef io fill:#F5F5F5,stroke:#616161,stroke-width:1px,color:#212121
```

CV and JD are parsed in parallel. The mode router (a `FunctionNode`, not an LLM) splits the flow:

- **Recruiter branch**: linear chain. Fit Analyzer scores fit, Verdict Router routes to Outreach Writer (on fit / borderline) or Gap Explainer (on no_fit).
- **Candidate branch**: parallel fan-out. Research Agent (Tavily MCP) and CV Optimizer run concurrently, synchronize through a `JoinNode`, then feed Interview Prep.

Internal `JoinNode`s are omitted from the diagram for clarity. See [`app/agent/agent.py`](backend/app/agent/agent.py) for the full topology.

## Architecture decisions

The graph encodes a deliberate separation between deterministic control flow and LLM-driven generation. Routing and synchronization stay in pure Python; only generation crosses an LLM boundary, and every output is constrained by a Pydantic schema before it leaves a node.

- **Control flow stays out of the LLMs.** Routing lives in `FunctionNode`s that decide branches in pure Python on already-typed state. `JoinNode`s wait for parallel branches to complete before firing downstream. No LLM ever picks which branch fires next, which removes a whole class of failure modes from the critical path.
- **One schema per agent.** Each LLM agent declares its own `output_schema`. Invalid output fails the node loud and fast instead of corrupting state in a downstream agent.
- **Tool-use escape hatch.** ADK currently disallows combining `output_schema` with tools on `gpt-5.4-mini`. The Research Agent uses the Tavily MCP toolset and emits `CompanyIntelligence` as a JSON string, validated with `model_validate_json` at the API boundary so the typed-state invariant is preserved at the edge.

## Agents

All agents run OpenAI `gpt-5.4-mini` via `LiteLlm`. The Outreach Writer is the only one dialled up to medium reasoning effort.

| Agent              | Role      | Output schema             |
| ------------------ | --------- | ------------------------- |
| CV Parser          | Parser    | `ParsedCV`                |
| JD Parser          | Parser    | `ParsedJD`                |
| Fit Analyzer       | Recruiter | `FitVerdict`              |
| Outreach Writer    | Recruiter | `OutreachDraft`           |
| Gap Explainer      | Recruiter | `GapReport`               |
| Research Agent     | Candidate | `CompanyIntelligence`     |
| CV Optimizer       | Candidate | `CVOptimizationBundle`    |
| Interview Prep     | Candidate | `InterviewPrepBundle`     |

## Tracing

Every `/v1/analyze` run is traced end-to-end with Langfuse. Sub-agent calls, tool calls, latency, and token counts nest under a parent agent observation. The filterable trace attributes propagated to Langfuse carry only metadata and sizes (`mode`, `model`, `version`, `cv_chars`, `jd_chars`); raw CV and JD content is kept out of the trace tags so traces stay free of PII.

## Stack

| Layer     | Stack                                                              |
| --------- | ------------------------------------------------------------------ |
| Backend   | Python 3.12, FastAPI, Google ADK v2, `uv`                          |
| Models    | OpenAI `gpt-5.4-mini` via `LiteLlm`                                |
| Research  | Tavily via MCP (`McpToolset`)                                      |
| Frontend  | Next.js 15, React 19, Tailwind v4, shadcn/ui, TanStack Query, Zod  |
| Tracing   | Langfuse                                                            |
| Deploy    | Docker (Cloud Run / Fly.io / HuggingFace Spaces)                   |

## Run it

### Prerequisites

- Python 3.12 with [uv](https://docs.astral.sh/uv/)
- An [OpenAI API key](https://platform.openai.com/api-keys) for `gpt-5.4-mini`
- A [Tavily API key](https://tavily.com) for the candidate-mode Research Agent

### Install and configure

```bash
cd backend
uv sync
cp .env.example .env   # fill in OPENAI_API_KEY and TAVILY_API_KEY
```

### Start the backend

```bash
uv run uvicorn app.main:app --reload --port 8080
```

API docs at . Try `POST /v1/analyze` with `{"cv_text": "...", "jd_text": "...", "mode": "recruiter" | "candidate"}`.

### Run the tests

```bash
uv run pytest tests/ -q
```

## License

[MIT](./LICENSE)

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Naji-Najari](https://github.com/Naji-Najari)
- **Source:** [Naji-Najari/career-copilot](https://github.com/Naji-Najari/career-copilot)
- **License:** MIT
- **Homepage:** https://career-copilot.najinajari.com

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-naji-najari-career-copilot
- Seller: https://agentstack.voostack.com/s/naji-najari
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
