Skip to main content
Glama
README.md
# steam-mcp

An MCP server for deciding which Steam games suit a particular person. It ranks
the store against what the player actually logs hours in, blended with whatever
they say they are in the mood for right now.

Ten tools. `recommend_games` is the front door; the rest exist so a ranking can
be interrogated rather than taken on faith.

| Tool | Needs key | What it does |
|---|---|---|
| `recommend_games` | no (better with) | Rank the store for a stated preference, personalised by library |
| `get_taste_profile` | yes | Tag affinities weighted by playtime, top genres, signature games |
| `search_games` | no | Structured catalog search: tags, price, platform, release date, sale |
| `get_game_details` | no | Description, tags, price, reviews, Metacritic, Deck compatibility |
| `find_similar_games` | no | "More like Hades": search on seed games' pooled tags |
| `get_game_reviews` | no | Score breakdown plus the most helpful review text |
| `list_tags` | no | Steam's tag vocabulary, for getting names exactly right |
| `get_my_library` | yes | Owned games with hours, most-played first |
| `get_wishlist` | no (public profile) | Wishlist with current price and discount |
| `get_recently_played` | yes | Last two weeks of play |

## Running it

```bash
npm install && npm run build
claude mcp add -s user steam-mcp -e STEAM_ID=<your SteamID64> -- node /path/to/steam-mcp/dist/index.js
```

Environment:

- `STEAM_ID` (optional): default player, as a SteamID64. Tools also accept a
  vanity name or profile URL per call.
- `STEAM_API_KEY` (optional): from <https://steamcommunity.com/dev/apikey>. Only
  the library, recent-play and vanity-resolution paths need it. Everything else,
  including the wishlist on a public profile, is keyless, so the server is useful
  with no credential at all. It just cannot personalise.

A disk cache lives at `$XDG_CACHE_HOME/steam-mcp` (default `~/.cache`). The
store's `appdetails` endpoint is throttled to roughly 200 per five minutes per
IP; the client paces that endpoint at 1.5s, the others far faster, and caches
aggressively (details six hours, tags and Deck data a week) so a second
recommendation in the same sitting is mostly free. Every tool that enriches a
list works under a deadline and reports how many games it skipped, so a long
request returns a partial answer rather than timing out at a proxy.

## How the ranking works

`src/taste.ts` holds the whole model.

**Profile.** Each played game's hours are attributed to its community tags in
proportion to their vote share, so a milsim's hours go mostly to Military and
Tactical and only a sliver to Multiplayer. Three corrections sit on top:

- Tags are weighted by rarity, derived from the popularity order of Steam's own
  tag dictionary (no extra requests). Without this every profile starts Action,
  Open World, Simulation, whoever the player is.
- Games from one studio are pooled before compression. Three Arma entries are
  three measurements of one taste, not three times the evidence.
- Hours are square-rooted. One outlier still leads, but does not write the
  whole profile.

Two-week play, when a key is available, counts a second time on top of lifetime
hours: once as history, once as what the player is into now.

**Score.** Two signals on the same 0..1 scale, blended equally: `fit`, the cosine
between the candidate's tag vector and the profile, relative to the best any
game could do; and `want`, how much of the candidate's tag mass is what the
player asked for. Reception then penalises below Steam's "Mostly Positive" line
(70%) and never rewards above it, because candidates already arrive sorted by
reviews and rewarding them again would count popularity twice. Every reported
`matchedOn` entry is in score points and says whether the library or the request
earned it.

**Order.** The final list is re-ranked greedily for variety: a candidate loses up
to 40% of its score for resembling something already chosen. Scores are reported
untouched; only the order changes, and the tool description says so.

## Tests

```bash
npm test
```

Both suites run against the live API, deliberately. `test/smoke.mjs` drives the
built server over real MCP stdio, which is the only place a silently dropped
schema or a changed store endpoint shows up. `test/taste.ts` runs the model over
`test/fixtures/library.json`, a real 45-game library, and asserts ranking
behaviour rather than exact numbers, since tag votes drift. Set `STEAM_API_KEY`
to also exercise the keyed tools.

## Deploying with a key

A long-lived stdio server cannot get its key from a request-scoped secret
broker, so the keyed deployment belongs wherever an environment variable can be
injected at process start: a supervisord `environment=` line, a Nomad variable,
a systemd `EnvironmentFile`. The server reads `STEAM_API_KEY` once at startup and
never writes it anywhere.

TDQS

A4.4/5.0

Scored across 10 tools

Disambiguation5/5

Each tool targets a distinct action and data source: taste profiling, recommendation, raw search, details, reviews, similar games, tags, and player-specific library/wishlist/recent activity. Even the three discovery tools are clearly separated by input type (preference statement, structured filters, seed games) and output purpose.

Naming Consistency5/5

All tool names follow a consistent lower_snake_case verb_noun pattern, with get_ as the dominant verb and action-specific verbs like recommend, search, find, and list used uniformly. There is no mixing of conventions or vague generic names.

Tool Count5/5

The 10 tools are well-scoped for a Steam-focused MCP server: they cover discovery, personalization, game details, reviews, and player data without unnecessary duplication or bloat. Each tool earns its place in the workflow.

Completeness5/5

The tool surface forms a complete read-only pipeline: understand the player, query the catalog, refine by tags, get details/reviews, and generate or sanity-check recommendations. The only possible gaps (e.g. account actions) are outside the server's apparent purpose.

Maintenance

ActivityMaintained
ResponsivenessNo issues