steam
Python client for the Steam network — CM protocol, PICS / CDN, WebAuth, Web API, Steam Guard, SteamIDs, master-server queries.
This is a fork of ValvePython/steam maintained under H47R15/steam. The upstream project is largely inactive; this fork exists to keep the library working against modern Python and current Steam wire protocols.
What changed vs. upstream
Python 3.13+ only. Dropped the py2 / py<3.4 compat shims (six, six.moves, raw_input, xrange, long, win_inet_pton, backports.lzma, enum34, …).
Modern protobuf runtime + regenerated ``_pb2`` files. Bumped from protobuf==3.20.3 to >=5.26,<7 and re-ran protoc (v33.2) against fresh SteamDB proto sources. The old per-message _reflection.GeneratedProtocolMessageType codegen shrunk ~20× to the modern _descriptor_pool.AddSerializedFile + _builder pattern (steammessages_base_pb2.py: 2 200 → 96 lines).
Full ``.pyi`` type stubs for every _pb2 file via mypy-protobuf — msg.field accesses now type-check under Pylance / pyright.
Poetry-first workflow. pip + Makefile + setup.py replaced by a single pyproject.toml; regeneration steps registered as poetry run pb-* console scripts (details below).
~50 new proto files picked up from upstream since the fork was last synced (family groups, game recording, remote client, SteamOS webui messages, HTML messages, virtual controller, community messages, and more). steam/enums/proto.py grew from 90 → 247 enums.
Real latent bug fixes surfaced while porting — e.g. a list + map(...) TypeError in struct.py, a tuple-vs-int mismatch in MarketingMessage.flags, hexlify(None) in avatar-URL fallback, broken CookieJar iteration in WebAuth.
Requirements
Python 3.13.11 (pinned via pyproject.toml). Any newer 3.13.x is fine. Older Pythons are not supported.
Poetry for dependency management.
protoc on PATH — required only when regenerating the _pb2 files (poetry run pb-compile). Install via brew install protobuf on macOS or the equivalent from your distro.
Install
Clone the repo and install with poetry:
git clone https://github.com/H47R15/steam.git
cd steam
poetry install --with dev --extras client
The client extra pulls in gevent + protobuf + gevent-eventemitter — required by SteamClient and CDN. Without it, only the requests-based subset (WebAPI / WebAuth / SteamID / master-server query) is functional.
Features
SteamClient — CM protocol client on top of gevent. Login flows (password / QR / refresh token), PICS product info, friends list, chat, game coordinator hooks.
AsyncSteamClient (new in 1.6+) — asyncio facade around SteamClient for FastAPI / Starlette / TaskIQ / any asyncio app. Runs the sync client on a dedicated daemon thread with an isolated gevent hub, so the asyncio process is never monkey-patched. Auto- reconnect, typed exceptions, event bridge, cancellation. See steam/aio/ and the Async wiki page.
AsyncSteamPool — multi-account pool for workloads that need concurrent connections to multiple Steam accounts. Concurrent bringup, round-robin, per-member failure isolation.
FastAPI + TaskIQ integrations — steam.aio.integrations provides lifespan context managers and Depends providers for both frameworks. Lazy imports — installing steam.aio doesn’t force FastAPI or TaskIQ into your dependency graph.
MCP tools — steam.mcp exposes AsyncSteamClient as Model-Context-Protocol tools an LLM agent can call. Framework- agnostic definitions + a FastMCP adapter (works with the official mcp SDK and the standalone fastmcp package).
CDNClient — content depot downloads with manifest parsing.
WebAuth / MobileWebAuth — obtain authenticated requests.Session cookies for store.steampowered.com / steamcommunity.com.
WebAPI — thin wrapper around Steam’s api.steampowered.com that introspects the interface catalogue at construction time.
SteamAuthenticator — enable / disable / verify Steam Guard 2FA.
SteamID — parse and convert between the 32-bit / 64-bit / STEAM_X:Y:Z / community-URL representations.
Master server query protocol — query masters directly or through SteamClient.
Async quick-start (FastAPI)
from contextlib import asynccontextmanager
from fastapi import Depends, FastAPI
from steam.aio import AsyncSteamClient
from steam.aio.integrations.fastapi import (
get_steam_client, steam_client_lifespan,
)
client = AsyncSteamClient()
async def _login(c):
await c.anonymous_login()
@asynccontextmanager
async def lifespan(app):
async with steam_client_lifespan(app, client, on_start=_login):
yield
app = FastAPI(lifespan=lifespan)
@app.get("/product/{app_id}")
async def product(
app_id: int,
steam: AsyncSteamClient = Depends(get_steam_client),
):
return await steam.get_product_info(apps=[app_id])
@app.get("/health")
async def health(
steam: AsyncSteamClient = Depends(get_steam_client),
):
return steam.status.__dict__
MCP quick-start
from mcp.server.fastmcp import FastMCP
from steam.aio import AsyncSteamClient
from steam.mcp import register_steam_tools
server = FastMCP("Steam")
client = AsyncSteamClient()
# ... start + login the client at app boot ...
register_steam_tools(server, client)
# server.run() as usual — LLM agents can now call
# steam.status / steam.get_product_info / steam.send_um
Dev workflow (poetry)
All commands run from the repo root.
poetry install --with dev --extras client # install everything
poetry run pytest # run the test suite (~83 tests, ~1s)
poetry run pytest -k test_webauth # filter to a subset
poetry run pytest --tb=short -q # concise output
poetry run pylint steam # optional lint pass
Regenerating protobufs
The _pb2.py and _pb2.pyi files under steam/protobufs are generated from .proto sources under protobufs/. Console scripts:
poetry run pb-fetch # download + normalize .proto files from SteamDB
poetry run pb-compile # protoc --python_out --mypy_out + post-process
poetry run pb-services # regenerate steam/core/msg/unified.py service map
poetry run pb-gen-enums # regenerate steam/enums/proto.py from *_pb2
poetry run pb-update # all four in sequence — the usual entry point
pb-fetch reads URLs from protobuf_list.txt (comments and blank lines skipped) and downloads them into protobufs/. Locally-maintained .proto files (gc.proto, test_messages.proto) are set aside via .notouch rename before the fetch and restored after.
pb-compile wipes steam/protobufs/*_pb2.{py,pyi} first, then runs a single protoc invocation over every .proto. Post-processing:
.py — sibling protobuf imports get the steam.protobufs. prefix so runtime import works without steam/protobufs/ on sys.path.
.pyi — DESCRIPTOR: _descriptor.Descriptor overrides inside each message class are stripped (they trip reportIncompatibleVariableOverride under types-protobuf 7.34+; the parent Message class’s union type is inherited instead).
VCR fixtures
Web-facing tests (test_webapi.py, test_webauth.py, test_steamid.py) replay recorded HTTP fixtures from vcr/*.yaml in RecordMode.NONE — no live network, no credentials needed for CI.
To regenerate the webapi.yaml cassette against a fresh Steam API response, copy .env.example to .env and fill in STEAM_API_KEY (see the template for instructions on where to get one), then follow the regen recipe at the top of tests/test_webapi.py.
The webauth_*.yaml cassettes are regenerated by tests/generete_webauth_vcr.py — needs real Steam credentials at run time; run interactively when the anonymized replay drifts from live.
Live smoke test
Beyond the unit suite, the CM handshake / anonymous-login / PICS-fetch end-to-end flow can be smoke-tested against live Steam:
from steam.client import SteamClient
client = SteamClient()
assert client.anonymous_login()
resp = client.get_product_info(apps=[553850], timeout=15) # Helldivers 2
print(resp['apps'][553850]['common']['name'])
client.logout()
client.disconnect()
Layout
steam/
├── steam/ # library source
│ ├── client/ # SteamClient, CDN, builtins/*
│ ├── core/ # CM protocol, message framing
│ ├── aio/ # AsyncSteamClient facade for asyncio apps
│ │ ├── client.py # AsyncSteamClient + ReconnectPolicy
│ │ ├── runner.py # cross-thread gevent → asyncio bridge
│ │ ├── errors.py # typed exception hierarchy
│ │ ├── pool.py # AsyncSteamPool (multi-account)
│ │ ├── status.py # ClientStatus + MetricsHook
│ │ └── integrations/ # fastapi.py + taskiq.py helpers
│ ├── mcp/ # Model-Context-Protocol tool wrappers
│ │ ├── tools.py # Pydantic schemas + async handlers
│ │ └── server.py # FastMCP adapter
│ ├── enums/ # SteamIntEnum wrappers (common.py hand-written,
│ │ # proto.py auto-generated by pb-gen-enums)
│ ├── protobufs/ # generated *_pb2.py + *_pb2.pyi
│ └── utils/
├── scripts/ # poetry console-script entry points (pb-*)
├── protobufs/ # .proto sources (fetched by pb-fetch)
├── typings/ # local pyright stubs (see typings/…/builder.pyi
│ # for the BuildServices typeshed override)
├── tests/ # pytest suite
├── vcr/ # recorded HTTP fixtures for offline test replay
├── docs/ # Sphinx source (rendered at steam.readthedocs.io
│ # — kept in-tree but not currently deployed
│ # from this fork)
└── pyproject.toml # poetry config + [tool.pyright]
Upstream links (reference only — refer to this fork for maintained code):
Upstream: https://github.com/ValvePython/steam
Old docs: https://steam.readthedocs.io/en/latest/ (mostly still applicable — the library shape has not diverged from upstream, only its Python-runtime and protobuf-vintage baseline)
Command-line companion (unmaintained upstream): https://github.com/ValvePython/steamctl
Security
We take security seriously — this package sits on the network path between your app and Steam, handles credentials, and is embedded inside FastAPI / TaskIQ / MCP servers by downstream users.
Report a vulnerability: use GitHub Security Advisories (preferred, private, coordinated-disclosure workflow). Full policy + report template in SECURITY.md.
Do NOT open a public GitHub issue for security reports — public disclosure before a fix ships puts every user at risk.
Automated checks run on every push, PR, and release before any wheel ships to PyPI:
pip-audit — every declared runtime + dev dep scanned against the OSV / PyPI advisory database.
bandit — Python-native SAST on steam.aio and steam.mcp at medium severity and above.
CodeQL — GitHub-native semantic SAST with cross-file dataflow analysis. Results in the repo’s Security tab.
OpenSSF Scorecard — automated repository-posture scoring; badge above.
Dependabot — weekly grouped dep-update PRs plus immediate security-update PRs whenever a CVE lands.
Every gate blocks the PyPI publish step — a failing scan means no release.
Layout after SECURITY.md: see the source tree above.
License
MIT (unchanged from upstream). See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pysteam_client-1.7.6.tar.gz.
File metadata
- Download URL: pysteam_client-1.7.6.tar.gz
- Upload date:
- Size: 945.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa35508f3ccca2d56a4c0ec9709739e9a3882fcab224d9fa8630d7038208bf46
|
|
| MD5 |
0a4ece3f6da248ce9b9bc4e11fb8b09b
|
|
| BLAKE2b-256 |
c6f1d2f64cdb07e656d84cf437dc2b95967d414dc587082e9abc6a71d1b19ba4
|
Provenance
The following attestation bundles were made for pysteam_client-1.7.6.tar.gz:
Publisher:
publish.yml on H47R15/steam
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pysteam_client-1.7.6.tar.gz -
Subject digest:
fa35508f3ccca2d56a4c0ec9709739e9a3882fcab224d9fa8630d7038208bf46 - Sigstore transparency entry: 2223768675
- Sigstore integration time:
-
Permalink:
H47R15/steam@2a338f06162e07fc8ae1f71e51ad4525e93cc987 -
Branch / Tag:
refs/tags/v1.7.6 - Owner: https://github.com/H47R15
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2a338f06162e07fc8ae1f71e51ad4525e93cc987 -
Trigger Event:
release
-
Statement type:
File details
Details for the file pysteam_client-1.7.6-py3-none-any.whl.
File metadata
- Download URL: pysteam_client-1.7.6-py3-none-any.whl
- Upload date:
- Size: 1.1 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a96a8c70a795892fb9579ea1eb9b356a7abad8d66c6fe1abb8f8ea9a590a4ec6
|
|
| MD5 |
a5578f205c3d719230268ca7e54b5dd9
|
|
| BLAKE2b-256 |
84334c192593437511e43dda64c30d6befcb306722c62859aab66543ae1d6d08
|
Provenance
The following attestation bundles were made for pysteam_client-1.7.6-py3-none-any.whl:
Publisher:
publish.yml on H47R15/steam
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pysteam_client-1.7.6-py3-none-any.whl -
Subject digest:
a96a8c70a795892fb9579ea1eb9b356a7abad8d66c6fe1abb8f8ea9a590a4ec6 - Sigstore transparency entry: 2223768740
- Sigstore integration time:
-
Permalink:
H47R15/steam@2a338f06162e07fc8ae1f71e51ad4525e93cc987 -
Branch / Tag:
refs/tags/v1.7.6 - Owner: https://github.com/H47R15
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2a338f06162e07fc8ae1f71e51ad4525e93cc987 -
Trigger Event:
release
-
Statement type: