Minecraft Modding MCP README

The full upstream README, mirrored for reference. Install config, tool schemas, adoption signals and our own overview live on the Minecraft Modding MCP listing page.

@adhisang/minecraft-modding-mcp

npm MIT License Node.js >=22.13.0 CI

English | 日本語

Note: This project is entirely vibe-coded — built with AI-assisted development without formal specs.


@adhisang/minecraft-modding-mcp is an MCP server for AI-assisted Minecraft modding workflows, built on the Model Context Protocol. Use it when an agent needs to inspect Minecraft source, resolve mappings, compare versions, analyze mod JARs, validate Mixin, Access Widener, or Access Transformer files, or work with NBT and registry data from an MCP client.

It runs over stdio and works with Claude Desktop, Claude Code, VS Code, Codex CLI, Gemini CLI, and other MCP-capable clients.

41 tools (6 entry + 35 expert) | 9 resources | 4 namespace mappings | SQLite-backed cache

Features

  • Source exploration: browse, list, and search decompiled Minecraft source with line-level context
  • Mapping-aware symbol work: convert class, field, and method names between obfuscated, mojang, intermediary, and yarn
  • Version comparison: compare class signatures, registry entries, and migration-oriented summaries across Minecraft versions
  • Mod JAR analysis: read Fabric, Forge, and NeoForge metadata, entrypoints, Mixin configs, dependencies, source, and remap previews
  • Project validation: validate Mixin source, .accesswidener files, and Forge/NeoForge Access Transformer files against the target version
  • NBT, registry, cache, and diagnostics: patch NBT payloads, inspect generated registry data, and manage cache/runtime state
  • MCP resources: expose versions, class source, artifact metadata, and mappings through URI-based resources

Protocol Support

The server implements MCP protocol revision 2026-07-28 and keeps the legacy initialize-based protocol (2025-11-25 back through 2024-10-07) fully supported in the same binary — no configuration needed:

  • Legacy clients initialize as before and see the same tool names, input contracts, and response envelopes — byte-compatible except for a short list of recorded deviations (see the legacy-exceptions list in docs/tool-reference.md → MCP Protocol Support).
  • Modern clients (2026-07-28) skip initialize, probe with server/discover, and send per-request io.modelcontextprotocol/* _meta. Modern results carry resultType and the server identity echo; the cacheable methods additionally carry cache metadata (ttlMs / cacheScope).
  • One stdio process serves one era, selected by the client's first signal; the selection persists across the server's internal worker restarts.

Wire-level details — era selection, the rejection and version-negotiation tables, cache values, and framing — are in docs/tool-reference.md → MCP Protocol Support.

Quick Start

Package Users

Requirements:

  • Node.js 22.13.0+
  • Java 17+ on PATH for decompile and remap flows: reading Minecraft source for a version that has no Loom sources jar, decompiling mod JARs, and remap-mod-jar. The default Vineflower needs Java 17; the server checks only that java runs, not its version. get-registry-data and registry diffs in compare-versions and compare-minecraft run the Minecraft server's data generator, so they need the Java version that Minecraft release requires (Java 21 for 1.21.x).

Start the server locally:

Terminal
npx -y @adhisang/minecraft-modding-mcp

Use this same command in MCP client configs. If automatic JAR downloads are blocked in your environment, set MCP_VINEFLOWER_JAR_PATH and MCP_TINY_REMAPPER_JAR_PATH there.

Client Setup

CLI clients can register the package command directly.

Claude Code:

Terminal
claude mcp add minecraft-modding -- npx -y @adhisang/minecraft-modding-mcp

OpenAI Codex CLI:

bash
codex mcp add minecraft-modding -- npx -y @adhisang/minecraft-modding-mcp

Run claude mcp list or codex mcp list after registration to verify the server is available.

The stdio transport auto-detects newline-delimited and Content-Length framing, so the same server command works across Codex and standard MCP clients.

Claude Desktop

Add the following to your claude_desktop_config.json:

config.json
{
  "mcpServers": {
    "minecraft-modding": {
      "command": "npx",
      "args": ["-y", "@adhisang/minecraft-modding-mcp"]
    }
  }
}

VS Code

Add the following to .vscode/mcp.json in your workspace:

config.json
{
  "servers": {
    "minecraft-modding": {
      "command": "npx",
      "args": ["-y", "@adhisang/minecraft-modding-mcp"]
    }
  }
}

Gemini CLI

Add the following to ~/.gemini/settings.json:

config.json
{
  "mcpServers": {
    "minecraft-modding": {
      "command": "npx",
      "args": ["-y", "@adhisang/minecraft-modding-mcp"]
    }
  }
}

Then run:

text
/mcp list

Custom Environment

Pass environment variables to override defaults:

config.json
{
  "mcpServers": {
    "minecraft-modding": {
      "command": "npx",
      "args": ["-y", "@adhisang/minecraft-modding-mcp"],
      "env": {
        "MCP_CACHE_DIR": "/path/to/custom/cache",
        "MCP_MAPPING_SOURCE_PRIORITY": "maven-first"
      }
    }
  }
}

When a build used a non-default Gradle User Home, pass gradleUserHome on cache-backed source, mapping, validation, and workflow calls. The server treats it as a per-call Gradle User Home and searches <gradleUserHome>/loom-cache and <gradleUserHome>/caches/fabric-loom instead of the MCP process's Gradle User Home; project-local roots under projectPath still apply. It does not accept arbitrary Loom cache directories.

Start Here

These six top-level workflow tools cover the common paths and return summary-first results. They are the best default starting points for agents and MCP clients.

All six return result.summary first and can include summary.nextActions when there is a clear follow-up step. Pick the tool from the table, then use the examples and reference docs for exact payloads.

ToolStart here for
inspect-minecraftversions, artifacts, classes, files, and source search
analyze-symbolsymbol existence checks, mapping conversion, lifecycle tracing, and workspace symbol resolution
compare-minecraftversion-pair diffs, class diffs, registry diffs, and migration-oriented overviews
analyze-modmod metadata, decompile/search flows, class source, bytecode member queries, and safe remap preview/apply
validate-projectworkspace summaries plus direct Mixin, Access Widener, and Access Transformer validation
manage-cachecache inventory, verification, and preview/apply cleanup workflows

Workflow Notes

These notes cover high-frequency decisions during onboarding. For the full pitfall list, exact contracts, migration notes, and environment variables, see docs/tool-reference.md.

  • search-class-source defaults to queryMode="auto" and keeps separator queries such as foo.bar, foo_bar, and foo$bar on the indexed path. Use queryMode="literal" for an explicit full substring scan.
  • If you do not already have an artifact, prefer subject.kind="workspace" for inspect-minecraft instead of guessing artifact details. subject.focus is an object, not a string: use { "kind": "class", "className": "..." }, { "kind": "search", "query": "..." }, or { "kind": "file", "filePath": "..." }. task="auto" dispatches only from subject.kind and focus.kind; it is not a natural-language planner. Invalid string focus returns class/search/file exampleCalls, while missing artifact context keeps the requested task in a retryable suggestedCall.
  • For inspect-minecraft task="search", use detail: "summary", include: ["samples"] to see the first five hits in result.search (or hits: [] on a miss). Use detail: "standard" or "full" to read the whole fetched page; the cursor advances past that page, not past the samples.
  • Response detail controls depend on the task. inspect-minecraft task="class-source", detail="full" still reads a source snippet; use get-class-source mode="full" for the whole file or mode="snippet" with line ranges for later sections. Use task="class-members" for member signatures. See inspection response controls for supported includes and source lookup context.
  • trace-symbol-lifecycle expects Class.method in symbol. Keep exact overload matching in the separate descriptor field.
  • For unobfuscated releases such as 26.1+, check-symbol-exists and analyze-symbol task="exists" validate mojang lookups against runtime bytecode when no mapping graph exists, and return mapping_unavailable when the runtime JAR itself is unreachable.
  • analyze-mod and validate-project require structured subject objects and canonical include groups; stale string-subject or domain-include payloads return ERR_INVALID_INPUT with a retryable suggestedCall.
  • validate-project task="project-summary" infers an omitted version from gradle.properties and names the inferred version in warnings; pass preferProjectVersion: false to turn inference off, in which case a call without version returns status: "blocked". The resolved version is passed to every discovered Mixin, Access Widener, and Access Transformer check. If files were discovered but no version can be inferred, the summary returns status: "blocked" with a retry that asks for an explicit version instead of guessing.
  • When validate-project task="project-summary" discovers no files, status stays "ok" but the headline reads Nothing to validate: ... and warnings states that nothing was validated, so an "ok" status alone does not mean any file passed.
  • validate-mixin and validate-project keep mapping-health lightweight for obfuscated and mojang validation, avoiding full Tiny mapping graph loads unless intermediary or yarn namespaces are requested.
  • validate-project task="project-summary" uses a lightweight artifact probe for tasks["minecraft.artifact.resolved"]; it does not decompile Minecraft or rebuild the source index just to report per-probe status. It does read the runtime jar's bytes to derive the artifactId it reports, and repeat probes of the same jar in one process reuse that digest.
  • validate-project has a supervisor-owned end-to-end deadline of 120 seconds, including queue time. Set MCP_VALIDATE_PROJECT_TIMEOUT_MS to an ASCII-decimal value from 10000 through 600000 to override it. A timeout returns ERR_TOOL_TIMEOUT; a running timeout restarts the isolated worker before queued calls resume, while a queue timeout leaves the current worker untouched.
  • Artifact downloads are capped at 512 MiB (536870912 bytes) each. Set MCP_MAX_DOWNLOAD_BYTES to an ASCII-decimal byte count to override it; values below 1 MiB are raised to 1 MiB, and anything else — non-numeric, malformed, or too large to be an exact integer — falls back to the default. The cap is checked twice: against Content-Length before any body is read (a header that is not a plain byte count is treated as absent rather than as a breach), and against the bytes actually received, so a chunked or mis-declared response is caught too. A download that exceeds it fails with ERR_LIMIT_EXCEEDED and is not retried; the partial file is deleted on a best-effort basis, so a file the server cannot remove may survive the refusal. A cached copy is never served in its place — a cap is a configuration verdict, not a passing outage, and standing a stale artifact in for it would hide the ceiling instead of reporting it. When every repository trips the cap, the terminal ERR_REPO_FETCH_FAILED reports it where a caller can actually read it: hints carries the sentence naming MCP_MAX_DOWNLOAD_BYTES and the byte count to clear, and context.repoFailureCode is ERR_LIMIT_EXCEEDED.
  • Nested (Jar-in-Jar) entries are capped at 64 MiB (67108864 bytes) of uncompressed data each. Set MCP_MAX_NESTED_JAR_ENTRY_BYTES to override it, on the same rules as the download cap: ASCII decimal digits, values below 1 MiB raised to 1 MiB, anything else falling back to the default. The size is checked against the entry's declared uncompressed size before the read starts and again against the bytes actually streamed. A breach fails that one inner jar with ERR_LIMIT_EXCEEDED; the shell jar's other inner jars still resolve.
  • Queued calls resume only after the replacement worker completes initialization replay. If replacement startup or replay fails, queued tool calls terminate with ERR_WORKER_RESTART instead of waiting indefinitely. If unresolved process-tree cleanup fills the supervisor's two live-generation slots, new requests fail with the existing restart envelope and unavailable notifications are warning-dropped until cleanup or reconnect. On POSIX, an already-gone process group counts as cleaned up rather than leaving a stale cleanup token.
  • If a workspace was built with GRADLE_USER_HOME=/tmp/... or another isolated Gradle home, pass that path as gradleUserHome so source, mapping, runtime, and project validation lookups use the same Loom cache instead of stale caches under the MCP process home.
  • manage-cache reports corrupt Mojang binary-remap cache directories under cacheKinds: ["binary-remap"] with status: "corrupt", and can delete them by selector.artifactId in preview/apply workflows.

Inspect Minecraft source from a version

config.json
{
  "tool": "inspect-minecraft",
  "arguments": {
    "task": "class-source",
    "subject": {
      "kind": "class",
      "className": "net.minecraft.server.Main",
      "artifact": {
        "type": "resolve-target",
        "target": {
          "kind": "version",
          "value": "1.21.10"
        }
      }
    }
  }
}

Map or check a symbol

config.json
{
  "tool": "analyze-symbol",
  "arguments": {
    "task": "map",
    "subject": {
      "kind": "method",
      "owner": "net.minecraft.server.MinecraftServer",
      "name": "tickServer"
    },
    "version": "1.21.10",
    "sourceMapping": "mojang",
    "targetMapping": "intermediary",
    "signatureMode": "name-only",
    "detail": "standard"
  }
}

Summarize a mod JAR

config.json
{
  "tool": "analyze-mod",
  "arguments": {
    "task": "summary",
    "subject": {
      "kind": "jar",
      "jarPath": "/path/to/mymod-1.0.0.jar"
    }
  }
}

Validate a workspace

config.json
{
  "tool": "validate-project",
  "arguments": {
    "task": "project-summary",
    "subject": {
      "kind": "workspace",
      "projectPath": "/workspace/modid",
      "discover": ["mixins", "access-wideners", "access-transformers"]
    },
    "preferProjectVersion": true,
    "preferProjectMapping": true
  }
}

Workspace summaries still default to discovering mixins and access wideners. Add "access-transformers" to subject.discover when you want Access Transformer files included in the summary run.

Documentation

Tool Surface

Start with these top-level workflow tools unless you already know the exact specialized operation you want. The lower-level tools remain available for narrow follow-up work and automation.

Top-Level Workflow Tools

ToolPurpose
inspect-minecraftInspect versions, artifacts, classes, files, source text, and workspace-aware lookup flows
analyze-symbolHandle symbol existence checks, namespace mapping, lifecycle tracing, workspace symbol resolution, and API overviews
compare-minecraftCompare version pairs, class diffs, registry diffs, and migration-oriented summaries
analyze-modSummarize mod metadata, decompile and search mod code, inspect class source, read class members from bytecode, and preview or apply remaps
validate-projectSummarize workspaces and run direct Mixin, Access Widener, or Access Transformer validation
manage-cacheList, verify, and preview or apply cache cleanup operations

Source Exploration

Tools for browsing Minecraft versions, resolving source artifacts, and reading or searching decompiled source code. get-class-members reuses a JAR signature at the same path while its modification time and size are unchanged; a change to either value triggers a fresh signature read.

ToolPurpose
list-versionsList available Minecraft versions from Mojang metadata and local cache
resolve-artifactResolve source artifacts from versions, JAR paths, or Maven coordinates
find-classFind simple or fully-qualified class names, including classes bundled in nested JARs
get-class-sourceRead class source from an artifact or resolve the backing artifact on demand
get-class-membersList constructors, fields, and methods from bytecode
search-class-sourceSearch indexed class source by symbol, text, or path
get-artifact-fileRead a full source file with a byte limit
list-artifact-filesList indexed source file paths with cursor pagination
index-artifactRebuild indexed metadata for an existing artifact

find-class accepts either an artifactId or the shared object target shape. For a workspace-relative dependency, pass target: { kind: "dependency", group, name, versionFromProject: true } with top-level projectPath. Fabric-style umbrella JARs are searched through their nested .class inventories; a top-level class match can then be passed to get-class-source or get-class-members, which resolve the containing nested JAR. Dotted inner-class matches are also readable through get-class-source. An empty result means no match in the class inventories that could be read: a nested JAR that cannot be read or exceeds the nested-entry size cap is skipped without a warning, and when the artifact's source coverage excludes net.minecraft and the query is a Minecraft-style class name, warnings says so and suggestedCall points to get-class-source.

For indexed source matches, a qualified name is checked against the full enclosing-type chain in that file and returned in the requested spelling; same-named types in other indexed files do not substitute for a missing type.

For unobfuscated releases such as 26.1+, obfuscated names the runtime jar's names as shipped, which are already Mojang names: both obfuscated and mojang are accepted, a namespace field that would report obfuscated (mappingApplied, returnedNamespace, and the other reported namespace fields) reports mojang instead, and provenance.unobfuscatedRuntime: true marks the artifact. requestedMapping is not relabelled, so for an omitted or obfuscated request, requestedMapping: "obfuscated" next to mappingApplied: "mojang" is an identity, not a fallback. mapping="mojang" uses the runtime/decompile path directly and skips Loom source-jar discovery. When an artifact or class tool resolves a 26.1+ target with intermediary or yarn, it falls back to the runtime names with a warning and reports them as mojang; the lifecycle tools keep reporting the requested intermediary or yarn. An explicit intermediary or yarn sent with an already-resolved artifactId skips that fallback: get-class-source and get-class-members still report mojang in mappingApplied, but get-class-members and batch-class-members entries keep the requested name in returnedNamespace. This applies to version targets, Minecraft runtime coordinates, and JAR targets whose own contents (a top-level version.json with a 26.1+ id, net/minecraft/SharedConstants.class, and no .java sources) prove a 26.1+ Minecraft runtime jar; see docs/tool-reference.md → Lookup Rules. Dependency jars whose own version only looks like 26.x keep obfuscated. manage-cache metadata and the access-widener/access-transformer validation provenance also keep obfuscated; see docs/tool-reference.md → Namespace Definitions.

Version Comparison & Symbol Tracking

Tools for comparing class and registry changes across Minecraft versions and tracing symbol existence over time.

ToolPurpose
trace-symbol-lifecycleTrace when Class.method exists across Minecraft versions
diff-class-signaturesCompare one class across two versions and return member deltas
compare-versionsCompare class and registry changes between two versions

Mapping & Symbols

Tools for converting symbol names between namespaces and checking symbol existence.

ToolPurpose
find-mappingLook up mapping candidates for class, field, or method symbols
resolve-method-mapping-exactStrict shortcut for find-mapping (kind=method, signatureMode=exact); requires the full owner+name+descriptor triple
get-class-api-matrixShow one class API across obfuscated, mojang, intermediary, and yarn
resolve-workspace-symbolResolve compile-visible symbol names from a Gradle workspace
check-symbol-existsCheck whether a class, field, or method exists in a namespace

The lookup tools resolve-artifact, find-mapping, resolve-method-mapping-exact, resolve-workspace-symbol, check-symbol-exists, get-class-source, get-class-members, search-class-source, and list-artifact-files, plus the four batch-* tools, share the detail (summary | standard | full) + include[] response contract for shorter responses (replacing the old per-tool compact flag); other expert tools do not take it. See docs/tool-reference.md for per-tool defaults and the full field list.

NBT Utilities

Tools for decoding, patching, and encoding Java Edition NBT binary data using a typed JSON representation.

ToolPurpose
nbt-to-jsonDecode Java Edition NBT binary payloads into typed JSON
nbt-apply-json-patchApply RFC 6902 patches to typed NBT JSON
json-to-nbtEncode typed JSON back to Java Edition NBT binary

Mod Analysis

Tools for extracting metadata from mod JARs, decompiling mod source, searching mod code, and remapping mod namespaces.

ToolPurpose
analyze-mod-jarExtract mod metadata, dependencies, entrypoints, mixin config info, and packaged access transformer paths from a JAR
decompile-mod-jarDecompile a mod JAR and optionally return one class source
get-mod-class-sourceRead one class source from the decompiled mod cache
search-mod-sourceSearch decompiled mod source by class, method, field, or content
remap-mod-jarRemap a Fabric or Quilt mod JAR to yarn or mojang names

analyze-mod-jar treats lowcodefml in META-INF/mods.toml as Forge; META-INF/neoforge.mods.toml or a NeoForge loader value identifies NeoForge.

Validation

Tools for validating Mixin source, Access Widener files, and Forge/NeoForge Access Transformer files against a target Minecraft version. Workspace options let validation use loader/runtime context when a project path is available.

ToolPurpose
validate-mixinValidate Mixin source against a target Minecraft version (returns validationStatus: "partial" with targetOutcomes when a stage budget defers work)
validate-access-widenerValidate Access Widener content against a target Minecraft version, optionally using runtime-aware Loom artifacts
validate-access-transformerValidate Access Transformer content against a target Minecraft version, optionally using Forge/NeoForge runtime artifacts
verify-mixin-targetSingle-call probe for owner / member existence with @Shadow / @Accessor / @Invoker advice

Registry & Diagnostics

Tools for querying generated registry data and inspecting server runtime state.

ToolPurpose
get-registry-dataRead generated registry snapshots and optionally include entry data
get-runtime-metricsInspect runtime metrics and latency snapshots

Batch Lookup

Tools that share one resolved artifact or Minecraft version across a fixed shortlist. Results include one status per item plus an aggregate summary. See Batch lookup contract for failure handling and retry mapping.

Within one MCP server process, batch class lookups that need the same binary fallback share one in-flight source indexing/decompile rebuild for that artifact.

ToolPurpose
batch-class-sourceRead source for many classes against one shared resolved artifact (1..50 entries per call)
batch-class-membersList members for many classes against one shared resolved artifact (1..50 entries per call)
batch-symbol-existsProbe symbol existence for many entries against one shared Minecraft-version artifact (workspace / version targets only)
batch-mappingsTranslate many symbols across mapping namespaces with one shared Minecraft version (no shared artifact)

Detailed parameter constraints, migration notes, resource behavior, and the full environment-variable matrix live in docs/tool-reference.md.

Development

Repository requirements:

  • Node.js 22.13.0+
  • pnpm
  • Java 17+ when running remap or decompile flows locally

Setup and run the repository:

bash
pnpm install
pnpm dev

Build the packaged shape:

bash
pnpm build
pnpm start

Always run:

bash
pnpm check
pnpm test

Run these when relevant:

  • pnpm test:file <path...> for focused ordinary suites
  • pnpm test:grep <name-pattern> for recursive ordinary suites filtered by test name
  • pnpm test:manual:stdio-smoke for MCP transport, registration, or manual workflow changes
  • pnpm test:manual:package-smoke when checking packaged install and distribution behavior
  • pnpm test:perf for search, index, or performance-sensitive changes
  • pnpm test:coverage or pnpm test:coverage:lcov for coverage checks (lines=80, branches=70, functions=80)
  • pnpm validate for the full local validation suite

Ordinary .test.ts files live in domain directories under tests/ (for example source-service/, entry-tools/, mapping/, mixin/, integration/mcp-tools/, contracts/, and utils/). Keep helper-only modules in tests/helpers; manual smoke, performance, and resource files remain in their existing special directories.

License

MIT