marktplaats-mcp
Search and monitor classified ads on Marktplaats/2dehands, analyze prices, vet sellers, and (with your own login) manage messages, favorites, and bids.
Search listings with query, category, subcategory, category-specific attributes, price range, condition, delivery options, distance from postcode, recency, sorting, and pagination.
Get full listing details: description, images, attributes, status, view/favorite counts, bidding state, shipping info, and seller response metrics.
Vet sellers via trust signals: verified bank/identity/phone, business verification, review score/count, and lowest acceptable bid.
Browse categories and discover valid category filters (brand, mileage, fuel, etc.) with counts.
Monitor new listings with a stateless cursorβonly returns ads placed after a given timestamp, never skipping any.
Analyze prices: median, quartiles, min/max/mean asking prices, plus cheapest matches for a search.
With your own login: read/send messages, contact sellers (including non-binding offers), place bids, manage favorites and your own listings, and check account notifications.
Safety-first: read-only tools are annotated; all write actions (message, bid, favorite) preview first and require explicit confirmation.
Provides tools for GitHub Copilot to search Marktplaats and 2dehands listings, retrieve listing details and seller profiles, browse categories, and monitor new listings.
Provides tools for JetBrains IDEs (AI Assistant / Junie) to search Marktplaats and 2dehands listings, retrieve listing details and seller profiles, browse categories, and monitor new listings.
Provides tools for OpenAI Codex CLI to search Marktplaats and 2dehands listings, retrieve listing details and seller profiles, browse categories, and monitor new listings.
Click on "Deploy 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 OLED TV under β¬400 near 3011 AB"
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: the Marktplaats & 2dehands MCP server
marktplaats-mcp is an MCP server for Marktplaats.nl (Netherlands) and 2dehands.be (Belgium), the Dutch and Belgian second-hand classifieds (tweedehands, petites annonces d'occasion). Search listings, filter on category attributes, vet sellers, compare prices and watch for new ads from Claude, ChatGPT, Cursor, Codex, Gemini or any other MCP client. With your own login it also reads and sends messages, places bids and manages your favorites and ads. No API key.
π Get started
No install: paste a URL. The hosted, read-only server runs at https://marktplaats-mcp.jaspnerd.dev/mcp. Add it as a custom connector in claude.ai (Settings β Connectors, works on the Free plan and mobile), ChatGPT, Mistral Le Chat, Perplexity or the Gemini app.
Claude Code: one command.
claude mcp add --scope user marktplaats -- uvx marktplaats-mcpAny other client. Install uv (brew install uv, or winget install --id=astral-sh.uv -e on Windows), then add the standard MCP config:
{ "mcpServers": { "marktplaats": { "command": "uvx", "args": ["marktplaats-mcp"] } } }One click:
Step-by-step instructions for 40 clients (Cursor, VS Code, Codex, Gemini CLI, Cline, Windsurf, JetBrains, Zed, opencode, Goose, ...), with the config path per OS and a link to each client's official guide: docs/clients.md.
Then ask: "Find a racefiets under β¬500 within 25 km of 1011 AB, frame 57-61 cm, and tell me if the sellers look legit."
Related MCP server: Begagnad MCP
π€ Use your own account (messages, favorites, bids, your ads)
Marktplaats has no public API and its login uses SMS two-factor authentication, so this server never asks for your password. It copies the session from a browser you are already logged into:
uvx --from 'marktplaats-mcp[login]' marktplaats-mcp loginThe session is stored in ~/.config/marktplaats-mcp/session.json, readable by your user only. Restart your MCP client and the account tools appear.
marktplaats-mcp login --site 2dehands # also import your 2dehands.be session
marktplaats-mcp login --read-only # never send, bid or change favorites
marktplaats-mcp login --window # open a browser window and log in there instead
marktplaats-mcp login --paste # paste a Cookie header from DevTools instead
marktplaats-mcp status # is the stored session still valid?
marktplaats-mcp logout # delete itmacOS: the system blocks command-line tools from reading browser data and does not ask. Once, open System Settings β Privacy & Security β Full Disk Access, add the terminal app you use (Terminal, iTerm, Warp, or VS Code), then quit and reopen it. Then run the login command again.
Windows: Chrome and Edge lock their cookie file while they run; the tool copies it first, so this normally just works. If it doesn't, close the browser and run the login again, or use
--paste.Linux: Chromium browsers store the cookie key in your keyring (GNOME Keyring or KWallet), which must be unlocked; Firefox needs nothing. Snap or Flatpak browsers keep their profile elsewhere, so use
--pastethere.Everywhere:
marktplaats-mcp login --pastenever needs permissions. In your browser on marktplaats.nl press F12 β Network, click any request, copy theCookierequest header and paste it.
Or set MARKTPLAATS_COOKIE / TWEEDEHANDS_COOKIE (the request Cookie header) in your client's config. Sessions last weeks; when one expires the tools tell you to log in again.
Sending, contacting a seller and bidding return a preview first and only act when called again with confirm=true. Bids are binding on Marktplaats; the tool refuses bids below the minimum. Automated ad placement is forbidden by Marktplaats' terms and deliberately not implemented. See Safety model.
π§° Tools
Tool | What it does | Account | Writes |
| Search with query, category, subcategory, category-specific attributes, price range, condition, delivery (pickup/shipping), distance from a postcode, recency, negative keywords, sorting and pagination | ||
| Full ad: description, attributes, status (active/closed), exact listing time, view and favorite counts, bidding state and minimum bid, shipping, images, seller response rate and account age. Accepts pasted URLs | ||
| Trust signals: verified bank account, identity, phone, business verification, payment method, review score and count, lowest bid the seller accepts | ||
| Everything one seller has on offer: spot dealers posing as private sellers and duplicate ads | ||
| The category tree (names and ids) used for filtering, also available as an MCP resource | ||
| Discover the filters for a category (brand, frame height, mileage, fuel, RAM, ...) with their valid values and counts | ||
| Newest-first monitoring with a stateless cursor: returns only ads placed after | ||
| Median, quartiles, min, max and mean asking prices for a search, plus the cheapest matches | ||
| Session check, unread messages and notifications | β | |
| Your inbox and full message threads | β | |
| Your ads (views, favorites, highest bid, expiry), favorites, bids and saved searches | β | |
| Reply in a thread, or ask a seller a question or make a non-binding offer. Preview first, | β | β |
| Bid on a listing. Preview first, refuses bids below the minimum, marked destructive | β | β |
| Save/unsave a listing; renew one of your expiring ads | β | β |
Read-only tools carry the matching MCP annotations, so clients skip confirmation prompts for them and ask for the write tools. Every tool returns structured output with a real schema. Two prompts, bargain_hunt and vet_listing, encode the common workflows.
What you can say, and what happens
You say | The agent calls |
"Is β¬450 a fair price for an iPhone 15 128 GB in good condition?" |
|
"Find a used Golf, 2018-2022, under 100,000 km, petrol, from a private seller" |
|
"Is this seller trustworthy? What else are they selling?" |
|
"Tell me when new bakfiets ads appear near Antwerp" |
|
"Ask the seller whether it's still available and offer β¬120" |
|
"Reply to Piet that I can pick it up Saturday" |
|
π Safety model
No credentials by default. Searching, details, seller checks, filters, price statistics and monitoring need no account.
Your session stays yours. The local server reads the cookie from your browser or a file only you can read, sends it only to marktplaats.nl / 2dehands.be, and never logs it. The hosted endpoint refuses to start with account credentials configured.
Writes are explicit. Sending and bidding preview first and require
confirm=true; bids below the minimum are refused;login --read-onlyorMARKTPLAATS_READ_ONLY=1disables writes entirely; every confirmed write is logged locally.Untrusted content is labelled. Listing text and messages are written by other users; the server tells the model to treat them as data, never as instructions.
Polite to the marketplace. Requests are spaced (
MARKTPLAATS_MIN_INTERVAL_MS, default 200), retried with backoff andRetry-After, and search pages are cached for a minute. The hosted endpoint is rate-limited per client and globally.No affiliate links, no tracking. Listing URLs are returned exactly as the marketplaces publish them.
β FAQ
Is there an MCP server for Marktplaats?
Yes, this one. Free, open source (MIT), no API key. Paste the hosted URL into claude.ai or run uvx marktplaats-mcp.
Does it work with 2dehands.be and Belgium?
Yes. Every tool takes site="2dehands", and language="nl" or "fr" narrows Belgian results to one language.
Do I need a Marktplaats account or API key?
No. Only the account tools need your own login, and they use your existing browser session rather than a password.
Can AI read and send my Marktplaats messages, or place bids?
Yes, with the local server after marktplaats-mcp login. Sending and bidding show a preview and only act after you confirm.
Where are my login credentials stored?
In ~/.config/marktplaats-mcp/session.json on your machine, readable by your user only, or in the environment variables you set yourself. They are only ever sent to marktplaats.nl / 2dehands.be. marktplaats-mcp logout removes them.
Can I use it without installing anything?
Yes: the hosted endpoint https://marktplaats-mcp.jaspnerd.dev/mcp works in claude.ai, including the Free plan and mobile apps. It offers the read-only tools.
Does it work with ChatGPT, Cursor, Gemini, VS Code and Cline?
Yes. See docs/clients.md for step-by-step instructions per client. Any client that runs stdio servers can use uvx marktplaats-mcp; clients that support remote servers can use the hosted URL.
Is this official or affiliated with Marktplaats?
No. It is an independent open source project with no ties to Marktplaats, 2dehands or Adevinta. It uses the same public JSON endpoints the websites use; that API is undocumented and may change, which is why a live canary runs every day.
Why do I sometimes see fewer results than the limit, or total_count looks high?
Paid promotions (DAGTOPPER, TOPADVERTENTIE) are filtered out by default; pass include_sponsored=true to see them. total_count is the marketplace's raw count before that filtering.
Which Python versions are supported?
3.10 and up. CI tests 3.11 through 3.13 on Linux, macOS and Windows.
π Docs
Install in your client: step-by-step for 40 clients
Configuration: environment variables for the local and hosted server
How this compares to the other Marktplaats MCP servers
πΊοΈ Roadmap
Cross-site search (NL and BE in one call)
Saved-search creation from the agent
Claude Desktop extension bundle (MCPB)
π€ Contributing
PRs welcome. See CONTRIBUTING.md for the dev setup: uv sync --all-groups, then uv run pytest. uv run python scripts/e2e_smoke.py runs the live canary.
This project reuses proven ideas from marktplaats-py, marktplaats-monitor, marktplaats-2dehands-mcp and PonClick/marktplaats-mcp. Details in THIRD_PARTY_NOTICES.md.
If this saved you a trip to Marktplaats, a star helps other people find it.
π License
MIT Β© 2026 jasp-nerd
mcp-name: io.github.jasp-nerd/marktplaats-mcp
Available Tools
8 toolsanalyze_pricesAnalyze pricesARead-onlyIdempotentInspect
Price statistics (min, quartiles, median, max, mean) over the most relevant asking prices for a search, plus the cheapest matches. Free, bidding-only and reserved ads are excluded and outliers beyond 1.5x the interquartile range are trimmed. Most reliable with a subcategory plus attributes (e.g. subcategory 'Mobiele telefoons | Apple iPhone', attributes {'Model': 'iPhone 15', 'Opslagcapaciteit': '128 GB'}) instead of free text, which drags in accessories.
| Name | Required | Description | Default |
|---|---|---|---|
| site | No | Which marketplace: marktplaats (Netherlands) or 2dehands (Belgium). | marktplaats |
| query | Yes | Free-text search, e.g. 'racefiets' or 'iphone 15'. May be empty if a category is given. | |
| exclude | No | Drop listings whose title or description contains any of these words, e.g. ['hoesje', 'defect', 'gezocht']. | |
| category | No | Top-level category name (Dutch, e.g. 'Fietsen en Brommers') or numeric id. See list_categories. | |
| delivery | No | 'shipping' for ads that can be shipped, 'pickup' for collection. | |
| language | No | 2dehands only: 'nl' for Dutch-language ads, 'fr' for French, 'all' (default). | |
| postcode | No | Dutch/Belgian postal code to search around, e.g. '1011 AB' or '2000'. Required for distance filtering and for distance_km in results. | |
| price_to | No | Maximum price in euros. | |
| condition | No | Filter by item condition. | |
| attributes | No | Category-specific filters as {filter: value}, using the labels from list_category_filters, e.g. {'Merk': 'Gazelle', 'Framehoogte': '57 tot 61 cm'} or {'Bouwjaar': '2018-2022', 'Kilometerstand': '-100000', 'Brandstof': 'Benzine'}. A list means any of those values. Ranges are 'min-max', 'min-' or '-max'. | |
| price_from | No | Minimum price in euros. | |
| distance_km | No | Max distance from postcode in kilometers (needs postcode). | |
| sample_size | No | Listings to sample, most relevant first (10-100). | |
| subcategory | No | Subcategory name (e.g. 'Fietsen | Racefietsen' or 'Fietsen | Heren | Herenfietsen') or numeric id. See list_categories with a parent. |
Output Schema
| Name | Required | Description |
|---|---|---|
| max | No | |
| min | No | |
| p25 | No | |
| p75 | No | |
| mean | No | |
| note | No | |
| site | Yes | |
| query | Yes | |
| median | No | |
| cheapest | No | |
| sample_size | Yes | |
| total_count | Yes | |
| excluded_outliers | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint and idempotentHint annotations, the description discloses concrete behavioral details: free, bidding-only and reserved ads are excluded, outliers beyond 1.5x IQR are trimmed, and statistics are based on the most relevant asking prices. This is genuine methodological transparency that an agent cannot infer from 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?
Three dense sentences: the first front-loads the core purpose, the second explains exclusions and outlier trimming, and the third gives a practical reliability tip. No filler or repetition of schema details.
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 14-parameter tool with 100% schema coverage, an output schema, and safety annotations, this description is complete enough. It explains the computation, exclusions, and reliability considerations; return values are covered by the output schema, so no further explanation is needed.
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 coverage is 100%, so the baseline is 3. The description adds meaningful guidance beyond the schema by recommending subcategory plus attributes over free-text query and explaining that free text drags in accessories. This helps an agent choose better parameter combinations.
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 names a specific verb and resource: it computes price statistics (min, quartiles, median, max, mean) and returns cheapest matches for a search. This is clearly distinct from sibling tools like search_listings or get_listing_details, so an agent can tell what the tool does without opening the schema.
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 gives clear context for how to use the tool: it operates over a search and is most reliable with a subcategory plus attributes rather than free text. It does not explicitly name alternatives or state when not to use it, but the context is strong enough to guide an agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_new_listingsCheck new listingsARead-onlyIdempotentInspect
Poll for listings placed after a given moment (newest first, paid promotions filtered out). Stateless: store the returned 'cursor' and pass it as 'since' on the next call. When the result is truncated the cursor only advances to the oldest ad returned, so nothing is ever skipped.
| Name | Required | Description | Default |
|---|---|---|---|
| site | No | Which marketplace: marktplaats (Netherlands) or 2dehands (Belgium). | marktplaats |
| limit | No | Max new listings to return (1-100). | |
| query | No | Free-text search, e.g. 'racefiets' or 'iphone 15'. May be empty if a category is given. | |
| since | No | ISO 8601 timestamp (e.g. '2026-07-15T09:00:00Z'); only listings placed after this moment are returned. Defaults to 24 hours ago. Pass the 'cursor' from the previous call to poll incrementally. | |
| exclude | No | Drop listings whose title or description contains any of these words, e.g. ['hoesje', 'defect', 'gezocht']. | |
| category | No | Top-level category name (Dutch, e.g. 'Fietsen en Brommers') or numeric id. See list_categories. | |
| delivery | No | 'shipping' for ads that can be shipped, 'pickup' for collection. | |
| language | No | 2dehands only: 'nl' for Dutch-language ads, 'fr' for French, 'all' (default). | |
| postcode | No | Dutch/Belgian postal code to search around, e.g. '1011 AB' or '2000'. Required for distance filtering and for distance_km in results. | |
| price_to | No | Maximum price in euros. | |
| condition | No | Filter by item condition. | |
| attributes | No | Category-specific filters as {filter: value}, using the labels from list_category_filters, e.g. {'Merk': 'Gazelle', 'Framehoogte': '57 tot 61 cm'} or {'Bouwjaar': '2018-2022', 'Kilometerstand': '-100000', 'Brandstof': 'Benzine'}. A list means any of those values. Ranges are 'min-max', 'min-' or '-max'. | |
| price_from | No | Minimum price in euros. | |
| distance_km | No | Max distance from postcode in kilometers (needs postcode). | |
| subcategory | No | Subcategory name (e.g. 'Fietsen | Racefietsen' or 'Fietsen | Heren | Herenfietsen') or numeric id. See list_categories with a parent. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | |
| site | Yes | |
| since | Yes | |
| cursor | Yes | |
| listings | Yes | |
| new_count | Yes | |
| truncated | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnly, idempotent, non-destructive), the description discloses critical behavior: the tool is stateless, paid promotions are filtered out, and when results are truncated the cursor deliberately only advances to the oldest returned ad so no listing is skipped. This is exactly the kind of behavioral nuance an agent needs.
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?
Three tight sentences, each earning its place: the core action, the cursor state protocol, and the truncation caveat. It is front-loaded and contains no filler.
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?
Given the high-quality input schema, annotations, and output schema, the description covers the non-obvious usage contract completely: stateless polling, cursor advancement semantics, and the no-skip guarantee. Nothing essential for correct invocation is missing.
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?
Input schema coverage is 100%, with rich per-parameter descriptions, so the baseline is 3. The description adds the cursor/since relationship, but most parameter meaning already lives in the schema; no compensation is needed.
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 uses a specific verb ('Poll') and resource ('listings'), and pinpoints the exact behavior: listings placed after a given moment, newest first, paid promotions filtered out. This clearly distinguishes it from general-purpose siblings like search_listings or list_seller_listings, even without naming them.
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 gives clear operational context: poll incrementally by storing and passing the returned cursor as 'since'. It does not explicitly state when to prefer this over search_listings or other siblings, so it stops short of full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_listing_detailsGet listing detailsARead-onlyIdempotentInspect
Fetch the full advertisement: complete description, attributes, status (active/closed), exact listing time, view and favorite counts, bidding state, shipping, images, and seller signals such as response rate and account age.
| Name | Required | Description | Default |
|---|---|---|---|
| site | No | Which marketplace: marktplaats (Netherlands) or 2dehands (Belgium). | marktplaats |
| listing_id | Yes | Listing id from search results (e.g. 'm2400641485') or a pasted marktplaats.nl / 2dehands.be listing URL. | |
| max_images | No | Max image URLs to return (0-20). |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | |
| url | Yes | |
| city | No | |
| note | No | |
| site | Yes | |
| price | No | |
| since | No | |
| title | No | |
| seller | No | |
| status | No | |
| bidding | No | |
| country | No | |
| delivery | No | |
| postcode | No | |
| reserved | No | |
| listed_at | No | |
| attributes | No | |
| buy_it_now | No | |
| image_urls | No | |
| price_type | No | |
| view_count | No | |
| category_id | No | |
| description | No | |
| image_count | No | |
| price_euros | No | |
| car_attributes | No | |
| favorited_count | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description is consistent with these hints and adds detail on the response contents, but it does not disclose additional behavioral traits such as rate limits or auth requirements.
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 a single dense sentence that front-loads the core action and resource, then efficiently lists all returned data categories. Every phrase adds value, and there is no filler 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?
Given a rich output schema, fully documented parameters, and annotations covering safety and idempotency, the description provides sufficient context for an agent to select and invoke the tool correctly. No critical behavioral or usage gap remains.
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%, so the input schema already documents listing_id, site, and max_images fully. The description does not add parameter-level meaning beyond what the schema provides, so the baseline 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 uses a specific verb ('Fetch') and names the exact resource ('the full advertisement'), then enumerates the included fields. This clearly distinguishes it from sibling tools like get_seller_profile or search_listings, which target different resources or scopes.
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 explains what the tool returns but gives no explicit guidance on when to use it versus alternatives such as list_seller_listings or search_listings. There are no when-to-use, when-not-to-use, or exclusion statements.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_seller_profileGet seller profileARead-onlyIdempotentInspect
Look up a seller's trust signals: verified bank account / identity / phone number, business verification, payment method, review score and count. Null means the marketplace does not report that signal. Use list_seller_listings to see everything the seller currently offers.
| Name | Required | Description | Default |
|---|---|---|---|
| site | No | Which marketplace: marktplaats (Netherlands) or 2dehands (Belgium). | marktplaats |
| seller_id | Yes | Numeric seller id from a listing's seller field. |
Output Schema
| Name | Required | Description |
|---|---|---|
| site | Yes | |
| seller_id | Yes | |
| average_score | No | |
| payment_method | No | |
| business_verified | No | |
| number_of_reviews | No | |
| bank_account_verified | No | |
| phone_number_verified | No | |
| identification_verified | No | |
| low_bid_threshold_percent | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and non-destructive behavior. The description adds the important interpretation that null means the marketplace does not report that signal, which helps the agent avoid misreading missing data as a problem.
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 sentences deliver the core purpose, the null semantics, and a cross-reference to a sibling tool with no filler. Everything earns its place.
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?
Annotations cover safety and idempotency, an output schema exists, parameters are fully documented, and the description provides the one interpretive detail an agent needs: what null means. Nothing essential is missing.
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%, so parameters are already fully documented in the schema. The description does not add much beyond indicating the seller context; per the rubric, baseline 3 is appropriate when the schema carries the parameter-semantics load.
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?
Description opens with a specific verb-resource pair ('Look up a seller's trust signals') and enumerates concrete signal types. It also names list_seller_listings as the sibling for current offerings, which distinguishes this tool from a nearby alternative.
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 implies the tool is for trust/verification data rather than active listings, and explicitly points to list_seller_listings when the agent needs current offers. It provides a clear context signal, though it does not spell out exhaustive when-not-to-use conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_categoriesList categoriesARead-onlyIdempotentInspect
Browse the category tree (shared by marktplaats.nl and 2dehands.be) to find names/ids for search_listings' category and subcategory filters.
| Name | Required | Description | Default |
|---|---|---|---|
| parent | No | Omit for all top-level categories; pass a top-level category name or id for its subcategories. |
Output Schema
| Name | Required | Description |
|---|---|---|
| level | Yes | |
| parent | No | |
| categories | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, and the description's 'Browse' aligns perfectly. The description adds context that the tree is shared between marktplaats.nl and 2dehands.be, which is useful beyond annotations. No contradiction.
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?
One sentence, front-loaded with the core purpose, no filler. The description is precisely as long as needed.
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 simple read-only tool with one optional parameter, an output schema, and annotations covering safety, the description is complete. It tells the agent what the tool does and why it's useful, leaving no essential gaps.
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 fully documents the single `parent` parameter, including its nullability and semantics. The description adds no additional parameter detail beyond the schema, so with 100% schema coverage, a baseline of 3 is appropriate.
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 it browses a category tree shared across two marketplaces, with the explicit purpose of finding names/ids for search_listings filters. This distinguishes it from sibling tools by tying it to a specific downstream use.
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 explains when to use this tool: to obtain category names/ids for search_listings filters. It implies that it's the go-to for exploring the category hierarchy, though it doesn't explicitly mention alternatives or when not to use it. Still, the purpose is actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_category_filtersList category filtersARead-onlyIdempotentInspect
Discover the filters available for a category or search (brand, frame height, mileage, fuel, RAM, ...), with their valid values and how many ads match each. Pass the labels to search_listings' 'attributes' parameter.
| Name | Required | Description | Default |
|---|---|---|---|
| site | No | Which marketplace: marktplaats (Netherlands) or 2dehands (Belgium). | marktplaats |
| query | No | Optional search text; needed when no category is given. | |
| category | No | Top-level category name (Dutch, e.g. 'Fietsen en Brommers') or numeric id. See list_categories. | |
| max_options | No | Max values per filter, most common first (1-200). | |
| subcategory | No | Subcategory name (e.g. 'Fietsen | Racefietsen' or 'Fietsen | Heren | Herenfietsen') or numeric id. See list_categories with a parent. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | |
| site | Yes | |
| query | No | |
| filters | Yes | |
| category | No | |
| subcategory | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate read-only, idempotent, and non-destructive behavior. The description adds useful context about output semantics: valid values and per-value ad counts, plus the fact that filters apply to either a category or a search. 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?
Two sentences front-load the purpose, include concrete filter examples, and end with an actionable downstream instruction. Every sentence earns its place with no redundancy or filler.
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?
Given the rich output schema, complete parameter descriptions, and safety annotations, the definition is sufficiently complete. It explains what the tool returns and how to use the result, while the schema covers parameter defaults and relationships to list_categories.
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%, so the schema fully documents all parameters. The description adds only a small semantic link between 'category or search' and the downstream use of labels, but it does not provide new parameter-level meaning.
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 states a specific action ('Discover the filters available for a category or search') and a clear resource: filters with valid values and match counts. It also differentiates itself from siblings by explaining that the returned labels feed into search_listings' 'attributes' parameter.
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?
It clearly conveys when to use the tool: when you need the available filters for a category or query, and it shows how the result should be consumed downstream. It does not explicitly name alternatives or when-not-to-use conditions, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_seller_listingsList a seller's listingsARead-onlyIdempotentInspect
Everything one seller currently has on offer. Useful to spot dealers posing as private sellers, duplicate or suspicious ads, and bundle deals.
| Name | Required | Description | Default |
|---|---|---|---|
| site | No | Which marketplace: marktplaats (Netherlands) or 2dehands (Belgium). | marktplaats |
| limit | No | Results per page (1-100). | |
| query | No | Optional text to filter the seller's ads. | |
| offset | No | Pagination: pass 'next_offset' from the previous result. | |
| compact | No | True (default) returns a token-efficient shortlist; False adds description, seller, images and attributes per listing. | |
| sort_by | No | 'relevance' (default), 'date' (newest first with desc), 'price' or 'location'. | date |
| seller_id | Yes | Numeric seller id. | |
| sort_order | No | 'asc' or 'desc'. | desc |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | |
| site | Yes | |
| limit | Yes | |
| offset | Yes | |
| listings | Yes | |
| returned | Yes | |
| next_offset | No | |
| total_count | Yes | |
| suggested_query | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds the 'currently has on offer' phrasing, implying real-time data, but does not disclose pagination behavior or result format beyond what the schema/output schema provide. It does not contradict 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 two sentences with no wasted words. The first sentence states the core purpose; the second lists practical use cases. It is front-loaded and efficient.
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 an output schema present and 100% parameter coverage, the description only needs to add contextual value, which it does via use cases. It does not repeat schema details, and nothing essential for selecting or invoking the tool is missing.
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%, so the schema fully documents all 8 parameters. The description adds no parameter-specific meaning beyond what the schema already states, which matches the baseline of 3 for high schema coverage.
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 resource ('everything one seller currently has on offer') and the implied verb 'list'. It is unambiguous about scope but does not explicitly differentiate from siblings like search_listings or get_seller_profile, though the 'one seller' scope distinguishes it naturally.
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 concrete use cases ('spot dealers posing as private sellers, duplicate or suspicious ads, and bundle deals'), giving clear context on when to use it. It does not state when not to use it or name alternatives, so it misses the exclusion guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_listingsSearch listingsARead-onlyIdempotentInspect
Search second-hand listings on Marktplaats or 2dehands with filters for category, category-specific attributes, price range, condition, delivery, recency and distance from a postal code. Paid promotions are filtered out unless include_sponsored is set.
| Name | Required | Description | Default |
|---|---|---|---|
| site | No | Which marketplace: marktplaats (Netherlands) or 2dehands (Belgium). | marktplaats |
| limit | No | Results per page (1-100). | |
| query | No | Free-text search, e.g. 'racefiets' or 'iphone 15'. May be empty if a category is given. | |
| offset | No | Pagination: pass 'next_offset' from the previous result. | |
| compact | No | True (default) returns a token-efficient shortlist; False adds description, seller, images and attributes per listing. | |
| exclude | No | Drop listings whose title or description contains any of these words, e.g. ['hoesje', 'defect', 'gezocht']. | |
| sort_by | No | 'relevance' (default), 'date' (newest first with desc), 'price' or 'location'. | relevance |
| category | No | Top-level category name (Dutch, e.g. 'Fietsen en Brommers') or numeric id. See list_categories. | |
| delivery | No | 'shipping' for ads that can be shipped, 'pickup' for collection. | |
| language | No | 2dehands only: 'nl' for Dutch-language ads, 'fr' for French, 'all' (default). | |
| postcode | No | Dutch/Belgian postal code to search around, e.g. '1011 AB' or '2000'. Required for distance filtering and for distance_km in results. | |
| price_to | No | Maximum price in euros. | |
| condition | No | Filter by item condition. | |
| attributes | No | Category-specific filters as {filter: value}, using the labels from list_category_filters, e.g. {'Merk': 'Gazelle', 'Framehoogte': '57 tot 61 cm'} or {'Bouwjaar': '2018-2022', 'Kilometerstand': '-100000', 'Brandstof': 'Benzine'}. A list means any of those values. Ranges are 'min-max', 'min-' or '-max'. | |
| price_from | No | Minimum price in euros. | |
| sort_order | No | 'asc' or 'desc'. | desc |
| distance_km | No | Max distance from postcode in kilometers (needs postcode). | |
| subcategory | No | Subcategory name (e.g. 'Fietsen | Racefietsen' or 'Fietsen | Heren | Herenfietsen') or numeric id. See list_categories with a parent. | |
| include_unpriced | No | Keep ads without an asking price (free, 'Bieden' without amount) when sorting by price or filtering on price. Default False: those ads would otherwise sort as β¬0 and flood the cheapest pages. | |
| include_sponsored | No | Include paid promotions (DAGTOPPER/TOPADVERTENTIE) and the sponsored top block. | |
| offered_since_days | No | Only listings placed within the last N days. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | |
| site | Yes | |
| limit | Yes | |
| offset | Yes | |
| listings | Yes | |
| returned | Yes | |
| next_offset | No | |
| total_count | Yes | |
| suggested_query | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering the safety profile. The description adds a non-obvious behavioral default: 'Paid promotions are filtered out unless include_sponsored is set.' This goes beyond structured fields and clarifies an important hidden behavior without contradicting the 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 exactly two sentences with no filler. The main purpose is front-loaded, followed by a compact list of filter dimensions and a key behavioral default. Every sentence earns its place.
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 tool with 21 parameters, a rich output schema, and detailed per-parameter descriptions, the description provides adequate orientation: what it searches, which platforms, and a notable default. It could explicitly mention pagination or sorting, but those are already documented in the schema, so nothing essential is missing.
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%, so the baseline is 3 and the schema already explains every parameter thoroughly. The description's enumeration of filter types adds no syntax or format details beyond what each parameter description provides. It does not need to compensate for any gap.
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 a specific verb ('Search') and a specific resource ('second-hand listings on Marktplaats or 2dehands'), and enumerates the available filter dimensions. It is not a tautology and gives a concrete sense of the tool's role. However, it does not explicitly distinguish itself from sibling tools like list_seller_listings or check_new_listings, so it falls short of a 5.
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 implies the tool is for finding listings by criteria, and the schema's parameter descriptions point to companion tools (list_categories, list_category_filters), providing indirect workflow guidance. There is no explicit 'use this when...' or 'use X instead when...' statement, so an agent must infer when to choose this over siblings.
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.
8 tool updates
v0.2.0- Added
analyze_prices - Changed
check_new_listings11 fields changed- added
Input schema / properties / attributesAdded value: +{ + "anyOf": [ + { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] + }, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Category-specific filters as {filter: value}, using the labels from list_category_filters, e.g. {'Merk': 'Gazelle', 'Framehoogte': '57 tot 61 cm'} or {'Bouwjaar': '2018-2022', 'Kilometerstand': '-100000', 'Brandstof': 'Benzine'}. A list means any of those values. Ranges are 'min-max', 'min-' or '-max'." +} - added
Input schema / properties / deliveryAdded value: +{ + "anyOf": [ + { + "enum": [ + "pickup", + "shipping" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "'shipping' for ads that can be shipped, 'pickup' for collection." +} - changed
Input schema / properties / distance_km / descriptionPrevious value: -"Max distance from postcode in kilometers."New value: +"Max distance from postcode in kilometers (needs postcode)." - added
Input schema / properties / excludeAdded value: +{ + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Drop listings whose title or description contains any of these words, e.g. ['hoesje', 'defect', 'gezocht']." +} - added
Input schema / properties / languageAdded value: +{ + "anyOf": [ + { + "enum": [ + "nl", + "fr", + "all" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "2dehands only: 'nl' for Dutch-language ads, 'fr' for French, 'all' (default)." +} - changed
Input schema / properties / postcode / descriptionPrevious value: -"Dutch/Belgian postal code to search around, e.g. '1011 AB' or '2000'. Required for distance filtering."New value: +"Dutch/Belgian postal code to search around, e.g. '1011 AB' or '2000'. Required for distance filtering and for distance_km in results." - changed
Input schema / properties / subcategory / descriptionPrevious value: -"Subcategory name (e.g. 'Fietsen | Racefietsen') or numeric id."New value: +"Subcategory name (e.g. 'Fietsen | Racefietsen' or 'Fietsen | Heren | Herenfietsen') or numeric id. See list_categories with a parent." - removed
Output schema / additionalPropertiesRemoved value: -true - added
Output schema / propertiesAdded value: +{ + "cursor": { + "title": "Cursor", + "type": "string" + }, + "listings": { + "items": { + "properties": { + "attributes": { + "anyOf": [ + { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Attributes" + }, + "category_id": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Category Id" + }, + "city": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "City" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Description" + }, + "distance_km": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Distance Km" + }, + "id": { + "title": "Id", + "type": "string" + }, + "image_urls": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Image Urls" + }, + "is_business": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Is Business" + }, + "is_sponsored": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Is Sponsored" + }, + "listed": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Listed" + }, + "price": { + "title": "Price", + "type": "string" + }, + "price_euros": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Price Euros" + }, + "reserved": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reserved" + }, + "seller": { + "anyOf": [ + { + "properties": { + "id": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Id" + }, + "is_verified": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Is Verified" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Name" + } + }, + "title": "Seller", + "type": "object" + }, + { + "type": "null" + } + ], + "default": null + }, + "title": { + "title": "Title", + "type": "string" + }, + "url": { + "title": "Url", + "type": "string" + } + }, + "required": [ + "id", + "title", + "price", + "url" + ], + "title": "Listing", + "type": "object" + }, + "title": "Listings", + "type": "array" + }, + "new_count": { + "title": "New Count", + "type": "integer" + }, + "note": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Note" + }, + "since": { + "title": "Since", + "type": "string" + }, + "site": { + "title": "Site", + "type": "string" + }, + "truncated": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Truncated" + } +} - added
Output schema / requiredAdded value: +[ + "site", + "since", + "cursor", + "new_count", + "listings" +] - added
Output schema / titleAdded value: +"NewListingsResult"
- Changed
get_listing_details6 fields changed- changed
Input schema / properties / listing_id / descriptionPrevious value: -"Listing id from search results, e.g. 'm2400641485'."New value: +"Listing id from search results (e.g. 'm2400641485') or a pasted marktplaats.nl / 2dehands.be listing URL." - added
Input schema / properties / max_imagesAdded value: +{ + "default": 5, + "description": "Max image URLs to return (0-20).", + "maximum": 20, + "minimum": 0, + "type": "integer" +} - removed
Output schema / additionalPropertiesRemoved value: -true - added
Output schema / propertiesAdded value: +{ + "attributes": { + "anyOf": [ + { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Attributes" + }, + "bidding": { + "anyOf": [ + { + "properties": { + "bids_count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Bids Count" + }, + "enabled": { + "title": "Enabled", + "type": "boolean" + }, + "highest_bid_euros": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Highest Bid Euros" + }, + "minimum_bid_euros": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Minimum Bid Euros" + } + }, + "required": [ + "enabled" + ], + "title": "Bidding", + "type": "object" + }, + { + "type": "null" + } + ], + "default": null + }, + "buy_it_now": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Buy It Now" + }, + "car_attributes": { + "anyOf": [ + { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Car Attributes" + }, + "category_id": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Category Id" + }, + "city": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "City" + }, + "country": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Country" + }, + "delivery": { + "anyOf": [ + { + "enum": [ + "pickup", + "shipping", + "both" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Delivery" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Description" + }, + "favorited_count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Favorited Count" + }, + "id": { + "title": "Id", + "type": "string" + }, + "image_count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Image Count" + }, + "image_urls": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Image Urls" + }, + "listed_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Listed At" + }, + "note": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Note" + }, + "postcode": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Postcode" + }, + "price": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Price" + }, + "price_euros": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Price Euros" + }, + "price_type": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Price Type" + }, + "reserved": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reserved" + }, + "seller": { + "anyOf": [ + { + "properties": { + "id": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Id" + }, + "is_verified": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Is Verified" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Name" + } + }, + "title": "Seller", + "type": "object" + }, + { + "properties": { + "active_since": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Active Since" + }, + "average_score": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Average Score" + }, + "id": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Id" + }, + "listings_count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Listings Count" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Name" + }, + "number_of_reviews": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Number Of Reviews" + }, + "response_label": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Response Label" + }, + "response_rate_percent": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Response Rate Percent" + }, + "type": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Type" + } + }, + "title": "SellerDetails", + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Seller" + }, + "since": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Since" + }, + "site": { + "title": "Site", + "type": "string" + }, + "status": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Status" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Title" + }, + "url": { + "title": "Url", + "type": "string" + }, + "view_count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "View Count" + } +} - added
Output schema / requiredAdded value: +[ + "id", + "site", + "url" +] - added
Output schema / titleAdded value: +"ListingDetails"
- Changed
get_seller_profile4 fields changed- removed
Output schema / additionalPropertiesRemoved value: -true - added
Output schema / propertiesAdded value: +{ + "average_score": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Average Score" + }, + "bank_account_verified": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Bank Account Verified" + }, + "business_verified": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Business Verified" + }, + "identification_verified": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Identification Verified" + }, + "low_bid_threshold_percent": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Low Bid Threshold Percent" + }, + "number_of_reviews": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Number Of Reviews" + }, + "payment_method": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Payment Method" + }, + "phone_number_verified": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Phone Number Verified" + }, + "seller_id": { + "title": "Seller Id", + "type": "integer" + }, + "site": { + "title": "Site", + "type": "string" + } +} - added
Output schema / requiredAdded value: +[ + "seller_id", + "site" +] - added
Output schema / titleAdded value: +"SellerProfile"
- Changed
list_categories4 fields changed- removed
Output schema / additionalPropertiesRemoved value: -true - added
Output schema / propertiesAdded value: +{ + "categories": { + "items": { + "properties": { + "id": { + "title": "Id", + "type": "integer" + }, + "name": { + "title": "Name", + "type": "string" + }, + "parent": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Parent" + } + }, + "required": [ + "id", + "name" + ], + "title": "Category", + "type": "object" + }, + "title": "Categories", + "type": "array" + }, + "level": { + "enum": [ + "L1", + "L2" + ], + "title": "Level", + "type": "string" + }, + "parent": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Parent" + } +} - added
Output schema / requiredAdded value: +[ + "level", + "categories" +] - added
Output schema / titleAdded value: +"CategoriesResult"
- Added
list_category_filters - Added
list_seller_listings - Changed
search_listings13 fields changed- added
Input schema / properties / attributesAdded value: +{ + "anyOf": [ + { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] + }, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Category-specific filters as {filter: value}, using the labels from list_category_filters, e.g. {'Merk': 'Gazelle', 'Framehoogte': '57 tot 61 cm'} or {'Bouwjaar': '2018-2022', 'Kilometerstand': '-100000', 'Brandstof': 'Benzine'}. A list means any of those values. Ranges are 'min-max', 'min-' or '-max'." +} - added
Input schema / properties / deliveryAdded value: +{ + "anyOf": [ + { + "enum": [ + "pickup", + "shipping" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "'shipping' for ads that can be shipped, 'pickup' for collection." +} - changed
Input schema / properties / distance_km / descriptionPrevious value: -"Max distance from postcode in kilometers."New value: +"Max distance from postcode in kilometers (needs postcode)." - added
Input schema / properties / excludeAdded value: +{ + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Drop listings whose title or description contains any of these words, e.g. ['hoesje', 'defect', 'gezocht']." +} - added
Input schema / properties / include_unpricedAdded value: +{ + "default": false, + "description": "Keep ads without an asking price (free, 'Bieden' without amount) when sorting by price or filtering on price. Default False: those ads would otherwise sort as β¬0 and flood the cheapest pages.", + "type": "boolean" +} - added
Input schema / properties / languageAdded value: +{ + "anyOf": [ + { + "enum": [ + "nl", + "fr", + "all" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "2dehands only: 'nl' for Dutch-language ads, 'fr' for French, 'all' (default)." +} - changed
Input schema / properties / offset / descriptionPrevious value: -"Pagination offset: page_number * limit."New value: +"Pagination: pass 'next_offset' from the previous result." - changed
Input schema / properties / postcode / descriptionPrevious value: -"Dutch/Belgian postal code to search around, e.g. '1011 AB' or '2000'. Required for distance filtering."New value: +"Dutch/Belgian postal code to search around, e.g. '1011 AB' or '2000'. Required for distance filtering and for distance_km in results." - changed
Input schema / properties / subcategory / descriptionPrevious value: -"Subcategory name (e.g. 'Fietsen | Racefietsen') or numeric id."New value: +"Subcategory name (e.g. 'Fietsen | Racefietsen' or 'Fietsen | Heren | Herenfietsen') or numeric id. See list_categories with a parent." - removed
Output schema / additionalPropertiesRemoved value: -true - added
Output schema / propertiesAdded value: +{ + "limit": { + "title": "Limit", + "type": "integer" + }, + "listings": { + "items": { + "properties": { + "attributes": { + "anyOf": [ + { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Attributes" + }, + "category_id": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Category Id" + }, + "city": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "City" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Description" + }, + "distance_km": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Distance Km" + }, + "id": { + "title": "Id", + "type": "string" + }, + "image_urls": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Image Urls" + }, + "is_business": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Is Business" + }, + "is_sponsored": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Is Sponsored" + }, + "listed": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Listed" + }, + "price": { + "title": "Price", + "type": "string" + }, + "price_euros": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Price Euros" + }, + "reserved": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reserved" + }, + "seller": { + "anyOf": [ + { + "properties": { + "id": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Id" + }, + "is_verified": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Is Verified" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Name" + } + }, + "title": "Seller", + "type": "object" + }, + { + "type": "null" + } + ], + "default": null + }, + "title": { + "title": "Title", + "type": "string" + }, + "url": { + "title": "Url", + "type": "string" + } + }, + "required": [ + "id", + "title", + "price", + "url" + ], + "title": "Listing", + "type": "object" + }, + "title": "Listings", + "type": "array" + }, + "next_offset": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Next Offset" + }, + "note": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Note" + }, + "offset": { + "title": "Offset", + "type": "integer" + }, + "returned": { + "title": "Returned", + "type": "integer" + }, + "site": { + "title": "Site", + "type": "string" + }, + "suggested_query": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Query" + }, + "total_count": { + "title": "Total Count", + "type": "integer" + } +} - added
Output schema / requiredAdded value: +[ + "site", + "total_count", + "offset", + "limit", + "returned", + "listings" +] - added
Output schema / titleAdded value: +"SearchResult"
5 tool updates
v0.1.1- First observed
check_new_listings - First observed
get_listing_details - First observed
get_seller_profile - First observed
list_categories - First observed
search_listings
TDQS
Scored across 8 tools
Each tool targets a distinct concern: listing retrieval, search, seller trust, seller inventory, category browsing, filter discovery, polling, and price analysis. There is no meaningful overlap between them.
Tool names follow a consistent verb_noun pattern (get_, search_, list_, check_, analyze_). Minor deviation: list_categories and list_category_filters are similar in prefix but clearly distinct in purpose.
8 tools is well-scoped for a marketplace MCP server. Each tool covers a distinct user need without redundancy or bloat.
The surface covers search, detail retrieval, seller trust, category/filter discovery, polling, and price analysis. Missing operations like placing bids or posting listings are likely out of scope for a read-only research-oriented server, so the gap is minor.
Maintenance
Related MCP Connectors
Search and browse global classifieds across 80 markets. No auth required for read-only access.
AI marketplace: search, buy, sell across Amazon, eBay, AliExpress. 13 tools.
Search Facebook Marketplace, inspect listings and analyze deals. Paid Spottable Pro/Max required.
Pay-per-use tool marketplace for AI agents. Search, price-check, and call APIs via MCP.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to interact with New Zealand's largest online marketplace through the Trade Me API. Supports searching listings, managing watchlists, placing bids, making purchases, and accessing marketplace data across all Trade Me categories.5-
- FlicenseNot gradedqualityFmaintenanceEnables 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-
- AlicenseNot gradedqualityFmaintenanceEnables AI assistants to search and view advertisements on Marktplaats.nl with extensive filtering options.18MIT
- AlicenseAqualityBmaintenanceEnables AI agents to search Dutch housing listings on Kamernet.nl, retrieve full listing details, and optionally reply to landlords; designed for personal use in finding rooms, studios, and apartments.31MIT