swehockey
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@swehockeyShow me the standings for Skåne U16P"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
swehockey
Look up Swedish ice-hockey data from stats.swehockey.se — schedules and results, standings, team rosters, and season-total scoring & goalie stats — from your AI assistant (via MCP) or the command line.
It's built for following youth series. Out of the box it covers Skåne U16P, U15P and U14P (boys, seasons 2024-25 and 2025-26); you can add any other league yourself — another district, age group, or the national/regional leagues.
What you can ask your assistant
Once it's connected, you can ask things like:
"How did the Skåne U16P teams do last weekend?"
"Show the current U14P standings."
"Who are Rögle's top scorers in U16P this season?"
"Which U15P goalies have the best save percentage?"
"List the teams in the U14P league."
It reads the official stats site and hands back clean, current data — no scraping or copy-pasting on your side.
Connect it to your AI assistant (MCP)
bin/swehockey-mcp is an MCP server — the
standard way to give an assistant new abilities. Point your assistant's MCP
configuration at it:
{
"mcpServers": {
"swehockey": {
"command": "bun",
"args": ["/abs/path/to/swehockey/bin/swehockey-mcp"]
}
}
}Replace the path with where you put this repo. You'll need Bun
installed (curl -fsSL https://bun.sh/install | bash), then run bun install
once inside the repo.
Your assistant then gets read-only tools to:
see which leagues are set up, and the tournaments in each;
browse districts and their cups;
get schedules & results, standings, and team lists;
get season-total scoring and goalie stats, grouped by club (and filterable to a single club).
It only reads — it can't change anything on the site or your machine. (Adding leagues is done in the catalog file, below.)
New to MCP setup? See coworkerai.io/guide/mcp-setup.
The leagues it knows about
The tool only answers about leagues listed in its catalog,
config/leagues.json. It ships with Skåne U16P / U15P /
U14P for 2024-25 and 2025-26. Anything else, you add.
Add your own leagues
The catalog is a plain JSON file you can grow. The easiest way:
Find the league with the built-in
discoverhelper (on the command line):./bin/swehockey discover-leagues # districts, grouped by region ./bin/swehockey discover-leagues 21103 # drill into one district (Skåne) ./bin/swehockey discover-leagues national # the national leagues (SHL, U20 Nationell, …) ./bin/swehockey discover-leagues regional # the region-wide leaguesAdd it by appending
--writeto a league's id — it writes the entry for you:./bin/swehockey discover-leagues 19001 --write
(Working with a coding assistant? You can also just ask it to "add the Stockholm U16 league" and let it run those for you.) Full details in Growing the catalog.
Prefer to edit by hand? Each entry is one league (a region + age-group + season) bundling the tournaments (the raw series on the site) it's made of:
{
"key": "skane-u16p-2025",
"region": "Skåne",
"ageGroup": "U16P",
"season": "2025-26",
"tournaments": [
{ "id": 18433, "name": "U16P Fortsättning" },
{ "id": 18434, "name": "U16P Grund A" }
]
}keyis the short handle you'll use (e.g. "standings forskane-u16p-2025").each tournament
idis swehockey's own number for that series — it's in the page URL,…/Overview/18433;nameis just a label.
Edits are picked up live — the file is re-read whenever it changes, so you don't have to restart the tool or the MCP server after adding a league. It's re-validated each time, so a typo (missing field, duplicate id) shows up as a clear error on the next request rather than misbehaving silently.
Command line (optional)
Everything the assistant can do is available directly too. Add --json to any
command for machine-readable output.
./bin/swehockey leagues # the leagues that are set up
./bin/swehockey leagues skane-u14p-2025 # one league's tournaments
./bin/swehockey schedule skane-u14p-2025 # games + results, chronological
./bin/swehockey standings skane-u16p-2025 # standings, one table per tournament
./bin/swehockey playerstat skane-u16p-2025 # scoring, season totals by club
./bin/swehockey playerstat skane-u16p-2025 --team "Rögle BK" # one club only
./bin/swehockey goaliestat skane-u16p-2025 # goalie stats by club
./bin/swehockey teams skane-u14p-2025 # the teams in a league
./bin/swehockey districts # ice-hockey districts, by region
./bin/swehockey cups 21103 # cups in a district (id from `districts`)
./bin/swehockey schedule 18436 # a single tournament or cup, by idMost commands take either a league key (from your catalog) or a raw numeric
tournament/cup id from the site. Run ./bin/swehockey help for the full list.
Cups. swehockey holds cups in its stats system (a "Cups" section per district).
districtsthencups <district-id>finds them — the "Cups" section plus any cup-named entry mis-filed above the divider. A cup id then works with the other read commands —scheduleespecially (cups are knockouts, so they usually have no standings or roster).
The rest is reference for maintaining and extending the tool.
Concepts: tournaments and leagues
Meaning | |
Tournament | one raw series as the site presents it, keyed by its numeric |
League | a broad grouping — one region + age-group + season (e.g. |
A youth season is often split into several tournaments (an autumn/spring split, re-seeded into strength groups), so one league holds ~4–7 tournaments. We don't model that autumn/spring split — swehockey doesn't mark it consistently, so we'd be guessing — tournaments are just listed in catalog order.
The catalog (config/leagues.json) is data, not code:
swehockey ids are season-specific and turn over every year, so you edit JSON to
add a season — no source changes. It's read on demand and cached against the
file's modified-time (src/catalog.ts), so changes are picked
up without a restart and each load re-validates — a bad entry (missing field,
wrong type, duplicate id/key) fails loudly. config/clubs.json works the same way.
Growing the catalog
Two developer commands find ids to add to the catalog (both can write straight to
it with --write — ids and names come verbatim from the source; neither is
exposed over MCP):
discover-season <league-key> — another season of a league you already
have. It follows that league's season-history links and reads the target
season's sibling dropdown:
./bin/swehockey discover-season skane-u16p-2025 # any season newer than 2025-26
./bin/swehockey discover-season skane-u16p-2025 2026-27 # a specific season
./bin/swehockey discover-season skane-u16p-2025 2026-27 --writeUntil the season exists it reports "not published yet".
discover-leagues [<id>|national|regional] — other leagues you haven't
mapped. Scopes are flat (district / national / regional), not a tree:
./bin/swehockey discover-leagues # 1. districts, grouped by region
./bin/swehockey discover-leagues 21103 # 2. a district's series (Skåne)
./bin/swehockey discover-leagues 21103 U15P # ...narrowed by name
./bin/swehockey discover-leagues 19001 # 3. a league's tournaments (a leaf)
./bin/swehockey discover-leagues 19001 --write # ...scaffold that league
./bin/swehockey discover-leagues national # 4. the Sweden-wide leagues
./bin/swehockey discover-leagues regional # 5. the region-wide leaguesNo arg → districts (entry points).
A district id → every series in that region's dropdown, flagged mapped vs unmapped. It's unfiltered on purpose: swehockey mixes leagues, championships (DM), training series and cups with no reliable separator (the Overview/Schedule link kind doesn't track it, and the "Cups" divider leaks cups above it), so it shows everything and you pick (a name filter helps). Read-only.
A league id → that league's tournaments, flagged mapped/unmapped.
national/regional→ the Sweden-wide leagues (from the "National" menu's Leagues column — SHL, U20 Nationell, SDHL, …) and the region-wide leagues (the "Regional" menu's Men/Women sections, by region — HockeyTvåan, U18 Regional, …). Both are listed directly in their nav menu and shown unfiltered (the sections also hold preseason/cup/district-team entries, with no reliable marker to separate them), so you pick. Drill into any league id like a leaf.
These three (district / national / regional) are siblings, not a hierarchy —
the catalog's region is just a label ("Skåne", "National", "Region Syd").
The only real nesting is region → district, already reflected by grouping the
district list under regions.
--write works on a league id (a leaf — a listing has nothing single to
scaffold). It recovers what the leaf page doesn't carry:
District leagues — region + name come from the parent district's dropdown (
--writescans the district dropdowns to find which one lists this id); season from the page's season-history links.National / regional leagues —
regionis"National"/ the region name ("Region Syd"); the age-group is taken from the league name (U18 Nationell→U18, else the name as-is, e.g.HockeyTvåan); season is the selected option of the page's season<select>. A league with no sub-divisions (SHL) is written as a single tournament. E.g.discover-leagues 19937 --write→national-u18-2025. Some regional pages expose no season picker, so--writereports "couldn't determine the season" rather than guess.
The catalog is validated before every write, so a scan can't corrupt it. Note the
season/league conflation: a scaffold is the current season — for a new season of
a newly-found league, run discover-season on it afterwards.
Club grouping (config/clubs.json)
A second config you can edit. It's a whitelist of multi-team clubs, used to
group player/goalie stats by club: a club often fields several teams (e.g.
Rögle BK Grön / Röd / Vit), and without this they'd be three separate rows
for the same player.
["Rögle BK", "IF Malmö Redhawks", "Helsingborg HC Ungdom"]If a team name contains a listed string, that club becomes the grouping key;
otherwise the team stands on its own. swehockey exposes no authoritative club id,
so this is a deliberate whitelist rather than a name-suffix guess (which could
merge the wrong teams) — add new multi-team clubs here as they appear. It's
only consulted by playerstat/goaliestat; the rest of the tool ignores it.
How player & goalie stats work
playerstat/goaliestat read the complete PlayersByTeam rosters and
aggregate (swehockey's own leader pages cap at the top 25, so they can't be
summed across a league — different point cutoffs each tournament would
undercount). They sum every counting stat across the league's tournaments and
recompute the rate columns (AVG = ΣTP/ΣGP, GAA = ΣGA·60/Σmin,
SVS% = ΣSVS/ΣSOG, W% = ΣW/(ΣW+ΣL)). On a single tournament it gives the full,
uncapped table.
Pass --team <name> (CLI) or the team argument (MCP) to keep only one
club's rows — case-insensitive partial match on the club name (rögle,
Rögle BK). Rank is assigned over the whole field first, so a filtered view
still shows each player's league-wide standing (the RK/rank column keeps
gaps). Each row carries an explicit rank in JSON.
Players are keyed by name + club, so a player's teams within one club
collapse into a single row (Rögle BK Grön/Röd/Vit → Rögle BK) — via the whitelist
in config/clubs.json. swehockey's trailing
eligibility markers (Name**, a dispensation/affiliated flag it adds in some
tournaments but not others) are stripped before keying too, so a player isn't
split into marked/unmarked entries. Goalies are sorted by SVS%, so small samples
can top the list; the GPI/MIP columns show how much they actually played.
Team "id": swehockey exposes no numeric team id on its league pages — a team's identifier is a short code (
MIF,RBK G), read off the team scoring/goalkeeping page. It's a per-tournament display abbreviation, so it can vary between tournaments (RBK GrönvsRBK G) and is occasionally just the full name. Shown as—when it can't be matched.
MCP tools
The server calls the same in-process query layer (src/queries.ts) the CLI uses
— no subprocess — and returns each query's JSON. Tools: list_leagues,
get_league, list_tournaments, list_districts, list_cups, get_teams,
get_schedule, get_standings, get_player_stats, get_goalie_stats (the last
two take an optional team filter). The discover-* commands are intentionally
not exposed — they're catalog maintenance, not queries.
Project layout
File | Purpose |
| CLI entry point ( |
| MCP server entry point (read tools for an agent) |
| Argument parsing + command dispatch + output formatting |
| MCP server (calls the query layer in-process) |
| Shared fetch + dispatch + JSON shaping (CLI & MCP) |
| Leagues → tournaments catalog + resolvers |
| HTTP client (HTTPS, retries on flaky/partial fetches) |
| Generic |
| Standings view → typed rows (rank, W/T/L, GF:GA, points) |
| Schedule view → typed games (date, teams, result, venue) |
| Complete rosters → aggregated player/goalie stats |
| Club whitelist + team→club mapping ( |
| Find not-yet-cataloged seasons / leagues (region scan) |
| Teams in a tournament, joined with their swehockey code |
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/troelskn/swehockey'
If you have feedback or need assistance with the MCP directory API, please join our Discord server