Minecraft Server Finder v2
Scanner for the internet for Minecraft Servers (scanner tool below)
Ain’t this really cool? Sometimes, you just want to meet new friends all across the world through Minecraft. Well, I gotchu since I scanned the whole internet for servers that you can join. Don’t trust me? Give my implmentation a try and see who you meet (or who you grief).
Important Information, Read Below:
This is the front end of a Minecraft server pinger. It requires a backend API to function. Specifically, one that returns JSON in the format of:
{
"online": "true/false",
"motd": {
"html": "HTML format of MOTD",
"clean": "Plain format of MOTD"
},
"version": "Version info",
"protocol": "Version protocol",
"players": {
"online": "Players currently online",
"max": "Maximum player count"
},
"icon": "Server Favicon",
}
To save you some time, I made my own custom API here that has instructions in the README file on how to setup and run as a local endpoint. While this isn’t 100% required, it is heavily recommended since the backup API is mcsrvstat, which I do not want to flood their servers with thousands of requests. Use this 3rd party API service only when necessary, use a local API when possible. The default local API endpoint is set at 127.0.0.1:6767 but can be changed to other addresses and ports.
Note: You might need to enable your browser to access local device endpoints so you can connect to your hosted API.
Instructions
- Check “Custom API” to be true and enter your API endpoint into the input box with the placeholder “Custom api address…”
- Enter the number of workers (threads) into the second input box with the placeholder “Specify number of workers…”
- Check any other options you want to enable such as “Show Offline”, “Have Players?”, or “Randomizer”
- Click the start button to start scanning. Preferrably open up your browser’s network debug tool with Ctrl+Shift+I –> Network.
- Click the stop button to stop the scan at any time. Results will be shown below this menu.
| Show Offline | Have Players? | Randomizer |
|---|---|---|
| Servers that do not respond are shown. They could still be valid Minecraft servers but likely not. | Filters servers that have at least one player. | Scans can be done sequentially or in random order. Random order is better. |
Minecraft Server Finder
Scan for online servers with options
*as of last scan time
How does this work?
From the surface, this seems to be an extremely complicated project. In many ways, it is. But it can definitely be summarized simply. So below, I will provide some form of a workflow on how this server scanner functions.
- Normally I would have to use a port scanning tool like masscan to scan entire IPv4 address space on different ports to find valid Minecraft servers. However, I don’t have good networking avaliable so I used the IPs found by kgurchiek’s tool.
-
But in order to reliably fetch the latest file off of Github, I would need to use Github’s API to find the hash of the latest uploaded ips file and download it. Which is exactly what I did:
Sample of the fetching code looks like:
const contentFetch = await fetch(`https://api.github.com/repos/${conf.repo}/contents/${conf.path}?ref=${conf.branch}`); // ... const contentData = await contentFetch.json(); const remoteSHA = contentData.sha const downloadURL = contentData.download_url // ... let commitDate = null; const commitsFetch = await fetch(`https://api.github.com/repos/${conf.repo}/commits?path=${conf.path}&sha=${conf.branch}&per_page=1`); // ... const commitsData = await commitsFetch.json(); for (const commit of commitsData) { const commitDetails = await fetch(`https://api.github.com/repos/${conf.repo}/commits/${commit.sha}`); if (!commitDetails.ok) continue; const commitData = await commitDetails.json(); const fileRecord = commitData.files?.find(file => file.filename === conf.path && file.sha === remoteSHA); if (fileRecord) { commitDate = commitData.commit.committer.date; break; } } // ... const downloadFetch = await fetch(downloadURL); // ...The website will then cache the file to the browser’s indexedDB so it doesn’t always have to download (unless file changes). I also made a Python equivalent using requests which can be found here.
-
The ips file is in a format where every 6 bytes represents a host. Each 6 bytes can be broken down into two sections: one 4 bytes and another 2 bytes. The first 4 bytes (each 8-bit) stores the IP address. The final 2 bytes (16-bit) store the port in big-endian format. So
11000000 10101000 00000001 00000001 : 00011010 01101111 = 192 168 1 1 : 0x1A6F = 192.168.1.1:6767
This is a really great method for storing these IPs in a compact manner.
-
Once the bytes are all read, it populates an array with elements of {ip, port}. This array is then filtered through the selection of user filters which are listed in the instructions. After a list of filtered servers is made, the browser starts pinging the servers in that list. This is also where the custom API comes in.
Browsers can’t directly create raw TCP requests to ping Minecraft servers and receive their response (at least not static websites like this one). Instead, the browser sends a HTTP request to the API which handles the Minecraft server status and reply back to the browser.
More specifically, the API primarily gets the online status, MOTD, version, player count/max, and favicon using mcstatus. The source code for the simple API is here.
from mcstatus import JavaServer, LegacyServer # actual Minecraft ping libraries from fastapi import FastAPI, HTTPException, Request, status # for browser to API actual processing from fastapi.responses import JSONResponse from fastapi.middleware.cors import CORSMiddleware # CORS for static website purposesThis step is also done by multiple workers since waiting for one server to finish before checking the next one would be painfully slow. Using workers solves this sequential problem. If the worker count is set to 10, the browser creates 10 asynchronous ping processes.
In the case that the local API doesn’t respond, it has a backup to use https://api.mcsrvstat.us/3/ as an endpoint.
-
The website processes the receives JSON data from the APIs, parses it, and then calls renders the results on screen. If the server is deemed valid and online, it will populate the server list in a “bubble-up form” where it rises to the top of the list once other offline servers around it are scanned and hidden. Note that this behavior only applies when “Show Offline” is disabled. Each valid server is displayed with its IP, version, favicon, player count/max, and a “View Raw JSON” button.
This is the main logic that does the rendering (and parsing):
if (status.online) { if (status.icon) { iconHtml = `<img src="${status.icon}" class="server-icon" alt="icon">`; } else { iconHtml = `<img src="/assets/img/pack.png" class="server-icon" alt="icon">`; } let motd = 'No MOTD provided'; if (status.motd) { if (Array.isArray(status.motd.html)) { motd = status.motd.html.join('<br>'); } else if (typeof status.motd.html === 'string') { motd = status.motd.html; } else if (Array.isArray(status.motd.clean)) { motd = status.motd.clean.join('<br>'); } else if (typeof status.motd.clean === 'string') { motd = status.motd.clean; } } const currentPlayers = status.players?.online || 0; const maxPlayers = status.players?.max || 0; const gameVersion = status.version || "Unknown"; detailsHtml = ` <div> <strong style="color: #eee;">${key}</strong> <span style="color: lime;">[Online]</span><br> <span style="color: #eee;">Version: ${gameVersion}</span><br> <span style="color: #eee;">Players: ${currentPlayers}/${maxPlayers}</span><br> <div style="margin-top: 5px; font-family: monospace; background: #1a1a1a; padding: 4px; border-radius: 4px;">${motd}</div> </div> `; } - Finally, the browser remembers the user’s preferred settings. Things like the checkboxes and input boxes values are stored to browser’s
localStoragewhich the website will restore these values next time. The ips file is also saved for future use inindexedDB.
Conclusion
And that’s basically the whole project. There are three main pieces working together:
- Masscan + Python: Find and prepare potential Minecraft IP Addresses
- Minecraft Server API: Takes in an IP and retrieves Minecraft Server statuses
- Frontend: Downloads scan data, sends API requests, and format the data into UI.
Yes. I am looking forward to making this tool better. I would love if you could leave feedback as Github issues here: https://github.com/echen0719/echen0719.github.io/issues. Any type of feedback will be appreciated. I am thinking of hosting the API myself with more lenient limits, but I don’t know yet.
Also, I am not liable for any damage or griefing that occurs on Minecraft servers with this tool. Everything you do afterwards with your results is up to you.