Skip to content

Master Server Queries

cbyte edited this page Jul 19, 2026 · 1 revision

Master Server Queries

steam.game_servers implements the Master Server Query Protocol — Valve's legacy UDP-based server discovery + A2S_INFO / A2S_PLAYER / A2S_RULES requests. Useful for enumerating game servers directly from the master, or interrogating an individual server for player counts, rules, and metadata.

Modern games route this through Steam itself; see the SteamGameServers mixin at steam/client/builtins/gameservers.py for the CM-based path. This page covers the direct UDP protocol.

No login required

The whole module is stateless UDP calls — no credentials, no SteamClient, no gevent. Just needs steam installed. No client extra.

from steam import game_servers as gs

Discover servers via a master

query_master(filter_text=r'\nappid\500', max_servers=20, region=MSRegion.World, master=MSServer.Source, timeout=2)

Generator that yields (ip, port) tuples. Filters follow the standard Valve filter grammar (backslash-separated, use raw strings):

for server_addr in gs.query_master(r'\appid\730\white\1', max_servers=3):
    print(server_addr)

# ('146.66.152.197', 27073)
# ('146.66.153.124', 27057)
# ('146.66.152.56',  27053)

Common filters:

  • \appid\N — only servers running app id N.
  • \empty\1 — only servers with at least one player.
  • \full\1 — only servers that are not full.
  • \secure\1 — only VAC-secured servers.
  • \dedicated\1 — dedicated only.
  • \gamedir\csgo — only servers running the specified mod.
  • \map\de_dust2 — only servers on a specific map.

Full grammar in steam/game_servers.py's module docstring. Also see Valve's wiki.

Region enum:

gs.MSRegion.US_East / .US_West / .SA / .Europe / .Asia / .Australia
        / .Middle_East / .Africa / .World

Master enum:

gs.MSServer.GoldSrc         # ('hl1master.steampowered.com', 27010) — shut down
gs.MSServer.Source          # ('hl2master.steampowered.com', 27011)
gs.MSServer.Source_27015    # ('208.64.200.65', 27015) — same master, different port

Warning: Valve's masters are heavily rate-limited. Big result sets time out silently; there's no way to resume a query. For reliable large-scale enumeration, use SteamClient().gameservers.query(...) from the CM path instead.

Query an individual server

Once you have an (ip, port), hit it directly with a2s_*:

a2s_info(server_addr, timeout=2, force_goldsrc=False, challenge=0)

Returns a dict with the server's _type ('source' or 'goldsrc'), name, map, folder, game, players, max_players, bots, protocol, environment, vac, app_id, etc.

info = gs.a2s_info(('146.66.152.197', 27073))
print(info['name'], info['map'], f"{info['players']}/{info['max_players']}")

force_goldsrc=True — accept only the GoldSrc response format (for old Half-Life 1 era games like Ricochet).

a2s_players(server_addr, timeout=2, challenge=0)

Returns a list of {'index', 'name', 'score', 'duration'} dicts, one per connected player.

players = gs.a2s_players(('146.66.152.197', 27073))
for p in players:
    print(f"{p['name']} — score={p['score']} duration={p['duration']:.1f}s")

a2s_rules(server_addr, timeout=2, challenge=0, binary=False)

Returns a dict of the server's sv_* cvars — CS-style loadouts, map lists, tick rate, whatever the game has chosen to expose. binary=True returns bytes values instead of decoded strings.

a2s_ping(server_addr, timeout=2)

Simple latency probe. Returns a float in milliseconds.

Full example: enum + interrogate

from steam import game_servers as gs

# Find a single TF2 server.
server_addr = next(gs.query_master(r'\appid\40\empty\1\secure\1'))

# Ping it.
print(f"ping: {gs.a2s_ping(server_addr):.1f} ms")

# What is it?
info = gs.a2s_info(server_addr)
print(info['name'], f"map={info['map']}", f"{info['players']}/{info['max_players']}")

# Who's on it?
for p in gs.a2s_players(server_addr):
    print(f"  {p['name']}{p['score']} score, {p['duration']:.0f}s")

# What are the rules?
rules = gs.a2s_rules(server_addr)
print('rules:', {k: rules[k] for k in list(rules)[:5]})

Where to go next

  • Need reliable server discovery for a large game? Use the CM-based path via SteamClient().gameservers.query(filter_text) — see steam/client/builtins/gameservers.py.
  • Building a server browser UI? a2s_info on each result gives you everything a real Steam server browser would show.

Clone this wiki locally