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

An MCP server for searching jobs on [XING](https://www.xing.com) — the leading professional network in the DACH region (Germany, Austria, Switzerland).

The MCP job-search ecosystem is heavily LinkedIn-centric, and the standard multi-board scraper (JobSpy) does not cover XING. This server fills that gap. **Most XING listings include a salary estimate**, which is unusual and hard to get elsewhere.

## Tools

| Tool | Purpose |
| --- | --- |
| `search_jobs` | Search one page of listings by keywords, location, radius, employment type |
| `search_jobs_paginated` | Search across multiple pages, rate-limited and deduplicated |
| `get_job_details` | Full posting incl. description converted to markdown |
| `get_company_jobs` | Open positions on a company's XING page |

## Install

```bash
uv venv && uv pip install -e .
```

### Claude Code

```bash
claude mcp add xing -- /absolute/path/to/xing_mcp/.venv/bin/xing-mcp
```

### Claude Desktop

```json
{
  "mcpServers": {
    "xing": {
      "command": "/absolute/path/to/xing_mcp/.venv/bin/xing-mcp"
    }
  }
}
```

## Configuration

| Env var | Default | Purpose |
| --- | --- | --- |
| `XING_MCP_USER_AGENT` | honest self-identifying UA | Override the User-Agent |
| `XING_MCP_RATE_LIMIT` | `1.0` | Minimum seconds between requests |
| `XING_MCP_CACHE_TTL` | `300` | Response cache TTL in seconds |

## What works, and what doesn't

XING has no public jobs API (`dev.xing.com` is plugins-only and closed to new registrations), so this server reads XING's **public job-search HTML pages**. Search parameters were mapped empirically against the live site.

**Supported filters** — verified working:

- `keywords`, `location`, `radius` (km), `page`
- `employment_type`: `FULL_TIME`, `PART_TIME`

**Not supported** — XING accepts these as URL parameters but they have no effect, so the server does not pretend to offer them:

- remote/home-office filtering
- sort order (results are relevance-ranked by XING)
- career/seniority level filtering — **filter by seniority in your prompt or by reading job titles instead**

**Login-gated results:** XING hides roughly a quarter to a third of listings from logged-out visitors. Those appear as `UnauthorizedJob` and cannot be retrieved. Every tool reports how many were withheld in a `note` field rather than silently returning a short list.

## How it works

Three parser tiers, tried in order, so a XING frontend change degrades rather than breaks:

1. **Apollo cache** (`parsers/apollo.py`) — XING server-renders its full GraphQL cache into the page. Richest source: salary, apply URL, company, dates.
2. **JSON-LD** (`parsers/jsonld.py`) — `schema.org/JobPosting` on detail pages, for descriptions and postal addresses.
3. **DOM fallback** (`parsers/dom.py`) — `data-testid` selectors. Sparse (no salary), but durable.

If all tiers fail, the tools return an explicit error. They never return an empty list to paper over a parse failure.

## Compliance

This server reads only public job pages and is intended for personal, user-directed job searching.

- XING's `robots.txt` **explicitly `Allow`s `/jobs/search`** for user-directed AI agents (`Claude-User`, `GPTUser`, `PerplexityBot`, …), while the catch-all `User-agent: *` disallows it.
- XING's internal GraphQL API (`/xing-one/api`, `/graphql/`) is `Disallow`ed for **every** agent. This server **never calls it** — the forbidden paths are hard-blocked in `client.py`.
- The default User-Agent identifies this software honestly and does not impersonate a named crawler.
- Requests are serialised at 1/second and cached.

**Caveats you should know about:** this server is not one of the named agents in XING's allowlist, so it sits in a grey area between that allowlist and the catch-all rule. XING/New Work SE's Terms of Service restrict automated data collection independently of `robots.txt`, and listings contain personal and company data subject to GDPR. Personal job hunting is a reasonable use; **commercial redistribution of scraped listings would need legal review.**

## Development

```bash
uv pip install -e ".[dev]"
pytest                    # 39 offline tests, no network
pytest -m live            # 8 tests against the live site
```

**Fixtures are synthetic on purpose.** This repo does not commit scraped XING
pages — that would republish XING's page content and employers' job-ad text,
which is exactly what the compliance note above warns against. The committed
fixtures are generated by `scripts/make_synthetic_fixtures.py` and reproduce the
*structures* the parsers depend on (Apollo cache layout, JSON-LD block, DOM
cards) using invented companies and salaries.

The trade-off is that offline tests cannot notice XING changing its site. That
is what the live suite is for — it checks that the Apollo tier still parses,
that salary estimates are still present, that pagination still returns distinct
results, that the `employmentType` hash ID still works, and that XING's
robots.txt still allowlists `/jobs/search` for AI agents. Run it periodically.

For local debugging against real pages:

```bash
python scripts/fetch_live_fixtures.py   # writes tests/fixtures_live/ (gitignored)
```

## License

MIT

TDQS

A4.3/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: search for jobs, get job details, search across pages, and get company jobs. The two search tools are differentiated by pagination and deduplication, with clear guidance to prefer the paginated one for multi-page queries.

Naming Consistency5/5

All tools follow the verb_noun pattern with consistent snake_case: search_jobs, search_jobs_paginated, get_job_details, get_company_jobs. This makes the tool set easy to predict and navigate.

Tool Count5/5

Four tools is well-scoped for a job search server, covering search, detail retrieval, pagination, and a company filter without redundancy or bloat.

Completeness4/5

The domain of job searching is well covered: searching with filters, pagination, job details, and company-specific listings. Minor gaps like browsing by category or filtering by salary range exist, but the core workflow is complete.

Maintenance

ActivitySlowing
ResponsivenessNo issues