@adhisang/minecraft-modding-mcp 1.2.0 → 2.0.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,44 @@ All notable changes to this project are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project aims to follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [2.0.0] - 2026-03-07
11
+
12
+ ### Changed
13
+ - Breaking change: the public mapping namespace `official` was removed and replaced with `obfuscated` across tool inputs, outputs, API matrix keys, diagnostics, and examples. Requests that still send `official` now fail with `ERR_INVALID_INPUT` and should be updated to `obfuscated`.
14
+ - Breaking change: `resolve-artifact` now accepts `target: { kind, value }` instead of top-level `targetKind` / `targetValue`. `get-class-source` and `get-class-members` now require `target: { type: "artifact", artifactId }` or `target: { type: "resolve", kind, value }` instead of top-level `artifactId` / `targetKind` / `targetValue`.
15
+ - Breaking change: `resolve-method-mapping-exact` is now method-only and no longer accepts `kind`; callers must send `owner` and `descriptor`.
16
+ - Breaking change: `validate-mixin` replaced the mutually exclusive top-level source selector fields (`source`, `sourcePath`, `sourcePaths`, `mixinConfigPath`, `sourceRoot`) with `input.mode` plus `input.source` / `input.path` / `input.paths[]` / `input.configPaths[]` and `sourceRoots[]`.
17
+ - Breaking change: `validate-mixin` now always returns normalized batch-style output with `mode`, `results[]`, and `summary`. The deprecated `summary.errors` field was removed; use `summary.processingErrors` instead.
18
+ - Breaking change: `search-class-source` now returns compact hits only. The removed `snippetLines`, `includeDefinition`, and `includeOneHop` inputs no longer trigger snippet/definition/relation expansion, `totalApprox` was removed from responses, and `symbolKind` is only valid with `intent=symbol`.
19
+ - MCP tool responses now mirror the `{ result?, error?, meta }` envelope in `structuredContent`, and failures also set `isError=true` for SDK-aware clients.
20
+ - MCP resources: JSON resources now return structured `{ result, meta }` success envelopes and `{ error, meta }` failures. Text resources (`class-source`, `artifact-file`) still return raw text on success, but now also use structured JSON errors on failure.
21
+
22
+ ### Fixed
23
+ - `resolve-artifact`: `targetKind=coordinate` now reuses the local Gradle `modules-2` cache in addition to the local Maven repository and configured source repos, so cached third-party libraries such as Architectury can resolve without manual cache spelunking.
24
+ - `resolve-artifact`: `mapping=mojang` + Loom merged source discovery now flags partial source coverage with `qualityFlags=["partial-source-no-net-minecraft"]` and a warning when the selected source jar does not actually contain `net.minecraft` entries.
25
+ - `get-class-source` / `get-class-members`: when an artifact is resolved from a `*-sources.jar`, the server now keeps the sibling binary jar and automatically falls back to it when source coverage is incomplete instead of treating the source jar as bytecode.
26
+ - `get-class-source`: partial-source binary fallback now bypasses the same sibling `*-sources.jar` that triggered the miss, and fallback failures for vanilla classes point to `get-class-api-matrix` instead of misleading `find-class` recovery.
27
+ - `get-class-members`: bytecode lookup now follows the resolved artifact namespace (`mappingApplied`) before remapping members back to the requested namespace, fixing merged Mojang artifacts that were incorrectly forced through obfuscated class names.
28
+ - `find-class`: zero-hit lookups against `mapping=obfuscated` now warn when the query looks like a deobfuscated Mojang class name.
29
+ - `find-class`: partial-source artifacts now suppress non-vanilla matches for vanilla-looking queries (for example `Item`) and return a warning instead of misleading modded classes.
30
+ - Tool input parsing: positive integer parameters now accept numeric strings such as `"10"` instead of failing validation immediately.
31
+ - Tool input parsing now leaves nested `typedJson` and JSON Patch `value` payload fields untouched, even when their keys happen to match top-level numeric option names such as `limit` or `maxLines`.
32
+
33
+ ### Performance
34
+ - `search-class-source`: reduce search latency, heap growth, and DB round-trips by returning compact hits only and skipping snippet hydration, relation expansion, and `totalApprox` count queries.
35
+ - Tool input preprocessing now stays shallow, avoiding recursive scans through large nested payloads such as NBT typed JSON and patch bodies.
36
+
37
+ ## [1.2.1] - 2026-03-05
38
+
39
+ ### Fixed
40
+ - MCP startup regression: removed eager `SourceService` pre-initialization during server startup so `tools/list` handshakes are not blocked by SQLite initialization on slower environments.
41
+ - Decompiler: skip Java/Vineflower availability checks when decompiled source is already cached, avoiding unnecessary startup errors on systems without Java.
42
+
43
+ ### Documentation
44
+ - Clarified startup behavior in README (`SourceService` remains lazy and is not pre-initialized before tool discovery).
45
+
8
46
  ## [1.2.0] - 2026-03-05
9
47
 
10
48
  ### Added
@@ -48,7 +86,6 @@ and this project aims to follow [Semantic Versioning](https://semver.org/spec/v2
48
86
  ### Changed
49
87
  - Lazy `SourceService` initialization — deferred until first tool/resource access, reducing cold-start latency during MCP handshake.
50
88
  - Eagerly init `SourceService` during MCP handshake idle time for faster first-request response.
51
- - Codecov workflow temporarily disabled.
52
89
 
53
90
  ### Performance
54
91
  - Avoid duplicate UTF-8 decode during truncation.
package/README.md CHANGED
@@ -11,14 +11,14 @@
11
11
 
12
12
  `@adhisang/minecraft-modding-mcp` is an [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that gives AI assistants deep access to Minecraft's source code, mappings, and mod tooling.
13
13
 
14
- It lets you explore decompiled Minecraft source, convert symbol names across four naming namespaces (`official`, `mojang`, `intermediary`, `yarn`), analyze and decompile Fabric/Forge/NeoForge mod JARs, validate Mixin and Access Widener files, read and patch NBT data, and query generated registry snapshots — all through a structured tool and resource interface designed for Claude Desktop, VS Code, and other MCP-capable clients.
14
+ It lets you explore decompiled Minecraft source, convert symbol names across four naming namespaces (`obfuscated`, `mojang`, `intermediary`, `yarn`), analyze and decompile Fabric/Forge/NeoForge mod JARs, validate Mixin and Access Widener files, read and patch NBT data, and query generated registry snapshots — all through a structured tool and resource interface designed for Claude Desktop, VS Code, and other MCP-capable clients.
15
15
 
16
16
  **29 tools** | **7 resources** | **4 namespace mappings** | **SQLite-backed cache**
17
17
 
18
18
  ## Features
19
19
 
20
20
  - **Source Exploration** — Browse and search decompiled Minecraft source code with line-level precision and cursor-paginated file listing
21
- - **Multi-Mapping Conversion** — Translate class, field, and method names between `official`, `mojang`, `intermediary`, and `yarn` namespaces
21
+ - **Multi-Mapping Conversion** — Translate class, field, and method names between `obfuscated`, `mojang`, `intermediary`, and `yarn` namespaces
22
22
  - **Symbol Lifecycle Tracking** — Trace when a method or field first appeared, disappeared, or changed across Minecraft versions
23
23
  - **Mod JAR Analysis** — Extract metadata, dependencies, entrypoints, and Mixin configs from Fabric/Forge/NeoForge mod JARs
24
24
  - **Mixin & Access Widener Validation** — Parse and validate Mixin source and `.accesswidener` files against a target Minecraft version
@@ -58,6 +58,7 @@ codex mcp list
58
58
  The stdio transport auto-detects both newline-delimited and `Content-Length` framing, so Codex and newline-based MCP clients can use the same server command.
59
59
 
60
60
  The server now lazily initializes heavyweight source/index services on first MCP request, reducing initial process startup latency for clients that only perform handshake/tool discovery.
61
+ To preserve handshake reliability across clients, startup does not eagerly pre-initialize `SourceService` before tool discovery.
61
62
 
62
63
  #### Gemini CLI
63
64
 
@@ -178,11 +179,11 @@ Tools for browsing Minecraft versions, resolving source artifacts, and reading/s
178
179
  | Tool | Purpose | Key Inputs | Key Outputs |
179
180
  | --- | --- | --- | --- |
180
181
  | `list-versions` | List available Minecraft versions from Mojang manifest + local cache | `includeSnapshots?`, `limit?` | `result.latest`, `result.releases[]`, `meta.warnings[]` |
181
- | `resolve-artifact` | Resolve source artifact from `version` / `jar` / `coordinate` | `targetKind`, `targetValue`, `mapping?`, `sourcePriority?`, `allowDecompile?`, `projectPath?`, `scope?`, `preferProjectVersion?`, `strictVersion?` | `artifactId`, `origin`, `mappingApplied`, `qualityFlags[]`, `adjacentSourceCandidates?`, `sampleEntries?`, `warnings[]` |
182
+ | `resolve-artifact` | Resolve source artifact from `version` / `jar` / `coordinate` | `target`, `mapping?`, `sourcePriority?`, `allowDecompile?`, `projectPath?`, `scope?`, `preferProjectVersion?`, `strictVersion?` | `artifactId`, `origin`, `mappingApplied`, `qualityFlags[]`, `adjacentSourceCandidates?`, `sampleEntries?`, `warnings[]` |
182
183
  | `find-class` | Resolve simple or fully-qualified class names inside an artifact | `className`, `artifactId`, `limit?` | `matches[]`, `total`, `warnings[]` |
183
- | `get-class-source` | Get class source by `artifactId` or resolve target on demand (`mode=metadata` by default) | `className`, `mode?`, `artifactId?`, `targetKind?`, `targetValue?`, `projectPath?`, `scope?`, `preferProjectVersion?`, `strictVersion?`, `startLine?`, `endLine?`, `maxLines?`, `maxChars?`, `outputFile?` | `mode`, `sourceText`, `returnedRange`, `truncated`, `charsTruncated?`, `outputFile?`, `artifactId`, mapping/provenance metadata |
184
- | `get-class-members` | Get class fields/methods/constructors from bytecode | `className`, `artifactId?`, `targetKind?`, `targetValue?`, `mapping?`, `access?`, `includeInherited?`, `maxMembers?`, `strictVersion?` | `members.{constructors,fields,methods}`, `counts`, `truncated`, `context`, `warnings[]` |
185
- | `search-class-source` | Search indexed class source for symbols/text/path | `artifactId`, `query`, `intent?`, `match?`, `packagePrefix?`, `fileGlob?`, `symbolKind?`, `snippetLines?`, `includeDefinition?`, `includeOneHop?`, `queryMode?`, `limit?`, `cursor?` | `hits[]`, `relations?`, `nextCursor?`, `totalApprox`, `mappingApplied` |
184
+ | `get-class-source` | Get class source by artifact target or resolve target on demand (`mode=metadata` by default) | `className`, `target`, `mode?`, `projectPath?`, `scope?`, `preferProjectVersion?`, `strictVersion?`, `startLine?`, `endLine?`, `maxLines?`, `maxChars?`, `outputFile?` | `mode`, `sourceText`, `returnedRange`, `truncated`, `charsTruncated?`, `outputFile?`, `artifactId`, mapping/provenance metadata |
185
+ | `get-class-members` | Get class fields/methods/constructors from bytecode | `className`, `target`, `mapping?`, `access?`, `includeInherited?`, `maxMembers?`, `strictVersion?` | `members.{constructors,fields,methods}`, `counts`, `truncated`, `context`, `warnings[]` |
186
+ | `search-class-source` | Search indexed class source for symbols/text/path | `artifactId`, `query`, `intent?`, `match?`, `packagePrefix?`, `fileGlob?`, `symbolKind?`, `queryMode?`, `limit?`, `cursor?` | `hits[]`, `nextCursor?`, `mappingApplied` |
186
187
  | `get-artifact-file` | Read full source file with byte guard | `artifactId`, `filePath`, `maxBytes?` | `content`, `contentBytes`, `truncated`, `mappingApplied` |
187
188
  | `list-artifact-files` | List indexed source file paths with cursor pagination | `artifactId`, `prefix?`, `limit?`, `cursor?` | `items[]`, `nextCursor?`, `mappingApplied` |
188
189
  | `index-artifact` | Rebuild index metadata for an existing artifact | `artifactId`, `force?` | `reindexed`, `reason`, `counts`, `indexedAt`, `durationMs` |
@@ -204,8 +205,8 @@ Tools for converting symbol names between namespaces and checking symbol existen
204
205
  | Tool | Purpose | Key Inputs | Key Outputs |
205
206
  | --- | --- | --- | --- |
206
207
  | `find-mapping` | Find mapping candidates for class/field/method symbols between namespaces | `version`, `kind`, `name`, `owner?`, `descriptor?`, `sourceMapping`, `targetMapping`, `sourcePriority?`, `disambiguation?` | `querySymbol`, `mappingContext`, `resolved`, `status`, `resolvedSymbol?`, `candidates[]`, `ambiguityReasons?`, `provenance?`, `meta.warnings[]` |
207
- | `resolve-method-mapping-exact` | Resolve one method mapping with strict owner+name+descriptor matching | `version`, `kind` (`method`), `name`, `owner`, `descriptor`, `sourceMapping`, `targetMapping`, `sourcePriority?` | `querySymbol`, `mappingContext`, `resolved`, `status`, `resolvedSymbol?`, `candidates[]`, `provenance?`, `meta.warnings[]` |
208
- | `get-class-api-matrix` | Show one class API as a mapping matrix (`official/mojang/intermediary/yarn`) | `version`, `className`, `classNameMapping`, `includeKinds?`, `sourcePriority?` | `classIdentity`, `rows[]`, `ambiguousRowCount?`, `meta.warnings[]` |
208
+ | `resolve-method-mapping-exact` | Resolve one method mapping with strict owner+name+descriptor matching | `version`, `name`, `owner`, `descriptor`, `sourceMapping`, `targetMapping`, `sourcePriority?` | `querySymbol`, `mappingContext`, `resolved`, `status`, `resolvedSymbol?`, `candidates[]`, `provenance?`, `meta.warnings[]` |
209
+ | `get-class-api-matrix` | Show one class API as a mapping matrix (`obfuscated/mojang/intermediary/yarn`) | `version`, `className`, `classNameMapping`, `includeKinds?`, `sourcePriority?` | `classIdentity`, `rows[]`, `ambiguousRowCount?`, `meta.warnings[]` |
209
210
  | `resolve-workspace-symbol` | Resolve compile-visible symbol names for a Gradle workspace (`build.gradle/.kts`) | `projectPath`, `version`, `kind`, `name`, `owner?`, `descriptor?`, `sourceMapping`, `sourcePriority?` | `querySymbol`, `mappingContext`, `resolved`, `status`, `resolvedSymbol?`, `candidates[]`, `workspaceDetection`, `meta.warnings[]` |
210
211
  | `check-symbol-exists` | Strict symbol presence check for class/field/method | `version`, `kind`, `name`, `owner?`, `descriptor?`, `sourceMapping`, `sourcePriority?`, `nameMode?`, `signatureMode?` | `querySymbol`, `mappingContext`, `resolved`, `status`, `resolvedSymbol?`, `candidates[]`, `meta.warnings[]` |
211
212
 
@@ -237,7 +238,7 @@ Tools for validating Mixin source and Access Widener files against a target Mine
237
238
 
238
239
  | Tool | Purpose | Key Inputs | Key Outputs |
239
240
  | --- | --- | --- | --- |
240
- | `validate-mixin` | Parse/validate Mixin source against target Minecraft version | `source?`, `sourcePath?`, `sourcePaths?`, `mixinConfigPath?`, `sourceRoot?`, `sourceRoots?`, `version`, `mapping?`, `sourcePriority?`, `projectPath?`, `scope?`, `preferProjectVersion?`, `minSeverity?`, `hideUncertain?`, `warningMode?`, `preferProjectMapping?`, `reportMode?`, `warningCategoryFilter?`, `treatInfoAsWarning?`, `explain?` | single: `valid`, `issues[]`, `warnings[]`, `structuredWarnings?`, `aggregatedWarnings?`, `summary` (incl. `parseWarnings`), `unfilteredSummary?`, `provenance?`, `resolvedMembers?`, `toolHealth?`, `confidenceScore?`; batch: `results[]`, `summary`, `toolHealth?` |
241
+ | `validate-mixin` | Parse/validate Mixin source against target Minecraft version | `input`, `sourceRoots?`, `version`, `mapping?`, `sourcePriority?`, `projectPath?`, `scope?`, `preferProjectVersion?`, `minSeverity?`, `hideUncertain?`, `warningMode?`, `preferProjectMapping?`, `reportMode?`, `warningCategoryFilter?`, `treatInfoAsWarning?`, `explain?` | `mode`, `results[]`, `summary`, `issueSummary?`, `toolHealth?`, `confidenceScore?` |
241
242
  | `validate-access-widener` | Parse/validate Access Widener content against target version | `content`, `version`, `mapping?`, `sourcePriority?` | `valid`, `issues[]`, `warnings[]`, `summary` |
242
243
 
243
244
  ### Registry & Diagnostics
@@ -251,33 +252,47 @@ Tools for querying generated registry data and inspecting server runtime state.
251
252
 
252
253
  ### Tool Constraints
253
254
 
254
- `get-class-source` requires either `artifactId` or `targetKind`+`targetValue`. Supplying both is rejected.
255
- `get-class-members` requires either `artifactId` or `targetKind`+`targetValue`, and needs a binary jar (`binaryJarPath`) to read `.class` entries.
256
- `validate-mixin` requires exactly one of `source`, `sourcePath`, `sourcePaths`, or `mixinConfigPath`. `sourcePath`/`sourcePaths[]` are normalized for host/WSL path formats before file reads. `mixinConfigPath` reads a mixin config JSON and auto-discovers source files for batch validation (`sourceRoots[]` or `sourceRoot` override lookup roots; otherwise common roots like `src/main/java`, `src/client/java`, `common/src/{main,client}/java`, `fabric/src/{main,client}/java`, `neoforge/src/{main,client}/java`, `forge/src/{main,client}/java`, and `quilt/src/{main,client}/java` are auto-detected from configured mixin classes).
257
- `validate-mixin` single-file responses include `provenance.resolutionNotes?` when mapping fallback occurs.
255
+ `resolve-artifact` now takes `target: { kind, value }`.
256
+ `get-class-source` requires `target`, where `target.type="artifact"` selects a previously resolved `artifactId` and `target.type="resolve"` supplies `{ kind, value }` directly.
257
+ `get-class-members` requires the same `target` object shape and still needs a binary jar (`binaryJarPath`) to read `.class` entries.
258
+ Positive integer tool parameters accept numeric strings such as `"10"` in addition to JSON numbers.
259
+ This numeric-string coercion only applies to documented top-level tool arguments; nested `typedJson` payloads and JSON Patch `value` objects are preserved verbatim.
260
+ `validate-mixin` requires `input.mode` to be exactly one of `inline`, `path`, `paths`, or `config`. `input.path`/`input.paths[]` are normalized for host/WSL path formats before file reads. `input.configPaths[]` reads mixin config JSON files and auto-discovers source files for batch validation (`sourceRoots[]` override lookup roots; otherwise common roots like `src/main/java`, `src/client/java`, `common/src/{main,client}/java`, `fabric/src/{main,client}/java`, `neoforge/src/{main,client}/java`, `forge/src/{main,client}/java`, and `quilt/src/{main,client}/java` are auto-detected from configured mixin classes).
261
+ `validate-mixin` always returns `mode`, `results[]`, and `summary`; single-input modes still use a one-element `results[]` array.
262
+ `validate-mixin` per-result responses include `provenance.resolutionNotes?` when mapping fallback occurs.
258
263
  `validate-mixin` validates `@Invoker` targets against methods only and `@Accessor` targets against fields only.
259
264
  `validate-mixin` parser supports both `.class` literal targets and `targets = "..."` / `targets = {"a", "b"}` string forms.
260
265
  `validate-mixin` parser handles multi-line annotations between `@Shadow`/`@Accessor` and declarations, and strips inline annotations from declaration lines.
261
266
  `validate-mixin` distinguishes `target-mapping-failed` (warning, uncertain) from `target-not-found` (error) when class mapping fails.
262
267
  `validate-mixin` issues and `structuredWarnings` include `category` (`mapping`, `configuration`, `validation`, `resolution`, or `parse`) to distinguish setup/tooling/parser limits from real validation errors.
263
268
  `validate-mixin` supports post-filtering with `minSeverity`, `hideUncertain`, and `warningCategoryFilter`; `treatInfoAsWarning=false` suppresses info-level entries in `structuredWarnings`.
264
- `validate-mixin` single-file responses include `resolvedMembers?` tracking each member's resolution status (`resolved` or `not-found`).
269
+ `validate-mixin` per-result responses include `resolvedMembers?` tracking each member's resolution status (`resolved` or `not-found`).
265
270
  `validate-mixin` with `explain=true` enriches each issue with `explanation` and `suggestedCall` (tool + params) for agent-driven recovery.
266
- `validate-mixin` batch `summary` uses `processingErrors` (exception count), `totalValidationErrors`, and `totalValidationWarnings` instead of the ambiguous `errors` field.
267
- `resolve-artifact` with `targetKind=version` uses Loom cache discovery from `projectPath` only when `mapping=mojang`; mapping failures include `searchedPaths`, `candidateArtifacts`, and `recommendedCommand` in error details.
268
- `resolve-artifact` supports `scope` (`vanilla`/`merged`/`loader`) and optional `preferProjectVersion=true` to override `targetValue` from `gradle.properties` (`minecraft_version`, `mc_version`, `minecraftVersion`) when `targetKind=version`.
271
+ `validate-mixin` summary uses `processingErrors`, `totalValidationErrors`, and `totalValidationWarnings`; the deprecated `summary.errors` field was removed.
272
+ `resolve-artifact` with `target.kind=version` uses Loom cache discovery from `projectPath` only when `mapping=mojang`; mapping failures include `searchedPaths`, `candidateArtifacts`, and `recommendedCommand` in error details.
273
+ `resolve-artifact` supports `scope` (`vanilla`/`merged`/`loader`) and optional `preferProjectVersion=true` to override `target.value` from `gradle.properties` (`minecraft_version`, `mc_version`, `minecraftVersion`) when `target.kind=version`.
274
+ `resolve-artifact` with `target.kind=coordinate` searches the local Maven repository, the local Gradle `modules-2` cache, and configured `MCP_SOURCE_REPOS` before reporting `ERR_SOURCE_NOT_FOUND`.
269
275
  `resolve-artifact` includes `sampleEntries` only when a source JAR is resolved; decompile-only paths leave it unset.
276
+ `resolve-artifact` adds `qualityFlags=["partial-source-no-net-minecraft"]` and a warning when a merged Loom source candidate does not contain `net.minecraft` sources; `get-class-source` now bypasses that sibling `*-sources.jar` during binary fallback so the fallback can actually reach the binary artifact.
270
277
  `find-class` returns type symbols (`class`/`interface`/`enum`/`record`) only; fully-qualified lookups are filtered by exact FQCN/file path to avoid false negatives when many classes share the same simple name.
271
- `search-class-source` uses `limit: 20` by default; `snippetLines` defaults to `8` and is clamped to `1..80`; `includeDefinition` and `includeOneHop` default to `false`.
278
+ `find-class` returns an explanatory warning when an `obfuscated` artifact is queried with names that look like deobfuscated Mojang classes.
279
+ `find-class` suppresses non-vanilla matches for vanilla-looking queries on artifacts flagged with `partial-source-no-net-minecraft`; in that situation it returns a warning instead of unrelated modded classes.
280
+ `search-class-source` uses `limit: 20` by default.
272
281
  `search-class-source` `queryMode` controls text search strategy: `auto` (default) uses indexed token search with literal fallback for separator queries, `token` keeps indexed token behavior only, and `literal` uses substring scan only.
273
282
  `search-class-source` with `match=regex` enforces `query.length <= 200` and a strict result cap of `100`.
283
+ `search-class-source` now returns compact file hits without snippets, line windows, relation expansion, or `totalApprox`.
284
+ Use `get-artifact-file` or `get-class-source` to inspect returned files after search.
285
+ `search-class-source` `symbolKind` is only supported when `intent=symbol`.
274
286
  `get-artifact-file` byte truncation now preserves UTF-8 character boundaries, preventing replacement-character (`�`) corruption when `maxBytes` cuts through multibyte text.
275
287
  `search-class-source` `fileGlob` supports `*`, `**`, and `?`; recursive patterns such as `net/minecraft/**/*.java` are supported.
276
288
  `get-class-source` fallback matching enforces package compatibility and returns `ERR_CLASS_NOT_FOUND` when only name-colliding classes from other packages exist.
289
+ `get-class-source` now falls back to the sibling binary artifact when a source-backed artifact is only partial (for example, merged Loom sources without `net.minecraft` entries); if that fallback still cannot produce source, the error now carries the partial-source context and suggests `get-class-api-matrix` instead of `find-class`.
290
+ `get-class-source` warns when fallback source text is returned in a different namespace than the requested mapping; the source text itself is not remapped.
277
291
  `get-class-source` mode defaults to `metadata` (symbol outline only); `mode=snippet` auto-sets `maxLines=200` when no line range/max is provided; `mode=full` returns the entire source. `outputFile` writes the selected text and returns the file path in `outputFile`.
278
292
  Decompile fallback for `resolve-artifact`/`get-class-source` now invokes Vineflower with flags before positional `<input-jar> <output-dir>` arguments to avoid false `ERR_DECOMPILER_FAILED` outcomes on valid jars.
279
- `resolve-artifact` with `targetKind=jar` only auto-adopts the exact sibling `"<jar-basename>-sources.jar"`. Other adjacent `*-sources.jar` files are returned as `adjacentSourceCandidates` info only and are never auto-selected.
280
- For `targetKind=coordinate` with a classifier (`group:artifact:version:classifier`), local Maven source lookup checks `<artifact>-<version>-<classifier>-sources.jar` first and then `<artifact>-<version>-sources.jar`.
293
+ `resolve-artifact` with `target.kind=jar` only auto-adopts the exact sibling `"<jar-basename>-sources.jar"`. Other adjacent `*-sources.jar` files are returned as `adjacentSourceCandidates` info only and are never auto-selected.
294
+ When a resolved artifact comes from a `*-sources.jar`, `get-class-members` now keeps the sibling binary jar (for example `minecraft-merged-<version>.jar`) instead of treating the source jar as bytecode, and it now looks up the class in the resolved artifact namespace before remapping member names back to the requested mapping.
295
+ For `target.kind=coordinate` with a classifier (`group:artifact:version:classifier`), local Maven source lookup checks `<artifact>-<version>-<classifier>-sources.jar` first and then `<artifact>-<version>-sources.jar`.
281
296
  Mod tool `jarPath` inputs are normalized to a canonical local `.jar` file path before existence checks, cache keying, and processing.
282
297
  `search-mod-source` enforces `query.length <= 200` and `limit <= 200`.
283
298
  `search-mod-source` detects source-only jars and searches `.java` entries directly without decompilation.
@@ -287,6 +302,12 @@ Mod tool `jarPath` inputs are normalized to a canonical local `.jar` file path b
287
302
  `check-symbol-exists` defaults to strict FQCN class inputs; set `nameMode=auto` to allow short class names (ambiguous matches return `status=ambiguous`).
288
303
  `check-symbol-exists` supports `signatureMode=name-only` to match methods by owner+name without requiring a descriptor. Single match returns `resolved`; multiple overloads return `ambiguous` with all candidates.
289
304
  `check-symbol-exists` always validates input shape first and returns `ERR_INVALID_INPUT` for invalid symbol combinations, even when mapping data is unavailable.
305
+ Migration notes:
306
+ - Replace `resolve-artifact` `targetKind` + `targetValue` with `target: { kind, value }`.
307
+ - Replace `get-class-source` / `get-class-members` top-level `artifactId` / `targetKind` / `targetValue` with `target: { type: "artifact", artifactId }` or `target: { type: "resolve", kind, value }`.
308
+ - `resolve-method-mapping-exact` is method-only and no longer accepts `kind`.
309
+ - Replace `validate-mixin` `source` / `sourcePath` / `sourcePaths` / `mixinConfigPath` / `sourceRoot` with `input.mode` plus `input.source` / `input.path` / `input.paths[]` / `input.configPaths[]` and `sourceRoots[]`. Use `summary.processingErrors` instead of `summary.errors`.
310
+ - `search-class-source` removed `snippetLines`, `includeDefinition`, and `includeOneHop`; responses now contain compact `hits[]` plus `nextCursor?` only, and `symbolKind` may only be used with `intent=symbol`.
290
311
  `remap-mod-jar` requires Java to be installed and only supports Fabric/Quilt mods.
291
312
 
292
313
  ## Resources
@@ -310,6 +331,9 @@ MCP resources provide URI-based access to Minecraft data, usable by any MCP clie
310
331
  | `class-members` | `mc://artifact/{artifactId}/members/{className}` | List constructors, methods, and fields for a class |
311
332
  | `artifact-metadata` | `mc://artifact/{artifactId}` | Metadata for a previously resolved artifact |
312
333
 
334
+ `versions-list`, `runtime-metrics`, `find-mapping`, `class-members`, and `artifact-metadata` return structured JSON envelopes on success (`{ result, meta }`) and failure (`{ error, meta }`).
335
+ `class-source` and `artifact-file` keep raw text responses on success, but still return structured JSON errors on failure.
336
+
313
337
  ## Response Envelope
314
338
 
315
339
  All tools return exactly one of:
@@ -317,6 +341,9 @@ All tools return exactly one of:
317
341
  - Success: `{ result: { ... }, meta: { requestId, tool, durationMs, warnings[] } }`
318
342
  - Failure: `{ error: { type, title, detail, status, code, instance, fieldErrors?, hints? }, meta: { requestId, tool, durationMs, warnings[] } }`
319
343
 
344
+ JSON resources follow the same `result/error/meta` pattern. Text resources return plain text on success.
345
+ The same JSON envelope is mirrored in MCP `structuredContent` for SDK-aware clients, and failures also set `isError=true`.
346
+
320
347
  ## Examples
321
348
 
322
349
  ### Source Exploration
@@ -326,9 +353,11 @@ All tools return exactly one of:
326
353
  {
327
354
  "tool": "resolve-artifact",
328
355
  "arguments": {
329
- "targetKind": "version",
330
- "targetValue": "1.21.10",
331
- "mapping": "official",
356
+ "target": {
357
+ "kind": "version",
358
+ "value": "1.21.10"
359
+ },
360
+ "mapping": "obfuscated",
332
361
  "allowDecompile": true,
333
362
  "projectPath": "/path/to/mod/workspace"
334
363
  }
@@ -340,7 +369,10 @@ All tools return exactly one of:
340
369
  {
341
370
  "tool": "get-class-source",
342
371
  "arguments": {
343
- "artifactId": "<artifact-id>",
372
+ "target": {
373
+ "type": "artifact",
374
+ "artifactId": "<artifact-id>"
375
+ },
344
376
  "className": "net.minecraft.server.Main",
345
377
  "startLine": 50,
346
378
  "endLine": 180,
@@ -357,8 +389,7 @@ All tools return exactly one of:
357
389
  "artifactId": "<artifact-id>",
358
390
  "query": "tickServer",
359
391
  "intent": "symbol",
360
- "match": "exact",
361
- "includeOneHop": true
392
+ "match": "exact"
362
393
  }
363
394
  }
364
395
  ```
@@ -370,7 +401,7 @@ All tools return exactly one of:
370
401
  "arguments": {
371
402
  "artifactId": "<artifact-id>",
372
403
  "className": "net.minecraft.server.Main",
373
- "mapping": "official",
404
+ "mapping": "obfuscated",
374
405
  "access": "all",
375
406
  "includeInherited": true,
376
407
  "maxMembers": 300
@@ -417,7 +448,7 @@ List source files under a specific package to understand project structure:
417
448
  "className": "net.minecraft.server.Main",
418
449
  "fromVersion": "1.20.1",
419
450
  "toVersion": "1.21.10",
420
- "mapping": "official"
451
+ "mapping": "obfuscated"
421
452
  }
422
453
  }
423
454
  ```
@@ -449,7 +480,7 @@ Get a high-level summary of what changed between two releases, including class a
449
480
  "version": "1.21.10",
450
481
  "kind": "class",
451
482
  "name": "a.b.C",
452
- "sourceMapping": "official",
483
+ "sourceMapping": "obfuscated",
453
484
  "targetMapping": "mojang",
454
485
  "sourcePriority": "loom-first",
455
486
  "disambiguation": {
@@ -469,7 +500,7 @@ Get a high-level summary of what changed between two releases, including class a
469
500
  "name": "tick",
470
501
  "owner": "a.b.C",
471
502
  "descriptor": "(I)V",
472
- "sourceMapping": "official",
503
+ "sourceMapping": "obfuscated",
473
504
  "targetMapping": "intermediary"
474
505
  }
475
506
  }
@@ -481,11 +512,10 @@ Get a high-level summary of what changed between two releases, including class a
481
512
  "tool": "resolve-method-mapping-exact",
482
513
  "arguments": {
483
514
  "version": "1.21.10",
484
- "kind": "method",
485
515
  "name": "f",
486
516
  "owner": "a.b.C",
487
517
  "descriptor": "(Ljava/lang/String;)V",
488
- "sourceMapping": "official",
518
+ "sourceMapping": "obfuscated",
489
519
  "targetMapping": "mojang"
490
520
  }
491
521
  }
@@ -498,7 +528,7 @@ Get a high-level summary of what changed between two releases, including class a
498
528
  "arguments": {
499
529
  "version": "1.21.10",
500
530
  "className": "a.b.C",
501
- "classNameMapping": "official",
531
+ "classNameMapping": "obfuscated",
502
532
  "includeKinds": "class,field,method"
503
533
  }
504
534
  }
@@ -515,7 +545,7 @@ Get a high-level summary of what changed between two releases, including class a
515
545
  "name": "f",
516
546
  "owner": "a.b.C",
517
547
  "descriptor": "(Ljava/lang/String;)V",
518
- "sourceMapping": "official"
548
+ "sourceMapping": "obfuscated"
519
549
  }
520
550
  }
521
551
  ```
@@ -530,7 +560,7 @@ Get a high-level summary of what changed between two releases, including class a
530
560
  "name": "f",
531
561
  "owner": "a.b.C",
532
562
  "descriptor": "(I)V",
533
- "sourceMapping": "official"
563
+ "sourceMapping": "obfuscated"
534
564
  }
535
565
  }
536
566
  ```
@@ -679,7 +709,10 @@ Check a Mixin class source for correctness against a target Minecraft version:
679
709
  {
680
710
  "tool": "validate-mixin",
681
711
  "arguments": {
682
- "source": "@Mixin(PlayerEntity.class)\npublic abstract class PlayerMixin {\n @Inject(method = \"tick\", at = @At(\"HEAD\"))\n private void onTick(CallbackInfo ci) {}\n}",
712
+ "input": {
713
+ "mode": "inline",
714
+ "source": "@Mixin(PlayerEntity.class)\npublic abstract class PlayerMixin {\n @Inject(method = \"tick\", at = @At(\"HEAD\"))\n private void onTick(CallbackInfo ci) {}\n}"
715
+ },
683
716
  "version": "1.21.10",
684
717
  "mapping": "yarn"
685
718
  }
@@ -694,10 +727,13 @@ Run the same validation settings against multiple Mixin source files:
694
727
  {
695
728
  "tool": "validate-mixin",
696
729
  "arguments": {
697
- "sourcePaths": [
698
- "/path/to/PlayerMixin.java",
699
- "/path/to/WorldMixin.java"
700
- ],
730
+ "input": {
731
+ "mode": "paths",
732
+ "paths": [
733
+ "/path/to/PlayerMixin.java",
734
+ "/path/to/WorldMixin.java"
735
+ ]
736
+ },
701
737
  "version": "1.21.10",
702
738
  "mapping": "yarn"
703
739
  }
@@ -779,14 +815,16 @@ Check server performance counters, cache sizes, and latency snapshots:
779
815
 
780
816
  | Namespace | Description |
781
817
  | --- | --- |
782
- | `official` | Mojang obfuscated names (e.g. `a`, `b`, `c`) |
818
+ | `obfuscated` | Mojang obfuscated names (e.g. `a`, `b`, `c`) |
783
819
  | `mojang` | Mojang deobfuscated names from `client_mappings.txt` (e.g. `net.minecraft.server.Main`) |
784
820
  | `intermediary` | Fabric stable intermediary names (e.g. `net.minecraft.class_1234`, `method_5678`) |
785
821
  | `yarn` | Fabric community human-readable names (e.g. `net.minecraft.server.MinecraftServer`, `tick`) |
786
822
 
823
+ The legacy public namespace name `official` was removed. Requests that still send `official` now fail validation and should be updated to `obfuscated`.
824
+
787
825
  ### Lookup Rules
788
826
 
789
- `find-mapping` supports lookup across `official`, `mojang`, `intermediary`, and `yarn`.
827
+ `find-mapping` supports lookup across `obfuscated`, `mojang`, `intermediary`, and `yarn`.
790
828
 
791
829
  Symbol query inputs use `kind` + `name` + optional `owner`/`descriptor`:
792
830
  - class: `kind=class`, `name=a.b.C` (default FQCN). For existence checks only, `nameMode=auto` allows short names like `C`.
@@ -795,12 +833,14 @@ Symbol query inputs use `kind` + `name` + optional `owner`/`descriptor`:
795
833
 
796
834
  `mapping: "mojang"` requires a source-backed artifact. If only decompile path is available, the server returns `ERR_MAPPING_NOT_APPLIED`.
797
835
 
798
- `resolve-artifact`, `get-class-members`, `trace-symbol-lifecycle`, and `diff-class-signatures` accept `official | mojang | intermediary | yarn` with constraints:
799
- - `intermediary` / `yarn` require a resolvable Minecraft version context (for example `targetKind=version` or a versioned coordinate).
800
- - for unobfuscated versions (for example 26.1+), requesting `intermediary` / `yarn` falls back to `official` with a warning.
836
+ `resolve-artifact`, `get-class-members`, `trace-symbol-lifecycle`, and `diff-class-signatures` accept `obfuscated | mojang | intermediary | yarn` with constraints:
837
+ - `intermediary` / `yarn` require a resolvable Minecraft version context (for example `target.kind=version` or a versioned coordinate).
838
+ - for unobfuscated versions (for example 26.1+), requesting `intermediary` / `yarn` falls back to `obfuscated` with a warning.
801
839
  - `mojang` requires source-backed artifacts; decompile-only paths are rejected with `ERR_MAPPING_NOT_APPLIED`.
802
840
 
803
- Method descriptor precision is best on Tiny-backed paths (`intermediary`/`yarn`). For `official <-> mojang`, Mojang `client_mappings` do not carry JVM descriptors, so descriptor queries may fallback to name matching and emit a warning.
841
+ If `find-class` or `get-class-source` returns no hit on an `obfuscated` artifact for names like `net.minecraft.world.item.Item`, the tool now warns that `obfuscated` means Mojang's obfuscated runtime names and recommends retrying with `mapping="mojang"` or translating via `find-mapping`.
842
+
843
+ Method descriptor precision is best on Tiny-backed paths (`intermediary`/`yarn`). For `obfuscated <-> mojang`, Mojang `client_mappings` do not carry JVM descriptors, so descriptor queries may fallback to name matching and emit a warning.
804
844
 
805
845
  Use `resolve-method-mapping-exact` when candidate ranking is not enough and the workflow needs strict `owner+name+descriptor` certainty.
806
846
  Use `find-mapping` `disambiguation.ownerHint` / `disambiguation.descriptorHint` to narrow ambiguous candidate sets.
@@ -866,6 +906,7 @@ The server runs as a single long-lived process communicating over stdio. Artifac
866
906
  - `SourceService` is the canonical implementation for artifact resolution, ingestion, and source querying.
867
907
  - `version` resolution downloads Mojang client JARs into cache and routes them through the same ingestion flow as `jar` and `coordinate` targets.
868
908
  - Tool responses are always wrapped as `{ result?, error?, meta }`.
909
+ - Tool responses also mirror that envelope into MCP `structuredContent`, and failures set `isError=true`.
869
910
  - `meta` includes `requestId`, `tool`, `durationMs`, and `warnings[]`.
870
911
 
871
912
  ## License
@@ -131,8 +131,6 @@ export async function decompileBinaryJar(binaryJarPath, cacheDir, options) {
131
131
  const outputDir = decompileOutputDir(cacheDir, normalizedBinaryJarPath, signature).replace(/[/\\]$/, "");
132
132
  try {
133
133
  mkdirSync(outputDir, { recursive: true });
134
- await assertVineflowerAvailable(options.vineflowerJarPath);
135
- await assertJavaAvailable();
136
134
  if (statSync(outputDir, { throwIfNoEntry: false })) {
137
135
  const existingJavaFiles = await collectJavaFiles(outputDir);
138
136
  if (existingJavaFiles.length > 0) {
@@ -154,6 +152,8 @@ export async function decompileBinaryJar(binaryJarPath, cacheDir, options) {
154
152
  };
155
153
  }
156
154
  }
155
+ await assertVineflowerAvailable(options.vineflowerJarPath);
156
+ await assertJavaAvailable();
157
157
  const profilesAttempted = [];
158
158
  let lastDecompileError;
159
159
  for (const profile of VINEFLOWER_FLAG_PROFILES) {