Skip to main content
Glama
gyopiazza

personio-mcp

by gyopiazza
README.md
# personio-mcp

**The missing Personio MCP**

> **Note:** This is a beta product and is not affiliated with Personio in any way.

MCP server exposing Personio's public APIs as tools:

- **Recruiting** (v2): jobs, job categories, candidates, applications, stage transitions
- **Employees** (v1): list/get/create/update employees, absence balances, attribute catalog,
  profile pictures
- **Time tracking** (v2): attendance periods and projects (CRUD)
- **Absences** (v1): time-off types, day-based time-offs, hour-based absence periods
- **Documents** (v1): document categories, document uploads
- **Custom reports** (v1): report metadata, report data, column labels

The v1 attendance/project endpoints are deprecated by Personio (sunset 2027-01-31), so this
server uses their v2 successors (`/v2/attendance-periods`, `/v2/projects`). All other personnel
endpoints follow the official v1 Personnel Data API.

Base URL: `https://api.personio.de`

## Credentials

1. **OAuth2 client** — in Personio: Marketplace > Connected integrations > *Create custom
   integration* (requires Core Pro plan). Gives you `client_id` / `client_secret`. Enable the
   scopes/API resources you need:
   - Recruiting: `personio:recruiting:read` (+ write for some flows)
   - Personnel data: employee read/write, absence read/write, attendance read/write,
     project read/write, document read/write, custom report read
   Note the integration's **company ID** — it is required for all personnel-data endpoints.
2. **Recruiting token** (only needed for `personio_create_application`) — static token under
   Settings > Integrations > API Credentials. The company ID is visible at
   `https://{YOUR_COMPANY}.personio.de/configuration/api/credentials/management`.

## Environment variables

| Variable | Required | Purpose |
| --- | --- | --- |
| `PERSONIO_CLIENT_ID` | yes | OAuth2 client ID |
| `PERSONIO_CLIENT_SECRET` | yes | OAuth2 client secret |
| `PERSONIO_COMPANY_ID` | recommended | Company ID; sent as `X-Company-ID` on all v1 personnel-data requests |
| `PERSONIO_RECRUITING_TOKEN` | for create_application | Static v1 recruiting API token |
| `PERSONIO_API_BASE_URL` | no | Override base URL (default `https://api.personio.de`) |

## Usage

Requires Node.js 20+. Run directly with npx (no install needed):

```sh
PERSONIO_CLIENT_ID=... PERSONIO_CLIENT_SECRET=... PERSONIO_COMPANY_ID=... npx -y personio-mcp@latest
```

### Client config (e.g. Claude Desktop / opencode)

```json
{
  "mcpServers": {
    "personio": {
      "command": "npx",
      "args": ["-y", "personio-mcp@latest"],
      "env": {
        "PERSONIO_CLIENT_ID": "...",
        "PERSONIO_CLIENT_SECRET": "...",
        "PERSONIO_COMPANY_ID": "..."
      }
    }
  }
}
```

### ChatGPT desktop app

The new ChatGPT desktop app supports local **STDIO** MCP servers and shares its
MCP configuration with Codex CLI and the IDE extension (stored in
`~/.codex/config.toml`).

**Option A — via `config.toml` (recommended, since it lets you set env vars)**

Add this to `~/.codex/config.toml`:

```toml
[mcp_servers.personio]
command = "npx"
args = ["-y", "personio-mcp@latest"]

[mcp_servers.personio.env]
PERSONIO_CLIENT_ID = "..."
PERSONIO_CLIENT_SECRET = "..."
PERSONIO_COMPANY_ID = "..."
# Only needed for personio_create_application:
# PERSONIO_RECRUITING_TOKEN = "..."
```

Then restart ChatGPT. Type `/mcp` in the composer to verify the server connected.

**Option B — via the UI**

1. Open **Settings**, then select **MCP servers**.
2. Select **Add server**.
3. Enter a name (e.g. `personio`), choose **STDIO**, and set the command to
   `npx -y personio-mcp@latest`.
4. Save, then select **Restart**.

Note: if you go through the UI, set the credentials in your shell environment so the server
can read them at startup — or prefer Option A, which keeps credentials scoped to the server entry.

## Tools

Health & recruiting:

- `personio_health_check` — verifies credentials work
- `personio_list_jobs`, `personio_get_job`
- `personio_list_job_categories`, `personio_get_job_category`
- `personio_list_candidates`, `personio_get_candidate`
- `personio_list_applications`, `personio_get_application`, `personio_list_application_stage_transitions`
- `personio_create_application` — submits an application (v1); requires the extra env vars above

Employees:

- `personio_list_employees` — offset-paginated; filter by email / updated_since / attributes[]
- `personio_get_employee`, `personio_create_employee`, `personio_update_employee`
- `personio_get_employee_absence_balance`
- `personio_list_employee_attributes` — attribute catalog incl. custom (dynamic) fields
- `personio_get_profile_picture` — returns image content; optional width

Time tracking:

- `personio_list_attendance_periods` — cursor-paginated; rich filters (person, project, dates, status)
- `personio_get_attendance_period`, `personio_create_attendance_period`,
  `personio_update_attendance_period`, `personio_delete_attendance_period`
- `personio_list_projects`, `personio_get_project`, `personio_create_project`,
  `personio_update_project`, `personio_delete_project`

Absences:

- `personio_list_time_off_types` — includes unit (day/hour) and approval requirements
- `personio_list_time_offs`, `personio_create_time_off`, `personio_get_time_off`, `personio_delete_time_off` — day-based absences
- `personio_list_absence_periods`, `personio_create_absence_period`, `personio_delete_absence_period` — hour-based absences

Documents:

- `personio_list_document_categories`
- `personio_upload_document` — multipart upload; pass text or base64 content (max 30MB)

Custom reports:

- `personio_list_custom_reports`, `personio_get_custom_report`, `personio_list_report_columns`

Notes from the Personio API:

- v2 endpoints (recruiting, attendance periods, projects) are cursor-paginated;
  tools return `pagination.next_cursor`.
- v1 personnel endpoints are offset-paginated; tools return
  `pagination.total_elements` / `pagination.next_offset`.
- Employees/applications don't expose custom attributes or tags via v2.
- Employee emails cannot be changed after creation.
- Application creation only works for currently published positions and is rate limited
  to ~100 applications/min per IP.
- Document uploads are limited to ~60 requests/min.