@adhisang/minecraft-modding-mcp 7.0.0 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +3 -2
  3. package/dist/entry-tools/analyze-mod-service.d.ts +2 -2
  4. package/dist/entry-tools/analyze-symbol-service.d.ts +2 -2
  5. package/dist/entry-tools/batch-class-members-service.d.ts +3 -2
  6. package/dist/entry-tools/batch-class-members-service.js +20 -6
  7. package/dist/entry-tools/batch-class-source-service.d.ts +3 -2
  8. package/dist/entry-tools/batch-class-source-service.js +10 -0
  9. package/dist/entry-tools/compare-minecraft-service.d.ts +27 -4
  10. package/dist/entry-tools/compare-minecraft-service.js +65 -4
  11. package/dist/entry-tools/entry-tool-schema.d.ts +2 -2
  12. package/dist/entry-tools/inspect-minecraft-service.d.ts +2 -2
  13. package/dist/entry-tools/manage-cache-service.d.ts +2 -2
  14. package/dist/entry-tools/validate-project/cases/project-summary.js +71 -12
  15. package/dist/entry-tools/validate-project-service.d.ts +2 -2
  16. package/dist/index.js +37 -15
  17. package/dist/source/artifact-resolver.d.ts +14 -0
  18. package/dist/source/artifact-resolver.js +106 -12
  19. package/dist/source/class-source/members-builder.d.ts +7 -0
  20. package/dist/source/class-source/members-builder.js +4 -1
  21. package/dist/source/class-source.d.ts +9 -2
  22. package/dist/source/class-source.js +173 -25
  23. package/dist/source/indexer.js +69 -1
  24. package/dist/source/lifecycle/mapping-helpers.d.ts +20 -1
  25. package/dist/source/lifecycle/mapping-helpers.js +29 -3
  26. package/dist/source/lifecycle/runtime-check.d.ts +25 -0
  27. package/dist/source/lifecycle/runtime-check.js +68 -39
  28. package/dist/source/symbol-resolver.js +88 -0
  29. package/dist/source-jar-reader.d.ts +33 -0
  30. package/dist/source-jar-reader.js +58 -0
  31. package/dist/source-resolver.d.ts +7 -0
  32. package/dist/source-resolver.js +20 -5
  33. package/dist/source-service.d.ts +5 -0
  34. package/dist/source-service.js +7 -0
  35. package/dist/storage/db.d.ts +62 -2
  36. package/dist/storage/db.js +181 -20
  37. package/dist/storage/sqlite.d.ts +31 -1
  38. package/dist/storage/sqlite.js +125 -16
  39. package/dist/tool-guidance.js +4 -1
  40. package/dist/tool-schemas.d.ts +64 -52
  41. package/dist/tool-schemas.js +9 -7
  42. package/dist/types.d.ts +9 -0
  43. package/dist/v1-parity-schemas.js +36 -2
  44. package/dist/version-diff-service.d.ts +23 -0
  45. package/dist/version-diff-service.js +101 -0
  46. package/dist/version-service.d.ts +14 -0
  47. package/dist/version-service.js +45 -3
  48. package/dist/workspace-mapping-service.d.ts +8 -0
  49. package/dist/workspace-mapping-service.js +35 -7
  50. package/docs/README-ja.md +2 -0
  51. package/docs/tool-reference.md +55 -11
  52. package/package.json +1 -1
@@ -186,16 +186,17 @@ Workspace detection is memoised in a process-resident `WorkspaceContextCache` (1
186
186
  - `analyze-symbol` infers an omitted `version` from `projectPath` (gradle.properties `minecraft_version`/`mc_version`); the response then carries `versionInference { version, source }` and a warning. An explicit `version` always wins. `inspect-minecraft` direct subjects without `subject.artifact` auto-resolve only when exactly one workspace is known to the process (provenance warning attached); several candidates are refused with `workspaceCandidates`. That unique workspace is then resolved through `target.kind="workspace"` like any other workspace subject, so it picks up the project's compile mapping and loader scope; the separately detected Minecraft version is retained only as the "is this workspace usable at all" guard.
187
187
 
188
188
  - Loom split-source workspaces publish a version as a `minecraft-common` / `minecraft-clientOnly` sources-jar pair with no merged jar. Version-target resolution indexes both halves (the companion jar appears in `provenance.companionSourceJars`), so client-only classes are queryable under the merged scope. If a class still cannot be found, the error's `exampleCalls` carries a `scope: "vanilla"` retry — the decompiled client jar also contains client-only classes.
189
- - `mapping="mojang"` requires source-backed artifacts on legacy obfuscated versions. For unobfuscated releases such as `26.1+`, the runtime/decompile path is accepted directly for version and versioned-coordinate targets. When source jars are not available but the version's Mojang tiny mappings, the tiny-remapper jar, and `MappingService.checkMappingHealth` are all healthy, `resolve-artifact` with `target.kind="version"` will transparently tiny-remap the binary jar (`obfuscated -> mojang`) and decompile the result, and the response carries `qualityFlags` `"binary-remapped"` and `"decompiled"` plus `provenance.transformChain` `"binary-remap:obf->mojang"` and `"decompile:vineflower"`. Coordinate and jar targets are not eligible for this fallback and still surface `ERR_MAPPING_NOT_APPLIED`. Source-backed and obfuscated artifacts keep their existing `artifactId` hashes — only the new mojang-remapped variant lives in a separate cache slot.
189
+ - `mapping="mojang"` requires source-backed artifacts on legacy obfuscated versions. For unobfuscated releases such as `26.1+`, the runtime/decompile path is accepted directly for version targets, Minecraft runtime coordinates such as `net.minecraft:client:26.1`, and jar targets proven to be a 26.1+ Minecraft runtime jar (see [Lookup Rules](#lookup-rules)). When source jars are not available but the version's Mojang tiny mappings, the tiny-remapper jar, and `MappingService.checkMappingHealth` are all healthy, `resolve-artifact` with `target.kind="version"` will transparently tiny-remap the binary jar (`obfuscated -> mojang`) and decompile the result, and the response carries `qualityFlags` `"binary-remapped"` and `"decompiled"` plus `provenance.transformChain` `"binary-remap:obf->mojang"` and `"decompile:vineflower"`. Coordinate and jar targets are not eligible for this fallback; a legacy coordinate or a jar that is not proven to be a 26.1+ runtime jar still surfaces `ERR_MAPPING_NOT_APPLIED`. Source-backed and obfuscated artifacts keep their existing `artifactId` hashes — only the new mojang-remapped variant lives in a separate cache slot.
190
190
  - Mojang binary-remap cache entries live under `<cacheDir>/remapped`. `manage-cache` lists valid files plus corrupt directories and leftover temp entries under `cacheKinds: ["binary-remap"]`; corrupt entries carry `status: "corrupt"` and `meta.artifactId`, so callers can preview or apply cleanup with `selector.artifactId`.
191
191
  - Jar-in-Jar shell jars (near-zero own classes with bundled `META-INF/jars/*.jar`, e.g. the Fabric API umbrella jar) no longer dead-end in `ERR_DECOMPILER_FAILED`. `resolve-artifact` detects the shell, skips decompilation, and returns the artifact with `qualityFlags: ["shell-jar"]` and the bundled inventory in `provenance.nestedJars`; `analyze-mod-jar` reports the same inventory as `nestedJars`. `get-class-source` / `get-class-members` lookups against a shell automatically redirect to the single nested jar containing the class and mark the response with `provenance.nestedJar` (`entryName` + `shellArtifactId`); a class found in several nested jars raises `ERR_NESTED_JAR_AMBIGUOUS` with `nestedJarCandidates` and per-candidate `suggestedCall` examples instead of picking one. Class-not-found errors on a shell carry the `nestedJars` inventory, on every access path that publishes one — the tool result envelope, `batch-*` entries, and `mc://` resource reads — with `nestedJarsTruncated: true` beside it when caps shortened the published list. That flag is omitted entirely when the inventory is complete, so read its absence as "complete", never as "unknown". The redirect is deliberately single-level: a nested jar that is itself a shell surfaces its own inventory when resolved directly as its own artifact. Extracted nested jars are content-addressed under `<cacheDir>/nested-jars`, observable through `manage-cache` with `cacheKinds: ["nested-jar"]`.
192
192
  - `list-artifact-files` indexes Java source paths only — `assets/` and `data/` prefixes list nothing. Text files under those prefixes ARE retrievable by exact path with `get-artifact-file`: when the index has no row, the tool reads the entry directly from the backing jar (`deliveryMode: "jar-read-through"` marks such responses). This works for any artifact with a backing jar — vanilla client jars and mod jars alike; for Jar-in-Jar shells it reads the shell's own entries only (resolve a nested jar as its own artifact to reach its resources). Read-through delivery is text-only with a 512 KiB per-file cap (`truncated: true` beyond it); binary entries (e.g. `.png`, `.ogg`) answer with size metadata plus `contentOmittedReason` instead of content. Traversal-shaped paths (`..`, absolute) are rejected with `ERR_INVALID_INPUT`, and a miss returns `ERR_FILE_NOT_FOUND` with `nearbyPaths` naming same-named entries elsewhere in the jar (directory layouts move between versions, e.g. `assets/minecraft/models/item/*` → `assets/minecraft/items/*`).
193
193
  - `search-class-source` defaults to `queryMode="auto"`. Use `queryMode="literal"` for explicit substring scans. `match="regex"` enforces `query.length <= 200` and caps results at `100`.
194
194
  - `search-class-source` returns compact hits only. Use `get-artifact-file` or `get-class-source` to inspect returned files.
195
- - `find-class` and `get-class-source` on `mapping="obfuscated"` expect Mojang obfuscated names. Deobfuscated queries warn and usually need `mapping="mojang"` or a `find-mapping` step first.
195
+ - On legacy (1.x) versions, `find-class` and `get-class-source` on `mapping="obfuscated"` expect Mojang obfuscated names. Deobfuscated queries warn and usually need `mapping="mojang"` or a `find-mapping` step first. On `26.1+` the `obfuscated` names already are Mojang names, so no mapping step applies; a miss points at near-miss class names instead (see [Lookup Rules](#lookup-rules)).
196
196
  - `get-class-members` exposes `annotationDefault` on annotation-type members (the `default` value of an `@interface` member) whenever the classfile carries it, and accepts `includeAnnotations: true` to additionally list runtime-visible member annotations such as `@java.lang.Deprecated` per member. The leaner `names`/`signatures` projections drop annotation fields. `analyze-mod` `task="members"` includes both without a flag.
197
197
  - On unobfuscated versions, `find-mapping`, `resolve-method-mapping-exact`, and `check-symbol-exists` report two structured `mappingContext` flags instead of per-response warning sentences (`get-class-api-matrix` reports a top-level `unobfuscatedRuntime: true` — its non-mojang columns are empty by design there): `unobfuscatedRuntime: true` replaces "Version X is unobfuscated; mapping graph is empty because the runtime already uses deobfuscated names.", and `runtimeValidated: true` replaces "Version X is unobfuscated; validated symbol existence against runtime bytecode." Do not pattern-match the old sentences.
198
198
  - `check-symbol-exists` defaults to strict FQCN class lookup. Use `nameMode="auto"` for short class names.
199
+ - On unobfuscated versions, the runtime-bytecode check behind `check-symbol-exists` answers a method query named `<init>` from the class's own constructors, so an existing constructor descriptor resolves instead of returning `not_found`.
199
200
  - On unobfuscated versions, every `not_found` and `mapping_unavailable` verdict from the mapping graph — classes and fields included, not just methods — is re-validated against runtime bytecode before being returned, so a graph that lacks a record for a real symbol (e.g. `EntityType.ITEM`) no longer produces false negatives. Genuinely-missing symbols still return `not_found` after the runtime check. Bytecode-derived response contexts report `mappingNamespace: "mojang"` on unobfuscated versions instead of a hardcoded `"obfuscated"`.
200
201
  - `check-symbol-exists` can use `signatureMode="name-only"` for overload discovery, but exact `descriptor` matching is still the most reliable path.
201
202
  - Inherited-member expansion (`get-class-members` with `includeInherited: true`, and the `check-symbol-exists` runtime-bytecode fallback that reuses it) suppresses super-class and interface resolution warnings for platform packages that are never inside a Minecraft jar (`java.*`, `javax.*`, `jdk.*`, `sun.*`, `com.mojang.serialization.*`). A warning about any other unresolved super type — including `com.mojang.blaze3d.*` — is a real signal.
@@ -259,6 +260,19 @@ Errors:
259
260
 
260
261
  Set `VERIFY_MIXIN_TARGET_OFF=1` at process start to remove the tool from `tools/list` entirely and reject direct calls. Use as a rollback path while the accessor-inference rules stabilize.
261
262
 
263
+ ## compare-minecraft migration-overview: `libraries`
264
+
265
+ `compare-minecraft` with `task="migration-overview"` includes a `migration.libraries` block (the `migration` block is returned at `detail: "standard"` or `"full"`) diffing the two versions' per-version JSON `libraries` array — the dependencies Minecraft itself ships with (LWJGL, Netty, etc.), which a class or registry diff cannot see. This is how a library swap such as LWJGL's GLFW binding being replaced by SDL surfaces, instead of silently changing behavior underneath a migration.
266
+
267
+ Entries are keyed by `group:artifact` (the Maven coordinate with the version, any trailing `@extension`, and any platform `natives-*` classifier stripped), so a routine version bump or the same library's per-platform native jars never read as churn. Comparison is order-independent: it does not matter what order the two sides' `libraries` arrays list their entries in, and a single side may legitimately carry more than one version for the same `group:artifact` key (Mojang manifests can list different versions on different platform rules) — every version seen on a side is tracked, not just the first.
268
+
269
+ - `migration.libraries.added` / `removed` — sorted arrays of `group:artifact:<versions>` strings for libraries present on only one side, where `<versions>` is the sorted, comma-joined list of distinct versions seen for that key on that side. A key with one version renders as before (e.g. `"org.libsdl:sdl3:3.2.0"`); a key with several platform-specific versions renders as e.g. `"g:a:1,2"`.
270
+ - `migration.libraries.addedCount` / `removedCount` — counts of the above.
271
+ - `migration.libraries.versionChangedCount` — count of `group:artifact` keys present on both sides whose version sets differ. No list is included.
272
+ - `summary.counts.librariesAdded` / `librariesRemoved` — the same added/removed counts, promoted into the top-level summary, so they are visible at `detail: "summary"` too.
273
+
274
+ The block is entirely additive: `summary.status` and `migration.impact` remain computed only from class and registry signals, unaffected by library changes. When per-version library details cannot be fetched (offline, or a fetch failure), the `libraries` block is omitted and a warning is added to the response instead of failing the whole `migration-overview` call. Fetching both sides' library lists is itself bounded by a short internal deadline (5 seconds, not configurable via any tool parameter or environment variable) so that an unreachable network — e.g. right after a restart, when class/registry data is already served from cached jars — cannot stall `migration-overview` for the full underlying fetch timeout; a deadline expiry is reported the same way as any other library-fetch failure: the block is omitted and a "timed out" warning is added. The library fetch already in flight is left to finish in the background and may still warm the cache for a later call.
275
+
262
276
  ## Batch lookup contract
263
277
 
264
278
  `batch-class-source`, `batch-class-members`, `batch-symbol-exists`, and `batch-mappings` share one envelope. Each call sends a fixed shortlist (1..50 entries) and receives a per-entry result plus an aggregate summary. The batch runs `entries.length` underlying calls but resolves the shared artifact ONCE (where applicable), so the round-trip cost is `1 resolve + N per-entry` rather than `N × (resolve + per-entry)`.
@@ -269,7 +283,7 @@ Common input fields:
269
283
  - `concurrency: number` (1..8, default 4) — passed to the worker pool. Above 8 is rejected with `ERR_INVALID_INPUT` (`fieldErrors[0].path === "concurrency"`).
270
284
  - `failFast: boolean` (default `false`) — when `true`, the first per-entry error sets an abort flag. Workers that have not yet picked up an entry short-circuit with `error.code === "ERR_BATCH_ABORTED"`. **In-flight workers continue to completion** — they are not cancelled (no AbortSignal wiring). Already-completed `ok` entries are still returned in `results`.
271
285
  - `detail: "summary" | "standard" | "full"` (default `summary`) + `include[]` — applies the same per-tool projection the corresponding single tool applies at that detail level to each entry's `result`. `detail: "summary"` matches the old `compact: true` per-entry shape; `detail: "full"` matches the old `compact: false` (byte-identical to the single tool's full output).
272
- - Per-tool shared inputs (`target`, `mapping`, `projectPath`, `version`, etc.) follow the same shape as the matching single tool.
286
+ - Per-tool shared inputs (`target`, `mapping`, `projectPath`, `version`, etc.) follow the same shape as the matching single tool. On `batch-class-source` and `batch-class-members`, `target` additionally accepts `{ "kind": "artifact", "artifactId": "..." }` to reuse an already-resolved artifact instead of resolving one — the same reuse shape `get-class-source` / `get-class-members` accept, and the exact shape their own per-entry `suggestedCall` proposes for a retry (see the table below). When `target.kind` is `"artifact"`, the shared `resolveArtifact` call is skipped entirely: `summary.sharedArtifactProvenance` is omitted (no provenance is invented for a reused artifact), and an unknown `artifactId` surfaces per-entry with the same `ERR_SOURCE_NOT_FOUND` a single-tool call would raise, rather than aborting the batch.
273
287
 
274
288
  Resource behavior: `concurrency` limits per-entry dispatch for one batch call. Within one MCP server process, entries or calls that need the same artifact index or decompiled fallback share the in-flight rebuild by `artifactId`. Separate MCP server processes sharing the same cache are not coordinated by this process-local guard.
275
289
 
@@ -387,9 +401,9 @@ Every `ProblemDetails` built from a caught error carries both fields, on every a
387
401
  Because only `issueOrigin` is overridable, the two axes can disagree, and one pairing does so by design. `ERR_CONTEXT_UNRESOLVED` raised on an artifact that carries no binary jar publishes `retryClass: "input"` together with `issueOrigin: "tool_issue"` whenever the tool, not the caller, chose that artifact. `issueOrigin` is the one to act on there: replaying the same artifact cannot produce a different answer, whatever `retryClass` suggests. Which requests count as tool-chosen:
388
402
 
389
403
  - `get-class-members` — every `target.kind` except `"jar"`, `{ "kind": "artifact", "artifactId": ... }` included. An `artifactId` is an opaque handle: its holder cannot tell from it whether the artifact has a binary jar, and cannot re-resolve it either, since `resolve-artifact` does not accept an `artifactId`. Only `target: { "kind": "jar", ... }`, where the caller named the exact jar, reports `issueOrigin: "code_issue"`.
390
- - `batch-class-members` — same rule, applied once to the shared target and repeated on every failed entry. Its target schema has no `"artifact"` kind at all, so only `"jar"` reports `code_issue`.
404
+ - `batch-class-members` — same rule, applied once to the shared target and repeated on every failed entry, including its own `{ "kind": "artifact", "artifactId": ... }` variant: only `"jar"` reports `code_issue`.
391
405
  - `inspect-minecraft` `task="class-members"` — same rule once more: only a subject whose artifact reference is `target: { "kind": "jar", ... }` reports `code_issue`. A subject naming a resolved artifact (`{ "type": "resolved-id", "artifactId": ... }`) reports `tool_issue`, matching the equivalent `get-class-members` target: it is the same opaque handle from an earlier resolve, and wrapping it in a subject does not give the caller any way to vet the artifact's binary jar.
392
- - `verify-mixin-target` — the same rule on its own `target`: the tool reads the target's members from bytecode, so every `target.kind` except `"jar"` reports `tool_issue`. Like `batch-class-members`, its target schema has no `"artifact"` kind at all, so only `"jar"` reports `code_issue`.
406
+ - `verify-mixin-target` — the same rule on its own `target`: the tool reads the target's members from bytecode, so every `target.kind` except `"jar"` reports `tool_issue`. Its target schema has no `"artifact"` kind at all (unlike `batch-class-members`), so only `"jar"` reports `code_issue`.
393
407
 
394
408
  To check whether an artifact carries a binary jar before retrying, call `manage-cache` with `action: "inspect"`, `selector: { "artifactId": ... }` and `include: ["cacheEntries"]`. The `cacheEntries` block reports that artifact's stored `meta.binaryJarPath` — read from the same row the members lookup reads, and absent when the row has none. The `include` is not optional: `manage-cache` defaults to `detail: "summary"`, which drops `cacheEntries` entirely, so without it the reply never shows the field (`detail: "standard"` or `"full"` opts the block back in as well).
395
409
 
@@ -444,6 +458,10 @@ These environment variables are read once at worker startup and provide rollback
444
458
  - `analyze-mod` `task="members"` (subject `{ kind: "class", jarPath, className }`) reads a mod class's constructors/fields/methods (all access levels, including private and protected) straight from bytecode — no decompiler runs on this path, unlike `task="class-source"` which costs a full decompile. Responses mark `extractionMethod: "bytecode-only"`; a class missing from the jar returns `ERR_CLASS_NOT_FOUND`.
445
459
  - Start with `validate-project` for workspace summaries and direct Mixin, Access Widener, or Access Transformer validation before using `validate-mixin`, `validate-access-widener`, or `validate-access-transformer` directly.
446
460
  - `validate-project task="project-summary"` discovers mixins and access wideners by default. Add `discover: ["access-transformers"]` when you also want Access Transformer files included in the workspace summary.
461
+ - `validate-project task="project-summary"` infers an omitted `version` from `gradle.properties` (`minecraft_version`, `mc_version`, or `minecraftVersion`) and adds the warning `version was inferred from the workspace: <version> (source: projectPath:gradle.properties (<projectPath>)).`; the run then behaves exactly like one with `preferProjectVersion: true`. An explicit `version` is used as given unless `preferProjectVersion: true` is also set, which replaces it with the detected project version. The resolved version is passed to every discovered Mixin, Access Widener, and Access Transformer check.
462
+ - `preferProjectVersion: false` turns inference off. Without a `version`, the summary then returns `status: "blocked"` with the headline `project-summary requires version or preferProjectVersion=true.` and a `summary.nextActions` retry that sets `preferProjectVersion: true`.
463
+ - When inference finds no version and discovery found files, the summary returns `status: "blocked"` with the headline `Could not resolve Minecraft version for discovered workspace validators.` Its `summary.nextActions` entry carries `version: "<minecraft-version>"`; replace the placeholder with the project's Minecraft version before retrying.
464
+ - When discovery finds no files, the summary keeps `status: "ok"` but reports `Nothing to validate: no <kinds> were found.` as the headline, where `<kinds>` names only the file kinds `subject.discover` searched, and adds a `warnings` entry beginning `Nothing was validated:`. An `"ok"` status alone therefore does not mean any file passed validation.
447
465
  - `validate-project task="project-summary"` returns an additive `tasks` field alongside the existing aggregate `result.summary` / `result.project` blocks. The headline `result.summary.status` is unchanged; the new field reports per-probe status so a `status: "blocked"` headline still preserves which probes succeeded.
448
466
 
449
467
  | Probe key | What it checks | `status: "ok"` evidence | Other states |
@@ -644,13 +662,34 @@ Tooling note: `pnpm test:manual:stdio-smoke` runs against the production supervi
644
662
 
645
663
  | Namespace | Description |
646
664
  | --- | --- |
647
- | `obfuscated` | Mojang obfuscated names such as `a`, `b`, `c` |
665
+ | `obfuscated` | The runtime jar's names as shipped. On legacy versions these are Mojang obfuscated names such as `a`, `b`, `c`; on unobfuscated releases (`26.1+`) the runtime ships Mojang names, so `obfuscated` and `mojang` name the same classes |
648
666
  | `mojang` | Mojang deobfuscated names from `client_mappings.txt` such as `net.minecraft.server.Main` |
649
667
  | `intermediary` | Fabric stable intermediary names such as `net.minecraft.class_1234` and `method_5678` |
650
668
  | `yarn` | Fabric community human-readable names such as `net.minecraft.server.MinecraftServer` and `tick` |
651
669
 
652
670
  The legacy public namespace name `official` was removed. Requests that still send `official` now fail validation and should be updated to `obfuscated`.
653
671
 
672
+ On an unobfuscated runtime (`26.1+`), `mappingApplied` keeps the label the request asked for: an omitted or `obfuscated` mapping reports `"obfuscated"`, and `mapping="mojang"` reports `"mojang"`. Both read the same Mojang names. The artifact's `provenance` then carries `unobfuscatedRuntime: true`; the field is absent for every other artifact. It is set for 26.1+ version targets, 26.1+ Minecraft runtime coordinates, and jar targets proven to be a 26.1+ Minecraft runtime jar, and it appears wherever the artifact provenance is returned: `resolve-artifact` `provenance` (omitted at its default `detail: "summary"`; pass `include: ["provenance"]` or `detail: "standard"` / `"full"`), `get-class-source` / `get-class-members` `provenance` (omitted at their default `detail: "standard"`; pass `include: ["provenance"]` or `detail: "full"`), and `sharedArtifactProvenance` on `batch-class-source`, `batch-class-members`, and `batch-symbol-exists`. A 26.1+ jar that an earlier release indexed without a version gains the version and the flag the next time `resolve-artifact` proves it; lookups by that `artifactId` then accept `mapping="mojang"`. It is the same flag name as `mappingContext.unobfuscatedRuntime`.
673
+
674
+ ### Known issue: obfuscated label on unobfuscated runtimes
675
+
676
+ On Minecraft `26.1+`, responses label the runtime's names `obfuscated` even though those names are Mojang names. The label is misleading for these versions, because nothing in them is obfuscated. It is kept unchanged for now, and a future major release will correct it.
677
+
678
+ The label appears whenever a request omits `mapping` or passes `mapping: "obfuscated"`:
679
+
680
+ - `mappingApplied: "obfuscated"` from `resolve-artifact`, `get-class-source`, `get-class-members`, and the batch tools, including `target.kind="workspace"` on a 26.1+ project that declares no `mappings` line.
681
+ - `query.mapping: "obfuscated"` from `diff-class-signatures` and `compare-minecraft` with `task="class-diff"`.
682
+ - `mapping: "obfuscated"` in the `tasks["minecraft.artifact.resolved"]` entry of `validate-project`.
683
+
684
+ `list-versions` reports these versions with `unobfuscated: true`, so the two responses disagree about the same names. The label is not changed yet because changing a response value that clients may already compare is a breaking change under this project's semantic-versioning policy.
685
+
686
+ Until the correction ships:
687
+
688
+ - Read `provenance.unobfuscatedRuntime: true` (or `mappingContext.unobfuscatedRuntime: true`) as the signal that the names are Mojang names, whatever `mappingApplied` says. `provenance` is omitted at the default detail levels described above.
689
+ - Pass `mapping: "mojang"` to get responses labelled `"mojang"`. On these versions it reads the same names.
690
+
691
+ Planned correction: a future major release will stop reporting `obfuscated` for runtimes whose names are Mojang names. The replacement is not decided yet: responses could report `mojang`, or a separate namespace value could be added. The CHANGELOG will announce it as a breaking change.
692
+
654
693
  ### Lookup Rules
655
694
 
656
695
  `find-mapping` supports lookup across `obfuscated`, `mojang`, `intermediary`, and `yarn`.
@@ -661,14 +700,17 @@ Symbol query inputs use `kind` plus `name` plus optional `owner` and `descriptor
661
700
  - field: `kind="field"`, `owner="a.b.C"`, `name="fieldName"`
662
701
  - method: `kind="method"`, `owner="a.b.C"`, `name="methodName"`, `descriptor="(I)V"`
663
702
 
664
- `mapping="mojang"` requires a source-backed artifact on legacy obfuscated versions. On unobfuscated releases such as `26.1+`, decompile-only/runtime paths are accepted directly for version and versioned-coordinate targets.
703
+ `mapping="mojang"` requires a source-backed artifact on legacy obfuscated versions. On unobfuscated releases such as `26.1+`, decompile-only/runtime paths are accepted directly for version targets, Minecraft runtime coordinates such as `net.minecraft:client:26.1`, and jar targets proven to be a 26.1+ Minecraft runtime jar.
704
+
705
+ A `target.kind="jar"` path counts as a 26.1+ Minecraft runtime jar only when the jar's own contents prove it: it has a top-level `version.json` whose `id` is an unobfuscated Minecraft version id such as `26.2`, `26.1-rc1`, or `26w14a`, it contains `net/minecraft/SharedConstants.class`, and it contains no `.java` sources. The file path is never used as evidence. Vanilla 26.x client jars and Loom's 26.x Minecraft jars carry all three. A proven jar reports that `id` as its `version`; a jar reached through a `target.kind="dependency"` target is never treated as a runtime jar. A jar that is not proven keeps the legacy rule: `mapping="mojang"` needs a source jar.
665
706
 
666
707
  `resolve-artifact`, `get-class-members`, `trace-symbol-lifecycle`, and `diff-class-signatures` accept `obfuscated | mojang | intermediary | yarn` with these constraints:
667
708
 
668
709
  - `intermediary` and `yarn` require a resolvable Minecraft version context such as `target.kind="version"` or a versioned Maven coordinate.
669
- - For unobfuscated versions such as `26.1+`, requesting `intermediary` or `yarn` falls back to `obfuscated` with a warning.
710
+ - For unobfuscated versions such as `26.1+`, including proven 26.1+ runtime jar targets, requesting `intermediary` or `yarn` falls back to `obfuscated` with a warning.
670
711
  - On legacy obfuscated versions, `mojang` requires source-backed artifacts and decompile-only paths are rejected with `ERR_MAPPING_NOT_APPLIED`.
671
- - On unobfuscated versions such as `26.1+`, `mojang` uses the runtime/decompile path directly for version and versioned-coordinate targets and skips Loom source-jar approximation.
712
+ - On unobfuscated versions such as `26.1+`, both `obfuscated` and `mojang` are accepted for version targets, Minecraft runtime coordinates, and proven 26.1+ runtime jar targets; `mojang` uses the runtime/decompile path directly (`provenance.transformChain` includes `"mapping:mojang-runtime-unobfuscated"`) and skips Loom source-jar approximation.
713
+ - On unobfuscated versions such as `26.1+`, `obfuscated` and `mojang` name the same runtime names. With `mapping="mojang"`, `diff-class-signatures` (`compare-minecraft task="class-diff"`) and `trace-symbol-lifecycle` therefore use member names exactly as read from the runtime jar. They do not look them up in the empty mapping graph, so members are no longer reported with "Could not remap" or "Could not map" warnings.
672
714
 
673
715
  When `trace-symbol-lifecycle` omits `descriptor`, the server resolves methods by owner and name and warns if overload ambiguity prevents a unique answer.
674
716
 
@@ -680,9 +722,9 @@ If callers accidentally append an inline signature suffix to `trace-symbol-lifec
680
722
 
681
723
  `trace-symbol-lifecycle`, `check-symbol-exists`, and `find-mapping` skip intermediary/yarn Tiny graph loading when the request only needs Mojang/obfuscated names, so cold `mojang <-> obfuscated` lifecycle and existence lookups no longer pay the full named-namespace graph cost.
682
724
 
683
- For decompile-only `ERR_MAPPING_NOT_APPLIED` failures, error details include `artifactOrigin`, `nextAction`, and `suggestedCall` so clients can recover without guessing.
725
+ For decompile-only `ERR_MAPPING_NOT_APPLIED` failures, error details include `artifactOrigin`, `nextAction`, and `suggestedCall` so clients can recover without guessing. For a jar target that is not proven to be a 26.1+ runtime jar, a refused request that did not set `scope="vanilla"` gets a `nextAction` saying that `mapping=obfuscated` reads the jar's names as shipped (already Mojang names on Minecraft 26.1+) and that a vanilla Minecraft release is read through `target.kind="version"`; its `suggestedCall` retries the same jar with `mapping: "obfuscated"` and the request's `scope`. A refused `scope="vanilla"` request keeps the scope guidance instead: without a `projectPath`, `nextAction` says that `scope=vanilla` blocks Loom cache discovery and `suggestedCall` retries with `mapping: "obfuscated"` and `scope: "vanilla"`; with a `projectPath`, `suggestedCall` retries with `mapping: "mojang"` and `scope: "merged"`. The one exception is a `projectPath` whose `gradle.properties` names a 26.1+ Minecraft version: that merged retry would repeat the refused request, so a jar or coordinate target is retried with `mapping: "obfuscated"` and `scope: "vanilla"` (a jar with the as-shipped wording above).
684
726
 
685
- If `find-class` or `get-class-source` returns no hit on an obfuscated Minecraft runtime artifact for names like `net.minecraft.world.item.Item`, the tool warns that `obfuscated` means Mojang's runtime names and recommends retrying with `mapping="mojang"` or translating via `find-mapping`. `find-class` does not issue that advice for dependency-resolved or Jar-in-Jar shell artifacts, whose native names are not evidence of Minecraft obfuscation.
727
+ If `find-class` or `get-class-source` returns no hit on an obfuscated legacy (1.x) Minecraft runtime artifact for names like `net.minecraft.world.item.Item`, the tool warns that `obfuscated` means Mojang's runtime names and recommends retrying with `mapping="mojang"` or translating via `find-mapping`. Neither tool issues that advice for dependency-resolved or Jar-in-Jar shell artifacts, whose native names are not evidence of Minecraft obfuscation, or for a 26.1+ Minecraft artifact, whose `obfuscated` names already are Mojang names. On a 26.1+ artifact, a `get-class-source` / `get-class-members` miss starts `nextAction` with the nearest `didYouMean` candidate (`Did you mean "<class>"?`) when the index has one, then points at `find-class`; when the artifact is labelled `obfuscated` and the caller did not pass a non-obfuscated `mapping`, it adds that retrying with a different mapping will not change the class names. A `find-class` miss on a 26.1+ artifact labelled `obfuscated` warns with up to three near-miss class names and the same note.
686
728
 
687
729
  Method descriptor precision is best on Tiny-backed paths (`intermediary` and `yarn`). For `obfuscated <-> mojang`, Mojang `client_mappings` do not carry JVM descriptors, so descriptor queries may fall back to name matching and emit a warning.
688
730
 
@@ -698,6 +740,8 @@ Use `find-mapping` `disambiguation.ownerHint` and `disambiguation.descriptorHint
698
740
 
699
741
  Use `resolve-workspace-symbol` when you need compile-visible names from actual Gradle Loom mappings in a workspace.
700
742
 
743
+ A Loom project for an unobfuscated version such as `26.1+` has no `mappings` line, because it compiles against the runtime (Mojang) names. When `build.gradle(.kts)` declares no mappings and the version is unobfuscated, `resolve-workspace-symbol` and `analyze-symbol task="workspace"` look the symbol up by name in the runtime jar's bytecode. They no longer return `mapping_unavailable` (`analyze-symbol` status `partial`). The response reports `workspaceDetection.resolved: true` and `mappingApplied: "mojang"` with empty `evidence`, and `mappingContext` reports `targetMapping: "mojang"` and `unobfuscatedRuntime: true`. A warning explains that no mappings declaration is needed. `sourceMapping` is echoed as requested, so the default `obfuscated` stays `obfuscated`. A class that is not in the Minecraft runtime jar, such as the library class `org.lwjgl.glfw.GLFW`, returns `not_found` with a warning that names the jar, and so does a member that the loaded class does not have. A method query named `<init>` is checked against the class's own constructors. `not_found` is reserved for those two answers: a lookup the runtime jar could not answer - a short (not fully qualified) class name, or a class that failed to load for any reason other than being absent - returns `mapping_unavailable` with a warning that gives the reason. `sourceMapping` `intermediary` or `yarn` returns `mapping_unavailable`, because those names do not exist on these versions. If the runtime jar cannot be resolved, the result also stays `mapping_unavailable`. The runtime lookup applies only when `projectPath` holds a readable `build.gradle(.kts)`: a missing, mistyped, or empty project directory keeps the `mapping_unavailable` result with the "No compile-time mapping declaration" warning. Projects that declare mappings, and legacy versions, keep the behavior described above.
744
+
701
745
  ## Environment Variables
702
746
 
703
747
  Path-based overrides treat blank values and the literal strings `undefined` and `null` as unset, so accidental client serialization does not create `./undefined` or `./null` cache roots or broken JAR override paths.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhisang/minecraft-modding-mcp",
3
- "version": "7.0.0",
3
+ "version": "7.1.0",
4
4
  "description": "MCP server for AI-assisted Minecraft modding: inspect decompiled source, resolve Mojang/Yarn/Intermediary mappings, diff versions, analyze Fabric/Forge/NeoForge mod JARs, and validate Mixin, Access Widener, and Access Transformer files.",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.30.1",