marktplaats-mcp
v1.0.6
Published
MCP server for efficient Marktplaats.nl access and scraping
Maintainers
Readme
marktplaats-mcp
A Model Context Protocol (MCP) server that provides efficient, token-optimized access to Marktplaats.nl listings for AI agents.
Overview
This MCP server replaces the need for agents to use generic Playwright commands to scrape Marktplaats. Instead of receiving full HTML pages (which are token-heavy), agents get structured JSON responses with only the relevant data.
Perfect for AI agents shopping for specific items with progressive search refinement.
Quick Start
# Install the MCP server
npm install -g marktplaats-mcp
# Install required browser
npx playwright install chromium
# Add to Claude Code
claude mcp add marktplaats marktplaats-mcpNow you can ask Claude Code: "Find me a racing bike under €500 in Amsterdam"
Key Benefits
- Token Efficient: Returns structured JSON instead of full HTML pages
- Smart Search: Provides pagination metadata so agents can refine searches
- Image Access: All image URLs are provided in full resolution
- Rate Limited: Built-in protection against overwhelming Marktplaats servers
- Cached Results: 15-minute cache for recently accessed listings
Tools
1. search_marktplaats
Search for products on Marktplaats with optional filters.
Input:
{
"searchTerm": "racefiets",
"priceMin": 100, // Optional: minimum price in EUR
"priceMax": 500, // Optional: maximum price in EUR
"postcode": "2021ZH", // Optional: Dutch postcode for location filtering
"radius": 10 // Optional: search radius in km
}Output:
{
"listings": [
{
"url": "https://www.marktplaats.nl/v/...",
"title": "Cube Aerial Racefiets",
"price": "€ 450",
"description": "Cube Aerial racefiets in goede staat...",
"thumbnail": "https://...",
"location": "Haarlem",
"isAd": false,
"isCommercial": false
}
// ... more listings
],
"metadata": {
"totalResults": 450,
"totalPages": 18,
"currentPage": 1,
"resultsPerPage": 25,
"searchTerm": "racefiets",
"filters": {
"priceMin": 100,
"priceMax": 500,
"postcode": "2021ZH",
"radius": 10
}
}
}2. get_listing_details
Get detailed information about a specific listing.
Input:
{
"url": "https://www.marktplaats.nl/v/fietsen-en-brommers/fietsen-racefietsen/m2291207164-cube-aerial-racefiets"
}Output:
{
"title": "Cube Aerial Racefiets Carbon Voorvork",
"price": "€ 450",
"description": "Cube Aerial racefiets in zeer goede staat...\n\nSpecificaties:\n- Carbon voorvork\n- Shimano 105 groepset\n- Maat 58cm\n...",
"images": [
"https://cdn.marktplaats.com/...?rule=ecg_mp_eps$_86", // Full-size (1024px)
"https://cdn.marktplaats.com/...?rule=ecg_mp_eps$_86",
"https://cdn.marktplaats.com/...?rule=ecg_mp_eps$_86"
],
"seller": {
"name": "Jan de Vries",
"location": "Haarlem, Noord-Holland",
"memberSince": "2015",
"verified": false
},
"attributes": [
{ "label": "Categorie", "value": "Racefietsen" },
{ "label": "Merk", "value": "Cube" },
{ "label": "Framemaat", "value": "58 cm" },
{ "label": "Materiaal frame", "value": "Aluminium" },
{ "label": "Aantal versnellingen", "value": "20" }
],
"location": {
"city": "Haarlem",
"province": "Noord-Holland",
"postcode": "2021"
},
"listingId": "m2291207164",
"url": "https://www.marktplaats.nl/v/fietsen-en-brommers/fietsen-racefietsen/m2291207164-cube-aerial-racefiets",
"postedDate": "2024-12-15",
"viewCount": 234
}Usage Example
Here's how an agent might use this MCP server to find a racing bike:
Initial Search
Agent: "I'll search for racing bikes in Haarlem under €500" Calls: search_marktplaats({ searchTerm: "racefiets", priceMax: 500, postcode: "2021ZH" }) Result: 450 results across 18 pagesRefine Search
Agent: "That's too many results. Let me narrow it down to €200-€500 within 5km" Calls: search_marktplaats({ searchTerm: "racefiets", priceMin: 200, priceMax: 500, postcode: "2021ZH", radius: 5 }) Result: 73 results across 3 pagesGet Details
Agent: "This Cube Aerial looks interesting, let me check the details" Calls: get_listing_details({ url: "https://..." }) Result: Full details with 5 high-resolution image URLsAnalyze Images
Agent: "Let me download these images to check the bike's condition" Downloads images directly from provided URLs Analyzes frame condition, components, etc.
Technical Implementation
Architecture
┌─────────────┐ MCP Protocol ┌─────────────────┐ Playwright ┌──────────────┐
│ AI Agent │◄───────────────────────┤ MCP Server │◄─────────────────►│ Marktplaats │
│ (Claude) │ Structured JSON │ (TypeScript) │ Web Scraping │ Website │
└─────────────┘ └─────────────────┘ └──────────────┘Key Components
MCP Server (
index.ts)- Handles MCP protocol communication
- Routes tool calls to appropriate handlers
- Manages server lifecycle
Marktplaats Scraper (
marktplaats-scraper.ts)- Playwright-based web scraping
- Intelligent data extraction
- Image URL resolution
- Caching layer
Rate Limiting
- 2-3 seconds between search requests
- 1-2 seconds between detail requests
- Exponential backoff on errors
Data Extraction
- JSON-LD structured data parsing
- DOM fallback strategies
- Dutch number format handling
Quick Start
Prerequisites
- Node.js 18+
- npm or yarn
Installation
# Install globally from npm
npm install -g marktplaats-mcp
# Install Playwright browsers (REQUIRED - the package won't work without this)
npx playwright install chromium⚠️ Important: You must run npx playwright install chromium after installing the package, otherwise the MCP server will fail to start.
Development/Source Installation (Optional)
If you want to modify the source code:
# Clone and setup
git clone https://github.com/vabole/marktplaats-helper.git
cd marktplaats-helper/mcp/
# Install dependencies
npm install
# Install Playwright browsers (required)
npx playwright install
# Build the server
npm run buildConfiguration for Claude Code
# Option 1: Use the npm package command (may require manual Playwright setup)
claude mcp add marktplaats marktplaats-mcp
# Option 2: Use absolute path to ensure it works (recommended)
claude mcp add marktplaats node $(npm root -g)/marktplaats-mcp/dist/index.js
# Verify it was added
claude mcp listNote: If you encounter connection issues with the npm command, use Option 2 (absolute path) which is more reliable.
Configuration for Claude Desktop
Add to your Claude Desktop configuration:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
Using npm package (recommended):
{
"mcpServers": {
"marktplaats": {
"command": "npx",
"args": ["marktplaats-mcp"]
}
}
}Using global installation:
{
"mcpServers": {
"marktplaats": {
"command": "marktplaats-mcp"
}
}
}Using local build:
{
"mcpServers": {
"marktplaats": {
"command": "node",
"args": ["/absolute/path/to/mcp/dist/index.js"]
}
}
}Important: For local builds, use absolute paths, not relative paths.
Configuration for Claude.ai
If using the web version of Claude, you'll need to deploy this as a remote MCP server. See MCP documentation for details.
Verification
Test your setup:
# Test the globally installed package
marktplaats-mcp --version
# Test with Claude Code (if configured)
# Just ask Claude: "Find me a laptop under €500"Testing the npm Package
To verify the globally installed package works correctly:
# Quick test (requires marktplaats-mcp to be installed globally)
git clone https://github.com/vabole/marktplaats-helper.git
cd marktplaats-helper/mcp/
# Run the npm package E2E test
node run-npm-e2e-test.js
# Or use npm script
npm run test:npm:devThis test verifies that:
- The globally installed package starts correctly
- MCP protocol communication works
- Search and detail fetching work as expected
- Progressive search refinement works
- All data fields are properly extracted
Development Testing
For development and source code testing:
# Run E2E test against local build
npm run test:e2e
# Use the friendly test runner
node run-e2e-test.jsUsage with AI Agents
Once configured, you can use the MCP server in your conversations with Claude:
Example Agent Conversations
Finding a Racing Bike:
You: I'm looking for a racing bike under €500 in the Amsterdam area. Can you help me find some options?
Claude: I'll help you search for racing bikes in Amsterdam under €500. Let me start with a broad search and then refine it based on what we find.
[Calls search_marktplaats with searchTerm="racefiets", priceMax=500, postcode="1012", radius=25]
I found 247 racing bikes under €500 in the Amsterdam area (25km radius). Let me get details on a few promising options...
[Calls get_listing_details for top 3 results]
Here are the best options I found:
1. **Trek 1.2 Road Bike** - €450 (Excellent condition, Shimano 105 groupset)
2. **Giant Defy 3** - €380 (Good starter bike, aluminum frame)
3. **Cannondale CAAD8** - €495 (Carbon fork, very light)
Would you like me to get more details about any of these, or search for something more specific?Progressive Search Refinement:
You: The Trek looks interesting, but €450 is still a bit high. Can you find similar bikes for under €350?
Claude: Let me refine the search to focus on bikes under €350 in Amsterdam.
[Calls search_marktplaats with updated price filter]
Great news! I found 89 racing bikes under €350. Here are some excellent alternatives to the Trek...Agent Capabilities
With this MCP server, AI agents can:
- Smart Search Strategy: Start broad, progressively narrow based on results
- Price Comparison: Compare similar items across different price ranges
- Location Optimization: Find the best deals within travel distance
- Detailed Analysis: Examine photos and descriptions to assess condition
- Market Research: Understand pricing trends for specific categories
Rate Limiting & Respectful Usage
The server automatically handles rate limiting:
- 2 seconds between search requests
- 1 second between listing detail requests
- 15-minute caching to avoid redundant requests
- Single browser instance for efficiency
Development
# Run in development mode
npm run dev
# Build the project
npm run build
# Test the npm-installed package (requires global install)
npm run test:npm
npm run test:npm:dev
node run-npm-e2e-test.js
# Test local development build
npm run test:e2e
npm run test:e2e:dev
node run-e2e-test.js
# Code quality
npm run lint
npm run typecheckE2E Test Scenario
The E2E test simulates a realistic AI agent workflow:
- Initial Search: Broad search for "racefiets" (racing bikes)
- Price Filtering: Narrow down to €200-€500 range
- Location Filtering: Further limit to Haarlem area (10km radius)
- Detail Fetching: Get full details for top 3 results
The test validates:
- Progressive result count reduction
- Proper pagination metadata
- Full-resolution image URLs
- Complete listing details extraction
- Token-efficient JSON responses
Best Practices
Search Optimization
- Start with broad searches to gauge result volume
- Progressively refine filters based on result count
- Use location filters to reduce irrelevant results
Image Analysis
- Images are provided in full resolution (1024px)
- Download only images you need to analyze
- Cache downloaded images locally
Rate Limiting
- Respect the built-in delays
- Don't make parallel requests to the same tool
- Use cached data when possible
Troubleshooting
Common Issues
Server not starting:
# Check if Playwright browsers are installed
npx playwright install
# Verify TypeScript compilation
npm run buildClaude Desktop not finding the server:
- Ensure you're using absolute paths in your config
- Check that the
dist/index.jsfile exists after building - Restart Claude Desktop after config changes
Search returning no results:
- Try broader search terms (e.g., "fiets" instead of "racefiets")
- Check if your price range is too restrictive
- Verify the postcode format (e.g., "2021ZH" not "2021 ZH")
Rate limiting errors:
- The server automatically handles rate limits
- If you see timeouts, the 15-minute cache may be helping reduce requests
- Respect the built-in delays for reliable operation
Performance Tips
- Use specific search terms to get better results
- Start with broader filters then progressively narrow
- Leverage caching - identical searches within 15 minutes are instant
- Batch similar requests - get details for multiple listings in sequence
FAQ
Q: Is this legal?
A: Yes, this performs automated browsing similar to what a human would do. It respects rate limits and robots.txt.
Q: Can I use this for commercial purposes?
A: Check Marktplaats's Terms of Service for commercial use restrictions. This tool is designed for personal shopping assistance.
Q: How often should I update?
A: The server is designed to be stable. Update when you need new features or Marktplaats changes their website structure.
Q: Can I add more search filters?
A: Yes! See the SearchFilters interface in src/types.ts. Additional filters can be added to the URL building logic.
Q: Does it work with other Marktplaats categories?
A: Yes! It works with any category. Just adjust your search terms (e.g., "laptop", "bureau", "auto").
Future Enhancements
- [ ] Additional search filters (condition, seller type, etc.)
- [ ] Saved searches with notifications
- [ ] Bulk listing analysis
- [ ] Historical price tracking
- [ ] Category-specific attributes
- [ ] Multi-language support
- [ ] Export to CSV/JSON functionality
License
MIT
Contributing
Contributions are welcome! Please ensure all scraping remains respectful of Marktplaats's servers and terms of service.
Development Guidelines
- Respect rate limits - Don't reduce the built-in delays
- Test thoroughly - Use the E2E tests before submitting changes
- Document changes - Update this README for new features
- Follow TypeScript best practices - Maintain type safety
