Skip to main content
Glama
README.md
# saleroom

What did that watch actually sell for — and what is one worth
today? saleroom is a read-only client for the altfinance
auction-results service, which tracks realized prices across
twenty luxury categories: watches, handbags, jewelry, gems,
cars and motorcycles, aircraft, wine and whisky, art, design,
fashion, coins and more. You can list the tables, inspect a
table's columns, run filtered and sorted queries over the
sales history, read summary statistics and price trends, ask
for a fair-value range on a single item, search the whole
market at once, consult a precomputed brand/model price
index, and view price alerts.

Nothing here trades, bids or changes anything: all nine
tools only read. Responses come back exactly as the service
returned them — nothing is trimmed, renamed or summarised on
the way through.

## Configuration

Two environment variables control the client:

- `ALTFINANCE_API_KEY` (required) — sent on every request
  as `Authorization: Bearer <key>`. When it is not set,
  every tool fails with `ALTFINANCE_API_KEY is not set`
  before any request is made.
- `ALTFINANCE_API_URL` (optional) — API base URL. Defaults
  to `https://api.altfndata.com`.

## Tools

- `list_tables` — the available auction tables, with live
  descriptions and column counts. No arguments.
- `get_table_schema` — column names and types for one
  table. Takes `table` (required).
- `query_table` — query a table with `filters`, `sort`,
  `fields` selection and pagination (`limit` 1–500,
  `offset` ≥ 0). Takes `table` (required) plus the optional
  arguments.
- `market_stats` — a realized-price summary for a table or
  a filtered segment: count, median, percentiles, average,
  min/max, sale-date span and top vendors. Takes `table`
  (required) and optional `filters`.
- `price_trend` — how realized prices moved over time,
  bucketed by `year`, `quarter` or `month`. Takes `table`
  (required), optional `bucket` and optional `filters`.
- `price_check` — a fair-value range for a single item from
  comparable sales, with source links. Takes `item`
  (required) and optional `category`. Live categories are
  handbags, watches and cars.
- `search` — whole-market keyword search across every
  category at once, merged by realized price. Takes
  `query` (required) and optional `category`.
- `market_index` — a precomputed model-level price index
  for a brand or model (handbags, watches, cars). Takes
  `query` (required) and optional `category`.
- `list_alerts` — a read-only view of price alerts, or
  guidance on enabling them. No arguments.

The twenty tables are: `watches`, `handbags`, `jewelry`,
`gems`, `automobile`, `motorcycle`, `aircraft`,
`wine_whisky`, `works_of_art`, `fine_art`, `design`,
`fashion`, `shoes`, `automobilia`, `books`, `coins`,
`other_automobile`, `perfume`, `accessories` and
`musical_instruments`.

A filter is `{column, operator, value}`. The operators are
`eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `like`, `in`,
`not_in`, `is_null` and `is_not_null`. Omit `value` for
`is_null` / `is_not_null`; pass an array for `in` /
`not_in`. A sort is `{field, direction}` with direction
`asc` or `desc`.

Validation happens before any request. An unknown operator
fails with `unknown filter operator: <op>`; a missing value
where one is required fails with `filter value is required
for operator <op>`; a `limit` outside 1–500 fails with
`limit must be an integer between 1 and 500`. An upstream
non-2xx reply fails with `altfinance error: HTTP <status>`
and an unreachable API with `altfinance unreachable`.

### Endpoint provenance

The original service's project record pins the nine tools,
the twenty table names, the filter operators, the sorting,
field-selection and pagination rules, the trend buckets and
the two environment variables — and that all nine endpoints
are read-only. It does not pin the per-tool argument names
beyond its prose, the filter/sort JSON shapes, the auth
header or the request paths. Those pieces are
reconstructions, labelled as such:

- `Authorization: Bearer <key>` header — reconstruction
  (the record pins API-key authentication only).
- `GET <base>/v1/tables` — `list_tables`.
- `GET <base>/v1/tables/{table}/schema` —
  `get_table_schema`.
- `POST <base>/v1/tables/{table}/query` with body
  `{filters?, sort?, fields?, limit?, offset?}` (unset
  fields omitted) — `query_table`.
- `POST <base>/v1/tables/{table}/stats` with body
  `{filters?}` — `market_stats`.
- `GET <base>/v1/tables/{table}/trend` with `bucket` and a
  JSON-encoded `filters` query parameter when set —
  `price_trend`.
- `POST <base>/v1/price-check` with body
  `{item, category?}` — `price_check`.
- `GET <base>/v1/search?q=&category=` — `search`.
- `GET <base>/v1/market-index?query=&category=` —
  `market_index`.
- `GET <base>/v1/alerts` — `list_alerts`.

## CLI

Each tool is a subcommand taking one JSON argument string:

```bash
npx @reneturcios/saleroom list_tables '{}'
npx @reneturcios/saleroom query_table '{"table":"watches","filters":[{"column":"brand","operator":"eq","value":"Rolex"}],"limit":10}'
npx @reneturcios/saleroom price_check '{"item":"Rolex Submariner 1968","category":"watches"}'
npx @reneturcios/saleroom --version
```

Output is the tool's result text (the upstream JSON on
success). Exit codes: `0` on success, `1` on a runtime
error (including a validation or upstream failure), `2` on
a usage error.

## MCP server

```bash
npx -y @reneturcios/saleroom mcp
```

MCP client config:

```json
{
  "mcpServers": {
    "saleroom": {
      "command": "npx",
      "args": ["-y", "@reneturcios/saleroom", "mcp"],
      "env": {
        "ALTFINANCE_API_KEY": "<your key>"
      }
    }
  }
}
```

## Docker

```bash
docker run -i ghcr.io/cloudcorprecords/saleroom
docker run --rm ghcr.io/cloudcorprecords/saleroom list_tables '{}'
```

## Development

```bash
npm install
npm run build   # tsc -> dist/
npm test        # tsx --test test/*.test.ts (fake fetch only, no network)
npm run dev     # run the CLI from source
```

## License

MIT — Copyright (c) 2026 Rene Turcios