Skip to main content
Glama

kleinanzeigen-mcp

Unofficial project. Not affiliated with, endorsed by, or connected to Kleinanzeigen. "Kleinanzeigen" is used only to describe what the software talks to. This software performs user-directed browser automation on publicly available listings — no account, no login.

A read-only Model Context Protocol server for public kleinanzeigen.de listings. It lets an AI agent search listings and read a single listing through a local browser session.

No AI, no chat UI, no cloud service, no login, no messaging.

Acceptable use

The tool reads public listings, one request at a time, on behalf of a single person. It deliberately does not:

  • log in, create accounts, or touch any account,

  • read inboxes, send messages, or manage saved searches,

  • solve or bypass CAPTCHAs, challenges or access controls,

  • rotate proxies or spoof fingerprints to evade blocks,

  • crawl or bulk-export listings.

Every action maps to one user request: one search, one listing. Searches are capped at 10 result pages. You are responsible for complying with the terms of service of any site you access through this software.

Related MCP server: Marketplace Finder MCP Server

Requirements

  • Node.js >= 20

Install

From npm:

npm install -g @washedguy/kleinanzeigen-mcp
npx patchright install chromium

Or from a checkout:

npm install
npx patchright install chromium
npm run build

The browser runtime is Patchright, a drop-in Playwright fork that closes Playwright's automation leaks (Runtime.enable, navigator.webdriver). If a real Google Chrome is installed it is used automatically for a more realistic fingerprint; override with KLEINANZEIGEN_CHANNEL=chrome|msedge|bundled.

Configure the MCP client

The server speaks MCP over stdio.

{
  "mcpServers": {
    "kleinanzeigen": {
      "command": "npx",
      "args": ["-y", "@washedguy/kleinanzeigen-mcp"]
    }
  }
}

From a checkout, point at the built entrypoint instead:

{
  "mcpServers": {
    "kleinanzeigen": {
      "command": "node",
      "args": ["/path/to/kleinanzeigen-mcp/dist/index.js"]
    }
  }
}

Tools

Tool

Input

Returns

search_listings

query, location?, radiusKm?, minPrice?, maxPrice?, sort?, maxPages?

{ results }

get_listing

id? or url?

Listing

sort is relevance (default), newest, price_asc or price_desc. location takes a city or postal code and combines with radiusKm. maxPages (1–10) walks the numbered result pages and de-duplicates by listing id. Note that promoted "Top-Anzeigen" are pinned to the top and ignore sorting.

Errors

Failures come back as small, safe payloads — never browser stack traces:

{ "error": "CHALLENGE_REQUIRED", "message": "Kleinanzeigen presented a challenge (e.g. CAPTCHA). Try again later from a normal browser session." }

Codes: CHALLENGE_REQUIRED, NAVIGATION_ERROR, LISTING_NOT_FOUND, RATE_LIMITED, INVALID_INPUT, INTERNAL_ERROR.

Examples

const { results } = await searchListings({ query: "Mac Mini M4", maxPrice: 500, sort: "price_asc" });
const listing = await getListing({ id: results[0].id });

How it works

MCP and browser automation are strictly separated: the MCP layer only validates inputs and formats outputs, and never touches the browser.

src/
├── index.ts                 # stdio entrypoint
├── mcp/                     # tools, schemas, response shape
├── kleinanzeigen/           # browser session, page readers, parsing, domain models
└── types/  utils/

Search results and listings are parsed from Kleinanzeigen's server-rendered HTML into domain models; raw HTML never reaches the MCP client.

Debugging

kleinanzeigen-mcp-debug   # or: npm run debug

Opens a visible browser and saves every page (and client-side route change) as HTML plus an index.jsonl into ./debug-snapshots/. To capture from normal tool calls instead:

KLEINANZEIGEN_SAVE_HTML=1 npm start
# or: KLEINANZEIGEN_SNAPSHOT_DIR=/tmp/ka-snaps npm run dev

Snapshots may contain public listing data and are git-ignored — do not commit them.

Development

npm run dev        # stdio server with watch mode
npm run verify     # typecheck + lint + tests (run before committing)
npm run check      # Biome lint/format/import-sort (write)
npm run test       # node:test via tsx

Linting and formatting use a single dev dependency (Biome); configuration is in biome.json.

Security

  • No login, credentials, cookies or tokens: the server only reads public pages.

  • Sessions are not persisted.

  • Challenges are never solved or bypassed: the server returns CHALLENGE_REQUIRED.

  • No proxy rotation, no account creation, no CAPTCHA solving, no bulk scraping.

  • Logs go to stderr only (stdout is the MCP transport).

Limitations

  • Read-only, public listings. No account features.

  • IP reputation is out of scope. If Kleinanzeigen temporarily blocks your IP range, wait it out and reduce request frequency.

  • Promoted listings appear above the requested sort order.

Available Tools

2 tools
get_listingGet listingA
Read-only

Open a single Kleinanzeigen listing and return its normalized details. Provide either id or url. Read-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
idNoKleinanzeigen ad id.
urlNoFull listing URL.

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and openWorldHint, so 'Read-only' largely restates structured data rather than adding it. The description does add that the returned data is 'normalized' and that only one listing is fetched, but says nothing about failure modes, missing ids, or rate limiting.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the action and resource; every clause carries information (action, target, return, invocation, safety) with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description carries the return burden and largely meets it by saying it returns 'normalized details' of one listing. It could be more specific about what fields the normalized payload contains, which is the only real gap for this two-parameter read tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds a genuinely useful semantic the schema lacks: the two optional parameters are alternatives ('provide either `id` or `url`'), clarifying that one is required despite neither being marked required.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a concrete verb and resource ('Open a single Kleinanzeigen listing') plus the outcome ('return its normalized details'), which distinguishes it from the plural sibling search_listings implicitly via 'single'. It never names the sibling, so differentiation is inferred rather than stated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by 'single listing' versus the search sibling, and the 'either `id` or `url`' note signals one way to invoke it. There is no explicit when-to-use/when-not or direct reference to search_listings for the multi-result case.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_listingsSearch listingsB
Read-only

Search Kleinanzeigen.de for listings and return normalized summaries. Read-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
sortNoSort order. Defaults to relevance.
queryYesSearch keywords, e.g. "Mac Mini M4".
locationNoOptional location or postal code.
maxPagesNoHow many result pages to fetch (1-10, default 1).
maxPriceNoMaximum price in EUR.
minPriceNoMinimum price in EUR.
radiusKmNoSearch radius in km.

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=true, so 'Read-only' is largely redundant with structured data. The only added value is 'return normalized summaries,' which hints at output shaping but doesn't say what normalization entails or whether results are paginated/capped.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short, front-loaded sentences with the core action first. Slight waste in the trailing 'Read-only,' which repeats the annotation rather than adding new information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description carries the burden of describing return values; 'normalized summaries' is the only signal about result shape and field content. The parameter surface is fully covered by the schema, but the return format and any result caps remain unspecified.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all seven parameters (query, location, price bounds, sort enum, radiusKm, maxPages) are already documented in the schema. The description adds no filtering, formatting, or default information beyond it, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (search), the resource (listings), the source (Kleinanzeigen.de), and the return shape (normalized summaries). It does not explicitly distinguish itself from the sibling get_listing, though the search-vs-fetch-detail split is obvious from the names.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: an agent can infer this is the entry point for keyword discovery and get_listing is for detail retrieval, but the description never says when to use one over the other or mentions the sibling. No prerequisites or exclusions are stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updatesv0.2.0
    • First observedget_listing
    • First observedsearch_listings

TDQS

A3.7/5.0

Scored across 2 tools

Disambiguation5/5

search_listings and get_listing have clearly distinct purposes: one performs a query and returns multiple summaries, the other retrieves a single listing by id or URL. There is no overlap or risk of misselection.

Naming Consistency5/5

Both tool names follow a consistent verb_noun snake_case pattern (search_listings, get_listing) and accurately reflect read-only behavior. The convention is predictable and unambiguous.

Tool Count3/5

With only two tools, the surface feels thin for a marketplace MCP. While search and detail retrieval are core, the server lacks ancillary tools that would make it feel well-scoped (e.g., category browsing or seller info).

Completeness4/5

The core read-only workflow is covered: users can search listings and retrieve full details for a single listing. Minor gaps exist, such as accessing seller profiles or navigating categories, but agents can work around them for basic browsing.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    F
    maintenance
    Enables AI agents to search and retrieve listings from Sweden's largest second-hand marketplaces, Blocket and Tradera. Returns unified data including prices, images, seller information, and direct links to listings.
    9
    -
  • A
    license
    A
    quality
    A
    maintenance
    Enables AI agents to search and monitor Dutch and Belgian classifieds (Marktplaats and 2dehands) for listings, seller profiles, and categories.
    8
    32 PyPI
    4
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables searching multiple second-hand marketplaces simultaneously from a local command line or AI assistant, providing unified results with pricing insights while respecting each source's terms and robots.txt.
    AGPL 3.0