DealScout is a local-first MVP for hunting online listings with deterministic Python orchestration, cheap Bedrock-based AI triage, SQLite caching, and Notion workspace sync over Notion's hosted MCP endpoint.
DealScout/
├── .env.example
├── README.md
├── requirements.txt
├── app/
│ ├── __init__.py
│ ├── actions.py
│ ├── bedrock_client.py
│ ├── config.py
│ ├── dedupe.py
│ ├── main.py
│ ├── models.py
│ ├── notion_mcp_client.py
│ ├── orchestrator.py
│ ├── parser.py
│ ├── prompts.py
│ ├── scraper.py
│ ├── scoring.py
│ ├── search_loader.py
│ ├── storage.py
│ └── utils.py
├── data/
│ ├── cache.db
│ └── sample_listings.json
├── scripts/
│ ├── bootstrap_notion.py
│ └── run_once.py
└── tests/
├── test_dedupe.py
├── test_models.py
├── test_orchestrator.py
├── test_scraper.py
└── test_scoring.py
DealScout is intentionally split into deterministic and AI-backed layers:
scraper.py,parser.py,dedupe.py,scoring.py, andorchestrator.pydo all web retrieval, normalization, filtering, dedupe, and feature computation in plain Python.bedrock_client.pysends only compact structured context to Amazon Bedrock and uses Amazon Nova Micro for low-cost triage decisions.storage.pykeeps local-first state in SQLite: dedupe cache, raw snapshots, checkpoints, and run history.notion_mcp_client.pyhandles OAuth 2.0 Authorization Code + PKCE, token refresh, secure local storage through the OS keychain, and Streamable HTTP MCP calls tohttps://mcp.notion.com/mcp.actions.pyapplies the sync policy so listings are not blindly inserted and Notion gets updated only after local filtering and a decision pass.
Current source adapters:
sample: local deterministic fixture data.ebay: official Browse API search via client-credentials OAuth.amazon: Amazon Product Advertising API search via signed PA-API requests.etsy: Etsy Open API active listing search via API key.bestbuy: Best Buy Products API retail search via API key.craigslist: RSS-based adapter kept for experimentation, but it is often rate-limited or blocked with403.
The app uses Notion's hosted MCP endpoint instead of the old self-hosted notion-mcp-server because:
- it works against the live user workspace with OAuth,
- it keeps auth local to the machine,
- it fits the "AI operating on workspace data" model Notion is actively shipping,
- it avoids owning and maintaining a separate Notion-side server.
Nova Micro is a good fit here because the model is only asked to do cheap structured judgments:
- track vs ignore,
- match score,
- deal score,
- task creation,
- short note generation.
All expensive or brittle work stays deterministic and local.
python3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtcp .env.example .envIf you already have integration-accessible Notion databases, update the TODO values:
NOTION_SEARCHES_DATABASE_IDNOTION_LISTINGS_DATABASE_IDNOTION_TASKS_DATABASE_IDNOTION_RUNS_DATABASE_ID
If you do not, the fastest path is to let DealScout bootstrap a fresh, integration-owned setup after you turn on Notion:
python scripts/bootstrap_notion.pyThat command:
- creates a new top-level
DealScoutpage that the current MCP OAuth session can access, - creates fresh
Searches,Listings,Tasks, andRunsdatabases under it, - seeds starter search rows by default,
- rewrites the four
NOTION_*_DATABASE_IDvalues in your local.env.
You need AWS credentials on the local machine with Bedrock access in the region from AWS_REGION.
Typical options:
aws configure- SSO with
aws sso login - environment variables such as
AWS_PROFILE
BEDROCK_MODEL_ID defaults to us.amazon.nova-micro-v1:0, which is a practical cross-region US inference profile for North American development.
DealScout now supports eBay's official Browse API.
You need an eBay Developer Program app keyset:
- Create an app in the eBay developer portal.
- In
Production, complete theMarketplace Account Deletioncompliance flow if your app persists eBay data. - Copy the application
Client IDandClient Secret. - Put them in
.env:
EBAY_CLIENT_ID=your-ebay-client-id
EBAY_CLIENT_SECRET=your-ebay-client-secret
AMAZON_PAAPI_PARTNER_TAG=your-amazon-partner-tag
AMAZON_PAAPI_ACCESS_KEY=your-amazon-paapi-access-key
AMAZON_PAAPI_SECRET_KEY=your-amazon-paapi-secret-key
ETSY_API_KEY=your-etsy-api-key
BESTBUY_API_KEY=your-bestbuy-api-key
ENABLED_SOURCES=ebay,amazon,etsy,bestbuyOptional eBay settings:
EBAY_MARKETPLACE_ID=EBAY_USEBAY_PRICE_CURRENCY=USDEBAY_RESULT_LIMIT=10
Amazon's official Product Advertising API can still be used for this project, but Amazon has announced that PA-API will be deprecated on April 30, 2026 and recommends new customers use Creators API going forward. If you already have PA-API access, DealScout can use it today; just treat it as a shorter-lived integration.
DealScout stores eBay listing data in SQLite and Notion, so for eBay production
compliance you should assume that your app is persisting eBay data. That means
you should configure Marketplace Account Deletion, not the Not persisting eBay data exemption.
Current eBay docs for this flow:
- Marketplace account deletion guide: https://developer.ebay.com/develop/guides-v2/marketplace-user-account-deletion
- Platform notifications overview: https://developer.ebay.com/api-docs/static/platform-notifications-landing.html
Recommended setup:
- In the eBay developer portal, go to your production keyset's
Alerts & Notificationstab. - Select
Marketplace Account Deletion. - Enter an email address for alerts.
- Set a public
https://...callback URL and a verification token. - Run the local receiver:
python scripts/ebay_notification_receiver.py --print-token
python scripts/ebay_notification_receiver.py- Expose the local receiver through a public HTTPS URL. For quick validation, a local tunnel works. For actual compliance, use a stable always-on public endpoint.
- Put the same URL/token in
.env:
EBAY_NOTIFICATION_ENDPOINT_URL=https://your-public-host/ebay/marketplace-account-deletion
EBAY_NOTIFICATION_VERIFICATION_TOKEN=your-verification-token
EBAY_NOTIFICATION_PORT=8081
EBAY_NOTIFICATION_PATH=/ebay/marketplace-account-deletionThe receiver writes incoming notifications to:
data/ebay_marketplace_account_deletion.jsonl
Official docs:
- Browse API overview: https://developer.ebay.com/api-docs/buy/static/api-browse.html
- Search endpoint: https://developer.ebay.com/api-docs/buy/browse/resources/item_summary/methods/search
- Client credentials OAuth: https://developer.ebay.com/api-docs/static/oauth-client-credentials-grant.html
- Amazon PA-API SearchItems: https://webservices.amazon.com/paapi5/documentation/search-items.html
- Amazon PA-API common request parameters: https://webservices.amazon.com/paapi5/documentation/common-request-parameters.html
- Amazon PA-API deprecation notice / Creators API guidance: https://affiliate-program.amazon.com/help/node/topic/GJMMT7G4C8K4Y3AY
- Etsy Open API overview: https://developers.etsy.com/documentation/
- Etsy request/authentication essentials: https://developers.etsy.com/documentation/essentials/requests/ and https://developers.etsy.com/documentation/essentials/authentication
- Best Buy developer APIs: https://developer.bestbuy.com/apis
DealScout uses Notion's hosted MCP endpoint:
https://mcp.notion.com/mcp
Flow details:
- first live run performs OAuth 2.0 Authorization Code with PKCE,
- the client registers dynamically if the authorization server allows it,
- tokens are stored in the local OS keychain through
keyring, - client metadata is stored at
~/.dealscout/notion_client.json, - refresh happens automatically on later runs.
If dynamic client registration is unavailable in your workspace, the code raises a TODO-style error telling you to provide a pre-registered client.
Recommended path:
python scripts/bootstrap_notion.pyManual path:
Create four databases in the workspace and record their IDs in .env.
Recommended property types:
| Property | Type |
|---|---|
| Search Name | Title |
| Query | Text |
| Category | Select or Text |
| Min Price | Number |
| Max Price | Number |
| Location | Text |
| Radius | Number |
| Preferred Keywords | Text |
| Avoid Keywords | Text |
| Must Have | Text |
| Nice To Have | Text |
| Condition Preference | Select |
| Alert Aggressiveness | Select |
| Active | Checkbox |
| Last Run At | Date |
| Property | Type |
|---|---|
| Title | Title |
| Search Relation | Relation to Searches |
| Source URL | URL |
| Marketplace | Select |
| Price | Number |
| Currency | Text |
| Location | Text |
| Posted At | Date |
| Condition | Select |
| Seller Name | Text |
| Extracted Attributes | Text |
| Estimated Fair Value | Number |
| Match Score | Number |
| Deal Score | Number |
| Priority | Select |
| Status | Select |
| Scam Risk | Select |
| Duplicate Key | Text |
| AI Notes | Text |
| Seller Message Draft | Text |
| Created By Run | Text |
| Listing Hash | Text |
| Image URL | URL |
| Property | Type |
|---|---|
| Task | Title |
| Related Listing | Relation to Listings |
| Related Search | Relation to Searches |
| Due Date | Date |
| Priority | Select |
| Status | Select |
| Reason | Text |
| Property | Type |
|---|---|
| Run Time | Title |
| Searches Processed | Number |
| Listings Seen | Number |
| Listings Added | Number |
| Listings Updated | Number |
| Tasks Created | Number |
| Errors | Text |
| Summary | Text |
Suggested select values:
- Status:
New,Reviewed,Hot,Contacted,Monitoring,Ignored,Suspected Scam,Closed - Priority:
Low,Medium,High,Urgent - Scam Risk:
Low,Medium,High
Once AWS and Notion are configured:
python scripts/run_once.pyRecommended live run with the official marketplace source:
AWS_PROFILE=your-profile ENABLED_SOURCES=sample,ebay,etsy,bestbuy python scripts/run_once.pyIf your hosted MCP workspace does not expose notion-query-data-sources, DealScout falls back to a local registry of search-row page IDs that is populated by bootstrap_notion.py. That keeps active search loading deterministic for the bootstrapped workspace.
Run flow:
- load active searches,
- fetch listings from enabled sources,
- normalize and deterministically filter,
- compute scoring features,
- call Nova Micro for a strict structured decision,
- search Notion for similar listings before inserting,
- create or update listing pages,
- create follow-up tasks when justified,
- log the run locally and optionally in Notion.
pytestCurrent tests cover:
- scoring,
- dedupe,
- scraper parsing and source wiring,
- decision model validation,
- basic orchestration flow.
notion_mcp_client.pyincludes TODO markers where exact workspace-specific MCP tool schemas may need adjustment.- View creation is intentionally left as a TODO behind
NOTION_CREATE_VIEWS=trueuntil the workspace'snotion-create-viewtool schema is confirmed. - If your Notion workspace does not expose a structured query tool for data sources, the client falls back to
notion-searchplusnotion-fetch, which is less deterministic.
- Configure
.envwith your Notion, AWS, and optional eBay settings. python scripts/bootstrap_notion.pyAWS_PROFILE=your-profile python scripts/run_once.py- Read the terminal summary.
- Inspect your Notion
Listings,Tasks, andRunsdatabases.