Search used car listings from Cars.com, Autotrader, and KBB (US) or Autotrader UK, Motors.co.uk, Cinch, and eBay Motors (UK) with AI assistants — plus UK MOT history checks
A dual-interface tool providing first-class support for both MCP and Agent Skill workflows:
- 🔌 MCP Server: Connect directly to MCP-enabled clients (Claude Desktop, Claude Code, Cursor, VS Code Copilot).
- 🧠 Agent Skill & CLI: Drive autonomous agents (Odysseus, OpenCode, subagents, or bash scripts) using
SKILL.mdand CLI subcommands with human-readable Markdown or structured JSON output.
Aggregates and searches car listings from multiple sources across the US and UK in parallel, extracts prices, specs, mileage, and dealer ratings, applies optional CARFAX-style filters (1-owner, no accidents, personal use) for US sources, and checks vehicle MOT history & active safety recalls from GOV.UK.
Powered by Python 3.11+, uv/uvx, CloakBrowser stealth browsing, and the official Python MCP SDK.
Choose the integration method that best suits your environment:
| Workflow | Best For | Entry Point | Output Formats |
|---|---|---|---|
| MCP Server | Claude Desktop, Claude Code, Cursor, VS Code | agentic-used-car-search serve or agentic-used-car-search (stdio) |
MCP tool call results |
| Agent Skill & CLI | Odysseus, OpenCode, autonomous agents, terminal scripts | agentic-used-car-search <search|detail|mot> / SKILL.md |
Formatted Markdown or structured JSON (--json) |
- Python 3.11+ (3.14 recommended;
uvwill fetch one for you) - uv installed (
curl -LsSf https://astral.sh/uv/install.sh | sh) - No Chrome install needed — CloakBrowser downloads its patched Chromium 151 build on first run (~200 MB, cached).
Use this for agent frameworks (e.g. Odysseus, OpenCode), autonomous background tasks, or direct terminal usage.
# 1. Search car deals (US or UK) with optional max distance radius
uv run agentic-used-car-search search --make Toyota --model Camry --price-max 25000 --max-distance 50
uv run agentic-used-car-search search --country UK --make BMW --model "3 Series" --transmission Automatic --max-distance 50
# 2. Get full listing details as Markdown or JSON
uv run agentic-used-car-search detail "https://www.cars.com/vehicledetail/..."
uv run agentic-used-car-search detail --json "https://www.autotrader.co.uk/car-details/..."
# 3. Check UK vehicle MOT history & safety recalls (with optional --retry and --json)
uv run agentic-used-car-search mot "KU16 YSC"
uv run agentic-used-car-search mot KU16YSC --retry --jsonSee SKILL.md (or skills/agentic-used-car-search/SKILL.md) for complete parameter specifications, JSON schemas, and agent prompting recipes.
Add the server to your MCP client config to expose search_car_deals, get_listing_details, and check_mot_history as interactive tools:
{
"mcpServers": {
"agentic-used-car-search": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/dan0v/agentic_used_car_search",
"agentic-used-car-search",
"--country",
"UK",
"--cloakbrowser-key",
"cb_xxxxxxxx"
]
}
}
}Two startup args:
--country— default country the server operates in ("US"or"UK"). Sets the default forsearch_car_dealswhen the client doesn't passcountry. Allows a deployment to be UK-only or US-only by configuration without per-call args. A per-callcountrystill overrides it.--cloakbrowser-key— CloakBrowser license key (free GitHub-sign-in key, or paid). Can also be read from theCLOAKBROWSER_LICENSE_KEYenv var; the CLI arg wins. The key selects the always-current Chromium 151 build; without it CloakBrowser falls back to the older free Chromium 146 build (still works, ages over time).
Where that config lives:
| Client | Config file |
|---|---|
| Claude Code | .mcp.json in your project, or ~/.claude.json |
| Claude Desktop (macOS) | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Claude Desktop (Windows) | %APPDATA%\Claude\claude_desktop_config.json |
| VS Code / Copilot | .vscode/mcp.json (under a servers key rather than mcpServers) |
| Cursor | ~/.cursor/mcp.json |
Notes:
- The transport is stdio — no port, no URL, nothing to start beforehand.
uvxinstalls into its cache on first run, so the first launch takes ~15-30s (plus the one-time Chromium download). Later launches are fast until the cache is cleared.
Verify it works without any client:
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"1"}}}' \
| uvx --from git+https://github.com/dan0v/agentic_used_car_search agentic-used-car-search --country USYou should see Agentic Used Car Search MCP Server running on stdio on stderr followed by a JSON result naming agentic-used-car-search on stdout.
Use this if you want to modify the scrapers — edits take effect on the next client restart, with no uvx cache in the way:
git clone https://github.com/dan0v/agentic_used_car_search.git
cd agentic_used_car_search
uv sync{
"mcpServers": {
"agentic-used-car-search": {
"command": "uv",
"args": ["run", "--directory", "/absolute/path/to/agentic_used_car_search", "agentic-used-car-search", "--country", "US"]
}
}
}# Full end-to-end MCP client test (hits Cars.com / Autotrader UK / GOV.UK for real, takes minutes)
uv run python test/test_mcp_client.py
# Quick scraper smoke test
just test-scraper
# ...or by hand
uv run python -c "import asyncio; from agentic_used_car_search.scrapers import scrape_carscom; \
from agentic_used_car_search.types import SearchParams; \
r = asyncio.run(scrape_carscom(SearchParams(make='Toyota', model='Camry', one_owner=True), 5)); \
[print(l.format()) for l in r.listings]"
# A UK search
uv run python -c "import asyncio; from agentic_used_car_search.scrapers import scrape_autotrader_uk; \
from agentic_used_car_search.types import SearchParams; \
r = asyncio.run(scrape_autotrader_uk(SearchParams(make='Toyota', model='Corolla', zip='SW1A 1AA', price_max=15000), 5)); \
[print(l.format()) for l in r.listings]"
# A UK MOT history check
uv run python -c "import asyncio, json; from agentic_used_car_search.scrapers import fetch_mot_history; \
r = asyncio.run(fetch_mot_history('YL08 NNV')); print(json.dumps(r.outstanding_issues, indent=2))"If you have just installed, just --list
shows every task (just check, just test, just build, ...).
- Multi-source aggregation: Search Cars.com, Autotrader, and KBB (US) or Autotrader UK, Motors.co.uk, Cinch, and eBay Motors (UK) simultaneously
- US & UK support: Pass
country: "UK"to search UK marketplaces with a postcode instead of a ZIP code - Smart filtering: CARFAX-style filters (1-Owner, No Accidents, Personal Use) for US sources
- MOT history checks (UK): Pull a UK vehicle's full MOT history from GOV.UK and get outstanding dangerous/major/minor defects, advisories, MOT expiry, and active safety recalls
- Deal ratings: Heuristic-based deal quality assessment (US sources)
- Parallel scraping: Fast concurrent queries across sources (
asyncio.gather) - Stealth browsing: CloakBrowser patches Chromium at the C++ source level (canvas, WebGL, WebRTC,
navigator.webdriver, CDP detection) — clears the Imperva/Cloudflare checks that JS-injection stealth plugins lose to
| Source | Price | Mileage | Color | VIN / Specs | Deal Rating | Dealer Info | CARFAX Filters |
|---|---|---|---|---|---|---|---|
| Cars.com | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Autotrader | ✅ | ✅ | ❌ | ❌ | ✅ | ||
| KBB | ✅ | ✅ | ❌ | ❌ | ✅ |
| Source | Price | Mileage | Location | Notes |
|---|---|---|---|---|
| Autotrader UK | ✅ | ✅ | ✅ | Default UK source; direct GraphQL API (/at-gateway); server-side filters for price, year, mileage, transmission, drivetrain, distance; detail page exposes registration |
| Motors.co.uk | ✅ | ✅ (approx.) | ✅ (distance) | Browser-scraped (Cazoo stack); mileage shown rounded (e.g. "41.2k"); client-side filters; skipped when transmission/drivetrain requested |
| Cinch | ✅ | ✅ | ❌ | Direct REST API; returns registration plate (vrm/fullRegistration); nationwide delivery; server-side price, year, transmission, drivetrain; client-side mileage |
| eBay Motors | ✅ | ✅ (browser) | Uses official Browse API when EBAY_CLIENT_ID/EBAY_CLIENT_SECRET are set; falls back to browser scraping otherwise. Server-side year, price, transmission; client-side mileage; skipped when drivetrain requested. No registration plate. |
Cars.com cards embed a data-vehicle-details JSON payload, which is where the
VIN, trim, body style, drivetrain, fuel type, exterior color, dealer identity and
CPO flag come from. The scraper reads that payload first and falls back to
parsing the visible card text, so a markup reshuffle degrades the results
instead of emptying them.
Two caveats:
- Exterior color in search results is a generic slug (
Silver,Gray,Blue), not the manufacturer's marketing name. Cars.com only publishes the latter ("Predawn Gray Mica") on the detail page — useget_listing_detailswhen the exact paint name matters. Interior color is detail-page only. - Autotrader, KBB and the UK source cards carry no equivalent
data-vehicle-detailspayload, so their listings return the basics only. The UK scrapers apply year/price/mileage filters client-side where the site lacks a server-side filter.
All parameters are optional.
| Parameter | Type | Description |
|---|---|---|
make |
string | Car manufacturer (e.g., "Toyota", "Honda"). Recommended; searches all cars if omitted |
model |
string | Car model (e.g., "Camry", "Accord"). Recommended; searches all cars if omitted |
country |
string | "US" (default) or "UK". Selects the default sources, default zip/postcode, and currency |
zip |
string | Location code. US: ZIP code (default: "90210"). UK: postcode (default: "SW1A 1AA") |
maxDistance |
integer | Search radius in miles. US: from ZIP code (0 = nationwide). UK: from postcode on Autotrader UK (0 = nationwide / 1500 mi). Motors.co.uk and Cinch do not honour this. Default: site default (~30-50 mi) |
yearMin |
integer | Minimum model year (applied server-side where supported, otherwise client-side) |
yearMax |
integer | Maximum model year (applied server-side where supported, otherwise client-side) |
priceMax |
integer | Maximum price. US: in USD. UK: in GBP |
mileageMax |
integer | Maximum mileage. Applied client-side for sources that lack a server-side mileage filter (e.g. Motors.co.uk, Cinch) |
maxResults |
integer | Max results per source (default: 10) |
sources |
array | Sources to query. US: ["cars.com", "autotrader", "kbb"]. UK: ["autotrader-uk", "motors", "cinch", "ebay"]. Default: ["cars.com"] (US) or ["autotrader-uk"] (UK) |
oneOwner |
boolean | US only. Filter for CARFAX 1-owner vehicles. Ignored by UK sources |
noAccidents |
boolean | US only. Filter for no accidents reported. Ignored by UK sources |
personalUse |
boolean | US only. Filter for personal use only (not rental/fleet). Ignored by UK sources |
transmission |
string | UK only. Filter by gearbox (e.g. "Manual", "Automatic"). Applied server-side by Autotrader UK, Cinch, and eBay Motors. Motors.co.uk is skipped with a warning |
drivetrain |
string | UK only. Filter by drivetrain (e.g. "RWD", "FWD", "AWD", "4WD", or full names). Applied server-side by Autotrader UK and Cinch. Motors.co.uk and eBay Motors are skipped with a warning |
2024 Toyota Camry SE
Price: $27,400 (dropped $1.4K)
Est. Payment: $513/mo
Mileage: 47,822 mi.
Exterior Color: White
Specs: SE | Sedan | FWD | Gasoline
VIN: 4T1G11AK4RU902993
Deal Rating: Good Deal
Badges: Certified Pre-Owned | 1-Owner | No Accidents
Awards: American-Made Index
Dealer: North Hollywood Toyota (4.5 stars)
Location: Los Angeles, CA (5 mi)
Source: Cars.com
Photo: https://platform.cstatic-images.com/in/v2/...jpg
https://www.cars.com/vehicledetail/...
Toyota Corolla 1.8 VVT-h Icon CVT Euro 6 (s/s) 5dr
Price: £14,309
Mileage: 56,847 miles
Location: Available from Portsmouth (62 miles)
Source: Autotrader UK
https://www.autotrader.co.uk/car-details/...
UK-only. Checks a UK-registered vehicle's MOT history via the GOV.UK service
(check-mot.service.gov.uk) and surfaces any outstanding issues — the most
recent test result, outstanding dangerous/major/minor defects and advisories,
the MOT expiry date, and any active safety recalls. Handy before buying a used
car listed on the UK sources.
The GOV.UK page is server-rendered with stable data-test-id attributes (the
service's own test hooks), so the scraper reads them directly rather than
fragile class names. The site sits behind an Imperva bot check, so a call can
take ~15-45s while it clears.
| Parameter | Type | Description |
|---|---|---|
registration |
string | Required. UK vehicle registration (number plate), with or without spaces. e.g. "YL08 NNV" or "YL08NNV" |
# MOT History: BMW 3 SERIES
**Registration:** YL08NNV
**Colour:** Silver
**Fuel:** Petrol
**First registered:** 24 July 2008
**MOT valid until:** 17 May 2027
**Source:** GOV.UK (https://www.check-mot.service.gov.uk/results?registration=YL08NNV)
## Outstanding Issues
**Latest test (18 May 2026):** PASS
**Mileage at last test:** 62,334 miles
**Major defects (repair immediately):**
- Offside Front Coil spring fractured or broken (5.3.1 (b) (i))
**Minor defects (repair soon):**
- Front Suspension arm ball joint dust cover severely deteriorated n/s & o/s (5.3.4 (b) (i))
**Advisories (monitor and repair if necessary):**
- Rear Tyre worn close to legal limit/worn on edge both (5.2.3 (e))
## ⚠️ Safety Recall
This vehicle has been recalled by BMW. Contact your local BMW dealership to arrange a free repair.
No outstanding safety recalls.
## Full MOT History (19 tests)
### 18 May 2026 — PASS
- Mileage: 62,334 miles
- Test number: 6469 9395 8456
- Expiry date: 17 May 2027
- Advisories:
- Rear Tyre worn close to legal limit/worn on edge both (5.2.3 (e))
...If no MOT record exists for the registration, the tool returns a clear "no record" message rather than failing.
Fetches a single listing's detail page and returns it as markdown. Search results only carry the summary card (title, price, mileage, deal rating, dealer); the detail page adds VIN, trim, engine, transmission, drivetrain, MPG, exterior and interior colors, the full options/features list, price history, vehicle history and seller notes.
For Autotrader UK, detail pages are harvested directly via HTTP SSR JSON hydration (__staticRouterHydrationData), returning rich structured data (including the vehicle registration plate, MOT status, and running costs) without consuming a browser session. For all other sites (or as fallback), the page is pruned (nav, ads, scripts, recommendation carousels removed) and converted to markdown with markdownify (a custom <dl> handler pairs each spec term/value into - **Term:** Value). Nothing to re-fix when the sites reshuffle their markup, and the caller sees every detail the page shows.
| Parameter | Type | Description |
|---|---|---|
url |
string | Required. Listing detail page URL from a search_car_deals result. Supported hosts: cars.com, autotrader.com, kbb.com, autotrader.co.uk, motors.co.uk, cinch.co.uk, ebay.co.uk (or ebay.com) |
includeLinks |
boolean | Keep hyperlink URLs (link text is kept either way; default: false) |
includeImages |
boolean | Keep image references (default: false) |
maxLength |
integer | Truncate markdown at N characters (default: 30000) |
# Used 2020 Toyota Camry SE
**Source:** Cars.com
**URL:** https://www.cars.com/vehicledetail/...
## Features & specs
VIN: 4T1G11AK3LU858833 / Stock #: C131351
- Predawn Gray Mica exterior color
- Dynamic Force 2.5L I-4 port/direct injection, DOHC, VVT-iE/VVT-i engine
- 28-39 mpg
- Front-wheel Drive drivetrain
- 8-Speed Automatic transmission
### Safety
- Automatic Emergency Braking
- Lane Departure WarningDetail pages are served behind an anti-bot interstitial more often than search pages are; the tool waits it out (up to 45s) rather than returning the challenge page, so a call can take ~20-60s.
- Scraping: CloakBrowser (a patched Playwright
Browser) —launch_asyncfor the async MCP server,humanize=Truefor human-like input timing - Concurrency:
asyncio.gatherfor parallel multi-source queries - Protocol: Implements MCP (Model Context Protocol) via the official Python SDK's lowlevel
Server - Data extraction: Source-specific parsers normalize listings into a common
CarListingdataclass - HTML→Markdown:
markdownify(with a custom<dl>converter) for the detail tool - Stealth engine: CloakBrowser downloads and caches patched Chromium (~200 MB under
~/.cache/cloakbrowser). No local Chrome install or driver configuration is needed.
The ebay UK source uses eBay's official Browse API when OAuth2
application credentials are present, and falls back to browser scraping
ebay.co.uk when they are not. The API path returns richer structured data
and avoids anti-bot checks entirely.
To enable the API path, register an application at the
eBay Developer Portal, then set the
client_id and client_secret (under Application Keys) as environment
variables in the client's env block:
{
"mcpServers": {
"agentic-used-car-search": {
"command": "uvx",
"args": ["--from", "git+https://github.com/dan0v/agentic_used_car_search", "agentic-used-car-search", "--country", "UK"],
"env": {
"EBAY_CLIENT_ID": "your-ebay-client-id",
"EBAY_CLIENT_SECRET": "your-ebay-client-secret"
}
}
}
}Without these, ebay still works via CloakBrowser scraping — just slower and
more fragile to markup changes. The token is cached in-process (~2h) so
repeated searches reuse it.
All diagnostics go to stderr — stdout is the MCP transport and anything written there corrupts the protocol stream.
| Level | What you get |
|---|---|
silent |
nothing |
error |
failures only |
info (default) |
one line per tool call and per scraper outcome |
debug |
request arguments, the built search URL for each site, per-scraper timings, retry attempts, progress-token resolution, and full stack traces |
trace |
everything in debug, plus a preview of the response payload |
Set the level with the CAR_DEALS_LOG_LEVEL environment variable, or pass
--verbose (equivalent to debug) or --trace on the command line. The
environment variable wins when both are given.
{
"mcpServers": {
"agentic-used-car-search": {
"command": "uvx",
"args": ["--from", "git+https://github.com/dan0v/agentic_used_car_search", "agentic-used-car-search", "--country", "US"],
"env": {
"CAR_DEALS_LOG_LEVEL": "debug"
}
}
}
}Running it directly:
CAR_DEALS_LOG_LEVEL=debug uv run agentic-used-car-search
uv run agentic-used-car-search --verboseEvery exception the server hits is written to stderr, including ones that are
also reported to the client as a tool error, and ones that escape the tool
handlers entirely. Stack traces (and the __cause__ chain that identifies
which browser call actually failed) appear at debug and above.
Note: the MCP SDK forwards only a fixed subset of environment variables to a server subprocess.
CAR_DEALS_LOG_LEVELtherefore has to be set in the client'senvblock as above — exporting it in your shell will not reach a client-launched server.
uv sync # install deps
just check # ruff lint + format check + mypy type check (the offline gate)
just syntax # smoke-test all imports
just test-scraper # quick Cars.com scraper smoke test
just test # live end-to-end test (minutes)
CAR_DEALS_LOG_LEVEL=debug just test # with server-side debug loggingContributions are welcome! Please follow this workflow:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Add tests for new functionality
- Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Please include test coverage for scraping/parsing changes to avoid regressions when source sites update.
MIT License - see LICENSE file for details
- Repository: https://github.com/dan0v/agentic_used_car_search
- Issues: https://github.com/dan0v/agentic_used_car_search/issues
- MCP Protocol: https://modelcontextprotocol.io