repo.mcmiddleearth.com is MCME's own Maven repository. MCME's libraries and plugins publish their release jars there, and every MCME build resolves its MCME dependencies from it. It also keeps a cached copy of the outside repositories our builds use, so a build keeps working when one of them is down. Reading is open to everyone, with no account; publishing needs a token. The server runs Reposilite; how it is run is in CI/CD (operators only).
The three repositories
| Repository | URL | What it holds |
|---|---|---|
releases |
https://repo.mcmiddleearth.com/releases |
MCME release artifacts, plus a few third-party jars that are no longer available elsewhere. Immutable: a version can be published once and never overwritten |
snapshots |
https://repo.mcmiddleearth.com/snapshots |
-SNAPSHOT builds from development branches. These can be replaced |
mirror |
https://repo.mcmiddleearth.com/mirror |
A caching copy of PaperMC, Maven Central, JitPack (com.github.* only), Scarsz Nexus, OnARandomBox, EssentialsX and libraries.minecraft.net (com.mojang.* only). Filled on the first request for an artifact |
The mirror never fetches com.mcmiddleearth artifacts from outside. MCME artifacts come only from releases and snapshots.
Using it in a build
Maven
<repositories>
<repository>
<id>mcme-releases</id>
<url>https://repo.mcmiddleearth.com/releases</url>
<snapshots><enabled>false</enabled></snapshots>
</repository>
<repository>
<id>mcme-snapshots</id>
<url>https://repo.mcmiddleearth.com/snapshots</url>
<releases><enabled>false</enabled></releases>
</repository>
<repository>
<id>mcme-mirror</id>
<url>https://repo.mcmiddleearth.com/mirror</url>
</repository>
<!-- Upstream fallbacks you still want, after the mirror -->
<repository>
<id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
</repositories>
List mcme-mirror before any upstream repository you keep as a fallback. Maven tries repositories in order, so an artifact the mirror already has is served without touching the upstream. MCME-Connect's pom.xml is a complete example.
Gradle
Kotlin DSL (build.gradle.kts):
repositories {
maven("https://repo.mcmiddleearth.com/releases")
maven("https://repo.mcmiddleearth.com/snapshots") // only if you use a -SNAPSHOT
maven("https://repo.mcmiddleearth.com/mirror")
mavenCentral()
maven("https://repo.papermc.io/repository/maven-public/")
}
Groovy DSL (build.gradle):
repositories {
maven { url = 'https://repo.mcmiddleearth.com/releases' }
}
Then depend on an artifact as usual, for example compileOnly("com.mcmiddleearth:PluginUtils:2.0.6"). MCME libraries and plugins are installed on the servers as plugins of their own, so the scope is provided (Maven) or compileOnly (Gradle).
What is published
Checked on 2026-11-02 against each artifact's maven-metadata.xml.
| Coordinate | Versions | Published by |
|---|---|---|
com.mcmiddleearth:mcme-base |
2.0.0, 2.0.1 (snapshots: 2.0.1-SNAPSHOT, 2.0.2-SNAPSHOT) |
MCME-Base CI |
com.mcmiddleearth:PluginUtils |
2.0.2 to 2.0.6; the legacy 1.9.0 to 1.9.2 | PluginUtils CI (1.9.x uploaded once, by hand) |
com.mcmiddleearth:MCME-Connect |
3.0.1, 3.0.3, 3.1.0, 3.1.1 | MCME-Connect CI |
com.mcmiddleearth:MCME-Architect |
3.0.0, 3.1.0, 3.1.1, 3.2.0, 3.2.1, 3.3.0, 3.3.1 | MCME-Architect CI |
com.mcmiddleearth:TheGaffer, thegaffer-core, thegaffer-velocity, thegaffer-parent |
3.0.1 | TheGaffer CI |
com.mcmiddleearth:Guidebook |
2.0.1 | Guidebook CI |
com.github.mryurihi:tbnbt |
0.1.4 | Uploaded by hand: JitPack no longer serves it, and MCME-Connect needs it |
To see the current list for one artifact, open its metadata, for example https://repo.mcmiddleearth.com/releases/com/mcmiddleearth/PluginUtils/maven-metadata.xml.
Rules worth knowing
- One coordinate per library. Use
com.mcmiddleearth:PluginUtils, not JitPack'scom.github.MCME:PluginUtils. Build tools treat different group ids as different libraries, so a build that gets both ends up with two copies and no version resolution between them. - Releases are final. Publishing a version that already exists fails with
409 Conflict. Release the next version instead. - PluginUtils 1.9.x comes with its original POMs, which name a dependency on a local server jar. Maven warns about an invalid POM; the jar itself resolves. No current plugin uses 1.9.x.
Publishing
Publishing is for artifacts other MCME code compiles against (the two libraries and the plugins other plugins build on), and for plugins whose release jars should be available from one checked place. Writing needs a token from the MCME operators. Tokens can write only under com/mcmiddleearth/.
From a Maven project
Point distributionManagement at the repository, with the server id mcme:
<distributionManagement>
<repository>
<id>mcme</id>
<url>https://repo.mcmiddleearth.com/releases</url>
</repository>
<snapshotRepository>
<id>mcme</id>
<url>https://repo.mcmiddleearth.com/snapshots</url>
</snapshotRepository>
</distributionManagement>
The credentials never go in the pom. Locally they go in ~/.m2/settings.xml:
<settings>
<servers>
<server>
<id>mcme</id>
<username>token-name</username>
<password>token-secret</password>
</server>
</servers>
</settings>
From a Gradle project
PluginUtils and Guidebook read the credentials from two environment variables, MCME_MAVEN_NAME and MCME_MAVEN_SECRET, and choose snapshots or releases from the version suffix. See PluginUtils' build.gradle (the publishing block). Without the variables, publish fails and every other task works as usual.
From GitHub Actions
MCME's workflows publish a release only from a release tag or a manual run, never from an ordinary push. (MCME-Base also publishes a -SNAPSHOT on every push to its development branch.)
- Maven:
actions/setup-javawrites thesettings.xmlentry when givenserver-id: mcme,server-username: MCME_MAVEN_NAMEandserver-password: MCME_MAVEN_SECRET; the deploy step sets those two environment variables from the repository's secrets of the same names. - Gradle: the publish step sets the same two environment variables from the secrets.
- Check before you deploy. Because
releasesrefuses a second upload, the workflows check that the tag matches the version (and, in several, that the changelog has a section for it) before the deploy step, so a failed check never leaves a half-published release. - Secrets have to reach the repository. The two secrets are organisation secrets shared with selected repositories only. A workflow in a repository that has not been granted them gets empty values, and the deploy fails with
401 Unauthorized. Ask an organisation admin to add the repository when you add a publish step. - Private repositories get their own token. On GitHub Free, organisation secrets don't reach private repositories, or personal ones. Such a repository gets its own token from the MCME operators, limited to its own artifact and stored in its repository secrets under the same two names, so the workflow doesn't change. Anyone can download what is published here, so a private repository should not publish a sources jar, and a jar that has to stay private stays on its repository's GitHub Releases instead.
Reference workflows: MCME-Base build.yml (Maven, snapshots from development, releases from v* tags), PluginUtils build.yml (Gradle) and TheGaffer build.yml (a multi-module build that deploys all modules at the end, so a failing module publishes nothing).
Troubleshooting
| Symptom | Cause |
|---|---|
409 Conflict on deploy |
That version is already in releases. Bump the version |
401 Unauthorized on deploy |
Wrong or empty credentials. In CI, check that the repository has been granted the secrets |
403 Forbidden on deploy |
The token may not write that path (it is outside com/mcmiddleearth/) |
| An MCME artifact is not found | Check the coordinate and version against the table above, and that mcme-releases (or mcme-snapshots for a -SNAPSHOT) is in your repositories |
| "Invalid POM" warning for PluginUtils | You resolve a 1.9.x version. Move to 2.0.2 or later |