# Using the MCP server

> Connect Hiresweep to AI tools such as Claude, ChatGPT, Cursor and Codex with the Model Context Protocol.

The Hiresweep MCP server lets an MCP-compatible AI tool, such as Claude, ChatGPT, Cursor or Codex, work with your Hiresweep account. It exposes tools for your resumes, your job tracker, Job Discovery searches and applications, so you can ask for changes in plain language.

## What is MCP?

The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) is a standard that lets LLM-powered tools connect to external services. Instead of being limited to the built-in chat UI, you can use any MCP client to interact with your resumes.

## Prerequisites

<Steps>
  <Step title="Choose your authentication method">
    Hiresweep MCP supports two authentication methods:

    - **OAuth2 (recommended):** best user experience for clients that support MCP OAuth.
    - **API key (fallback):** works in all clients that can send custom headers.

    Use OAuth2 whenever your MCP client supports it. Use API key only when OAuth is unavailable in that client.

  </Step>

  <Step title="If using API key, create one">
    Head over to [https://hiresweep.com](https://hiresweep.com), sign in, and open **Settings** → **Developers** → **API keys**. Select **Create API key**, give it a name, and copy the key. It's only shown once.

    For the full walkthrough, see [Using the API](https://docs.hiresweep.com/guides/using-the-api).

  </Step>
</Steps>

## Configuration

There are two transport options, and each can use either OAuth2 or API key depending on your client capabilities.

### Method 1: Streamable HTTP (recommended)

If your client supports the `url` field (e.g. **Cursor**, **Codex**, Claude custom connectors), use this.

#### Option A: OAuth2 (recommended)

Most OAuth-capable clients only need the MCP URL:

```json
{
  "mcpServers": {
    "hiresweep": {
      "url": "https://hiresweep.com/mcp"
    }
  }
}
```

Then connect/sign in from the client UI (or with the client's OAuth login command).

#### Option B: API key (fallback)

If OAuth is not supported in your client, send `x-api-key`:

```json
{
  "mcpServers": {
    "hiresweep": {
      "url": "https://hiresweep.com/mcp",
      "headers": {
        "x-api-key": "your-api-key"
      }
    }
  }
}
```

### Method 2: mcp-remote

If your client only supports `command` / `args` (for example, local-only Claude Desktop config), use [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) as a bridge. This requires [Node.js](https://nodejs.org) **20 or later**.

`mcp-remote` is most commonly used with API keys:

```json
{
  "mcpServers": {
    "hiresweep": {
      "command": "npx",
      "args": ["mcp-remote", "https://hiresweep.com/mcp", "--header", "x-api-key:your-api-key"]
    }
  }
}
```

<Info>Replace `your-api-key` with the API key you created in the prerequisites step.</Info>

### Where to put the config

| Client            | Config file                                                                                      |
| ----------------- | ------------------------------------------------------------------------------------------------ |
| Cursor            | `.cursor/mcp.json` in your project or home directory                                             |
| Claude Desktop    | `claude_desktop_config.json` ([docs](https://modelcontextprotocol.io/quickstart/user))           |
| Codex             | `~/.codex/config.toml` or `.codex/config.toml` ([docs](https://developers.openai.com/codex/mcp)) |
| Other MCP clients | Refer to the client's documentation                                                              |

## Authentication details

Hiresweep MCP accepts authentication in this order:

1. **Bearer token (OAuth2 access token)** via `Authorization: Bearer <token>`
2. **API key fallback** via `x-api-key: <key>`

If neither is valid, the MCP endpoint responds with `401` and advertises OAuth metadata using:

- `WWW-Authenticate: Bearer resource_metadata="https://hiresweep.com/.well-known/oauth-protected-resource"`

This lets OAuth-capable MCP clients discover and complete the OAuth flow automatically.

### OAuth2 flow used by this server

Hiresweep is configured as an OAuth authorization server for MCP clients:

- The MCP endpoint is `https://hiresweep.com/mcp`.
- OAuth discovery metadata is exposed under `/.well-known/*` endpoints.
- If the user is not signed in, authorization sends them to `/auth/login` and then resumes the OAuth request.
- A signed-in user sees a consent screen at `/auth/oauth-consent` with the assistant's name and every permission it asked for. They tick the permissions it gets and choose **Allow** or **Deny**. Deny returns `error=access_denied` to the client.
- Hiresweep remembers the grant per user and assistant. A later request for permissions already granted skips the screen; asking for more shows it again.
- PKCE (`S256`) is required, and the client, redirect URI, PKCE parameters and session are checked again when the user approves.
- Users review and disconnect assistants under **Settings** → **Developers** → **Connected assistants** (see [Managing connected assistants](https://docs.hiresweep.com/guides/managing-connected-assistants)). Disconnecting removes the grant and every token the assistant holds, and its current access token stops working on `/mcp` at once.

### Permissions (OAuth scopes)

Each kind of action is a separate permission. An assistant only sees, and can only call, the tools its permissions cover; calling another tool returns an error that names the missing permission.

| Scope            | Allows                                                                    | Tools                                                                                                                                  |
| ---------------- | ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `resumes:read`   | Read resumes, tags, analyses and statistics; download PDFs                | `list_resumes`, `list_resume_tags`, `read_resume`, `get_resume_analysis`, `download_resume_pdf`, `get_resume_statistics`, resources, prompts |
| `resumes:write`  | Create, import, duplicate, patch, update, lock and unlock resumes         | `create_resume`, `import_resume`, `duplicate_resume`, `apply_resume_patch`, `update_resume`, `lock_resume`, `unlock_resume`            |
| `resumes:delete` | Delete resumes (**irreversible**)                                         | `delete_resume`                                                                                                                        |
| `jobs:read`      | Read the job tracker and Job Discovery matches                            | `list_applications`, `get_application`, `list_discovery_matches`, `get_job_search`                                                    |
| `jobs:write`     | Add jobs from a link, change status and notes                             | `add_job`, `update_application`                                                                                                        |
| `discovery:run`  | Draft and start job searches (**uses the plan's search allowance**)       | `draft_job_search`, `start_job_search`                                                                                                 |
| `apply:run`      | Start and submit applications (**spends application credits, cannot be undone**) | `apply_to_job`, `submit_application`                                                                                            |

A client that asks for no scope gets `resumes:read jobs:read` (read-only) plus `offline_access`. On the consent screen, the permissions that spend credits or cannot be undone start unticked.

**API keys are not scoped.** A key sent as `x-api-key` keeps the full access of the account that created it, including applying and deleting. Prefer OAuth for assistants. OAuth access tokens are accepted only on `/mcp`; the REST and RPC APIs use your session or an API key.

## Popular client setup

### Cursor

**OAuth2 (recommended):**

```json
{
  "mcpServers": {
    "hiresweep": {
      "url": "https://hiresweep.com/mcp"
    }
  }
}
```

**API key fallback:**

```json
{
  "mcpServers": {
    "hiresweep": {
      "url": "https://hiresweep.com/mcp",
      "headers": {
        "x-api-key": "your-api-key"
      }
    }
  }
}
```

### Codex (CLI / IDE extension)

Add server:

```bash
codex mcp add hiresweep --url https://hiresweep.com/mcp
```

Then log in with OAuth:

```bash
codex mcp login hiresweep
```

API key fallback (`config.toml`):

```toml
[mcp_servers.hiresweep]
url = "https://hiresweep.com/mcp"
http_headers = { "x-api-key" = "your-api-key" }
```

### Claude (web app custom connector)

Add `https://hiresweep.com/mcp` as a custom remote MCP connector, then connect with OAuth in Claude's connector UI.

### Claude Desktop (local config file)

Use `mcp-remote` bridge with API key (example shown above in **Method 2**).

## External references

- [Cursor MCP docs](https://cursor.sh/docs/mcp)
- [MCP quickstart for users (Claude Desktop example)](https://modelcontextprotocol.io/quickstart/user)
- [OpenAI Codex MCP docs](https://developers.openai.com/codex/mcp)
- [Claude custom connectors (remote MCP)](https://claude.com/docs/connectors/custom/remote-mcp)
- [MCP Authorization spec](https://modelcontextprotocol.io/specification/latest/basic/authorization)

## Available tools

Tool names use canonical unprefixed `snake_case` names.

| Tool                    | Description                                                                                                                        |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `list_resumes`          | List all resumes with IDs, names, tags, and status. Supports filtering by tags and sorting by last updated, creation date, or name |
| `list_resume_tags`      | List every distinct tag in use across your resumes (sorted)                                                                        |
| `read_resume`           | Get the full data of a specific resume by ID                                                                                       |
| `get_resume_analysis`   | Get the latest saved AI analysis for a resume (from the web app), if any                                                           |
| `create_resume`         | Create a new, empty resume with a name and slug. Optionally pre-fill with sample data                                              |
| `import_resume`         | Create a resume from a full ResumeData JSON export (random name/slug). Large files may exceed client limits                        |
| `duplicate_resume`      | Create a copy of an existing resume with a new name and slug                                                                       |
| `apply_resume_patch`    | Apply JSON Patch (RFC 6902) operations to modify a resume's data                                                                   |
| `update_resume`         | Update metadata only: name, slug, tags, `isPublic`. Returns canonical share URL; passwords are not managed via MCP                 |
| `delete_resume`         | Permanently delete a resume and all associated files. **Irreversible**                                                             |
| `lock_resume`           | Lock a resume to prevent edits, patches, and deletion                                                                              |
| `unlock_resume`         | Unlock a previously locked resume to re-enable editing                                                                             |
| `get_resume_statistics` | Get view and download statistics for a resume                                                                                      |
| `list_applications`      | List tracked jobs (applications), filtered by status and paged                                                                     |
| `get_application`        | Get one tracked job: posting summary, status, notes, match score, which resume it sends, latest apply run                          |
| `add_job`                | Start tracking a job from the link to its description                                                                              |
| `update_application`     | Change a tracked job's status and/or notes                                                                                         |
| `list_discovery_matches` | List new jobs Job Discovery found                                                                                                  |
| `draft_job_search`       | Draft a Job Discovery search for a resume (one AI action)                                                                          |
| `get_job_search`         | Get a job search's status and Targets                                                                                              |
| `start_job_search`       | Start a drafted job search. **Uses the plan's search allowance**                                                                   |
| `apply_to_job`           | Fill an employer's application form. **Spends an application credit; may submit by itself if auto-submit is on**                  |
| `submit_application`     | Submit a filled form waiting for Submit. **Spends an application credit; irreversible**                                            |

### Breaking change (tool names)

Older clients may refer to prefixed or dot-separated names. Those names are no longer registered; update automations and saved prompts to the canonical names above.

## Available resources

Resources follow MCP conventions: **static** items appear in `resources/list`; **parameterized** access is declared in `resources/templates/list` and read via `resources/read` once you know the ID.

| Discovery                             | What you get                                                                                  |
| ------------------------------------- | --------------------------------------------------------------------------------------------- |
| `resources/list`                      | Static resources only — currently **`resume://_meta/schema`** (ResumeData JSON Schema)        |
| `resources/templates/list` | **`resume://{id}`** — template for reading full resume JSON by ID (not enumerated per resume) |
| `list_resumes` (tool)      | **Primary way to discover resume IDs** — resumes are not listed as separate MCP resources     |

| URI                     | Description                                                              |
| ----------------------- | ------------------------------------------------------------------------ |
| `resume://_meta/schema` | ResumeData JSON Schema — use for valid JSON Patch paths and value types  |
| `resume://{id}`         | Full resume data as JSON — use an ID from `list_resumes`                 |

### Breaking change (schema URI)

The schema resource was previously `resume://schema`. It is now **`resume://_meta/schema`**. Update any saved prompts, automations, or client configs that referenced the old URI.

### Static server card (`/.well-known/mcp/server-card.json`)

`GET /.well-known/mcp/server-card.json` returns a JSON document ([SEP-1649](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1649)) with `serverInfo`, optional authentication metadata, and summaries of tools, resources, resource templates, and prompts. It is generated to match the live MCP server and can be used for discovery when a client cannot run a full capability scan against `/mcp/`.

## Available prompts

Prompts are pre-built workflows that provide the AI with structured instructions and context. Each prompt embeds the resume data and the schema resource (`resume://_meta/schema`) automatically.

| Prompt           | Description                                                                                                                                                  |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `build_resume`   | Guide you step-by-step through building a resume from scratch — basics, summary, experience, education, skills, and design                                   |
| `improve_resume` | Review your resume and suggest concrete improvements to wording, impact, metrics, and structure                                                              |
| `review_resume`  | Get a structured, professional critique with a scorecard (1–10 across seven dimensions) and prioritized recommendations. **Read-only** — no changes are made |

## Usage examples

Once your MCP client is connected, you can use natural language to interact with your resumes:

### Browsing

- "List my resumes"
- "Show me my resume named 'Software Engineer'"
- "What skills are listed on my resume?"
- "Show me the stats for my resume"

### Creating and managing

- "Create a new resume called 'Frontend Engineer 2026'"
- "Import this exported ResumeData JSON as a new resume"
- "What tags do I use across my resumes?"
- "Duplicate my 'Software Engineer' resume for a product manager role"
- "Make my resume public and give me the share link"
- "Lock my finalized resume so it can't be accidentally edited"
- "Delete my old draft resume"

### Editing

- "Update my name to Jane Doe"
- "Change my headline to Senior Software Engineer"
- "Add TypeScript to my skills with an Advanced proficiency level"
- "Add a new experience entry for my role as Staff Engineer at Acme Corp from Jan 2024 to Present"
- "Remove the third item from my skills section"

### Styling

- "Change the template to bronzor"
- "Set the primary color to blue"
- "Hide the interests section"

### Using prompts

- "Help me build my resume from scratch" (uses `build_resume`)
- "Review my resume and give me a score" (uses `review_resume`)
- "Improve the wording on my resume" (uses `improve_resume`)

<Tip>
  The AI will use `read_resume` to inspect your current resume before making changes with `apply_resume_patch`. This
  ensures the correct JSON paths are used. Use `update_resume` for name, slug, tags, and public visibility (not for
  section content).
</Tip>

## Troubleshooting

| Issue                                                         | Solution                                                                                                                       |
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| "Unauthorized" with no login prompt                           | Your client may not support MCP OAuth discovery. Use API key mode (`x-api-key`)                                                |
| OAuth login opens but fails redirect/callback                 | Confirm your client's MCP OAuth callback settings and retry the connection                                                     |
| "API error (401)"                                             | Your API key is invalid or expired. Create a new one in **Settings** → **Developers** → **API keys**                           |
| "API error (404)"                                             | The resume ID doesn't exist. Use `list_resumes` to find valid IDs                                                             |
| An error mentioning `RESUME_LOCKED`                           | The resume is locked. Unlock it in Hiresweep or with `unlock_resume`                                                          |
| Connection refused                                            | Check that the URL is exactly `https://hiresweep.com/mcp`                                                                      |
| "ReferenceError: File is not defined" when using `mcp-remote` | You're running Node.js 18. `mcp-remote` requires **Node.js 20 or later** — upgrade with `nvm use 20` or `nvm alias default 20` |
