Versions
Which Minecraft versions are built in, how one is picked per connection, and how to pin one.
mc-protocol ships one version: Minecraft Java 26.2, protocol 776. The code is laid out so a second version is a directory plus a registration, but nothing else is built in yet.
Pick a version
The root import always tracks the newest built-in version. A subpath pins one:
import { Server, Client, Proxy, helpers } from "mc-protocol"; // newest (26.2 today)
import { Server, Client, Proxy, helpers } from "mc-protocol/26.2"; // pinned; "mc-protocol/776" is an alias
From a subpath, Server defaults versions to [776], Client defaults version to 776, Proxy accepts 776 from players, and helpers is helpers.forVersion(776). Passing the options explicitly overrides the defaults either way.
The root export also exposes the registry:
import { versions, getVersion, DEFAULT_PROTOCOL, createVersionedApi } from "mc-protocol";
DEFAULT_PROTOCOL; // 776
versions().map((v) => v.name); // ["26.2"]
getVersion(776).packets.play.clientbound.byName.Login; // { id, packet }
getVersion(999); // throws RangeError
const { Server } = createVersionedApi(776); // what "mc-protocol/26.2" does
Negotiation
Every connection starts with Intension, which carries protocolVersion. The Client on each side reads it and switches both packet builders to that version’s tables before the next packet is decoded.
On the server side, Server({ versions }) lists the protocols it accepts (default [DEFAULT_PROTOCOL]; unknown numbers throw a RangeError):
protocolVersion |
nextState |
Result |
|---|---|---|
in versions |
any | Tables switch to that version. client.version reports it. |
not in versions |
1 (status) |
Tables stay on the default. StatusRequest and PingRequest work, so the list entry can show which versions you accept. |
not in versions |
2 or 3 (login, transfer) |
LoginDisconnect with the reason Unsupported protocol version 999; this server supports 776 (26.2), the socket ends, and Server emits versionRejected(client, protocol). Later bytes on that socket are ignored. |
On the client side, Client({ version }) selects the tables and fills Intension.protocolVersion when you leave it out. If you send another built-in protocol number, the client follows it. A number without built-in tables is sent unchanged and the tables stay on version; that is enough to ping a server of another version.
Proxy gives its player-facing Server the proxy’s versions; the upstream Client adopts the player’s negotiated version when the forwarded Intension goes out.
Helpers
The data-backed helpers (getBlockStateId, getItemId, createSlot, the map helpers, ChunkHelper, and the world generators) are bound to the default version. helpers.forVersion(protocol) returns the same helper set bound to another registered version’s block states, items, lighting table, and map palette:
import { helpers } from "mc-protocol";
const h = helpers.forVersion(776);
h.getBlockStateId("oak_stairs", { facing: "east" });
new h.ChunkHelper(); // same as new helpers.ChunkHelper({ version: 776 })
Helpers with no per-version data (commands, particles, entity metadata, flags) are shared as is.
Layout
src/Core/Versions/
index.ts registry: registerVersion, getVersion, versions, DEFAULT_PROTOCOL
api.ts createVersionedApi(protocol)
776/
index.ts ProtocolVersion for 26.2: name, packet tables, data
packets.ts generated: byId / byName per state and bound
Packets/ <state>/<bound>/<PacketName>.ts, one file per packet
Helpers/ wire codecs for this version
Data/ registries, tags, blocks, items, lighting, map colors
src/versions/
26.2.ts, 776.ts entry modules for "mc-protocol/26.2" and "mc-protocol/776"
Each packet file is named after its name and exports its numeric wire ID as id. packets.ts is generated by node tools/generate-packet-index.ts; rerun it after adding, removing, renaming, or changing the ID of a packet. Block and item registries are rebuilt with tools/generate-blocks.ts and tools/generate-items.ts. Adding a version means creating src/Core/Versions/<protocol>/ with the same shape, registering it in src/Core/Versions/index.ts, and adding an entry module plus a package.json export. The packet definition files themselves must be generated from Minecraft’s protocol data, and that generator is not in the repository yet.