carsearch-mcp
The carsearch MCP server lets an agent search, analyze, monitor, compare, and score Canadian used-car listings backed by a persistent historical database.
Search historical/local listings with rich filters: make, model, generation, price, mileage, year, location/radius, province, transmission, drivetrain, seller type, keywords, and more.
Run fresh live marketplace searches and store/update listings with price/status history.
Retrieve full listing or physical-vehicle records, price history, change events, and photos.
Get comparable-price analyses with medians, quartiles, mileage adjustment, and market premiums.
Compare multiple listings side by side with risks, deal signals, and project scores.
Find deals, price drops, long-sitting listings, and rank project cars under configurable profiles.
Analyze and score individual listings, including description risk flags and optional image analysis.
Analyze market trends: price over time, mileage bands, manual/AWD premiums, dealer vs private, turnover, cheapening.
Manage saved searches: create, list, run, delete, and monitor them on a schedule.
Fetch alerts for new matches, price drops, target prices, rare manuals, and high deal/project scores.
Check collector/provider status, database counts, runs, HTTP metrics, and supported generation codes.
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., "@carsearch-mcp Find manual BMW 328i under $7k within 800km of Toronto"
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.
carsearch — Canadian used-car search, monitoring & market-analysis platform
carsearch turns Canadian marketplace listings into a persistent, searchable,
historical database and exposes it to Claude Code (or any agent) over MCP,
plus a full CLI. It collects real listings from AutoTrader.ca (more
providers pluggable), keeps every price/status change as history, deduplicates
physical vehicles across listings, geocodes properly (real distances), extracts
risk signals from descriptions, computes comparable-price statistics, scores
project cars under configurable profiles, detects deals, reruns saved searches
on a schedule and raises alerts.
Ask Claude things like:
Find me every manual BMW E90 328i under $8,000 within 800 km of Toronto, prefer private sellers, reject rust buckets, rank by project-car value.
What interesting project cars under $7k appeared in Ontario in the last 48 hours?
Is this $6,200 Audi TT actually cheap relative to similar listings we've observed?
Show me every price drop > 10% this week. / Cars sitting 30+ days where the seller already cut the price twice.
Status per phase, tested commands and known issues: PROJECT_STATUS.md.
Architecture (short)
providers/ (autotrader ✓, cargurus/kijiji/facebook interface+probe) → VehicleListing (canonical)
→ collectors/ (checkpointed ProviderRun, ingest w/ snapshots+events, raw payloads)
→ dedupe/ (VIN → weighted soft signals → vehicles + candidates) → geo/ (geocode, haversine)
→ SQLite/PostgreSQL (SQLAlchemy) → search/ analysis/ (description, comps, deals, market)
→ scoring/ (profiles + model knowledge JSON) → monitoring/ (saved searches, scheduler) → notifications/
→ cli/ (carsearch …) and mcp/ (23 tools)Details: docs/architecture.md, docs/providers.md, docs/schema.md.
Related MCP server: federal-spend-ai
Installation
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]" # add ".[postgres]" for PostgreSQL
cp .env.example .env # optional; SQLite in ./data works out of the box
carsearch db-init # creates/upgrades data/carsearch.dbPython ≥ 3.11 (developed on 3.14). No browser, no API keys required for AutoTrader.
Database setup
Default:
sqlite:///./data/carsearch.db(WAL). Nothing to do.PostgreSQL:
CARSEARCH_DATABASE_URL=postgresql+psycopg://user:pass@host/carsearchin.env,pip install -e ".[postgres]",carsearch db-init. Schema/migrations insrc/carsearch/database/(versioned, recorded inschema_migrations).
Crawling (collecting real data)
# targeted, with detail pages for new listings (VIN, exact coordinates, drivetrain, created date)
carsearch crawl autotrader --make BMW --model "3 Series" --transmission manual --max-price 8000 --min-year 2006 --max-year 2013 --details new
# regional bulk (20 listings/page, ~1.5 s/page, no detail pages)
carsearch crawl autotrader --max-price 7000 --location Toronto --radius-km 500 --max-pages 200 --details none
# province scope (centroid + covering radius server-side, exact province locally)
carsearch crawl autotrader --province ON --transmission manual --max-price 6000 --seller-type private
# incremental refresh: stop after 3 consecutive pages with nothing new/changed
carsearch crawl autotrader --transmission manual --max-price 8000 --stop-when-seen 3
# resume an interrupted run
carsearch crawl autotrader --resume 12
# re-check listings not seen for 3 days (marks removed on 404); fetch missing detail pages; geocode backfill
carsearch refresh autotrader --older-than-days 3 --limit 200
carsearch details autotrader --limit 200
carsearch geocode --limit 60
scripts/bootstrap_crawl.sh # example multi-band bootstrap used to seed the DBAutoTrader caps a query at 200 pages (4000 listings) → split by price band/region for full coverage (truncated=True in the run summary tells you when).
Searching
carsearch search --make BMW --model 328i --max-price 7000 --transmission manual --location Toronto --radius-km 800 --seller-type private
carsearch search --generation E90 --keywords '"one owner" -salvage' --province ON,QC --sort price_asc
carsearch new --since 48h --province ON --max-price 7000
carsearch price-drops --min 10 --since 7d
carsearch deals --province ON --max-price 7000 --profile project_car_enthusiast
carsearch deals --location Toronto --radius-km 500 --transmission manual --max-price 7000 --since 7d \
--profile project_car_enthusiast --sort-by project --exclude-flags salvage_title,frame_rust,doesnt_run # "best project cars" ranking
carsearch listing 42 # full record + price history + description flags
carsearch history 42 # snapshots + change events
carsearch comps 42 # comparable-price analysis with methodology
carsearch score 42 --profile project_car_enthusiast
carsearch analyze 42 # everything above + deal signals in one JSON
carsearch market --metric manual_premium --make Subaru --model WRX
carsearch market --metric price_by_mileage --generation E90 --province ON
carsearch market --metric cheapening --days 90
carsearch status [--check-providers] · carsearch runs · carsearch alertsEvery command accepts --json for machine-readable output.
Monitoring / saved searches / alerts
carsearch saved seed # the four example searches from the brief
carsearch saved create "manual E90 328i under $8k" '{"make":"BMW","model":"3 Series","min_year":2006,"max_year":2011,"max_price":8000,"transmission":"manual"}' \
--interval-minutes 240 --alert-rules '{"price_drop_pct":10,"target_price":6500,"min_deal_score":65}' --profile project_car_enthusiast
carsearch saved run "manual E90 328i under $8k" # incremental crawl → new listings + alerts
carsearch schedule # long-running loop: runs due searches, maintenance
carsearch schedule --once # one pass (cron-friendly)Alerts go to console, data/alerts.jsonl and an optional webhook (CARSEARCH_WEBHOOK_URL);
new sinks = subclass notifications.alerts.AlertSink. Every alert carries reasons[] (and risks).
MCP server
carsearch serve-mcp # stdio (default) | --transport streamable-http --port 8765Tools: search_cars, search_live_marketplace, get_listing, get_vehicle,
get_new_listings, get_price_history, get_listing_changes, get_comparables,
compare_cars, find_deals, find_price_drops, find_long_sitting_listings,
analyze_listing, score_listing, analyze_market, list_saved_searches,
create_saved_search, run_saved_search, delete_saved_search, get_alerts,
get_status, get_generation_codes, analyze_listing_images. All return
structured JSON with pagination (limit/offset/next_offset); heavy fields
(description, photos, raw) are opt-in.
Connect Claude Code
claude mcp add carsearch -- /ABSOLUTE/PATH/autotrader/.venv/bin/carsearch serve-mcp
# or in .mcp.json:
{ "mcpServers": { "carsearch": { "command": "/ABSOLUTE/PATH/autotrader/.venv/bin/carsearch", "args": ["serve-mcp"] } } }Then: "Find me the best manual project cars under $7,000 CAD within 500 km of
Toronto that appeared in the last week. Compare them against historical prices,
flag major mechanical/rust risks from the listings, and rank the top 10." —
Claude will typically call search_cars/get_new_listings (or
search_live_marketplace for fresh data), then analyze_listing/compare_cars.
How checkpoints work
Each crawl is a provider_runs row. After every page the listings are
committed and last_checkpoint.next_page is advanced; per-listing failures are
logged in errors and skipped. Detail enrichment commits per listing
(detail_fetched_at). A run that dies is failed/interrupted and
carsearch crawl --resume <id> continues from next_page (already fetched
pages come from the local http_cache). Saved-search state lives in the DB.
See docs/architecture.md.
How to add a provider
Implement BaseProvider in src/carsearch/providers/<name>/, map to
VehicleListing in a parser.py (keep raw), register it, add fixtures +
tests, document it in docs/providers.md. Nothing else changes.
Tests
pytest -q # 42 tests: normalization, parser fixtures, ingest/price history, dedupe,
# geo/search, analysis (flags/comps/scoring/deals/market), crawler checkpoints, MCP toolsNo test touches the network (real payload fixtures + a fake provider).
SQLite is fine for hundreds of thousands of listings; switch to PostgreSQL for concurrent writers.
Available Tools
23 toolsanalyze_listingB
Everything about one listing: full record, price history, description risk/positive flags with evidence, comparables, project-car score with component explanations, deal signals.
Inputs: listing_id (required), profile, include_images, include_comparables_list. Returns: object
analyze_listing_imagesA
Cache the listing's photos (sha256 + perceptual hash) and run the pluggable vision backend (checklist: rust, rockers, paint mismatch, damage, interior, warning lights, mods, tires, stance, engine bay).
Inputs: listing_id (required), force. Returns: object
analyze_marketC
Market analytics: median prices over time / by mileage / by group, manual & AWD premiums, dealer vs private, cheapening models, turnover, long-sitting.
Inputs: days, make, model, metric, +11 more. Returns: object
compare_carsA
Side-by-side comparison of several listings: key facts, comps position, project score, deal signals and description risk flags.
Inputs: listing_ids (required), profile. Returns: object
create_saved_searchB
Create or update a saved search that the scheduler reruns; alerts fire on new matches, price drops, deals.
Inputs: name (required), params (required), notes, provider, +4 more. Returns: object
delete_saved_searchB
Delete a saved search.
Inputs: name_or_id (required). Returns: object
find_dealsA
Rank listings by deal signals and/or project-car score: comps position, price drops, time on market, seller, description risk flags — each item carries reasons, risks, risk_flags, project_score. Use sort_by='project' + a profile to answer 'best project cars'.
Inputs: make, limit, model, since, +15 more. Returns: object
find_long_sitting_listingsC
Active listings on the market for at least min_days (optionally with several price cuts).
Inputs: make, limit, model, offset, +7 more. Returns: object
find_price_dropsB
Listings whose asking price dropped by >= min_pct within the window (single or cumulative drops).
Inputs: make, limit, model, since, +7 more. Returns: object
get_alertsC
Recent alerts (new matches, price drops, target price, rare manuals, deal scores) with reasons.
Inputs: rule, limit, since. Returns: object
get_comparablesB
Comparable-price analysis: sample size, median/mean/quartiles, mileage-adjusted median, manual/AWD/dealer premiums, subject percentile and methodology. Pass a listing_id OR a vehicle spec.
Inputs: make, trim, year, model, +9 more. Returns: object
get_generation_codesA
Supported generation/chassis labels per make/model (for the generation filter) and scoring profiles.
Inputs: no named parameters. Returns: object
get_listingC
Full listing record with price history, change events, description flags, vehicle link and same-vehicle candidates.
Inputs: listing_id (required), include_photos. Returns: object
get_listing_changesC
Change events across the database (or for one listing) within a window.
Inputs: make, limit, model, since, +5 more. Returns: object
get_new_listingsB
Listings first observed since a given time (newest first).
Inputs: make, limit, model, since, +8 more. Returns: object
get_price_historyB
Price/mileage/status snapshots and the derived summary (days on market, drops, absolute/percent change).
Inputs: listing_id (required). Returns: object
get_statusB
Collector health: DB counts by source/province, recent runs, HTTP metrics, provider capabilities.
Inputs: check_providers. Returns: object
get_vehicleB
A physical vehicle (dedupe cluster) with all listings that were matched to it across marketplaces/time.
Inputs: vehicle_id (required). Returns: object
list_saved_searchesB
Saved (monitored) searches with schedule state.
Inputs: no named parameters. Returns: object
run_saved_searchA
Run a saved search now: crawls incrementally, returns new listings (with deal/project scores) and any alerts triggered.
Inputs: name_or_id (required), max_pages. Returns: object
score_listingC
Project-car score (0-100) with per-component scores/weights/explanations under a named or custom profile.
Inputs: listing_id (required), profile. Returns: object
search_carsA
Search the local historical database of collected listings with rich filters, geography and pagination.
Inputs: make, sort, trim, limit, +30 more. Returns: object
search_live_marketplaceA
Run a fresh marketplace search (stores everything with history), then return matching listings from the local DB including ones seen earlier. Use for up-to-the-minute results.
Inputs: make, sort, limit, model, +17 more. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 23 tools
Each tool targets a distinct resource or analytical mode: search vs. live search, listing vs. vehicle vs. price history vs. changes, comparables vs. comparison vs. market analysis. Even the find_* tools are separated by clear signals (deals, price drops, long-sitting), so an agent should be able to select the right tool confidently.
Tool names consistently follow a snake_case verb_noun pattern: search_cars, get_listing, find_deals, analyze_listing, list_saved_searches, delete_saved_search. Minor variations like search_live_marketplace or analyze_listing_images remain readable and fit the same convention.
At 23 tools, the server is on the heavy side and falls into the 16-25 range that feels dense. The broad car-search/analysis domain justifies many of them, but the overall surface could be streamlined or grouped further.
The tool surface covers the full workflow: historical and live search, listing/vehicle detail, price history and changes, comparables, market analytics, image/listing analysis, scoring, saved-search lifecycle, and alert retrieval. Saved searches support create/update, run, list, and delete, so there are no obvious dead ends for the stated domain.
Maintenance
Related MCP Connectors
Market data tools for the MCP ecosystem: server stats, events, search, leaderboards, package trends.
MCP server for FormBro Canadian immigration application automation.
Public MCP server for discovering open jobs. Search, filter, and get application links.
Unlock the power of real-time cryptocurrency data with our Crypto Price Insights MCP server.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceMCP server for structured public vehicle data from StartMyCar, providing tools to list makes, models, problems, reviews, fuse box data, manuals, guides, and compare models.10 npmMIT
- AlicenseNot gradedqualityCmaintenanceMCP server for analyzing Canadian federal spending data, offering tools for contract search, NLP, semantic search, anomaly detection, and money-flow tracing.MIT
- AlicenseNot gradedqualityCmaintenanceMCP server for the used-Mac market, enabling AI assistants to search live listings across multiple marketplaces, get price statistics, check listing trust, lookup serial numbers, retrieve condition reports, and create email alerts.31 npm2MIT
- FlicenseAqualityDmaintenanceMCP server for searching and monitoring RedFlagDeals deals. Provides tools to search deals, get deal details, and set up monitors for new deals.6-