Skip to main content
Glama
README.md
# handshake-mcp

An [MCP](https://modelcontextprotocol.io) server that gives AI assistants like Claude access to [Handshake](https://joinhandshake.com) — search jobs, apply, track applications, and research employers through your own browser session.

> **Disclaimer:** This project is independent and unaffiliated with Handshake. Automated access may violate Handshake's Terms of Service. Use for personal productivity only.

## Tools

| Tool | Description |
|---|---|
| `hs_search_jobs` | Search by keyword, location, or job type |
| `hs_get_job` | Full description, requirements, salary, deadline |
| `hs_apply` | Submit an application, attach resume/cover letter |
| `hs_save_job` / `hs_unsave_job` | Save / unsave jobs (follow) |
| `hs_get_applications` / `hs_withdraw_application` | Application tracking |
| `hs_search_employers` / `hs_get_employer` | Company research (keyword search) |
| `hs_get_profile` | Your Handshake student profile |
| `hs_upload_document` / `hs_get_documents` / `hs_delete_document` | Manage resumes and cover letters |

## Quick start

### With uvx (recommended)

```bash
# First-time login
uvx handshake-mcp --login

# Add to Claude Code (~/.claude/.mcp.json)
```

```json
{
  "mcpServers": {
    "handshake": {
      "command": "uvx",
      "args": ["handshake-mcp"]
    }
  }
}
```

### From source

```bash
git clone https://github.com/shahparam11/handshake-mcp-server.git
cd handshake-mcp
uv sync

# First-time login
uv run handshake-mcp --login
```

Add to `~/.claude/.mcp.json`:

```json
{
  "mcpServers": {
    "handshake": {
      "command": "uv",
      "args": ["run", "--project", "/path/to/handshake-mcp", "handshake-mcp"]
    }
  }
}
```

Restart Claude Code. The `hs_*` tools are now available.

### With Docker

```bash
docker build -t handshake-mcp .

# Login (mounts session storage)
docker run -it -v ~/.handshake-mcp:/root/.handshake-mcp handshake-mcp --login

# Run as MCP server
docker run -i -v ~/.handshake-mcp:/root/.handshake-mcp handshake-mcp
```

## CLI

```bash
handshake-mcp --login    # authenticate via browser
handshake-mcp --status   # check session validity
handshake-mcp --logout   # clear saved session
handshake-mcp --version  # print version
```

## How it works

On `--login`, a Patchright Chromium browser opens. After you log in, the full browser profile (cookies, localStorage, IndexedDB) is saved to `~/.handshake-mcp/`. Subsequent tool calls use these cookies via an `httpx` client against Handshake's internal REST API at `app.joinhandshake.com/stu/`.

CSRF protection uses the **double-submit cookie** pattern — the `CSRF-TOKEN` cookie value is reflected back as the `X-CSRF-Token` request header.

> **Note:** Handshake's internal API is undocumented. If a tool returns 404, open browser DevTools on Handshake → Network tab, find the matching request path, and update the relevant `handshake_mcp/tools/*.py` file.

## Session refresh

```bash
handshake-mcp --login
```

## Project layout

```
handshake_mcp/
├── cli_main.py       # Entry point — --login/--logout/--status/server
├── server.py         # FastMCP server factory
├── auth.py           # Patchright login + profile/cookie storage
├── client.py         # Authenticated httpx client
├── exceptions.py     # CredentialsNotFoundError, SessionExpiredError
└── tools/
    ├── jobs.py           # hs_search_jobs, hs_get_job, hs_apply, hs_save/unsave_job
    ├── employers.py      # hs_search_employers, hs_get_employer
    ├── applications.py   # hs_get_applications, hs_withdraw_application
    └── profile.py        # hs_get_profile, hs_upload/get/delete_document
```

## Development

```bash
uv sync --group dev
uv run pytest --cov
uv run ruff check .
```

## License

MIT — see [LICENSE](LICENSE).

TDQS

A3.8/5.0

Scored across 12 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: searching, retrieving details, applying, managing saved jobs, and handling applications. No two tools overlap in functionality; even similar actions like get_job and search_jobs are well-differentiated (detail vs. list) with clear guidance in descriptions.

Naming Consistency5/5

All tools follow a consistent pattern: 'hs_' prefix + verb_noun (e.g., hs_get_job, hs_save_job, hs_search_jobs). Verbs are operational (get, search, save, unsave, apply, withdraw) and nouns are the target resources. No mixing of styles or irregularities.

Tool Count5/5

12 tools is an appropriate number for a Handshake student client. It covers the essential operations (search, retrieve, apply, manage saved jobs and applications, view profile and documents) without being overwhelming or sparse.

Completeness4/5

The tool set covers the core student workflow comprehensively: search jobs/employers, get details, save/unsave, apply, withdraw, view applications, and manage documents. Minor gaps like updating profile or uploading documents are absent but likely outside the MCP's scope.

Maintenance

ActivityStale
ResponsivenessNo issues