Search Kleinanzeigen.de, Germany's largest classifieds site, for second-hand listings
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent β or use 1-click editor setup below.
π‘ Paste the JSON block into your client's configuration file under mcpServers, then restart the application.
MCP servers for hunting deals on the German-speaking classifieds sites. TypeScript, over stdio locally or Streamable HTTP self-hosted; works with Claude Code, Claude Desktop, or any other MCP client.
Two servers ship from this repo, each registered separately:
| Server | Site | Entry point |
|---|---|---|
willmehr | willhaben.at (Austria) | dist/index.js |
kleinanzeigen-mcp | kleinanzeigen.de (Germany) | dist/kleinanzeigen/index.js |
They publish as two npm packages, willmehr
and kleinanzeigen-mcp, released
together from this repo at the same version.
The willhaben server was built by reverse-engineering the willhaben web app's own JSON
API from a HAR capture. The Kleinanzeigen server is a port of
jnslmk/kleinanzeigen-mcp β see
Kleinanzeigen below.
Or from a clone, which is what you want for hacking on it or self-hosting:
Either way you get both servers locally, in full mode. Both are listed in the
official MCP registry, as io.github.taneron/willmehr and
io.github.taneron/kleinanzeigen, so a client that reads the registry can find them
without this README. The willhaben account tools need
a session cookie of your own β see Authentication; everything else
works anonymously and needs no setup.
To run it as a shared HTTP server instead, on your own box, see Hosting. Nothing in this project phones home to anyone else's instance.
Both servers run in one of two modes. Same code, same binary β the mode is chosen at
startup with --public / --full or WILLMEHR_MODE, and defaults to full.
full (default) | public | |
|---|---|---|
| willhaben account tools | registered | not registered |
.env / WILLHABEN_COOKIE | loaded | never read; ignored with a warning on stderr |
| willhaben request spacing | 400 ms | 900 ms |
| Kleinanzeigen spacing / pages / batch | 800 ms / 5 / 20 | 1500 ms / 3 / 10 |
public is what makes this safe to host for other people: the process holds no
credential, and registers no tool that could use one, so a shared deployment cannot
leak a session it never loads. The tighter pacing is the other half β in public mode
every user shares one outbound IP, and both sites rate-limit per IP.
Account tools deliberately have no hosted equivalent. willhaben authenticates through
Keycloak with PKCE, so there is no scoped token a third party could be granted β the
only thing a hosted server could ask for is the raw session cookie, which reads
messages and acts as the account. Anyone who wants those four tools runs full mode
locally with their own cookie. See Hosting.
Four public tools, no account needed:
| Tool | Purpose |
|---|---|
willhaben_search | Search the marketplace with structured filters; auto-paginates |
willhaben_get_ad | Full detail for one ad: description, images, seller trust signals |
willhaben_find_deals | Price the market for a query, rank listings below the median |
willhaben_discover_filters | Resolve willhaben's opaque numeric category/brand ids |
Four account tools, requiring a session cookie:
| Tool | Purpose |
|---|---|
willhaben_my_profile | Your profile and numeric user id |
willhaben_my_watchlist | Ads saved to your watchlist |
willhaben_my_conversations | Recent buyer/seller chats |
willhaben_my_alert_count | Number of active saved-search alerts |
Or from source:
willmehr publishes from the repo root. kleinanzeigen-mcp publishes from
build/kleinanzeigen-mcp, staged by npm run pack:kz β it copies the built output the
Kleinanzeigen entry point reaches (its own directory plus the shared mode module) and
generates a manifest around it, so both packages ship the same commit at the same
version. server.json and server.kleinanzeigen.json are the matching MCP registry
entries.
Register it with Claude Code:
Or in a client's MCP config:
willhaben authenticates through Keycloak with PKCE, so there is no username/password grant to automate. Instead, lift the session from a logged-in browser:
npm run session -- ~/Downloads/www.willhaben.at.harnpm run check:authnpm run session writes .env (mode 0600, gitignored) and never prints cookie
values. npm run check:auth exercises all four account tools and stops at the first
401 rather than repeatedly failing auth against your account.
The cookie must contain BBX_JSESSIONID (the session) and x-bbx-csrf-token. The
CSRF token is read out of the cookie automatically β willhaben's web app mirrors that
cookie into a same-named request header on every /webapi/ call, and the server
reproduces that. WILLHABEN_CSRF_TOKEN only exists to override it.
The server loads .env from the package root itself, so MCP clients don't need to
pass the cookie through their config.
BBX_JSESSIONID is sent with a five-day Max-Age, but the server invalidates it well
before that β a session captured and replayed 38 minutes later was already
rejected. It is not IP- or header-binding: the same jar, replayed verbatim with the
browser's complete header set from the same machine and IP, still returns 401 while
anonymous requests continue to work.
Treat the session as short-lived. Re-run npm run session right before you need the
account tools, rather than expecting a capture to keep working for days.
| Variable | Default | Purpose |
|---|---|---|
WILLHABEN_COOKIE | β | Session cookie for account tools |
WILLHABEN_CSRF_TOKEN | from cookie | Override the CSRF token |
WILLHABEN_MIN_INTERVAL_MS | 400 (900 public) | Minimum spacing between requests |
WILLMEHR_MODE | full | full or public β see Modes |
Resolve ids before filtering. Categories and brands are opaque integers. Ask
willhaben_discover_filters first β it returns each filter value with its id and a
hit count for your current query:
Which laptop brands have listings under β¬300 in Vienna right now?
Narrow before ranking deals. willhaben_find_deals compares each listing against
the median of its result set, so the query has to describe one kind of item. Searching
thinkpad mixes β¬900 laptops with β¬5 docking stations and every "discount" it reports
is noise. Searching thinkpad x1 carbon inside category 5831 (Notebooks) with
priceFrom: 150 gives a median worth measuring against.
Watch for suspiciouslyCheap. Any listing under 20% of the median is flagged.
Sometimes that's a genuine bargain; more often it's a placeholder price, a parts-only
listing, or bait. The flag is a prompt to read the ad, not a verdict.
Sniping. Combine sort: "newest" with maxAgeHours: 2 to see only what appeared
in the last couple of hours.
Find me underpriced ThinkPad X1 Carbons from private sellers in Vienna, posted in the last day, and tell me which are worth messaging about.
The agent chains willhaben_discover_filters β willhaben_find_deals β
willhaben_get_ad on the top candidates to check seller age and ad text.
Notes from the HAR analysis, since none of this is documented publicly:
x-wh-client is required. Every /webapi/ route returns a bare 400 with an
empty body without it. This looks exactly like a malformed query parameter and is
the single easiest thing to get stuck on.navigatorGroups[], where
each facet declares the query parameter it maps to and every legal value with a hit
count. willhaben_discover_filters is a thin projection of that, which is why it
stays correct when willhaben adds categories.1 newest, 3 price ascending, 4 price descending, 0 relevance.publicapi.willhaben.at and
api.willhaben.at both refuse anonymous callers. The ad page is Next.js, so the
full payload is read from __NEXT_DATA__, using the lighter
/_next/data/<buildId>/...json route when the buildId is known and falling back to
HTML when willhaben redeploys and the id rotates.{name, values[]} bag. src/normalize.ts flattens it.No reviews yet β be the first to share how this listing worked for you.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/kleinanzeigen-mcp)<a href="https://allmcps.com/mcp/kleinanzeigen-mcp"><img src="https://allmcps.com/api/badge/kleinanzeigen-mcp?style=directory" alt="Kleinanzeigen MCP on AllMCPs" /></a>