Lightweight Minecraft API + infrastructure toolkit: player profiles & textures, Java/Bedrock server status probes, and Votifier (v1/v2) clients for Node and other fetch-capable runtimes. Some helpers rely on Node networking or binary modules.
This toolkit wraps Mojang APIs. Rate limits and availability still apply. Write endpoints (name change, skin upload) are not yet included.
# ✨ Auto-detect
npx nypm install minecraft-toolkit
# npm
npm install minecraft-toolkit
# yarn
yarn add minecraft-toolkit
# pnpm
pnpm install minecraft-toolkit
# bun
bun install minecraft-toolkit
# deno
deno install minecraft-toolkitimport {
fetchPlayerProfile,
fetchPlayerSkin,
fetchPlayerUUID,
fetchPlayerSummary,
fetchPlayers,
resolvePlayer,
fetchSkinMetadata,
} from "minecraft-toolkit";
const profile = await fetchPlayerProfile("26bz");
const summary = await fetchPlayerSummary("26bz");
const skin = await fetchPlayerSkin("26bz");
const uuid = await fetchPlayerUUID("26bz");
const batch = await fetchPlayers(["Notch", "26bz"], { delayMs: 50 });
const resolved = await resolvePlayer("069a79f444e94726a5befca90e38aaf5");
const skinMeta = await fetchSkinMetadata("26bz");Fetch-based helpers run anywhere fetch exists (Node 18+, Bun, Workers). Node networking and PNG helpers are not edge-safe. All API-style failures surface as MinecraftToolkitError.
import {
isValidUsername,
isUUID,
normalizeUUID,
uuidWithDashes,
uuidWithoutDashes,
getSkinURL,
getCapeURL,
getSkinModel,
extractTextureHash,
} from "minecraft-toolkit";
isValidUsername("26bz"); // true
uuidWithDashes("069a79f444e94726a5befca90e38aaf5");
const profile = await fetchPlayerProfile("26bz");
const skinUrl = getSkinURL(profile);
const hash = extractTextureHash(skinUrl);
const model = getSkinModel(profile); // "slim" | "default"import { fetchSkinMetadata, computeSkinDominantColor } from "minecraft-toolkit";
const meta = await fetchSkinMetadata("26bz", {
dominantColor: true,
sampleRegion: { x: 8, y: 8, width: 8, height: 8 },
});
console.log(meta.dominantColor); // e.g. "#f2d2a9"
const accent = await computeSkinDominantColor(meta.skin.url, {
x: 40,
y: 8,
width: 8,
height: 8,
});Composite a skin texture into a ready-to-use PNG (buffer, base64, and dataUri), without pulling in a canvas dependency. Accepts a username, UUID, or a raw skin URL.
import { renderPlayerHead, renderPlayerBust } from "minecraft-toolkit";
const head = await renderPlayerHead("26bz", { size: 128 }); // face + hat overlay
const bust = await renderPlayerBust("26bz", { size: 128 }); // head + torso + arms
console.log(head.dataUri); // "data:image/png;base64,..."overlay(defaulttrue) toggles the hat/jacket/sleeve overlay layers.modelforces"default"or"slim"arm width when rendering from a raw skin URL (model is auto-detected when resolving by username/UUID).renderPlayerBustmirrors the right arm for legacy 64x32 skins that don't carry left-limb pixel data.
The internal response cache and a rate-limit-aware retry helper are exposed for building your own resilient wrappers around any of the fetch-based helpers.
import { createCache, withCache, withRetry, fetchPlayerProfile } from "minecraft-toolkit";
const cache = createCache({ ttlSeconds: 30 });
const profile = await withRetry(() =>
withCache(cache, "profile:26bz", () => fetchPlayerProfile("26bz")),
);withRetry(fn, options)retries only onMinecraftToolkitErrorwithstatusCode: 429, honoring the MojangRetry-Afterheader (retryAfter) when present and falling back to exponential backoff (minDelayMs/maxDelayMs, default 3 retries).createCache({ ttlSeconds, maxSize })returns aResponseCache(ornullwhen{ cache: false });withCache(cache, key, resolver)is a no-op passthrough whencacheisnull.
Poll a server on an interval and only get notified when something actually changes (online state, player count, or MOTD) — no need to hand-roll diffing for a status page or Discord bot.
import { watchServerStatus } from "minecraft-toolkit";
const watcher = watchServerStatus("mc.hypixel.net", {
intervalMs: 30_000,
onChange: (status, previous) => console.log(`players: ${status.players.online}`),
onError: (error) => console.error(error),
});
// later
watcher.stop();onUpdate fires on every poll; onChange fires only when online, players.online, players.max, or motd differ from the previous poll. Accepts the same options as fetchServerStatus.
A valid Microsoft/Xbox Live access token is required for minecraftservices.com endpoints. Missing or expired tokens throw MinecraftToolkitError with statusCode: 401.
import {
fetchNameChangeInfo,
checkNameAvailability,
validateGiftCode,
fetchBlockedServers,
} from "minecraft-toolkit";
const accessToken = process.env.MC_ACCESS_TOKEN;
const windowInfo = await fetchNameChangeInfo(accessToken);
const availability = await checkNameAvailability("fresh_name", accessToken);
const isGiftValid = await validateGiftCode("ABCD-1234", accessToken);
const blockedServer = await fetchBlockedServers(); // no token requiredvalidateGiftCode returns true/false for 200/404 responses without throwing.
Probe Java and Bedrock servers without bringing your own RakNet/TCP logic.
import {
fetchServerStatus,
fetchJavaServerStatus,
fetchBedrockServerStatus,
} from "minecraft-toolkit";
const javaStatus = await fetchJavaServerStatus("mc.hypixel.net", { port: 25565 });
const bedrockStatus = await fetchBedrockServerStatus("play.example.net", { port: 19132 });
// fetchServerStatus picks the right probe based on the `edition` field
const autoStatus = await fetchServerStatus("my.realm.net", { edition: "bedrock" });
console.log(javaStatus.players.online, bedrockStatus.motd);Both helpers normalize MOTD text, favicon/Base64 icons, latency, and version info. Errors surface as
MinecraftToolkitError with contextual status codes.
import { fetchServerIcon } from "minecraft-toolkit";
const icon = await fetchServerIcon("play.example.net");
console.log(icon.base64); // "iVBOR..."
console.log(icon.byteLength); // raw PNG size in bytesThe helper reuses the Java status ping to extract the favicon, returning:
dataUri: ready-to-renderdata:image/png;base64,...base64: raw Base64 payloadbuffer+byteLengthfor further processing (e.g., resizing, hashing)
If the server doesn’t expose an icon, it throws MinecraftToolkitError (404).
Send vote notifications to classic Votifier v1 (RSA public key) and NuVotifier v2 (token/HMAC) servers without re-implementing either protocol.
import { sendVotifierVote } from "minecraft-toolkit";
const result = await sendVotifierVote({
host: "votifier.myserver.net",
port: 8192, // defaults to 8192 if omitted
publicKey: process.env.VOTIFIER_PUBLIC_KEY, // v1 servers
serviceName: "MyTopList",
username: "26bz",
address: "198.51.100.42",
token: listingSiteConfig.token, // v2 servers (optional)
protocol: "auto", // let the handshake decide between v1/v2
});
console.log(result.acknowledged, result.version, result.protocol);- Provide either a legacy RSA public key (for protocol v1) or a NuVotifier token (protocol v2). Server listing sites typically store each server's token and pass it here;
protocol: "auto"will select the right flow based on the handshake. timestampaccepts aDateor millisecond value (default:Date.now()). All failures bubble asMinecraftToolkitError.
Convert legacy § or & codes into safe HTML fragments or CSS class spans.
import { toHTML, generateCSS, stripCodes, hasCodes, convertPrefix } from "minecraft-toolkit";
const motd = "§aWelcome §lHeroes§r!";
const inline = toHTML(motd); // <span style="color: #55ff55">Welcome ...</span>
const classes = toHTML(motd, { mode: "class", classPrefix: "mc" });
const css = generateCSS(); // drop into a <style> tag
stripCodes(motd); // "Welcome Heroes!"
hasCodes(motd); // true
convertPrefix("&aHi", "toSection"); // "§aHi"getMaps() exposes the color and format metadata if you want to build custom renderers.