Skip to main content
Glama

ebay-mcp

MCP server for eBay buyer-side workflows: search, watch, bid, buy, manage MyeBay. Hybrid stack — modern Buy/Browse REST API for search and item lookup, legacy Trading API (still functional in 2026) for everything stateful.

⚠️ Beta (v0.5.0). Browse + Trading APIs wired, sandbox + production both supported. All 15 tools are production live-verified — including the three money-commit tools which have been used to close real eBay transactions through the safety stack (confirm-amount gate + $500 cap + OS-modal Yes/No dialog). Read the money commits section before enabling production.

Scope

Read-only (low risk)

  • search, get_item (Browse API)

  • get_watchlist, get_active_bids, get_won_items, get_lost_items, get_purchase_history (Trading API)

Watchlist writes (low risk — no money commit)

  • add_to_watchlist, remove_from_watchlist

Money commits (high risk — safety-gated)

  • place_bid(item_id, max_bid_amount, confirm_amount, ...) — Trading PlaceOffer with Action=Bid. Proxy bid on an auction.

  • buy_now(item_id, confirm_amount, ...) — Trading PlaceOffer with Action=Purchase. Commits to a Buy-It-Now sale.

  • make_best_offer(item_id, offer_amount, confirm_amount, ...) — Trading PlaceOffer with Action=BestOffer. Submits an offer the seller can accept/counter/decline.

Safety stack (every money tool):

  1. Confirm-amount gate. Every call requires confirm_amount exactly equal to the bid/buy/offer amount. The LLM has to repeat the dollar figure; mismatches return a structured refusal payload (not an exception) so the LLM can read it and retry with corrected params.

  2. $500 per-call cap. Amounts above $500 refuse with reason: "cap_exceeded". Two ways to authorize a higher spend:

    • Per-call: pass max_bid_override >= amount on the tool call. Lower overrides refuse with reason: "override_too_low".

    • Operator-wide: set EBAY_MCP_ALLOW_HIGH_VALUE=1 in the MCP server's environment.

  3. Human-in-the-loop confirm dialog. After the programmatic gates clear, the MCP pops a topmost, system-modal Yes/No dialog (Windows: MessageBoxW via ctypes; macOS/Linux: tkinter.messagebox) showing the tool, host, item ID, amount, currency, and quantity. The default button is NO, ESC cancels, and there is no auto-dismiss or timeout. Click YES to send the call to eBay; anything else returns a reason: "user_declined" refusal and no Trading call fires. There is intentionally no env-var bypass — tests stub the dialog directly. Production-host dialogs carry a *** PRODUCTION HOST — REAL MONEY *** header; sandbox dialogs say Sandbox host (no real money)..

  4. Active-host visibility. Successful calls against default_host = "production" include a warning field in the response ("PRODUCTION HOST — this call committed real money on eBay."). server_info() flags the active host before any call.

  5. No silent half-commits. No auth token cached → the underlying Trading API call raises before touching eBay, not mid-flight.

All money tools also surface eBay-side errors (insufficient bid, currency mismatch, listing ended, etc.) as TradingApiError with the parsed Errors block attached.

Out of scope (v0)

  • ❌ Selling side (use eBay's Sell API directly for that — different shape entirely)

  • ❌ Snipe-bidding with auto-trigger (one tool call = one bid, no scheduling)

  • ❌ Multi-account: v0 is one user account per host config; add multi-account later if needed

Related MCP server: SlimWeb Client MCP

Install

Not yet on PyPI. From source:

git clone https://github.com/acato/ebay-mcp
cd ebay-mcp
uv sync
uv run ebay-mcp

Windows: avoid Microsoft Store Python

If uv picks Microsoft Store Python (path under \WindowsApps\PythonSoftwareFoundation...) when creating the venv, the MCP runs fine from a terminal but fails to launch from GUI hosts like the Claude desktop app, IDE extensions, or scheduled tasks. You will see:

Unable to create process using "...\WindowsApps\PythonSoftwareFoundation.Python.3.12_...\python.exe"

Pin uv to a non-Store interpreter — uv's managed Python is easiest:

uv python install 3.12
uv venv --python 3.12 --python-preference only-managed --clear
uv sync

Verify: Get-Content .venv\pyvenv.cfg — the home = line should point under AppData\Roaming\uv\python\..., not \WindowsApps\.

Configure

Sandbox-first. Get your sandbox keyset from developer.ebay.com → Application Keysets → Sandbox. Copy examples/config.toml to ~/.config/ebay-mcp/config.toml:

default_host = "sandbox"

[hosts.sandbox]
app_id = "..."             # SBX App ID (Client ID)
dev_id = "..."             # Developer Account Dev ID
cert_id = "..."            # SBX Cert ID (Client Secret) — env var preferred
redirect_uri = "https://localhost/oauth/callback"

# [hosts.production]
# app_id = "..."
# dev_id = "..."
# cert_id = "..."
# redirect_uri = "https://localhost/oauth/callback"

Per-host env vars override file values:

  • EBAY_MCP_<HOST>_CERT_ID — overrides cert_id (recommended for production)

  • EBAY_MCP_<HOST>_APP_ID, EBAY_MCP_<HOST>_DEV_ID — overrides for completeness

User-level OAuth tokens cache to ~/.config/ebay-mcp/token-cache-<host>.json automatically after the manual authorization-code flow (see auth.py docs once Day 1b lands).

Use with Claude Code

claude mcp add ebay-mcp -- uv run --directory /path/to/ebay-mcp ebay-mcp

Use with Claude Desktop

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "ebay-mcp": {
      "command": "C:\\Users\\you\\AppData\\Local\\Microsoft\\WinGet\\Links\\uv.exe",
      "args": ["run", "--directory", "C:\\path\\to\\ebay-mcp", "ebay-mcp"]
    }
  }
}

Documentation

  • DESIGN.md — architecture, tool surface, safety patterns, OAuth flow

  • CONTRIBUTING.md — dev setup, sandbox testing, release process

License

Apache 2.0. See LICENSE and NOTICE.

Trademarks

"eBay" is a trademark of eBay Inc. This project is an independent integration with the standard eBay public APIs and is not affiliated with, endorsed by, or sponsored by eBay Inc.

Available Tools

15 tools
add_to_watchlistA

Add an item to the authenticated user's watchlist.

Trading API AddToWatchList. Fully reversible — call remove_from_watchlist with the same item_id to undo.

Args: item_id: numeric eBay item ID (from search, get_item, etc.) host: configured host. Defaults to default_host.

Returns: dict with host, item_id, added: True, and watch_list_count (total items in the watchlist after the operation). Raises ValueError on empty item_id. On eBay-side errors (item ended, already watched, etc.) the Trading API raises TradingApiError with details.

Inputs: item_id (required), host. Returns: object

buy_nowA

Purchase a Buy It Now listing immediately at the listed price.

Trading API PlaceOffer with Action=Purchase. The buyer commits to pay the listing's BIN price; eBay creates the order on success.

PRODUCTION HOST WARNING: when the active host is "production", a successful call commits real money on eBay. Inspect server_info() or list_hosts() before committing.

Args: item_id: numeric eBay item ID. Get from search() or get_item(). confirm_amount: must equal the listing's Buy-It-Now price exactly. The repeated dollar amount is a safety gate against stale prices or typos. Look up the current price with get_item() right before calling. quantity: number of units to purchase (default 1). Multi-quantity BIN listings can have a per-buyer limit; eBay rejects with TradingApiError if violated. currency: ISO currency code matching the listing (default "USD"). max_bid_override: optional ceiling that authorizes amounts above the $500 per-call safety cap. Pass a value >= confirm_amount to bypass the cap for this call. host: configured host name. Defaults to default_host.

Returns: On success: dict with host, item_id, action="Purchase", amount, currency, quantity, placed=True, and (on production) a warning. On safety-gate failure: structured refusal payload. Raises ValueError / TradingApiError as in place_bid.

Inputs: item_id (required), confirm_amount (required), quantity, currency, +2 more. Returns: object

complete_user_authA

Finish OAuth2 user auth by exchanging the authorization code for tokens.

The code is the value of the code query parameter in the URL eBay redirected to after start_user_auth's auth_url. Optionally pass state to verify against what start_user_auth issued (CSRF defense).

Args: code: the authorization code from eBay's redirect URL. state: optional — the state value from the redirect URL. If provided, must match what start_user_auth stored. Mismatch returns a structured refusal payload. host: which configured host to authenticate against. Defaults to config's default_host. Must match the host used in start_user_auth.

Returns: On success: {host, authenticated: true, access_expires_at, refresh_expires_at} On state mismatch: {refused: true, reason: "state_mismatch", host, message: ...}

Inputs: code (required), state, host. Returns: object

get_active_bidsA

Return auctions where the user has a currently-active bid.

Trading API GetMyeBayBuying.BidList. Includes both winning and outbid items still in their bidding period.

Same response shape as get_watchlist. Empty hits + total=0 means you have no active bids.

Inputs: limit, offset, host. Returns: object

get_itemA

Fetch full details for a single eBay item by ID.

Args: item_id: the eBay item ID (e.g., "v1|353528728623|0"). Get these from search() results. marketplace: eBay marketplace ID (default "EBAY_US"). host: which configured host to use. Defaults to config's default_host.

Returns: Full item dict including description, shipping options, seller details, return terms, item location, and the standard summary fields. If the item doesn't exist or has ended, returns {"item_id": item_id, "host": host, "missing": true}.

Inputs: item_id (required), marketplace, host. Returns: object

get_lost_itemsA

Return auctions where the user bid but did not win.

Trading API GetMyeBayBuying.LostList. Default lookback ~30 days; older items roll off.

Same response shape as get_watchlist.

Inputs: limit, offset, host. Returns: object

get_watchlistA

Return the authenticated user's watched items.

Uses Trading API GetMyeBayBuying with the WatchList container. Requires that the user has authenticated via start_user_auth + complete_user_auth for the chosen host.

Args: limit: items per page (1-200). Default 100. offset: pagination offset. Trading API pages from 1; we translate. host: configured host name. Defaults to default_host.

Returns: dict with host, container, total, limit, offset, and hits (a list of item summaries: item_id, title, price, currency, ends_at, bid_count, seller, web_url, listing_type, quantity_available).

Inputs: limit, offset, host. Returns: object

get_won_itemsA

Return items the user won at auction or bought via Buy It Now.

Trading API GetMyeBayBuying.WonList. This is your effective "purchase history" for the eBay-native default lookback window (eBay shows the last 30 days by default; older items roll off the WonList container).

Same response shape as get_watchlist.

Inputs: limit, offset, host. Returns: object

list_hostsA

List every configured host with its status (default flag and cert availability).

Useful for diagnosing why a tool call against a particular host might fail before you make the call.

Inputs: no named parameters. Returns: result

make_best_offerA

Submit a Best Offer on a listing that has Best Offer enabled.

Trading API PlaceOffer with Action=BestOffer. The seller can accept, counter, or decline; this call only places the offer.

PRODUCTION HOST WARNING: when the active host is "production" and the seller accepts, the offer becomes a binding sale at the offer amount.

Args: item_id: numeric eBay item ID. Must have Best Offer enabled — check buying_options on get_item() output for "BEST_OFFER". offer_amount: the price the buyer offers, in currency. Must be > 0. Many sellers configure auto-decline below a threshold. confirm_amount: must equal offer_amount exactly. Safety gate. quantity: number of units the offer covers (default 1). currency: ISO currency code matching the listing (default "USD"). max_bid_override: optional ceiling that authorizes offer amounts above the $500 per-call safety cap. Pass a value >= offer_amount to bypass. host: configured host name. Defaults to default_host.

Returns: On success: dict with host, item_id, action="BestOffer", amount, currency, quantity, placed=True, optionally best_offer_id (for follow-up via Trading GetBestOffer / Accept flows), and (on production) a warning. On safety-gate failure: structured refusal payload. Raises ValueError / TradingApiError as in place_bid.

Inputs: item_id (required), offer_amount (required), confirm_amount (required), quantity, +3 more. Returns: object

place_bidA

Place a proxy bid on an eBay auction.

Trading API PlaceOffer with Action=Bid. eBay treats max_bid_amount as a proxy ceiling — it bids the minimum needed to outbid the current high bidder, and continues raising up to max_bid_amount as competing bids come in.

PRODUCTION HOST WARNING: when the active host is "production", a successful call commits real money on eBay. Inspect server_info() or list_hosts() before committing.

Args: item_id: numeric eBay item ID. Get from search() or get_item(). max_bid_amount: the proxy bid ceiling in currency. Must be > 0. confirm_amount: must equal max_bid_amount exactly. The repeated dollar amount is a safety gate against typos. quantity: number of units (default 1; only relevant for multi-quantity auctions). currency: ISO currency code matching the listing (default "USD"). Must match the listing's currency or eBay refuses. max_bid_override: optional ceiling that authorizes amounts above the $500 per-call safety cap. Pass a value >= max_bid_amount to bypass the cap for this call. Lower values are refused. host: configured host name. Defaults to default_host. The active host (sandbox vs production) is surfaced in the response.

Returns: On success: dict with host, item_id, action="Bid", amount, currency, placed=True, current_price, minimum_to_outbid, high_bidder, and (on production) a warning field. On safety-gate failure: structured refusal payload (refused=True, reason, message, plus the offending values). Raises ValueError on empty item_id, non-positive amounts, etc. On eBay-side errors (listing ended, currency mismatch, insufficient bid, etc.) raises TradingApiError.

Inputs: item_id (required), max_bid_amount (required), confirm_amount (required), quantity, +3 more. Returns: object

remove_from_watchlistA

Remove an item from the authenticated user's watchlist.

Trading API RemoveFromWatchList. Fully reversible — call add_to_watchlist with the same item_id to undo.

Args: item_id: numeric eBay item ID currently on the watchlist. host: configured host. Defaults to default_host.

Returns: dict with host, item_id, removed: True, and watch_list_count (total items in the watchlist after the operation). Raises ValueError on empty item_id. eBay-side errors (item not on watchlist, etc.) surface as TradingApiError.

Inputs: item_id (required), host. Returns: object

server_infoA

Return server version, active host, and configuration locations.

The active_host field reflects what default_host is set to (or what would be used when a tool call omits the host parameter). When set to "production", the response includes a warning field — real money is at stake on bid/buy operations.

Inputs: no named parameters. Returns: object

start_user_authA

Begin OAuth2 user authentication for buyer-side eBay operations.

Watchlist, MyeBay reads, bidding, and buying all require a user token. This tool returns an auth_url for you (the human) to open in a browser. After signing in and granting permissions, eBay redirects to the configured redirect_uri with a code query parameter — pass that to complete_user_auth to finalize.

Most workflows only run this once per host; tokens persist 18 months and auto-refresh.

Args: host: which configured host to authenticate against. Defaults to config's default_host.

Returns: dict with host, auth_url, state, and instructions. The auth_url is what the human needs to open; the state is round-tripped to verify the callback genuinely came from this flow.

Inputs: host. Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.2/5.0

    Scored across 15 tools

    Disambiguation5/5

    Each tool targets a distinct operation (search, watchlist CRUD, bidding, buying, auth, etc.). Overlapping tools like get_watchlist, get_active_bids, get_lost_items, get_won_items are clearly distinguished by state and documented. No ambiguity.

    Naming Consistency5/5

    All tool names use lowercase with underscores and follow a consistent verb_noun pattern (e.g., add_to_watchlist, get_item, place_bid, buy_now, start_user_auth). No mixed conventions or cryptic names.

    Tool Count5/5

    15 tools is well-scoped for the server's purpose (eBay buyer operations). Every tool covers a necessary function without redundancy, and the count is within the ideal 3-15 range.

    Completeness4/5

    Covers all core buyer actions: search, item details, authentication, watchlist, bidding, buying (BIN and Best Offer), and purchase history (won/lost/active). Minor gaps exist (e.g., no tool for seller messaging or order cancellation), but the primary workflow is complete.

    Maintenance

    ActivityNo data
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Minimal MCP server for searching eBay listings via the Browse API, enabling keyword search with filters, sorting, pagination, and retrieving full item details.
      1
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      An MCP server providing AI assistants comprehensive access to eBay's Sell APIs for inventory management, order fulfillment, marketing, analytics, and more, with hosted multi-user and local modes.
      37 npm
      5
      MIT
    • F
      license
      Not graded
      quality
      D
      maintenance
      MCP server providing unified access to eBay, Shopify, Best Buy, and Etsy marketplace data via the Commerce API, enabling product searches and listing retrieval across multiple retailers.
      -