Skip to main content
Glama
surplus-auctions-mcp

surplus-auctions-mcp

surplus-auctions-mcp

GovDeals as agent tools. Every week, thousands of U.S. cities, counties, school districts, police departments and state agencies auction off pickup trucks, police cruisers, school buses, excavators, laptops and office furniture on GovDeals, often far below market value. GovDeals has no public API, so agents can't use it directly.

This MCP server gives any MCP-compatible assistant five tools for searching, inspecting and comparing GovDeals auctions. TinyFish does the page reading underneath.

You:    Find pickup trucks under $8k ending this week in Texas, then compare mileage on the best three.
Agent:  search_auctions → get_auction_details ×3 → compare_auctions
        "The 2015 Silverado (San Antonio) is cheapest at $1,100 + 12.5% premium, but it has no engine.
         The 2009 F-350 has the lowest mileage (81,938) at $2,640 all-in and closes tomorrow at 1:10 PM CT…"

Quick start

You need Node 20+ and a TinyFish API key (create one). The normal path uses only TinyFish Fetch, which is free up to 1,000 URLs a day.

git clone <this repo> surplus-auctions-mcp && cd surplus-auctions-mcp
npm install          # also builds dist/
export TINYFISH_API_KEY=sk-tinyfish-...
npm run health       # live check: should print 3× PASS

Then connect it to your assistant (below).

Related MCP server: GovAuctions MCP server

Connect it to your assistant

Every client runs the same command: node /absolute/path/to/surplus-auctions-mcp/dist/src/index.js, with TINYFISH_API_KEY in its environment.

Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows), then restart the app:

{
  "mcpServers": {
    "surplus-auctions": {
      "command": "node",
      "args": ["/absolute/path/to/surplus-auctions-mcp/dist/src/index.js"],
      "env": { "TINYFISH_API_KEY": "sk-tinyfish-..." }
    }
  }
}

Claude Code

claude mcp add surplus-auctions -e TINYFISH_API_KEY=sk-tinyfish-... -- node /absolute/path/to/surplus-auctions-mcp/dist/src/index.js

Cursor, Windsurf and other stdio clients

Add a server with the same command and environment variable as above.

ChatGPT and other remote clients (Streamable HTTP)

MCP_HTTP_TOKEN=choose-a-secret npm run start:http      # serves http://localhost:3333/mcp

Expose it over HTTPS (for example cloudflared tunnel --url http://localhost:3333 or any reverse proxy), then add https://<host>/mcp as a connector in ChatGPT (Settings → Connectors, developer mode). If MCP_HTTP_TOKEN is set, clients must send Authorization: Bearer <token>.

Settings

Env var

Default

Meaning

TINYFISH_API_KEY

(required)

Your TinyFish key

SURPLUS_AGENT_FALLBACK

on

When GovDeals changes its pages, retry with TinyFish Agent (uses credits, slower). off returns a SITE_CHANGED error instead

PORT

3333

HTTP mode only

MCP_HTTP_TOKEN

unset

HTTP mode only: require this bearer token

See .env.example for the same list with comments. The server does not read .env files: set these with export in your shell or in your MCP client's env block, as shown above.


Using it

Ask your assistant in plain language. It picks the tools. Some prompts to try:

  1. "Find pickup trucks under $8,000 in Texas ending this week, then compare mileage and total cost on the three best."

  2. "What police cars or SUVs close in the next 24 hours anywhere in the U.S.? Show me the five cheapest."

  3. "I need an excavator under $50k in Florida. Show me what's available, then give me full details on the cheapest one, including the buyer's premium and where I'd pick it up."

  4. "Is the surplus auction tool working right now?"

A typical session goes: search → pick a few → get details → compare → open the listing and bid on GovDeals. The server never bids for you.

The five tools

Tool

Use it to

Key inputs

Returns

search_auctions

Find items

keyword, state, category, min_price, max_price, ending_within_hours (max 336), limit

auctions[] (id, title, url, current_bid, ends_at, hours_left, closes_in, state, city), warnings

list_ending_soon

See what closes in the next N hours

hours (max 336), state, category, keyword, max_price

Same as search, soonest first

get_auction_details

Decide whether to bid

auction_id (from search, or a GovDeals asset URL)

Bid and bid count, exact end time, agency, pickup location, buyer's premium, reserve status, condition, description, and for vehicles year / make / model / mileage / hours / VIN

compare_auctions

Choose between 2–5 lots

auction_ids[]

Side-by-side rows with estimated total (bid + premium) and highlights: cheapest, lowest mileage, newest, ending first

health_check

Check whether GovDeals still works

none

pass / degraded / fail per tool, with the reason

Ids look like govdeals:27018-390 (GovDeals' own Lot#). Full GovDeals asset URLs also work.

Categories: vehicles, heavy_equipment, trailers, boats_marine, computers_electronics, furniture, office_equipment, industrial_tools, medical, real_estate, other. Vehicles and trailers are filtered by GovDeals itself. The rest are matched by keyword, and the response says so in warnings.

Reading the numbers

  • Prices are current bids in USD, and they change constantly. ends_at is UTC.

  • estimated_total is the bid plus the buyer's premium. It does not include sales tax, title fees or transport.

  • Mileage and hours come from the seller's listing and are sometimes wrong or missing. Check the listing before you bid.

A real session

Recorded 2026-11-03 in Claude Code against live GovDeals data (bids and times have since moved on):

You:    Find pickup trucks under $8,000 in Texas ending this week, then compare mileage and total cost on the three best.

search_auctions {keyword: "pickup truck", category: "vehicles", state: "TX", max_price: 8000, ending_within_hours: 144, limit: 20}
  → 20 auctions, e.g. govdeals:24637-96  2018 Ford F-150  $3,150  ends 2026-11-05T20:00Z  Corpus Christi

compare_auctions {auction_ids: [govdeals:24637-96, govdeals:24637-90, govdeals:31894-8, govdeals:4052-1806, govdeals:4052-1805]}
  → govdeals:24637-96  2018 Ford F-150         72,679 mi  bid $3,150  total $3,543.75 (12.5% premium)
    govdeals:24637-90  2016 Ford F-150         86,653 mi  bid $2,815  total $3,166.88
    govdeals:31894-8   2019 Ford F-250 SD     159,880 mi  bid $1,000  total $1,100.00 (10% premium)
    govdeals:4052-1806 2016 Silverado 2500HD  197,605 mi  bid $3,250  total $3,656.25
    govdeals:4052-1805 2016 Ford F-350 SD     142,919 mi  bid $3,000  total $3,375.00
  highlights: lowest_mileage = govdeals:24637-96, lowest_estimated_total = govdeals:31894-8

Agent: The 2018 F-150 has the lowest mileage (72,679 mi, ~$3,544 all-in). The 2019 F-250 is the cheapest
       (~$1,100) but has 159,880 mi. The 2016 F-150 sits between them at ~$3,167 and needs a jump to start.

The same session also covered a Florida excavator search (search_auctions → get_auction_details) and a health_check (3× pass).


How TinyFish Fetch and Agent are used

tool call → build the GovDeals URL from typed inputs
          → TinyFish Fetch renders the page to markdown
          → strict parser + field validation → structured JSON (extraction: "fetch")
              ↳ page changed or blocked → TinyFish Agent reads it with an output_schema
                → structured JSON (extraction: "agent_fallback" + FETCH_PARSER_DRIFT warning)
                  ↳ Agent fails too → typed error (SITE_CHANGED / SITE_BLOCKED)

Fetch does the everyday work. GovDeals is a JavaScript app, so plain HTTP sees an empty shell. Every search and detail page is rendered by Fetch in a real browser and returned as markdown, then parsed. A search is one Fetch call. Result cards whose title didn't render are filled from their detail pages in one extra Fetch batch.

Agent found the site's search parameters, and is the safety net.

  • Discovery. GovDeals hides its filters behind forms and JavaScript. Calibration runs gave Agent goals like "search GovDeals for 'pickup truck', filter to Texas, sort by closing soon, report the address-bar URL". That revealed the real query parameters (stateName=Texas, category=6, price in cents as price=c-0:800000, sf=auctionclose), now encoded and commented in govdeals.ts.

  • Fallback. If a parser stops recognizing a page, the tool re-runs the task with Agent (stealth profile). The data still comes back, tagged extraction: "agent_fallback" with a FETCH_PARSER_DRIFT warning so the drift stays visible.

Why Fetch first: an Agent search took 3–4.5 minutes (19 browser steps) in testing. The same search via Fetch takes 15–50 seconds and uses no Agent credits.

Breaking loudly, not silently

An agent can always tell "nothing matched" apart from "the site broke":

  • If GovDeals can't be read, the tool returns a typed error, never an empty list. An empty auctions list means the site really had no matches.

  • Parsers are strict. Required fields (price line, end time, the Lot# marker) must be present or the parser raises drift. A results page that shows listings but yields no parseable rows counts as drift, not as "empty".

  • TinyFish reports COMPLETED even when the goal failed, so the result payload is inspected as well.

  • The health check disables the Agent fallback, so a redesign shows up as a failure instead of being hidden. The test suite simulates redesigns against recorded pages (for example GovDeals dropping its Lot#: marker) and asserts the right tool reports fail / SITE_CHANGED.


Troubleshooting

Errors come back with a code, a message, a retryable flag and a hint.

Code

What it means and what to do

TINYFISH_AUTH

The API key is missing or wrong. Set TINYFISH_API_KEY

RATE_LIMITED

TinyFish rate or credit limit. Wait a minute and check your balance

UPSTREAM_TIMEOUT

Retry once, or narrow the search with a state or category

SITE_BLOCKED

GovDeals blocked the browser. Retry in a few minutes

SITE_CHANGED

GovDeals changed its layout. Run health_check and report it

NOT_FOUND

The auction closed, sold or was withdrawn

INVALID_INPUT

Bad id, state, or contradictory filters (for example min price above max)

TINYFISH_ERROR

Other TinyFish failure. Retry once

An empty auctions list means GovDeals really had no matches. A broken site returns an error instead.

Slow responses. Each GovDeals page takes about 15–50 seconds to load, so a multi-step conversation can take a few minutes. If your client has a tool timeout, raise it. Searches are cached for 60 seconds and details for 30 seconds.

Health check.

npm run health                  # exit 0 healthy · 1 broken · 2 degraded
npm run health -- --with-agent  # also test the Agent fallback
npm run health -- --json

The same check is available to your assistant as the health_check tool.


Development

npm test            # offline, against real GovDeals pages recorded in test/fixtures
npm run typecheck
npm run build       # rebuild dist/ after changing the source
npm run smoke       # live end-to-end over MCP stdio
npm run edge        # live edge cases: other states, filters, bad ids, empty results
npm run calibrate   # re-capture live pages into test/fixtures/live/ after a site change
src/
  index.ts              stdio + Streamable HTTP entry point
  server.ts             MCP tool definitions (zod input/output schemas)
  service.ts            search, caching, compare
  health.ts             live checks
  sources/              GovDeals URL builder, page parsers, Fetch → Agent fallback
  tinyfish/client.ts    TinyFish Agent + Fetch client
test/
  fixtures/             recorded GovDeals pages (contact details redacted)
  helpers/fixture.ts    test stand-in for TinyFish

.github/workflows/health.yml runs the tests on every push and the live health check daily. Add TINYFISH_API_KEY as a repo secret.

Limitations

  • Read-only. No bidding, no login, no watchlists.

  • Covers GovDeals only.

  • Use within GovDeals' terms of service. Results link back to the original listing, where all bidding happens.

MIT licensed.

Available Tools

5 tools
compare_auctionsCompare auctions side by sideA
Read-onlyIdempotent

Compare 2–5 GovDeals auctions side by side (bid, estimated total with buyer's premium, end time, location, year, make, model, mileage, hours, condition) and highlight the cheapest, lowest-mileage, newest and soonest-ending. Accepts ids from search results .

Inputs: auction_ids (required). Returns: rows, notes, failed, highlights

get_auction_detailsGet auction detailsB
Read-onlyIdempotent

Full details for one auction: current bid and bid count, exact end time, selling agency, pickup location, buyer's premium, reserve status, condition, description, and for vehicles/equipment the year, make, model, mileage, engine hours and VIN.

Inputs: auction_id (required). Returns: id, url, city, state, +22 more

health_checkCheck that GovDeals still worksA
Read-only

Run live canary checks against GovDeals for every tool and report pass / degraded / fail with the reason. Use when a tool returns SITE_CHANGED or results look wrong. Takes 30–90 seconds.

Inputs: no named parameters. Returns: checks, overall, checked_at

list_ending_soonList auctions ending soonA
Read-onlyIdempotent

List government surplus auctions that close within the next N hours, soonest first — the best time to find bargains. Optionally narrow by state, category, keyword and max price.

Inputs: hours (required), limit, state, keyword, +2 more. Returns: auctions, warnings, total_returned

search_auctionsSearch government surplus auctionsA
Read-onlyIdempotent

Search active government surplus auctions on GovDeals. Returns normalized listings (title, current bid, end time, location) sorted by soonest ending, plus a per-site status. Use get_auction_details for mileage, VIN, buyer's premium and pickup info.

Inputs: limit, state, keyword, category, +3 more. Returns: auctions, warnings, total_returned

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A3.9/5.0

    Scored across 5 tools

    Disambiguation4/5

    Most tools have clearly distinct roles: details, comparison, and health checks are unambiguous. The main overlap is between search_auctions and list_ending_soon, since both return filtered auction listings, though the latter is explicitly time-scoped and bargain-oriented. Descriptions provide enough guidance to choose correctly in most cases.

    Naming Consistency4/5

    Names mostly follow a verb_noun or verb_phrase pattern: search_auctions, get_auction_details, compare_auctions. list_ending_soon and health_check deviate slightly by omitting an explicit resource noun, but remain readable and consistent in snake_case.

    Tool Count5/5

    Five tools is well-scoped for a read-only auction research server. Each tool earns its place: discovery, time-filtered discovery, detail retrieval, comparison, and diagnostics.

    Completeness4/5

    The surface covers search, time-based discovery, details, comparison, and health checking, which are the core workflows for auction research. Gaps exist around bidding, watchlists, saved searches, or alerts, but those may be intentionally out of scope for a read-only integration.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      C
      maintenance
      Provides access to government auctions data for physical-asset auctions including surplus, seized, and forfeited items. Designed for AI agents to query and retrieve auction information via natural language.
      132 npm
      2
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      GovAuctions.app is a free public site for searching government surplus auctions. This MCP server exposes its data: live listings from GSA and other public sellers across the US, UK, CA and AU, sold-price comps from 170,000+ closed auctions, and a 0-100 Flip Score resale signal.
      10 npm
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables searching live US auction lots and auction events across commercial auction houses and government surplus sources by keyword, state, or proximity to a ZIP, and retrieving sold-price comps and coverage data.
      269 npm
      1
      MIT