steam-library-mcp
# steam-library-mcp
A TypeScript MCP server for Steam library intelligence: ownership, store/review/DLC briefs, deals, taste-based discovery, wishlist releases, co-op planning, achievement objectives, storage, updates, and confirmed local actions.
It is model-agnostic: any MCP client/host that supports local stdio servers can run it, not just Codex. See [docs/mcp-client-setup.md](docs/mcp-client-setup.md) for Claude Desktop/Code, Codex, and generic MCP client setup patterns.
The server is read-only toward your Steam account by default. It does not buy, trade, gift, automatically send chat messages, modify your account, scrape Steam login pages, read cookies, store sessions, or handle Steam credentials.
Optional action tools can be enabled, but only with `STEAM_ENABLE_ACTIONS=true`. Launch/install/browser/chat-window/download-window tools require confirmation and default to dry-run previews where applicable. The friend-invite helper only opens existing friends' chats and never presses Send. Uninstall additionally requires `STEAM_ALLOW_UNINSTALL=true`, verifies the game is locally installed, asks through MCP user elicitation when supported (or requires exact confirmation text), and only opens Steam's own native confirmation flow.
## What It Can Answer
- Do I own Outriders?
- What games have I bought but barely played?
- What have I played recently?
- What Steam games are installed locally?
- Recommend something from my Steam library for a 1-hour session.
- Show my achievement progress for this game.
- What changed on my Steam wishlist this week?
- Did any wishlisted games release or announce a playtest, beta, or demo?
Steam owned-game API data does not include reliable genres or tags. Recommendations are based on available playtime, recent activity, installed status, name/query matches, and optional local MCP tags.
## Security Model
- Read-only mode is the default.
- Action and local-write tools are not registered unless `STEAM_ENABLE_ACTIONS=true`.
- No Steam password, cookie, Steam Guard, browser data, or login session handling.
- No purchases, trades, gifts, automated chat sends, profile changes, account changes, silent installs, or silent uninstalls.
- API keys are read from environment variables only.
- API keys are redacted from thrown errors.
- Logs go to stderr, not stdout, so MCP stdio is not polluted.
- No telemetry and no third-party analytics.
Cache/state files may contain owned games, wishlist items, release metadata, playtime, achievement progress, profile summary data, local notes, local tags, backlog status, and action history. Treat `STEAM_CACHE_DIR`, `STEAM_WISHLIST_STATE_PATH`, `STEAM_LOCAL_DB_PATH`, and `STEAM_ACTION_LOG_PATH` as private.
Wishlist retrieval uses Steam's first-party but undocumented `IWishlistService/GetWishlist/v1` endpoint because Steam has no documented consumer wishlist API. Names, release status, and demo availability come from the first-party but undocumented Store `appdetails` endpoint. Either may change, and access can depend on Steam privacy settings. Playtest/beta monitoring uses best-effort keyword matching against Steam's documented public news API; matches are signals, not guaranteed availability.
## Requirements
- Node.js 20+
- A Steam Web API key
- Your SteamID64
- Public-enough Steam profile/game details for the data you want Steam to return
Get a Steam Web API key at:
```text
https://steamcommunity.com/dev/apikey
```
Find your SteamID64 from your profile URL, a Steam ID lookup site, or by setting `STEAM_VANITY_NAME` and using the `steam_resolve_vanity_url` tool after setup.
## Setup
```bash
cd /ABSOLUTE/PATH/TO/steam-library-mcp
npm install
cp .env.example .env
```
Edit `.env`:
```bash
STEAM_API_KEY=your_steam_web_api_key_here
STEAM_ID_64=your_17_digit_steamid64_here
```
The server loads `.env` from its current working directory for direct local runs. Environment variables passed by Codex or your shell take precedence.
If you want Codex to guide the setup for you, use the playbook in [docs/setup-with-codex.md](docs/setup-with-codex.md). It covers the same safe flow used to set this up locally: discover SteamID64 from Steam account metadata, open the official API key page, handle the Steam Guard Mobile Authenticator requirement, and verify the key without printing it.
Helpful setup scripts:
```bash
npm run setup:accounts
npm run setup:verify
```
Build and test:
```bash
npm run check
npm run test
npm run build
```
With a private `.env` and a built server, an exhaustive live-but-safe pass is available:
```bash
npm run qa:full
```
It calls all 34 tools, uses temporary cache/state paths, and keeps every external action in dry-run mode.
Start directly:
```bash
npm run start
```
## Environment Variables
Required:
| Variable | Purpose |
| --- | --- |
| `STEAM_API_KEY` | Steam Web API key. Never commit this. |
| `STEAM_ID_64` | Default SteamID64 to query. |
Read-only options:
| Variable | Default | Purpose |
| --- | --- | --- |
| `STEAM_VANITY_NAME` | unset | Optional vanity profile name. |
| `STEAM_INCLUDE_PLAYED_FREE_GAMES` | `true` | Include played free games in owned-game results. |
| `STEAM_CACHE_TTL_HOURS` | `24` | Cache TTL for Steam API responses. |
| `STEAM_CACHE_DIR` | OS user cache dir | Cache location. |
| `STEAM_LOCAL_LIBRARY_PATH` | auto-detect | Override local Steam library path or `libraryfolders.vdf`. |
| `STEAM_REQUEST_TIMEOUT_MS` | `15000` | Steam API request timeout. |
| `STEAM_WISHLIST_STATE_PATH` | cache dir JSON | Persistent local wishlist comparison state. |
| `STEAM_WISHLIST_METADATA_MAX_APPS` | `100` | Maximum wishlist apps enriched with Store release/demo metadata per check. |
| `STEAM_STORE_COUNTRY` | `US` | Country used for Store metadata. |
| `STEAM_STORE_LANGUAGE` | `english` | Language used for Store metadata. |
| `STEAM_WEEKLY_DISCOVERY` | `true` | Include local taste-based new-game recommendations in weekly briefs. |
| `STEAM_TASTE_SAMPLE_SIZE` | `30` | Most-played owned games sampled for the local taste profile. |
| `STEAM_DISCOVERY_MAX_CANDIDATES` | `24` | Featured Store candidates enriched and scored per discovery run. |
| `STEAM_WEEKLY_REPORT_PATH` | cache dir Markdown | Suggested destination used by the weekly Python companion. |
Action/local options:
| Variable | Default | Purpose |
| --- | --- | --- |
| `STEAM_ENABLE_ACTIONS` | `false` | Registers the optional action/local-write tools. Leave unset/false for a 21-tool read-only surface. |
| `STEAM_REQUIRE_CONFIRMATION` | `true` | Requires exact confirmation text for browser and local write actions. Launch/install always require exact confirmation. |
| `STEAM_ALLOW_BROWSER_OPEN` | `true` | Allows tools that open Steam web pages in your browser when actions are enabled. |
| `STEAM_ALLOW_STEAM_PROTOCOL` | `true` | Allows validated Steam protocol opens when actions are enabled. Uninstall still needs its separate flag. |
| `STEAM_ALLOW_UNINSTALL` | `false` | Separately enables opening Steam's native uninstall confirmation flow. |
| `STEAM_ALLOW_LAUNCH_ARGS` | `false` | Reserved safety flag. The tools do not expose arbitrary launch args by default. |
| `STEAM_ALLOW_LOCAL_NOTES` | `true` | Allows writes to the MCP local database only. |
| `STEAM_ACTION_LOG_PATH` | cache dir JSONL | Local action audit log path. |
| `STEAM_ACTION_LOG_MAX_BYTES` | `2000000` | Rotates the active action log before it exceeds this size. |
| `STEAM_ACTION_LOG_MAX_BACKUPS` | `3` | Number of rotated action-log files retained. |
| `STEAM_LOCAL_DB_PATH` | cache dir JSON | MCP-owned local notes/backlog/tags DB path. |
| `STEAM_LOCAL_DB_MAX_BYTES` | `5000000` | Maximum serialized local notes database size. |
| `STEAM_LOCAL_NOTES_PER_GAME` | `200` | Maximum notes retained per game. |
| `STEAM_LOCAL_NOTE_MAX_CHARS` | `10000` | Maximum characters in one note. |
To omit all action and local-write tools from MCP discovery, keep:
```bash
STEAM_ENABLE_ACTIONS=false
```
You can also deny-list action tools in Codex config.
## Tools
Steam-account-read-only tools (some update local cache/state files):
- `steam_get_profile`
- `steam_resolve_vanity_url`
- `steam_get_owned_games`
- `steam_search_library`
- `steam_get_game`
- `steam_get_recently_played`
- `steam_get_achievements`
- `steam_get_installed_games`
- `steam_library_stats`
- `steam_recommend_from_library`
- `steam_get_wishlist`
- `steam_check_wishlist_updates`
- `steam_game_brief`
- `steam_find_deals`
- `steam_discover_games`
- `steam_storage_commander`
- `steam_update_center`
- `steam_achievement_objectives`
- `steam_plan_game_night`
- `steam_weekly_brief`
- `steam_refresh_cache`
Optional action/local tools:
- `steam_launch_game`
- `steam_open_store_page`
- `steam_open_community_hub`
- `steam_open_achievements_page`
- `steam_open_install_flow`
- `steam_uninstall_game`
- `steam_prepare_game_night_invites`
- `steam_open_download_manager`
- `steam_add_local_game_note`
- `steam_set_local_backlog_status`
- `steam_set_local_mood_tags`
- `steam_get_local_game_notes`
- `steam_action_history`
## Confirmation Text
When actions are enabled, these tools require exact confirmation text:
| Tool | Confirmation |
| --- | --- |
| `steam_launch_game` | `LAUNCH <appid>` |
| `steam_open_install_flow` | `INSTALL FLOW <appid>` |
| `steam_uninstall_game` | Built-in MCP user confirmation when supported, or exact `UNINSTALL <appid>` fallback; Steam confirms again. |
| `steam_prepare_game_night_invites` | `OPEN CHATS <count>` for a real open; it never sends the message. |
| `steam_open_download_manager` | `OPEN DOWNLOADS` for a real open. |
| `steam_open_store_page` | `OPEN STORE <appid>` when `STEAM_REQUIRE_CONFIRMATION=true` |
| `steam_open_community_hub` | `OPEN COMMUNITY <appid>` when `STEAM_REQUIRE_CONFIRMATION=true` |
| `steam_open_achievements_page` | `OPEN ACHIEVEMENTS <appid>` when `STEAM_REQUIRE_CONFIRMATION=true` |
| `steam_add_local_game_note` | `NOTE <appid>` when `STEAM_REQUIRE_CONFIRMATION=true` |
| `steam_set_local_backlog_status` | `SET STATUS <appid>` when `STEAM_REQUIRE_CONFIRMATION=true` |
| `steam_set_local_mood_tags` | `SET TAGS <appid>` when `STEAM_REQUIRE_CONFIRMATION=true` |
Launch and install-flow tools default to `dryRun=true`. They only open Steam when `dryRun=false` and confirmation is correct. Install flow only opens Steam's own `steam://install/<appid>` flow; Steam may prompt you and the MCP does not silently install anything.
Browser-opening tools only open HTTPS URLs on Steam-owned domains. Steam protocol tools only allow validated run/install/uninstall app IDs, the Downloads page, and message windows for 17-digit friend IDs.
The uninstall tool never deletes manifests or game directories. A dry run returns the required confirmation without changing anything. A real call requires action mode, the separate uninstall flag, a locally installed app, user confirmation, and then Steam's own native confirmation dialog.
Local notes, backlog status, and mood tags are stored only in the MCP local database. They never modify Steam files.
## Wishlist Monitoring And Automations
`steam_get_wishlist` reads a wishlist without using cookies or a browser session. `steam_check_wishlist_updates` compares it with local state and reports newly released games, newly available demos, same-currency price drops, release-date changes, additions/removals, and recent Steam news posts that mention playtests, betas, demos, alphas, technical tests, or free weekends.
`steam_weekly_brief` also returns Markdown containing owned-game rediscovery picks and optional taste-based new-game recommendations. The MCP does not schedule itself. A Codex automation can call the tool directly; the included `scripts/steam-weekly-watch.py` can call it over stdio and atomically write the Markdown for Task Scheduler or another host. The first run creates a baseline without reporting every existing item as new.
See [docs/wishlist-monitoring.md](docs/wishlist-monitoring.md) for automation and privacy details, [docs/feature-guide.md](docs/feature-guide.md) for every new feature and caveat, [docs/publishing.md](docs/publishing.md) for packaging/version behavior, and [docs/audit.md](docs/audit.md) for the safety audit.
## Codex MCP Registration
This section is Codex-specific. For Claude Desktop, Claude Code, Gemini/Grok-capable MCP hosts, IDE agents, or generic MCP clients, see [docs/mcp-client-setup.md](docs/mcp-client-setup.md).
macOS/Linux:
```bash
npm install
npm run build
codex mcp add steam-library \
--env STEAM_API_KEY="$STEAM_API_KEY" \
--env STEAM_ID_64="$STEAM_ID_64" \
-- node /ABSOLUTE/PATH/TO/steam-library-mcp/dist/index.js
codex mcp list
```
Windows PowerShell:
```powershell
npm install
npm run build
codex mcp add steam-library `
--env STEAM_API_KEY="$env:STEAM_API_KEY" `
--env STEAM_ID_64="$env:STEAM_ID_64" `
-- node C:\ABSOLUTE\PATH\TO\steam-library-mcp\dist\index.js
codex mcp list
```
Action mode example:
```bash
codex mcp add steam-library \
--env STEAM_API_KEY="$STEAM_API_KEY" \
--env STEAM_ID_64="$STEAM_ID_64" \
--env STEAM_ENABLE_ACTIONS=true \
--env STEAM_REQUIRE_CONFIRMATION=true \
--env STEAM_ALLOW_UNINSTALL=false \
-- node /ABSOLUTE/PATH/TO/steam-library-mcp/dist/index.js
```
Codex `config.toml` example with approval prompts:
```toml
[mcp_servers.steam-library]
command = "node"
args = ["/ABSOLUTE/PATH/TO/steam-library-mcp/dist/index.js"]
startup_timeout_sec = 10
tool_timeout_sec = 60
default_tools_approval_mode = "prompt"
enabled = true
[mcp_servers.steam-library.env]
STEAM_API_KEY = "your_steam_web_api_key_here"
STEAM_ID_64 = "your_17_digit_steamid64_here"
STEAM_ENABLE_ACTIONS = "false"
[mcp_servers.steam-library.tools.steam_get_owned_games]
approval_mode = "auto"
[mcp_servers.steam-library.tools.steam_search_library]
approval_mode = "auto"
[mcp_servers.steam-library.tools.steam_launch_game]
approval_mode = "prompt"
[mcp_servers.steam-library.tools.steam_open_install_flow]
approval_mode = "prompt"
```
Read-only-only Codex config:
```toml
[mcp_servers.steam-library]
command = "node"
args = ["/ABSOLUTE/PATH/TO/steam-library-mcp/dist/index.js"]
default_tools_approval_mode = "prompt"
disabled_tools = [
"steam_launch_game",
"steam_open_store_page",
"steam_open_community_hub",
"steam_open_achievements_page",
"steam_open_install_flow",
"steam_uninstall_game",
"steam_prepare_game_night_invites",
"steam_open_download_manager",
"steam_add_local_game_note",
"steam_set_local_backlog_status",
"steam_set_local_mood_tags",
"steam_get_local_game_notes",
"steam_action_history"
]
[mcp_servers.steam-library.env]
STEAM_API_KEY = "your_steam_web_api_key_here"
STEAM_ID_64 = "your_17_digit_steamid64_here"
STEAM_ENABLE_ACTIONS = "false"
```
Codex reads MCP server instructions during initialization. This server instructs agents to search before ownership answers, respect Steam visibility caveats, and avoid write actions unless explicitly enabled and confirmed.
## Example Prompts
- `Do I own Outriders?`
- `Search my Steam library for worldslayer.`
- `What have I played recently?`
- `What games have I bought but barely played?`
- `List locally installed Steam games.`
- `Recommend something installed for a 1-hour session.`
- `Show my achievement progress for a game without hidden-achievement spoilers.`
- `Reveal the hidden achievement objectives for this game and tell me which official descriptions are unavailable.`
- `Build my weekly Steam brief with wishlist price drops and new-game discovery.`
- `Find co-op games I share with these friends.`
- `Audit my installed games and make a plan to free 100 GB without touching favorites.`
- `Dry-run launching OUTRIDERS and tell me the exact confirmation text.`
- `Dry-run uninstalling an installed game and tell me what confirmations would be required.`
- `Check my wishlist for releases or new playtest, beta, and demo news.`
## Local Steam Detection
The MCP reads:
- `libraryfolders.vdf`
- `appmanifest_*.acf`
Common paths checked:
- Windows: `C:\Program Files (x86)\Steam\steamapps\libraryfolders.vdf`
- Windows: `C:\Program Files\Steam\steamapps\libraryfolders.vdf`
- macOS: `~/Library/Application Support/Steam/steamapps/libraryfolders.vdf`
- Linux: `~/.steam/steam/steamapps/libraryfolders.vdf`
- Linux: `~/.local/share/Steam/steamapps/libraryfolders.vdf`
Set `STEAM_LOCAL_LIBRARY_PATH` if your Steam library is elsewhere.
## Credits
Steam Library MCP was conceived and directed by [@Dark-Hunt3r1](https://github.com/Dark-Hunt3r1), who defined its requirements, safety boundaries, and product decisions and remains its maintainer.
OpenAI Codex was used as an AI development tool for substantial implementation, test creation and execution, documentation, security review, sanitization, and release preparation.
This is an independent project and is not affiliated with or endorsed by Valve or OpenAI.
## Troubleshooting
`STEAM_API_KEY is required`
Set `STEAM_API_KEY` in the MCP environment. Do not put it in source code.
`STEAM_ID_64 is required`
Set `STEAM_ID_64` to your 17-digit SteamID64. If you know only a vanity name, use `steam_resolve_vanity_url` after setup or resolve it externally.
Empty owned library response
Check Steam profile and game-details privacy settings. Steam may omit hidden/private games, family-shared games, free games without playtime, or metadata it cannot expose through the Web API.
Achievement errors
Some games do not expose achievements through Steam Web API. Profile privacy or game privacy can also block achievement access.
HTTP 401/403
Check the API key, SteamID64, privacy settings, and whether the key is valid for the requested endpoint.
HTTP 429
Steam rate-limited the request. Wait and retry, or avoid `forceRefresh`.
Local installed games missing
Set `STEAM_LOCAL_LIBRARY_PATH` to a Steam root folder, a `steamapps` folder, or a specific `libraryfolders.vdf`. The MCP only reads local manifest files and never treats local install status as proof of ownership.
Action tool is missing
Set `STEAM_ENABLE_ACTIONS=true` and restart/reload the MCP server. Tool registration is decided at startup. Keep `default_tools_approval_mode = "prompt"` in Codex if you want Codex to ask before calling action tools.
Wrong confirmation
Use the exact confirmation string for the resolved appid, for example `LAUNCH 680420`.
Wishlist unavailable
Steam does not provide a documented consumer wishlist API. The MCP uses first-party but undocumented wishlist and Store metadata endpoints without cookies or login scraping. Availability can depend on Steam privacy settings; if Valve changes either endpoint, the tool returns an explicit error or marks missing metadata unavailable instead of guessing.
Uninstall tool is missing or says disabled
Set both `STEAM_ENABLE_ACTIONS=true` and `STEAM_ALLOW_UNINSTALL=true`, then restart the MCP. Keep host-level approval prompts enabled. The tool still requires MCP user elicitation or exact `UNINSTALL <appid>` confirmation, verifies the app is installed, and Steam displays another native confirmation.
TDQS
Scored across 21 tools
Each tool targets a unique aspect of Steam library management, from listing games and achievements to managing storage and creating weekly briefs. Despite several get_-prefixed tools, they clearly differ by the specific data retrieved (e.g., achievements vs. owned games). No two tools appear to have overlapping functionality.
All tool names follow a consistent pattern: the steam_ prefix followed by descriptive, snake_case phrases. Verbs like get_, find_, and check_ are used predictably, and even compound names like steam_achievement_objectives or steam_plan_game_night are clearly readable. No mixing of conventions occurs.
With 21 tools, the server covers a broad range of library-related operations without being overwhelming. Each tool addresses a distinct need, and the count feels proportional to the complexity of Steam's library feature set.
The tools provide comprehensive coverage of library operations: retrieval, search, statistics, achievements, wishlist, storage, updates, recommendations, and social planning. While write operations like removing games are absent, the server's scope aligns with a library-focused assistant, leaving few obvious gaps.