marktplaats-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@marktplaats-mcpsearch for a used racing bike near Utrecht max 400 euros"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
marktplaats-mcp
A read-only MCP server for marktplaats.nl, the Dutch classifieds site. It lets an agent search listings and read price, specs, condition, delivery method, location and seller.
Built with the har-to-mcp skill: the site's own browser traffic was recorded once, then the internal API was called directly.
No browser runs at query time.
Status
Capture date: 2026-08-16. Verified against the live site the same day: 42 client checks and 14 MCP protocol checks, all passing.
Consumer sites change. Re-record when tools start failing. See "Re-recording" below.
Related MCP server: opensooq-mcp
Credentials
None. Every tool is a public, logged-out GET request. There are no tokens, no cookies, no accounts, and nothing to refresh.
This is the whole reason the server is simple. Read-only public search needs no session.
No environment variable is required. Two optional ones tune the rate limiter, below.
Rate limiting
This reads an internal API on a live consumer site, so the client is built to behave politely rather than quickly.
Requests are serialised with a minimum gap between them. If an agent fires eight searches at once they queue into one orderly stream instead of fanning out.
Throttling and transient 5xx are retried with exponential backoff and jitter, honouring
Retry-Afterwhen the site sends it.
Variable | Default | Notes |
|
| Minimum gap between request starts. Clamped to 0-60000. |
|
| Retries after the first attempt. Clamped to 0-10. |
The defaults are deliberately conservative. If bulk work feels slow, do less of it rather than
turning the gap down. If the site starts returning HTTP 429, raise
MARKTPLAATS_MIN_INTERVAL_MS instead of retrying harder.
Install
Requires Node.js 20 or newer.
git clone <this-repo-url> marktplaats-mcp
cd marktplaats-mcp
npm install
npm run buildRegister with Claude Code. Run this from the repo root and it fills in the path for you:
claude mcp add marktplaats -- node "$PWD/dist/server.js"Or add it to any MCP client config, using an absolute path to your clone:
{
"mcpServers": {
"marktplaats": {
"command": "node",
"args": ["/absolute/path/to/marktplaats-mcp/dist/server.js"]
}
}
}Check it works:
npm run test:mcpTools
search_listings
Search the site. This is the primary tool and it already carries price, specs and delivery, so most questions need only this one call.
Argument | Type | Notes |
| string, required | Free text, for example |
| 1-100 | Default 30. |
| integer | For paging. |
|
| Default |
| number | Asking price in euros. |
| array of | Several may be given. |
|
| See the delivery note below. |
| string, number | Dutch postcode such as |
| boolean | Default true. |
get_listing
Full detail for one listing, by id (a1517154667) or URL.
Adds what search does not carry: shipping carrier and transit days, view count, favourites, listed-since date, seller tenure, category path, bidding and reserved state, CO2 estimate, and the full description.
get_seller
A seller's public profile by numeric seller id. Useful for telling a private seller from a shop.
Field notes
Delivery has three values, not two.
shipping (Verzenden), pickup (Ophalen), and both (Ophalen of Verzenden).
both is the most common value on the site, at roughly 13 of every 30 results.
Filtering by delivery: "shipping" also returns both listings, which is correct, because those sellers will ship.
Only shipping and pickup are filterable; the site has no filter for both.
Price can be absent.
priceEur is null when the listing takes bids, is free, or names no price.
Read priceType and priceLabel in that case.
Sponsored results are included and flagged.
isSponsored is true for any paid placement.
sponsoredType tells them apart: dagtopper is a boosted private listing (the site shows "Topadvertentie"), admarkt is a professional-seller advert.
Filter on isSponsored if you want organic results only.
Dutch values are kept.
Every translated field has a Raw twin: condition and conditionRaw, delivery and deliveryRaw.
Use the raw value to check a translation against what the site shows.
limit is enforced by this client, not the site.
The search API injects sponsored placements on top of the requested limit, so limit=3 can return 18 rows.
The client slices back to the requested count, keeping the site's own ordering.
How it works
The site is server-rendered Next.js. It has no public API. Two internal routes carry everything:
Route | Type | Used for |
| JSON | Search. Same payload the results page embeds. |
| JSON | Seller profiles. |
| HTML | Detail. Redirects to the canonical URL; data is in |
Filters map to query parameters like this:
Price is a range facet:
attributeRanges[]=PriceCents:<from>:<to>. A plainPriceCentsFromis silently ignored.Condition and delivery are attribute ids:
attributesById[]=30and similar. Confirmed live: Nieuw 30, Zo goed als nieuw 31, Gebruikt 32, Niet werkend 13940, Refurbished 14050, Ophalen 33, Verzenden 34.Distance is
postcode=1011AB&distanceMeters=5000.
What is fragile
Everything above comes from JSON except two reads on the detail page.
get_listing parses the rendered HTML for the spec table (Attributes-module-item) and the description (Description-module-description).
Those two are the first things to break if the site restyles.
If they break, get_listing still returns price, seller, category, shipping, stats and flags, because those come from window.__CONFIG__.
search_listings does not depend on any DOM parsing at all.
The AWS WAF bot-control SDK is present on the site. It did not challenge plain HTTP requests during the capture or during verification. If it starts to, the tools will surface the HTTP status in the error message.
Testing
npm test # both suites
npm run test:client # 42 checks against the live site
npm run test:mcp # 14 checks over the real MCP stdio protocolBoth are read-only and safe to run. They hit the live site, so they need network access and take about a minute.
CI mirrors that split. Type check and build run on every push and never touch the site. The live suites run weekly, as an early warning that the site changed.
Call a tool by hand without wiring up a client:
npm run ask -- search '{"query":"iphone 15 pro","maxPriceEur":500}'
npm run ask -- listing a1517154667
npm run ask -- seller 57429132Re-recording
If the site changes, re-run the capture and re-check the parsing.
Capture drives a real browser, so it needs Playwright. The MCP server does not, which is why Playwright is not a dependency of this package and a normal install stays small. Install it only when you need to re-record:
npm install -D playwright
npx playwright install chromium
npm run capture # drives a headless Chromium over the public search flowAlready have Playwright elsewhere? Point at it instead of installing a second copy:
MARKTPLAATS_PLAYWRIGHT=/path/to/node_modules/playwright npm run captureThe HAR lands in captures/ and screenshots in shots/. Both are gitignored, and must stay
that way. A HAR records real request headers, so yours will contain your own consent, WAF and
analytics cookies. The capture never logs in, so these are anonymous identifiers rather than
account credentials, but they still identify your browser session. Never commit a HAR, and never
git add -f those directories.
Then follow the har-to-mcp skill from Phase 1.
Project layout
src/client.ts typed HTTP client for marktplaats.nl, knows nothing about MCP
src/server.ts the MCP surface, contains no parsing
scripts/verify.mjs client checks against the live site
scripts/smoke-mcp.mjs checks over the real MCP stdio protocol
scripts/capture.mjs re-records the HAR, needs Playwright
scripts/ask.mjs call a tool from the shellKeeping the two src files apart is deliberate. Parsing changes stay in client.ts, and the
tool surface in server.ts stays stable.
captures/, shots/ and work/ are gitignored build-time artefacts and never ship.
Scope
Read-only, by design.
Nothing here logs in, posts an advert, places a bid, messages a seller, adds to a cart, or buys.
Every tool is a GET and is annotated readOnlyHint: true.
Automated access may sit outside the site's terms of service. You are responsible for how you use it. Keep request rates low and sane.
This is an unofficial client. It is not affiliated with, endorsed by, or supported by Marktplaats or its owners.
Contributing
Contributions are welcome. See CONTRIBUTING.md for setup, tests and the review rules. The short version: keep it read-only, keep request rates low, and never commit a capture.
Code of conduct: CODE_OF_CONDUCT.md
Security issues: SECURITY.md, reported privately, never as a public issue
Release history: CHANGELOG.md
If a tool stopped working, that is usually the site changing rather than a code bug. Open a A tool stopped working issue; the template collects what is needed to tell the two apart.
License
ISC.
Available Tools
3 toolsget_listingGet one marktplaats.nl listingARead-only
Fetch full detail for one listing by id or URL. Adds what search does not carry: shipping carrier and transit days, view and favourite counts, listed-since date, seller tenure, category path, bidding and reserved state, and the full description.
| Name | Required | Description | Default |
|---|---|---|---|
| listing | Yes | Listing id such as "a1517154667", or a full marktplaats.nl/v/... URL. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so the safety profile is known. The description adds useful behavioral context by detailing the exact fields returned (shipping carrier, counts, dates, etc.), which is not otherwise disclosed. It stops short of error-handling details, but the annotations lower the burden.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences and quick to read. The first sentence states the core function, and the second lists the value-added fields. No unnecessary words or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by listing the fields returned, giving the agent a clear idea of the response content. It doesn't mention error cases or the response format, but for a simple read-only fetch of a single resource, it is sufficiently complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 100% coverage for the single parameter 'listing', with a description explaining it can be an id or a full URL. The tool description merely repeats 'by id or URL' without adding new meaning, so it doesn't elevate beyond the baseline score.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool fetches full detail for a single listing by id or URL, and it distinguishes itself from search_listings by enumerating the additional fields it returns. The verb 'fetch' and the resource 'listing' are specific, making the purpose unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says it 'Adds what search does not carry,' which clearly informs when to use this tool instead of search_listings. This provides direct guidance on tool selection relative to a sibling tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_sellerGet a marktplaats.nl seller profileARead-only
Fetch a seller's public profile by numeric seller id, as returned in search results. Useful for judging whether a seller is a private person or a shop.
| Name | Required | Description | Default |
|---|---|---|---|
| sellerId | Yes | Numeric seller id from a listing. | |
| sellerName | No | Seller display name, if you have it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only and open-world; the description adds that the profile is public (no auth needed) and that the ID comes from search results, which helps the agent understand the source and safety. It does not detail error handling, but that's beyond what's expected here.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the action and resource, and the second sentence adds purpose without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only profile fetch with only one required parameter, the description provides enough context on what the tool does, where the ID comes from, and how the result can be used. Without an output schema, it could explain return fields, but the purpose makes the presence of profile information sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already fully describes both parameters with 100% coverage, including the numeric seller id and optional seller name. The description's mention of 'numeric seller id' reinforces the schema but adds little new meaning, so baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool fetches a seller's public profile by numeric seller id, and differentiates it from listing-related siblings by focusing on seller information. It also explains the use case of determining private vs shop, which further clarifies purpose.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides a clear context: useful for judging seller type after obtaining the ID from search results. It does not explicitly name alternatives or when-not-to-use, but the context is sufficient to infer when to call it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_listingsSearch marktplaats.nlARead-only
Search marktplaats.nl (Dutch classifieds) for products. Returns price, condition, delivery, category specs, location and seller for each hit. delivery is "shipping", "pickup", "both" (seller offers either) or "unknown". Paid placements are included and flagged with isSponsored. Prices are euros; priceEur is null when a listing takes bids or names no price.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results. Default 30. | |
| query | Yes | What to search for, e.g. "iphone 15" or "racefiets". | |
| offset | No | Skip this many results, for paging. | |
| sortBy | No | Result order. Default relevance. | |
| delivery | No | Filter by delivery. "shipping" also keeps listings marked "both", because those sellers will ship. Only these two values are filterable. | |
| postcode | No | Dutch postcode to measure distance from, e.g. "1011AB". | |
| condition | No | Keep only these conditions. Several may be given. | |
| distanceKm | No | Only listings within this many km of postcode. Needs postcode. | |
| maxPriceEur | No | Highest asking price in euros. | |
| minPriceEur | No | Lowest asking price in euros. | |
| onlyWithPrice | No | Drop listings with no asking price: wanted-ads, trades, giveaways and open-bid auctions. Set this whenever you sort by "price_asc", which otherwise returns every zero-price listing first. Default false. | |
| searchInDescription | No | Match the query in listing bodies too, not only titles. Default true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true. The description adds substantial behavioral context beyond these: the meanings of delivery values ('shipping', 'pickup', 'both', 'unknown'), that paid placements are included and flagged with isSponsored, and that prices are in euros with null for bids/no-price listings. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is five concise sentences that are front-loaded with the core purpose, followed by essential response semantics. Every sentence provides useful information with no redundancy or fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of explaining return values. It covers key fields (price, condition, delivery, category specs, location, seller, isSponsored) and clarifies delivery and price edge cases. However, it does not describe the overall response envelope (e.g., list structure, pagination metadata), leaving some ambiguity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% (all 12 parameters have descriptions). The tool description does not add parameter-level semantics; its delivery and price details are about response fields, not input parameters. Thus, it stays at the baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function with a specific verb ('Search') and resource ('marktplaats.nl (Dutch classifieds)'). It also lists the returned fields, distinguishing it from sibling tools like get_listing and get_seller, which are focused on retrieving individual items rather than searching.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no explicit guidance on when to use this tool versus alternatives. There is no mention of get_listing or get_seller, and no exclusions or prerequisites are given. The agent must infer usage solely from the tool name and basic function description.
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. Dates show when Glama detected each change.
3 tool updates
v0.1.0- First observed
get_listing - First observed
get_seller - First observed
search_listings
TDQS
Each tool targets a distinct resource: search_listings searches the marketplace, get_listing fetches one listing's details, and get_seller fetches a seller's profile. There is no overlap between these operations.
All tool names follow a consistent verb_noun pattern: search_listings, get_listing, get_seller. Naming style is uniform snake_case with clear verbs.
Three tools is an appropriate, well-scoped set for a read-only classifieds search server. Each tool is essential and there is no redundancy.
The core read workflows (search, view detail, view seller) are covered, which is sufficient for a marketplace lookup server. However, the surface lacks a direct way to list all listings by a seller (or other browse/filter operations), which would round out the domain.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Agent-native marketplace. Bootstrap, list inventory, search, negotiate, and trade via MCP.
MCP server for Open Archives: Dutch genealogical records and historical page transcriptions.
MCP Server for an Agent Task Marketplace
Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.
Related MCP Servers
AlicenseNot gradedqualityDmaintenanceMCP server for scraping product prices, offers, reviews, and details from Amazon, Google Shopping, Bol.com, and Coolblue via natural language commands, with spend-cap protections.321MIT- AlicenseNot gradedqualityCmaintenanceA read-only MCP server that gives LLM agents live access to OpenSooq, the largest classifieds marketplace in Kuwait, enabling search, pricing, seller reputation, and deal finding.2MIT
- AlicenseNot gradedqualityFmaintenanceEnables AI assistants to search and view advertisements on Marktplaats.nl with extensive filtering options.16MIT
- AlicenseAqualityAmaintenanceEnables AI agents to search and monitor Dutch and Belgian classifieds (Marktplaats and 2dehands) for listings, seller profiles, and categories.52MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Bitsy-Chuck/marketplaat_mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server