@adhisang/minecraft-modding-mcp 4.2.1 → 6.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.
Files changed (144) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/README.md +5 -4
  3. package/dist/access-transformer-parser.d.ts +2 -1
  4. package/dist/access-transformer-parser.js +10 -1
  5. package/dist/access-widener-parser.d.ts +1 -0
  6. package/dist/access-widener-parser.js +6 -3
  7. package/dist/build-suggested-call.js +31 -10
  8. package/dist/cache-registry.d.ts +8 -0
  9. package/dist/cache-registry.js +50 -32
  10. package/dist/config.d.ts +1 -0
  11. package/dist/config.js +4 -0
  12. package/dist/decompiler/vineflower.js +8 -2
  13. package/dist/entry-tools/analyze-mod-service.d.ts +24 -24
  14. package/dist/entry-tools/analyze-mod-service.js +2 -1
  15. package/dist/entry-tools/analyze-symbol-service.d.ts +57 -22
  16. package/dist/entry-tools/analyze-symbol-service.js +139 -34
  17. package/dist/entry-tools/batch-class-members-service.d.ts +3 -1
  18. package/dist/entry-tools/batch-class-members-service.js +6 -6
  19. package/dist/entry-tools/batch-class-source-service.d.ts +3 -1
  20. package/dist/entry-tools/batch-class-source-service.js +5 -6
  21. package/dist/entry-tools/batch-mappings-service.d.ts +3 -1
  22. package/dist/entry-tools/batch-mappings-service.js +4 -5
  23. package/dist/entry-tools/batch-symbol-exists-service.d.ts +3 -1
  24. package/dist/entry-tools/batch-symbol-exists-service.js +4 -5
  25. package/dist/entry-tools/compare-minecraft-service.d.ts +10 -10
  26. package/dist/entry-tools/compare-minecraft-service.js +1 -1
  27. package/dist/entry-tools/entry-tool-schema.d.ts +1 -1
  28. package/dist/entry-tools/inspect-minecraft/handlers/artifact.js +1 -3
  29. package/dist/entry-tools/inspect-minecraft/handlers/class-members.js +4 -3
  30. package/dist/entry-tools/inspect-minecraft/handlers/class-overview.js +0 -5
  31. package/dist/entry-tools/inspect-minecraft/handlers/class-source.js +0 -1
  32. package/dist/entry-tools/inspect-minecraft/handlers/file.js +26 -2
  33. package/dist/entry-tools/inspect-minecraft/handlers/list-files.js +0 -1
  34. package/dist/entry-tools/inspect-minecraft/handlers/search.d.ts +8 -0
  35. package/dist/entry-tools/inspect-minecraft/handlers/search.js +13 -2
  36. package/dist/entry-tools/inspect-minecraft/handlers/versions.d.ts +1 -1
  37. package/dist/entry-tools/inspect-minecraft/handlers/versions.js +3 -2
  38. package/dist/entry-tools/inspect-minecraft/internal.d.ts +90 -89
  39. package/dist/entry-tools/inspect-minecraft/internal.js +32 -14
  40. package/dist/entry-tools/inspect-minecraft-service.d.ts +218 -218
  41. package/dist/entry-tools/inspect-minecraft-service.js +1 -1
  42. package/dist/entry-tools/manage-cache-service.d.ts +4 -4
  43. package/dist/entry-tools/response-contract.d.ts +3 -1
  44. package/dist/entry-tools/response-contract.js +3 -2
  45. package/dist/entry-tools/validate-project/cases/mixin.js +2 -1
  46. package/dist/entry-tools/validate-project/cases/project-summary.js +5 -3
  47. package/dist/entry-tools/validate-project-service.d.ts +42 -36
  48. package/dist/entry-tools/validate-project-service.js +3 -1
  49. package/dist/entry-tools/verify-mixin-target-service.d.ts +30 -0
  50. package/dist/entry-tools/verify-mixin-target-service.js +120 -29
  51. package/dist/error-mapping.d.ts +51 -0
  52. package/dist/error-mapping.js +157 -2
  53. package/dist/index.js +147 -76
  54. package/dist/java-process.js +1 -1
  55. package/dist/json-rpc-framing.d.ts +4 -0
  56. package/dist/json-rpc-framing.js +23 -1
  57. package/dist/mapping/internal-types.d.ts +24 -0
  58. package/dist/mapping/loaders/tiny-maven.js +46 -20
  59. package/dist/mapping/lookup.d.ts +13 -2
  60. package/dist/mapping/lookup.js +60 -2
  61. package/dist/mapping/types.d.ts +6 -0
  62. package/dist/mapping-service.d.ts +26 -2
  63. package/dist/mapping-service.js +212 -55
  64. package/dist/mcp-helpers.d.ts +1 -0
  65. package/dist/mcp-helpers.js +25 -3
  66. package/dist/minecraft-explorer-service.js +24 -11
  67. package/dist/mixin/access-validators.js +33 -1
  68. package/dist/mixin/annotation-validators.js +73 -9
  69. package/dist/mixin/parsed-validator.js +3 -2
  70. package/dist/mixin-parser.js +119 -7
  71. package/dist/mod-decompile-service.d.ts +2 -0
  72. package/dist/mod-decompile-service.js +21 -3
  73. package/dist/mod-remap-service.d.ts +20 -1
  74. package/dist/mod-remap-service.js +101 -45
  75. package/dist/mojang-tiny-mapping-service.js +5 -2
  76. package/dist/nbt/java-nbt-codec.js +46 -16
  77. package/dist/nbt/json-patch.js +51 -12
  78. package/dist/nbt/typed-json.d.ts +1 -0
  79. package/dist/nbt/typed-json.js +12 -2
  80. package/dist/nbt/types.d.ts +2 -2
  81. package/dist/observability.d.ts +6 -0
  82. package/dist/observability.js +10 -0
  83. package/dist/page-cursor.d.ts +17 -0
  84. package/dist/page-cursor.js +0 -0
  85. package/dist/path-converter.js +10 -3
  86. package/dist/registry-service.d.ts +2 -0
  87. package/dist/registry-service.js +41 -2
  88. package/dist/repo-downloader.js +4 -3
  89. package/dist/resources.js +45 -9
  90. package/dist/response-utils.d.ts +29 -4
  91. package/dist/response-utils.js +95 -5
  92. package/dist/source/access-validate.js +12 -2
  93. package/dist/source/artifact-resolver.js +2 -2
  94. package/dist/source/class-source/members-builder.d.ts +44 -1
  95. package/dist/source/class-source/members-builder.js +51 -4
  96. package/dist/source/class-source/snippet-builder.d.ts +13 -0
  97. package/dist/source/class-source/snippet-builder.js +54 -4
  98. package/dist/source/class-source-helpers.d.ts +4 -4
  99. package/dist/source/class-source-helpers.js +77 -20
  100. package/dist/source/class-source.d.ts +19 -0
  101. package/dist/source/class-source.js +144 -40
  102. package/dist/source/file-access.js +3 -2
  103. package/dist/source/indexer.js +29 -9
  104. package/dist/source/lifecycle/mapping-helpers.js +28 -3
  105. package/dist/source/lifecycle/runtime-check.js +20 -6
  106. package/dist/source/search.d.ts +1 -1
  107. package/dist/source/search.js +117 -30
  108. package/dist/source/validate-mixin/pipeline/resolve.js +23 -3
  109. package/dist/source/validate-mixin.d.ts +2 -1
  110. package/dist/source/validate-mixin.js +45 -4
  111. package/dist/source/workspace-target.js +17 -10
  112. package/dist/source-jar-reader.d.ts +54 -1
  113. package/dist/source-jar-reader.js +121 -10
  114. package/dist/source-resolver.js +2 -2
  115. package/dist/source-service.d.ts +28 -7
  116. package/dist/source-service.js +9 -1
  117. package/dist/stdio-supervisor.d.ts +2 -2
  118. package/dist/stdio-supervisor.js +29 -9
  119. package/dist/storage/db.js +24 -1
  120. package/dist/storage/files-repo.d.ts +15 -0
  121. package/dist/storage/files-repo.js +67 -37
  122. package/dist/storage/symbols-repo.d.ts +15 -0
  123. package/dist/storage/symbols-repo.js +53 -19
  124. package/dist/symbols/symbol-extractor.js +35 -6
  125. package/dist/text-truncate.d.ts +7 -0
  126. package/dist/text-truncate.js +21 -0
  127. package/dist/tiny-remapper-resolver.js +10 -0
  128. package/dist/tool-contract-manifest.js +2 -2
  129. package/dist/tool-execution-gate.js +12 -1
  130. package/dist/tool-guidance.d.ts +6 -2
  131. package/dist/tool-guidance.js +63 -13
  132. package/dist/tool-schemas.d.ts +561 -496
  133. package/dist/tool-schemas.js +175 -139
  134. package/dist/types.d.ts +1 -0
  135. package/dist/version-diff-service.js +5 -0
  136. package/dist/version-service.d.ts +3 -0
  137. package/dist/version-service.js +18 -2
  138. package/dist/warning-details.d.ts +30 -0
  139. package/dist/warning-details.js +80 -0
  140. package/dist/workspace-mapping-service.js +9 -0
  141. package/docs/README-ja.md +2 -2
  142. package/docs/examples.md +26 -2
  143. package/docs/tool-reference.md +22 -17
  144. package/package.json +1 -1
package/dist/types.d.ts CHANGED
@@ -112,6 +112,7 @@ export interface Config {
112
112
  fetchTimeoutMs: number;
113
113
  fetchRetries: number;
114
114
  searchScanPageSize: number;
115
+ searchScanMaxBytes: number;
115
116
  indexInsertChunkSize: number;
116
117
  maxMappingGraphCache: number;
117
118
  maxSignatureCache: number;
@@ -145,6 +145,11 @@ export class VersionDiffService {
145
145
  });
146
146
  }
147
147
  const warnings = [];
148
+ if (input.maxClassResults != null &&
149
+ Number.isFinite(input.maxClassResults) &&
150
+ input.maxClassResults > MAX_CLASS_RESULTS_LIMIT) {
151
+ warnings.push(`maxClassResults was clamped to ${MAX_CLASS_RESULTS_LIMIT} from ${input.maxClassResults}.`);
152
+ }
148
153
  const startedAt = Date.now();
149
154
  log("info", "version-diff.start", { fromVersion, toVersion, category });
150
155
  const includeClasses = category === "classes" || category === "all";
@@ -16,6 +16,7 @@ export type ListVersionsOutput = {
16
16
  snapshots?: VersionEntry[];
17
17
  cached: string[];
18
18
  totalAvailable: number;
19
+ warnings?: string[];
19
20
  };
20
21
  export type ResolvedVersionJar = {
21
22
  version: string;
@@ -47,6 +48,7 @@ export declare class VersionService {
47
48
  private manifestCache;
48
49
  private readonly versionDetailCache;
49
50
  private readonly resolveLocks;
51
+ private indexWriteChain;
50
52
  constructor(config: Config, fetchFn?: typeof fetch);
51
53
  listVersions(input?: ListVersionsInput): Promise<ListVersionsOutput>;
52
54
  listVersionIds(input?: ListVersionIdsInput): Promise<string[]>;
@@ -60,6 +62,7 @@ export declare class VersionService {
60
62
  private cacheIndexPath;
61
63
  private loadCacheIndex;
62
64
  private recordCacheEntry;
65
+ private recordCacheEntryInternal;
63
66
  private trimVersionDetailCache;
64
67
  }
65
68
  /**
@@ -38,6 +38,9 @@ export class VersionService {
38
38
  manifestCache;
39
39
  versionDetailCache = new Map();
40
40
  resolveLocks = new Map();
41
+ // Serializes index.json read-modify-write so parallel resolutions of different
42
+ // versions can't clobber each other (resolveLocks only guards the same version).
43
+ indexWriteChain = Promise.resolve();
41
44
  constructor(config, fetchFn = globalThis.fetch) {
42
45
  this.config = config;
43
46
  this.fetchFn = fetchFn;
@@ -47,6 +50,10 @@ export class VersionService {
47
50
  const manifest = await this.fetchManifest();
48
51
  const includeSnapshots = input.includeSnapshots ?? false;
49
52
  const limit = clampLimit(input.limit, 20, 200);
53
+ const warnings = [];
54
+ if (input.limit != null && Number.isFinite(input.limit) && input.limit > 200) {
55
+ warnings.push(`limit was clamped to 200 from ${input.limit}.`);
56
+ }
50
57
  const versions = manifest.versions ?? [];
51
58
  const releases = versions
52
59
  .filter((entry) => entry.type === "release")
@@ -65,7 +72,8 @@ export class VersionService {
65
72
  releases,
66
73
  snapshots: includeSnapshots ? snapshots : undefined,
67
74
  cached: Array.from(new Set(cached)).sort((a, b) => a.localeCompare(b)),
68
- totalAvailable: versions.length
75
+ totalAvailable: versions.length,
76
+ ...(warnings.length ? { warnings } : {})
69
77
  };
70
78
  }
71
79
  async listVersionIds(input = {}) {
@@ -389,7 +397,15 @@ export class VersionService {
389
397
  return { entries: [] };
390
398
  }
391
399
  }
392
- async recordCacheEntry(entry) {
400
+ recordCacheEntry(entry) {
401
+ // Chain onto the previous write so reads and writes never interleave. The
402
+ // caller still awaits its own write's result, but the shared chain swallows
403
+ // failures so one rejected write cannot poison subsequent writes.
404
+ const next = this.indexWriteChain.then(() => this.recordCacheEntryInternal(entry));
405
+ this.indexWriteChain = next.catch(() => undefined);
406
+ return next;
407
+ }
408
+ async recordCacheEntryInternal(entry) {
393
409
  const indexPath = this.cacheIndexPath();
394
410
  const existing = await this.loadCacheIndex();
395
411
  const deduped = existing.entries.filter((candidate) => candidate.version !== entry.version);
@@ -0,0 +1,30 @@
1
+ export type WarningCategory = "pagination" | "mapping" | "coverage" | "validation" | "general";
2
+ export type WarningSeverity = "warning" | "info";
3
+ export type WarningDetail = {
4
+ /** Stable machine code for the warning family. */
5
+ code: string;
6
+ category: WarningCategory;
7
+ severity: WarningSeverity;
8
+ /** Index into `meta.warnings[]` that holds the original human-readable text. */
9
+ index: number;
10
+ /** Input fields a caller can adjust to address the warning, when applicable. */
11
+ affectedFields?: string[];
12
+ };
13
+ /**
14
+ * Build the structured `warningDetails[]` companion for a list of warning strings.
15
+ * The mapping is 1:1 and order-preserving, so each entry's `index` equals its
16
+ * position and dereferences the text via `warnings[index]`.
17
+ */
18
+ export declare function classifyWarnings(warnings: string[]): WarningDetail[];
19
+ /**
20
+ * Cap of structured warningDetails entries emitted at `detail:"summary"`.
21
+ */
22
+ export declare const SUMMARY_WARNING_DETAIL_CAP = 5;
23
+ /**
24
+ * At `detail:"summary"` the structured warningDetails companion is capped to a small
25
+ * representative set to keep responses lean. The full human-readable text still lives
26
+ * in `meta.warnings[]`, and each kept entry's `index` continues to dereference it, so
27
+ * no information is lost — only the redundant structured duplicate is trimmed. Standard
28
+ * and full detail return the companion unchanged.
29
+ */
30
+ export declare function capWarningDetailsForSummary(warningDetails: WarningDetail[], isSummary: boolean): WarningDetail[];
@@ -0,0 +1,80 @@
1
+ // Structured companion to the string `meta.warnings`. Each warning string is
2
+ // classified into a high-value family so agents can branch on category/severity
3
+ // without parsing prose. The original text is NOT duplicated here; each entry
4
+ // references its warning by position via `index` (read `meta.warnings[index]`).
5
+ // First matching rule wins; more specific patterns precede broader ones.
6
+ const WARNING_RULES = [
7
+ {
8
+ test: /Member list was truncated|truncated to \d+ (entries|rows)|Raise maxCandidates|Raise maxRows/i,
9
+ code: "result_truncated",
10
+ category: "pagination",
11
+ severity: "info",
12
+ affectedFields: ["maxMembers", "maxRows", "maxCandidates", "cursor"]
13
+ },
14
+ {
15
+ test: /\bwas clamped to\b/i,
16
+ code: "input_clamped",
17
+ category: "validation",
18
+ severity: "info"
19
+ },
20
+ {
21
+ test: /are not indexed|non-Java resources are not indexed/i,
22
+ code: "resource_not_indexed",
23
+ category: "coverage",
24
+ severity: "info"
25
+ },
26
+ {
27
+ test: /namespace translation requires a version|could not be applied because the artifact has no version|Could not (re)?map .* (from .* to|to .* namespace)|Remap failed for|Mapping lookup failed|No exact class symbol matched|Unsupported .* namespace/i,
28
+ code: "namespace_fallback",
29
+ category: "mapping",
30
+ severity: "warning",
31
+ affectedFields: ["mapping", "version"]
32
+ },
33
+ {
34
+ test: /falling back to vanilla|resolution failed; falling back|sources jar\.?\s*Falling back|does not include net\.minecraft/i,
35
+ code: "partial_coverage",
36
+ category: "coverage",
37
+ severity: "warning",
38
+ affectedFields: ["scope"]
39
+ }
40
+ ];
41
+ function classifyWarning(message, index) {
42
+ for (const rule of WARNING_RULES) {
43
+ if (rule.test.test(message)) {
44
+ return {
45
+ code: rule.code,
46
+ category: rule.category,
47
+ severity: rule.severity,
48
+ index,
49
+ ...(rule.affectedFields ? { affectedFields: rule.affectedFields } : {})
50
+ };
51
+ }
52
+ }
53
+ return { code: "general", category: "general", severity: "info", index };
54
+ }
55
+ /**
56
+ * Build the structured `warningDetails[]` companion for a list of warning strings.
57
+ * The mapping is 1:1 and order-preserving, so each entry's `index` equals its
58
+ * position and dereferences the text via `warnings[index]`.
59
+ */
60
+ export function classifyWarnings(warnings) {
61
+ return warnings.map((message, index) => classifyWarning(message, index));
62
+ }
63
+ /**
64
+ * Cap of structured warningDetails entries emitted at `detail:"summary"`.
65
+ */
66
+ export const SUMMARY_WARNING_DETAIL_CAP = 5;
67
+ /**
68
+ * At `detail:"summary"` the structured warningDetails companion is capped to a small
69
+ * representative set to keep responses lean. The full human-readable text still lives
70
+ * in `meta.warnings[]`, and each kept entry's `index` continues to dereference it, so
71
+ * no information is lost — only the redundant structured duplicate is trimmed. Standard
72
+ * and full detail return the companion unchanged.
73
+ */
74
+ export function capWarningDetailsForSummary(warningDetails, isSummary) {
75
+ if (!isSummary || warningDetails.length <= SUMMARY_WARNING_DETAIL_CAP) {
76
+ return warningDetails;
77
+ }
78
+ return warningDetails.slice(0, SUMMARY_WARNING_DETAIL_CAP);
79
+ }
80
+ //# sourceMappingURL=warning-details.js.map
@@ -65,6 +65,15 @@ function buildDependencyPropertyKeys(group, name) {
65
65
  `${groupSegment}_${name}_version`,
66
66
  `${camelGroupName}Version`
67
67
  ];
68
+ // Umbrella fallback: submodules of an umbrella package (e.g. Fabric API's
69
+ // net.fabricmc.fabric-api:fabric-screen-handler-api-v1) rarely declare their own
70
+ // version — the parent declares a single umbrella property (fabric_api_version /
71
+ // fabricApiVersion) that all submodules inherit. When the artifact name differs from
72
+ // the group's last segment, append the umbrella's keys as LOWER-priority candidates so
73
+ // submodule version detection no longer fails with ERR_DEPENDENCY_VERSION_UNRESOLVED.
74
+ if (groupSegment !== name) {
75
+ keys.push(`${groupSegment.replace(/-/g, "_")}_version`, `${camelCaseDependencyName(groupSegment)}Version`);
76
+ }
68
77
  const seen = new Set();
69
78
  const deduped = [];
70
79
  for (const key of keys) {
package/docs/README-ja.md CHANGED
@@ -15,7 +15,7 @@
15
15
 
16
16
  stdio で動作し、Claude Desktop、Claude Code、VS Code、Codex CLI、Gemini CLI などの MCP 対応クライアントから利用できます。
17
17
 
18
- **37 ツール**(6 エントリー + 31 エキスパート) | **7 リソース** | **4 マッピング名前空間** | **SQLite ベースのキャッシュ**
18
+ **41 ツール**(6 エントリー + 35 エキスパート) | **9 リソース** | **4 マッピング名前空間** | **SQLite ベースのキャッシュ**
19
19
 
20
20
  ## 特長
21
21
 
@@ -301,7 +301,7 @@ Minecraft バージョン間でのクラス / レジストリ変更比較と、
301
301
  | ツール | 役割 |
302
302
  | --- | --- |
303
303
  | `find-mapping` | クラス、フィールド、メソッドのシンボルに対するマッピング候補を調べる |
304
- | `resolve-method-mapping-exact` | ownernamedescriptor の厳密一致で 1 つのメソッドマッピングを解決する |
304
+ | `resolve-method-mapping-exact` | `find-mapping`(kind=method, signatureMode=exact)の厳密版ショートカット。owner+name+descriptor の三つ組が必須 |
305
305
  | `get-class-api-matrix` | 1 つのクラス API を `obfuscated`、`mojang`、`intermediary`、`yarn` で見比べる |
306
306
  | `resolve-workspace-symbol` | Gradle ワークスペースからコンパイル時に見えるシンボル名を解決する |
307
307
  | `check-symbol-exists` | 名前空間内でクラス、フィールド、メソッドが存在するかを確認する |
package/docs/examples.md CHANGED
@@ -105,7 +105,7 @@ Start with these top-level workflow tools when possible. They cover the common w
105
105
  "tool": "get-class-source",
106
106
  "arguments": {
107
107
  "target": {
108
- "type": "artifact",
108
+ "kind": "artifact",
109
109
  "artifactId": "<artifact-id>"
110
110
  },
111
111
  "className": "net.minecraft.server.Main",
@@ -137,7 +137,7 @@ Start with these top-level workflow tools when possible. They cover the common w
137
137
  "tool": "get-class-members",
138
138
  "arguments": {
139
139
  "target": {
140
- "type": "artifact",
140
+ "kind": "artifact",
141
141
  "artifactId": "<artifact-id>"
142
142
  },
143
143
  "className": "net.minecraft.server.Main",
@@ -395,6 +395,30 @@ Start with these top-level workflow tools when possible. They cover the common w
395
395
 
396
396
  If the input JAR was already built with Mojang mappings, use `targetMapping: "mojang"` to get a copied output JAR and a `fromMapping: "mojang"` result.
397
397
 
398
+ ### Bridge a mod hit to a Minecraft-side check
399
+
400
+ When `search-mod-source` or `get-mod-class-source` surfaces a class or member that
401
+ looks like a Minecraft target (for example a Mixin `@Shadow`/`@Inject` target, or a
402
+ symbol from a crash stack), verify it against the target Minecraft version before
403
+ trusting it. Feed the owner/member into `verify-mixin-target`. When your owner/member
404
+ are in a readable namespace (e.g. `mojang`/`yarn`) but the resolved artifact is
405
+ obfuscated, set `autoRemap: true` to translate them automatically in one call:
406
+
407
+ ```json
408
+ {
409
+ "tool": "verify-mixin-target",
410
+ "arguments": {
411
+ "target": { "kind": "version", "value": "1.21.10" },
412
+ "owner": "net.minecraft.world.entity.LivingEntity",
413
+ "member": { "kind": "method", "name": "tickServer", "descriptor": "()V" },
414
+ "mapping": "mojang",
415
+ "autoRemap": true
416
+ }
417
+ }
418
+ ```
419
+
420
+ For a plain "does this symbol exist in this version?" question, use `analyze-symbol task="exists"` instead.
421
+
398
422
  ## Validation
399
423
 
400
424
  ### Validate Mixin source
@@ -23,15 +23,15 @@ Start here when you are not sure which tool to reach for. In every row, the left
23
23
  | "Does this Mixin target the right class and descriptor?" | `validate-mixin` (works standalone with `version=1.21.10`; provide inline source, a path, or a mixin config). |
24
24
  | "Validate every Mixin / Access Widener / Access Transformer in a workspace." | `validate-project` (`task="project-summary"` discovers everything; `task="mixin"|"access-widener"|"access-transformer"` validates a single subject). |
25
25
  | "Inspect the Minecraft workspace or an artifact without picking a lower-level tool." | `inspect-minecraft` — use this when you want the server to resolve the artifact and pick the right sub-tool. |
26
- | "Trace when a symbol was added, renamed, or removed across versions." | `trace-symbol-lifecycle` (or `analyze-symbol task="lifecycle"` for the summarized 5-version window). |
27
- | "Compare two MC versions or two class versions." | `compare-minecraft` (`task="class"` for a single class diff; `task="versions"` for a full summary). |
26
+ | "Trace when a symbol was added, renamed, or removed across versions." | `trace-symbol-lifecycle` (or `analyze-symbol task="lifecycle"`, which now exposes `fromVersion`/`toVersion`/`maxVersions`/`includeTimeline`). |
27
+ | "Compare two MC versions or two class versions." | `compare-minecraft` (`task="class-diff"` for a single class diff; `task="versions"` for a full summary). |
28
28
  | "Inspect or remap an existing `.jar` file." | `analyze-mod` / `analyze-mod-jar` / `remap-mod-jar`. |
29
29
 
30
30
  ## Essential Conventions
31
31
 
32
32
  - Start with the top-level workflow tools when possible. `inspect-minecraft`, `analyze-symbol`, `compare-minecraft`, `analyze-mod`, `validate-project`, and `manage-cache` cover the common workflows and return summary-first results with follow-up hints.
33
33
  - `resolve-artifact` uses `target: { kind, value }`. `kind` is one of `"version"`, `"jar"`, `"coordinate"`, `"workspace"`, or `"dependency"` (see "Workspace and dependency target shapes" below).
34
- - `get-class-source` and `get-class-members` use `target: { type: "artifact", artifactId }` or `target: { type: "resolve", kind, value }` (the same `kind` set as `resolve-artifact`).
34
+ - `get-class-source` and `get-class-members` use `target: { kind, value }` — the same `kind`-based shape as `resolve-artifact` (`"version"`, `"jar"`, `"coordinate"`, `"workspace"`, `"dependency"`), plus `target: { kind: "artifact", artifactId }` to reuse an already-resolved artifact.
35
35
  - `find-class`, `search-class-source`, `list-artifact-files`, and `find-mapping` keep their existing input shapes (an `artifactId` or a `version`); they do not currently accept `target.kind="workspace"` or `target.kind="dependency"`.
36
36
  - `validate-mixin` and `validate-project task="mixin"` use `input.mode="inline" | "path" | "paths" | "config" | "project"`.
37
37
  - Positive integer tool arguments accept numeric strings such as `"10"` for documented top-level parameters.
@@ -46,12 +46,14 @@ Start here when you are not sure which tool to reach for. In every row, the left
46
46
  | --- | --- | --- |
47
47
  | `"ok"` | `counts.total > 0`, OR `counts.total === 0` AND binary extraction succeeded AND `decompiledFallback` did not fire (genuinely empty class). | none |
48
48
  | `"partial"` | `decompiledFallback` is populated (bytecode returned zero but the indexed decompiled source supplied member names; `qualityFlags` includes `"members-from-decompiled-source"`). | `decompiledFallback`, `decompiledMemberCounts` |
49
- | `"members_unavailable"` | Binary signature extraction threw a non-`ERR_CLASS_NOT_FOUND` error AND no decompiled fallback was available. | `unavailableReason: string`, `suggestedCall: { tool: "get-class-source", params: { target: { type: "artifact", artifactId }, className, mode: "snippet", mapping } }` (the params validate against `get-class-source`'s input schema). |
49
+ | `"members_unavailable"` | Binary signature extraction threw a non-`ERR_CLASS_NOT_FOUND` error AND no decompiled fallback was available. | `unavailableReason: string`, `suggestedCall: { tool: "get-class-source", params: { target: { kind: "artifact", artifactId }, className, mode: "snippet", mapping } }` (the params validate against `get-class-source`'s input schema). |
50
50
 
51
51
  The shape is purely additive: `members` / `counts` / `decompiledFallback` / `decompiledMemberCounts` / `qualityFlags` are unchanged for callers that ignore `status`. `ERR_CLASS_NOT_FOUND` still propagates as a thrown error rather than as `members_unavailable`. Set `MEMBERS_STATUS_LEGACY=1` at process start to omit `status` / `unavailableReason` / `suggestedCall` entirely (legacy shape).
52
52
  - `search-class-source` accepts `queryNamespace`. When set and the artifact's `mappingApplied` differs, `intent="symbol"` queries for fully-qualified class names are translated through `find-mapping` (source=`queryNamespace`, target=artifact namespace) before the indexed search runs; the response carries a `translatedQuery` block describing the rewrite. `intent="text"` / `intent="path"` do not translate — text search is a literal match against the artifact namespace; the response surfaces a `warnings` array instead. `sourcePriority` is only consulted during translation.
53
- - `resolve-artifact`, `find-mapping`, `resolve-method-mapping-exact`, `resolve-workspace-symbol`, and `check-symbol-exists` default `compact` to `true`. Pass `compact: false` for the full diagnostic shape. When enabled, compact mode strips empty arrays, null values, and empty objects from the response. For `resolve-artifact`, compact mode also omits `provenance`, `artifactContents`, `sampleEntries`, `adjacentSourceCandidates`, `binaryJarPath`, `coordinate`, `repoUrl`, and `resolvedSourceJarPath`. For mapping tools, compact mode has two projections: (1) the redundant `candidates` array is omitted entirely when the result is a single full-confidence exact-match resolution; (2) when the result is unresolved with more than three candidates, the top three keep full metadata while the tail is slimmed to `{kind, symbol, owner, name, descriptor, confidence, matchKind}` and the response surfaces `candidateDetailsTruncated: true`. `candidatesTruncated` retains its pre-compact meaning ("more candidates exist upstream than this response returned") and is set independently by the service when `maxCandidates` clipped the list — the two signals can both appear.
54
- - `get-class-source`, `get-class-members`, `search-class-source`, and `list-artifact-files` accept `compact: true` (opt-in, default `false`) to strip debug/diagnostic metadata and empty fields. `get-class-source` omits `provenance`, `artifactContents`, and `qualityFlags`. `get-class-members` omits `provenance`, `artifactContents`, `qualityFlags`, and `context`; `decompiledFallback` and `decompiledMemberCounts` are preserved. `search-class-source` and `list-artifact-files` omit `artifactContents` only the primary `hits` / `items` payload is always preserved.
53
+ - All expert and batch tools share the entry-tool **`detail`** (`summary` | `standard` | `full`) + **`include[]`** response contract (the per-tool `compact` boolean is gone). `summary` is the terse shape (drops diagnostics/empties, slims candidates), `standard` keeps fields but drops heavy diagnostics, `full` keeps everything. Per-tool defaults are chosen so the default response is unchanged: `resolve-artifact`, `find-mapping`, `resolve-method-mapping-exact`, `resolve-workspace-symbol`, `check-symbol-exists`, and the four `batch-*` tools default **`summary`**; `get-class-source`, `get-class-members`, `search-class-source`, and `list-artifact-files` default **`standard`**. (Migration: `compact: true` `detail: "summary"`; `compact: false` `detail: "full"`.)
54
+ - At `detail: "summary"`, empty arrays / null / empty objects are stripped. For `resolve-artifact` it also omits `provenance`, `artifactContents`, `sampleEntries`, `adjacentSourceCandidates`, `binaryJarPath`, `coordinate`, `repoUrl`, and `resolvedSourceJarPath` `include: ["provenance"|"artifact"|"samples"|"candidates"|"paths"]` re-adds the matching field(s). For mapping tools, `summary` (1) omits the redundant `candidates` array on a single full-confidence exact-match resolution and (2) slims the tail to `{kind, symbol, owner, name, descriptor, confidence, matchKind}` with `candidateDetailsTruncated: true` when an unresolved result has more than three candidates; `include: ["candidates"]` keeps the full candidate list. `candidatesTruncated` keeps its independent meaning ("more candidates exist upstream than returned").
55
+ - `get-class-source` and `get-class-members` omit the diagnostic fields `provenance`, `artifactContents`, and `qualityFlags` at `detail: "summary"` and `detail: "standard"` (the lean common path). Pass `include: ["provenance"]` (or the legacy alias `includeProvenance: true`) or use `detail: "full"` to include all three. `detail: "summary"` additionally strips empty fields, and for `get-class-members` also strips `context`; `decompiledFallback` and `decompiledMemberCounts` are preserved. `search-class-source` and `list-artifact-files` omit `artifactContents` at `detail: "summary"` (re-add via `include: ["artifact"]`) — the primary `hits` / `items` payload is always preserved.
56
+ - `get-class-members` returns a slim member shape: `accessFlags` is dropped (modifiers are in `javaSignature`), `ownerFqn` is hoisted to a single block-level `members.ownerFqn` when all members share one owner (per-member only when `includeInherited` surfaces multiple owners), and **field** `jvmDescriptor` is omitted by default. Method/constructor `jvmDescriptor` is always present for overload disambiguation. Pass `include: ["descriptors"]` (or the legacy alias `includeDescriptors: true`) to also emit field descriptors.
55
57
  - Windows and WSL path forms are normalized for `jarPath`, `projectPath`, and environment-variable path overrides.
56
58
  - Heavy analysis tools are serialized in-process to protect stdio stability. Queue overflow returns `ERR_LIMIT_EXCEEDED`.
57
59
  - All tools and JSON resources use the standard `{ result?, error?, meta }` envelope. `class-source` and `artifact-file` resources return raw text on success and structured JSON on failure.
@@ -90,7 +92,7 @@ Workspace detection is memoised in a process-resident `WorkspaceContextCache` (1
90
92
  - `remap-mod-jar` requires Java and supports Fabric/Quilt inputs. Mojang-mapped inputs can only be copied through `targetMapping="mojang"`.
91
93
  - `search-mod-source` enforces `query.length <= 200` and `limit <= 200`.
92
94
  - `get-registry-data` can return names and counts only with `includeData=false`, or clip detailed payloads with `maxEntriesPerRegistry`.
93
- - `validate-mixin` summary-first workflows should combine `includeIssues=false`, `reportMode="compact"`, and `warningMode="aggregated"`.
95
+ - `validate-mixin` defaults `reportMode="summary-first"`: it hoists shared provenance/warnings/incomplete reasons and drops per-result `resolvedMembers`/`toolHealth`/`structuredWarnings`. Pass `reportMode="full"` (or `explain=true`) to get per-result `resolvedMembers`/`toolHealth`/`resolutionTrace` back. For the leanest output combine `includeIssues=false`, `reportMode="compact"`, and `warningMode="aggregated"`.
94
96
  - `validate-mixin` top-level failures expose `failedStage` as a first-class field on the serialized `error` envelope (alongside `code`, `hints`, `suggestedCall`) — one of `"input-validation" | "resolve" | "mapping-health" | "parse" | "target-lookup"`. Branch on that before inspecting `message` to recover automatically (e.g. retry `resolve` failures with `scope="vanilla"`, retry `target-lookup` failures with a different `mapping`). Nested errors that already carry a `failedStage` are preserved so upstream tags (e.g. from `resolve-artifact`) surface unchanged.
95
97
  - `validate-mixin` per-result `quickSummary` appends `Scope fell back from "<requested>" to "<applied>" (<reason>).` when `provenance.scopeFallback` is set and `Mapping health degraded: <degradations>.` when `toolHealth.overallHealthy === false`. Clean validations keep the original one-line summary; the extra notes only attach when the pipeline actually fell back or detected a degraded mapping.
96
98
  - `mapping-health` stays lightweight for `obfuscated` and `mojang` requests. It avoids full Tiny mapping graph loads unless the caller requests `intermediary` or `yarn`, where Tiny namespace availability is part of the health check.
@@ -148,7 +150,7 @@ Common input fields:
148
150
  - `entries: Array<...>` — 1..50 per-entry payloads. Tool-specific shape (see each subsection).
149
151
  - `concurrency: number` (1..8, default 4) — passed to the worker pool. Above 8 is rejected with `ERR_INVALID_INPUT` (`fieldErrors[0].path === "concurrency"`).
150
152
  - `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`.
151
- - `compact: boolean` (default `true`) — applies the same per-tool projection that the corresponding single tool's `compact: true` mode applies. When `false`, per-entry `result` is byte-identical to the single tool's `compact: false` output.
153
+ - `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).
152
154
  - Per-tool shared inputs (`target`, `mapping`, `projectPath`, `version`, etc.) follow the same shape as the matching single tool.
153
155
 
154
156
  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.
@@ -191,8 +193,8 @@ Per-entry retry semantics: each `error.suggestedCall` proposes the **matching si
191
193
 
192
194
  | Batch tool | Single tool retry |
193
195
  |---|---|
194
- | `batch-class-source` | `get-class-source` (with `target: { type: "artifact", artifactId: <shared> }`) |
195
- | `batch-class-members` | `get-class-members` (with `target: { type: "artifact", artifactId: <shared> }`) |
196
+ | `batch-class-source` | `get-class-source` (with `target: { kind: "artifact", artifactId: <shared> }`) |
197
+ | `batch-class-members` | `get-class-members` (with `target: { kind: "artifact", artifactId: <shared> }`) |
196
198
  | `batch-symbol-exists` | `check-symbol-exists` (with `version` derived from the resolved artifact) |
197
199
  | `batch-mappings` | `find-mapping` (with `version` carried from the top-level batch input) |
198
200
 
@@ -208,7 +210,7 @@ Read source for many classes against one shared resolved artifact. Per-entry: `{
208
210
 
209
211
  ### batch-class-members
210
212
 
211
- List members for many classes against one shared resolved artifact. Per-entry: `{ className, access?, includeSynthetic?, includeInherited?, memberPattern?, maxMembers? }`. Shared inputs match `batch-class-source`. Result shape per entry mirrors `get-class-members`, including the `status` field (`"available"` / `"unavailable"` / etc.).
213
+ List members for many classes against one shared resolved artifact. Per-entry: `{ className, access?, includeSynthetic?, includeInherited?, memberPattern?, maxMembers? }`. Shared inputs match `batch-class-source`. Result shape per entry mirrors `get-class-members`, including the `status` field (`"ok"` / `"partial"` / `"members_unavailable"`).
212
214
 
213
215
  ### batch-symbol-exists
214
216
 
@@ -265,7 +267,8 @@ These environment variables are read once at worker startup and provide rollback
265
267
 
266
268
  - Start with `inspect-minecraft` for version, artifact, class, file, and search workflows before dropping to `list-versions`, `resolve-artifact`, `get-class-source`, `get-class-members`, `search-class-source`, `get-artifact-file`, or `list-artifact-files`.
267
269
  - Start with `analyze-symbol` for symbol mapping, existence, lifecycle, workspace, and API overview workflows before using `find-mapping`, `resolve-method-mapping-exact`, `check-symbol-exists`, `trace-symbol-lifecycle`, `resolve-workspace-symbol`, or `get-class-api-matrix` directly.
268
- - `analyze-symbol task="lifecycle"` treats its required `version` as the upper bound for the lifecycle scan and intentionally limits the high-level helper to a recent 5-version window. Use `trace-symbol-lifecycle` directly when you need explicit `fromVersion` / `toVersion` control or a wider history.
270
+ - `analyze-symbol task="lifecycle"` accepts `fromVersion`/`toVersion`/`maxVersions`/`includeTimeline`/`includeSnapshots` (lifecycle-only; rejected on other tasks). The legacy `version` field is a back-compat alias for `toVersion` (range end). The default scan window is the service default of 120 versions (max 400); pass `maxVersions: 5` for the old narrow window. Use `trace-symbol-lifecycle` directly only for parity with the expert tool.
271
+ - `analyze-symbol` `subject.kind` accepts `"symbol"` to auto-detect the concrete kind from the selector (owner+descriptor ⇒ method, owner only ⇒ field, otherwise ⇒ class); the inferred kind is surfaced as a warning. For `task="api-overview"` the inferred kind is always class.
269
272
  - Start with `compare-minecraft` for version-pair, class diff, registry diff, and migration-summary flows before using `compare-versions`, `diff-class-signatures`, or `get-registry-data` directly.
270
273
  - Start with `analyze-mod` for metadata-first mod inspection and safe remap preview/apply flows before using `analyze-mod-jar`, `decompile-mod-jar`, `get-mod-class-source`, `search-mod-source`, or `remap-mod-jar` directly.
271
274
  - 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.
@@ -289,7 +292,7 @@ These environment variables are read once at worker startup and provide rollback
289
292
  - `validate-access-transformer` accepts `atNamespace="srg" | "mojang" | "obfuscated"`. When `projectPath` points at a Forge or NeoForge workspace, the tool can infer that namespace automatically and validate against loader/runtime artifacts for `scope="loader"`.
290
293
  - Start with `manage-cache` for cache inventory and safe cleanup. Use `executionMode="preview"` before `executionMode="apply"`.
291
294
  - Replace `resolve-artifact` `targetKind` and `targetValue` with `target: { kind, value }`.
292
- - Replace `get-class-source` and `get-class-members` top-level `artifactId`, `targetKind`, and `targetValue` with `target: { type: "artifact", artifactId }` or `target: { type: "resolve", kind, value }`.
295
+ - Replace `get-class-source` and `get-class-members` top-level `artifactId`, `targetKind`, and `targetValue` with `target: { kind, value }` (same shape as `resolve-artifact`) or `target: { kind: "artifact", artifactId }`. The earlier `target: { type: "artifact", artifactId }` form is gone — use `{ kind: "artifact", artifactId }`; the redundant `{ type: "resolve", ... }` wrapper is still accepted but `type` is ignored.
293
296
  - `resolve-method-mapping-exact` is method-only and no longer accepts `kind`.
294
297
  - Replace `validate-mixin` `source`, `sourcePath`, `sourcePaths`, `mixinConfigPath`, and `sourceRoot` with `input.mode` plus `input.source`, `input.path`, `input.paths[]`, `input.configPaths[]`, and `sourceRoots[]`.
295
298
  - `search-class-source` removed snippet, definition, and relation expansion. Responses now contain compact `hits[]` plus `nextCursor?`, and `symbolKind` is only valid with `intent="symbol"`.
@@ -309,13 +312,15 @@ MCP resources provide URI-based access to Minecraft data for clients that suppor
309
312
 
310
313
  | Resource | URI Template | Description |
311
314
  | --- | --- | --- |
312
- | `class-source` | `mc://source/{artifactId}/{className}` | Java source code for a class within a resolved artifact |
315
+ | `class-source` | `mc://source/{artifactId}/{className}` | Java source code for a class within a resolved artifact (raw text). |
316
+ | `class-source-json` | `mc://source-json/{artifactId}/{className}` | Full class source plus metadata (`artifactId`, `mappingApplied`, `totalLines`, `returnedRange`, `provenance`, `warnings`) as a structured JSON envelope — easier to cite and continue than the raw-text `class-source`. |
313
317
  | `artifact-file` | `mc://artifact/{artifactId}/files/{filePath}` | Raw content of a file within a resolved artifact |
314
- | `find-mapping` | `mc://mappings/{version}/{sourceMapping}/{targetMapping}/{kind}/{name}` | Look up a mapping between two naming namespaces |
318
+ | `find-mapping` | `mc://mappings/{version}/{sourceMapping}/{targetMapping}/{kind}/{name}` | Look up a **class** mapping between two naming namespaces. The URI carries no `owner`, so use `find-member-mapping` (or the `find-mapping` tool) for field/method lookups. |
319
+ | `find-member-mapping` | `mc://mappings/{version}/{sourceMapping}/{targetMapping}/{kind}/{owner}/{name}` | Look up a **field or method** mapping, including the `owner` class the member belongs to. For exact method overload resolution use the `find-mapping` tool with a `descriptor`. |
315
320
  | `class-members` | `mc://artifact/{artifactId}/members/{className}` | List constructors, methods, and fields for a class |
316
321
  | `artifact-metadata` | `mc://artifact/{artifactId}` | Metadata for a previously resolved artifact |
317
322
 
318
- `versions-list`, `runtime-metrics`, `find-mapping`, `class-members`, and `artifact-metadata` return structured JSON envelopes on success (`{ result, meta }`) and failure (`{ error, meta }`).
323
+ `versions-list`, `runtime-metrics`, `find-mapping`, `find-member-mapping`, `class-source-json`, `class-members`, and `artifact-metadata` return structured JSON envelopes on success (`{ result, meta }`) and failure (`{ error, meta }`).
319
324
 
320
325
  `class-source` and `artifact-file` keep raw text responses on success, but still return structured JSON errors on failure.
321
326
 
@@ -380,7 +385,7 @@ If `find-class` or `get-class-source` returns no hit on an `obfuscated` artifact
380
385
 
381
386
  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.
382
387
 
383
- Use `resolve-method-mapping-exact` when candidate ranking is not enough and the workflow needs strict `owner + name + descriptor` certainty.
388
+ Use `resolve-method-mapping-exact` when candidate ranking is not enough and the workflow needs strict `owner + name + descriptor` certainty. It is a strict shortcut for `find-mapping` (kind=method, signatureMode=exact) that additionally requires a **complete** descriptor projection — it returns `mapping_unavailable` when the descriptor's class references cannot all be projected to the target namespace, whereas `find-mapping`'s exact mode resolves those leniently. Prefer `find-mapping kind=method signatureMode=exact` unless you specifically need that strict-completeness guarantee.
384
389
 
385
390
  Use `find-mapping` `disambiguation.ownerHint` and `disambiguation.descriptorHint` to narrow ambiguous candidate sets.
386
391
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhisang/minecraft-modding-mcp",
3
- "version": "4.2.1",
3
+ "version": "6.0.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
  "main": "dist/index.js",