@adhisang/minecraft-modding-mcp 4.1.0 → 4.2.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 (70) hide show
  1. package/CHANGELOG.md +21 -2
  2. package/README.md +9 -2
  3. package/dist/entry-tools/analyze-symbol-service.d.ts +12 -0
  4. package/dist/entry-tools/analyze-symbol-service.js +7 -0
  5. package/dist/entry-tools/batch-class-members-service.d.ts +1 -0
  6. package/dist/entry-tools/batch-class-members-service.js +2 -0
  7. package/dist/entry-tools/batch-class-source-service.d.ts +1 -0
  8. package/dist/entry-tools/batch-class-source-service.js +2 -0
  9. package/dist/entry-tools/batch-mappings-service.d.ts +1 -0
  10. package/dist/entry-tools/batch-mappings-service.js +1 -0
  11. package/dist/entry-tools/batch-symbol-exists-service.d.ts +1 -0
  12. package/dist/entry-tools/batch-symbol-exists-service.js +2 -0
  13. package/dist/entry-tools/compare-minecraft-service.d.ts +9 -0
  14. package/dist/entry-tools/compare-minecraft-service.js +3 -1
  15. package/dist/entry-tools/inspect-minecraft/handlers/class-members.js +1 -0
  16. package/dist/entry-tools/inspect-minecraft/handlers/class-overview.js +3 -1
  17. package/dist/entry-tools/inspect-minecraft/handlers/class-source.js +1 -0
  18. package/dist/entry-tools/inspect-minecraft/handlers/list-files.js +1 -0
  19. package/dist/entry-tools/inspect-minecraft/handlers/search.js +2 -1
  20. package/dist/entry-tools/inspect-minecraft/internal.d.ts +17 -0
  21. package/dist/entry-tools/inspect-minecraft/internal.js +10 -0
  22. package/dist/entry-tools/inspect-minecraft-service.d.ts +40 -0
  23. package/dist/entry-tools/validate-project/cases/project-summary.d.ts +6 -1
  24. package/dist/entry-tools/validate-project/cases/project-summary.js +83 -9
  25. package/dist/entry-tools/validate-project/internal.d.ts +29 -18
  26. package/dist/entry-tools/validate-project/internal.js +37 -19
  27. package/dist/entry-tools/validate-project-service.d.ts +15 -1
  28. package/dist/entry-tools/validate-project-service.js +3 -2
  29. package/dist/entry-tools/verify-mixin-target-service.d.ts +2 -0
  30. package/dist/entry-tools/verify-mixin-target-service.js +1 -0
  31. package/dist/gradle-paths.d.ts +8 -3
  32. package/dist/gradle-paths.js +34 -5
  33. package/dist/index.js +29 -9
  34. package/dist/mapping/loaders/tiny-loom.d.ts +1 -1
  35. package/dist/mapping/loaders/tiny-loom.js +5 -2
  36. package/dist/mapping/types.d.ts +5 -0
  37. package/dist/mapping-service.d.ts +6 -1
  38. package/dist/mapping-service.js +26 -18
  39. package/dist/mixin-validator.d.ts +1 -1
  40. package/dist/mixin-validator.js +1 -1
  41. package/dist/source/access-validate.js +12 -8
  42. package/dist/source/artifact-resolver.d.ts +7 -1
  43. package/dist/source/artifact-resolver.js +120 -7
  44. package/dist/source/class-source/members-builder.d.ts +1 -0
  45. package/dist/source/class-source/members-builder.js +1 -1
  46. package/dist/source/class-source.d.ts +1 -0
  47. package/dist/source/class-source.js +9 -1
  48. package/dist/source/indexer.js +17 -0
  49. package/dist/source/lifecycle/diff.js +6 -6
  50. package/dist/source/lifecycle/mapping-helpers.d.ts +3 -3
  51. package/dist/source/lifecycle/mapping-helpers.js +17 -9
  52. package/dist/source/lifecycle/trace.js +2 -2
  53. package/dist/source/search.js +1 -0
  54. package/dist/source/state.d.ts +5 -0
  55. package/dist/source/state.js +5 -0
  56. package/dist/source/symbol-resolver.js +4 -1
  57. package/dist/source/validate-mixin/pipeline/mapping-health.js +2 -1
  58. package/dist/source/validate-mixin/pipeline/resolve.js +1 -0
  59. package/dist/source/validate-mixin/pipeline/target-lookup.js +12 -7
  60. package/dist/source-resolver.d.ts +1 -0
  61. package/dist/source-resolver.js +1 -1
  62. package/dist/source-service.d.ts +35 -1
  63. package/dist/source-service.js +5 -2
  64. package/dist/tool-contract-manifest.d.ts +1 -1
  65. package/dist/tool-contract-manifest.js +2 -2
  66. package/dist/tool-schemas.d.ts +91 -0
  67. package/dist/tool-schemas.js +20 -0
  68. package/docs/README-ja.md +4 -2
  69. package/docs/tool-reference.md +13 -7
  70. package/package.json +15 -3
@@ -16,6 +16,7 @@ export const ENCODE_COMPRESSIONS = ["none", "gzip"];
16
16
  export const nonEmptyString = z.string().trim().min(1);
17
17
  export const optionalNonEmptyString = z.string().trim().min(1).optional();
18
18
  export const optionalPositiveInt = z.number().int().positive().optional();
19
+ export const gradleUserHomeSchema = optionalNonEmptyString.describe("Gradle User Home to use for Loom/Gradle cache lookups instead of the MCP process GRADLE_USER_HOME.");
19
20
  // Optional descriptor: "" and whitespace-only strings are normalized to undefined so that
20
21
  // tools with signatureMode="name-only" can accept "caller omitted descriptor" inputs whether
21
22
  // the caller passed an empty string or omitted the field entirely. Malformed descriptors are
@@ -98,6 +99,7 @@ export const resolveArtifactShape = {
98
99
  sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
99
100
  allowDecompile: z.boolean().default(true),
100
101
  projectPath: optionalNonEmptyString.describe("Optional workspace root path for Loom cache-assisted source resolution"),
102
+ gradleUserHome: gradleUserHomeSchema,
101
103
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
102
104
  preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override target.value"),
103
105
  strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false."),
@@ -114,6 +116,7 @@ export const getClassSourceShape = {
114
116
  sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
115
117
  allowDecompile: z.boolean().default(true),
116
118
  projectPath: optionalNonEmptyString.describe("Optional workspace root path for Loom cache-assisted source resolution"),
119
+ gradleUserHome: gradleUserHomeSchema,
117
120
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
118
121
  preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override target.value"),
119
122
  strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false."),
@@ -149,6 +152,7 @@ export const getClassMembersShape = {
149
152
  memberPattern: optionalNonEmptyString,
150
153
  maxMembers: optionalPositiveInt.describe("default 500, max 5000"),
151
154
  projectPath: optionalNonEmptyString,
155
+ gradleUserHome: gradleUserHomeSchema,
152
156
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
153
157
  preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override version"),
154
158
  strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false."),
@@ -174,6 +178,7 @@ export const verifyMixinTargetShape = {
174
178
  mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
175
179
  sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
176
180
  projectPath: optionalNonEmptyString.describe("Workspace root path for target.kind=workspace and Loom cache assistance."),
181
+ gradleUserHome: gradleUserHomeSchema,
177
182
  target: resolveArtifactTargetSchema.describe(RESOLVE_ARTIFACT_TARGET_DESCRIPTION),
178
183
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
179
184
  preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override target.value"),
@@ -196,6 +201,7 @@ export const batchClassSourceShape = {
196
201
  sourcePriority: mappingSourcePrioritySchema.optional(),
197
202
  allowDecompile: z.boolean().optional(),
198
203
  projectPath: optionalNonEmptyString,
204
+ gradleUserHome: gradleUserHomeSchema,
199
205
  scope: artifactScopeSchema.optional(),
200
206
  preferProjectVersion: z.boolean().optional(),
201
207
  strictVersion: z.boolean().optional(),
@@ -250,6 +256,7 @@ export const batchClassMembersShape = {
250
256
  sourcePriority: mappingSourcePrioritySchema.optional(),
251
257
  allowDecompile: z.boolean().optional(),
252
258
  projectPath: optionalNonEmptyString,
259
+ gradleUserHome: gradleUserHomeSchema,
253
260
  scope: artifactScopeSchema.optional(),
254
261
  preferProjectVersion: z.boolean().optional(),
255
262
  strictVersion: z.boolean().optional(),
@@ -278,6 +285,7 @@ export const batchSymbolExistsShape = {
278
285
  sourcePriority: mappingSourcePrioritySchema.optional(),
279
286
  allowDecompile: z.boolean().optional(),
280
287
  projectPath: optionalNonEmptyString,
288
+ gradleUserHome: gradleUserHomeSchema,
281
289
  scope: artifactScopeSchema.optional(),
282
290
  preferProjectVersion: z.boolean().optional(),
283
291
  strictVersion: z.boolean().optional(),
@@ -310,6 +318,7 @@ export const batchMappingsShape = {
310
318
  version: nonEmptyString.describe("Minecraft version shared by every entry. Per-entry version is rejected; this batch shape is intentionally single-version."),
311
319
  sourcePriority: mappingSourcePrioritySchema.optional(),
312
320
  projectPath: optionalNonEmptyString,
321
+ gradleUserHome: gradleUserHomeSchema,
313
322
  concurrency: z.number().int().min(1).max(8).optional(),
314
323
  failFast: z.boolean().optional(),
315
324
  compact: z.boolean().optional(),
@@ -329,6 +338,7 @@ export const searchClassSourceShape = {
329
338
  cursor: optionalNonEmptyString,
330
339
  queryNamespace: sourceMappingSchema.optional().describe("Namespace of the query. When set and intent='symbol' with a fully-qualified class name, the query is translated through find-mapping before searching the artifact namespace. Ignored for text/path intents (warning surfaced)."),
331
340
  sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first. Used only when queryNamespace triggers translation."),
341
+ gradleUserHome: gradleUserHomeSchema,
332
342
  compact: z.boolean().default(false).describe("When true, strip the artifactContents summary and empty fields from the response. Default false.")
333
343
  };
334
344
  export const searchClassSourceSchema = z.object(searchClassSourceShape).superRefine((value, ctx) => {
@@ -361,6 +371,7 @@ export const traceSymbolLifecycleShape = {
361
371
  toVersion: optionalNonEmptyString,
362
372
  mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn (default obfuscated)"),
363
373
  sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
374
+ gradleUserHome: gradleUserHomeSchema,
364
375
  includeSnapshots: z.boolean().default(false),
365
376
  maxVersions: optionalPositiveInt.default(120).describe("max 400"),
366
377
  includeTimeline: z.boolean().default(false)
@@ -372,6 +383,7 @@ export const diffClassSignaturesShape = {
372
383
  toVersion: nonEmptyString,
373
384
  mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn (default obfuscated)"),
374
385
  sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
386
+ gradleUserHome: gradleUserHomeSchema,
375
387
  includeFullDiff: z.boolean().default(true).describe("When false, omit from/to snapshots from modified entries and keep only key+changed")
376
388
  };
377
389
  export const diffClassSignaturesSchema = z.object(diffClassSignaturesShape);
@@ -384,6 +396,7 @@ export const findMappingShape = {
384
396
  sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
385
397
  targetMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
386
398
  sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
399
+ gradleUserHome: gradleUserHomeSchema,
387
400
  signatureMode: z.enum(["exact", "name-only"]).default("name-only")
388
401
  .describe("exact: descriptor required for kind=method; name-only (default): match by owner+name only"),
389
402
  disambiguation: z
@@ -463,6 +476,7 @@ export const resolveMethodMappingExactShape = {
463
476
  sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
464
477
  targetMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
465
478
  sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
479
+ gradleUserHome: gradleUserHomeSchema,
466
480
  maxCandidates: optionalPositiveInt.default(5).describe("Limit returned candidates (default 5, max 200). Raise when you need the full candidate list."),
467
481
  compact: z.boolean().default(true).describe("Omit top-level empty arrays, null/undefined values, and empty objects from the response. "
468
482
  + "Also omit redundant candidates array for single full-confidence exact-match resolutions. "
@@ -505,6 +519,7 @@ export const getClassApiMatrixShape = {
505
519
  classNameMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
506
520
  includeKinds: classApiKindsSchema.optional().describe("comma-separated: class,field,method"),
507
521
  sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
522
+ gradleUserHome: gradleUserHomeSchema,
508
523
  maxRows: optionalPositiveInt.describe("Limit returned rows (max 5000)")
509
524
  };
510
525
  export const getClassApiMatrixSchema = z.object(getClassApiMatrixShape);
@@ -517,6 +532,7 @@ export const resolveWorkspaceSymbolShape = {
517
532
  descriptor: optionalDescriptorString.describe("JVM descriptor. Empty strings are treated as omitted."),
518
533
  sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
519
534
  sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
535
+ gradleUserHome: gradleUserHomeSchema,
520
536
  maxCandidates: optionalPositiveInt.default(5).describe("Limit returned candidates for field/method lookups (default 5, max 200). Raise when you need the full candidate list."),
521
537
  compact: z.boolean().default(true).describe("Omit top-level empty arrays, null/undefined values, and empty objects from the response. "
522
538
  + "Also omit redundant candidates array for single full-confidence exact-match resolutions. "
@@ -589,6 +605,7 @@ export const checkSymbolExistsShape = {
589
605
  descriptor: optionalDescriptorString.describe("required for kind=method unless signatureMode=name-only. Empty strings are treated as omitted."),
590
606
  sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
591
607
  sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
608
+ gradleUserHome: gradleUserHomeSchema,
592
609
  nameMode: classNameModeSchema.default("fqcn").describe("fqcn | auto"),
593
610
  signatureMode: z.enum(["exact", "name-only"]).default("exact")
594
611
  .describe("exact: require descriptor for methods; name-only: match by owner+name only"),
@@ -711,6 +728,7 @@ export const validateMixinShape = {
711
728
  sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
712
729
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
713
730
  projectPath: optionalNonEmptyString.describe("Optional workspace root path for Loom cache-assisted source resolution"),
731
+ gradleUserHome: gradleUserHomeSchema,
714
732
  preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override version"),
715
733
  minSeverity: z.enum(["error", "warning", "all"]).default("all")
716
734
  .describe("'error'=errors only, 'warning'=errors+warnings, 'all'=everything"),
@@ -738,6 +756,7 @@ export const validateAccessWidenerShape = {
738
756
  mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
739
757
  sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
740
758
  projectPath: optionalNonEmptyString.describe("Optional workspace root path for Loom cache-assisted runtime validation"),
759
+ gradleUserHome: gradleUserHomeSchema,
741
760
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
742
761
  preferProjectVersion: z.boolean().default(false)
743
762
  .describe("When true, detect MC version from gradle.properties and override version")
@@ -749,6 +768,7 @@ export const validateAccessTransformerShape = {
749
768
  atNamespace: z.enum(["srg", "mojang", "obfuscated"]).optional().describe("srg | mojang | obfuscated"),
750
769
  sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
751
770
  projectPath: optionalNonEmptyString.describe("Optional workspace root path for Forge/NeoForge runtime validation"),
771
+ gradleUserHome: gradleUserHomeSchema,
752
772
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
753
773
  preferProjectVersion: z.boolean().default(false)
754
774
  .describe("When true, detect MC version from gradle.properties and override version")
package/docs/README-ja.md CHANGED
@@ -158,6 +158,8 @@ stdio トランスポートは、改行区切り形式と `Content-Length` フ
158
158
  - `trace-symbol-lifecycle` の `symbol` には `Class.method` を指定します。厳密なオーバーロード指定は別フィールドの `descriptor` を使ってください。
159
159
  - ワークスペースのソースカバレッジが部分的な場合でも、バニラクラスを確認できます。`inspect-minecraft task="list-files"` は、その場合に部分的な結果とフォローアップガイダンスを返します。
160
160
  - `analyze-mod` と `validate-project` は、オブジェクト形式の `subject` と正規の `include` グループを要求します。古い文字列形式の `subject` やドメイン名形式の `include` には `ERR_INVALID_INPUT` と、再試行しやすい `suggestedCall` を返します。
161
+ - `validate-mixin` と `validate-project` は、`obfuscated` / `mojang` 検証では `mapping-health` を軽量に保ちます。`intermediary` / `yarn` 名前空間を要求しない限り、完全な Tiny マッピンググラフは読み込みません。
162
+ - `validate-project task="project-summary"` の `tasks["minecraft.artifact.resolved"]` は軽量なアーティファクト probe です。probe 状態を返すためだけに Minecraft のデコンパイルやソースインデックス再構築は行いません。追加の `tasks` フィールドを省きたい場合は `VALIDATE_PROJECT_TASKS_OFF=1` を使います。
161
163
 
162
164
  ### あるバージョンの Minecraft ソースを確認する
163
165
 
@@ -250,7 +252,7 @@ stdio トランスポートは、改行区切り形式と `Content-Length` フ
250
252
 
251
253
  ### トップレベルワークフローツール
252
254
 
253
- <!-- BEGIN GENERATED TOOL TABLE: v3-entry-tools -->
255
+ <!-- BEGIN GENERATED TOOL TABLE: top-level-workflow-tools -->
254
256
  | ツール | 役割 |
255
257
  | --- | --- |
256
258
  | `inspect-minecraft` | バージョン、アーティファクト、クラス、ファイル、ソース本文、ワークスペース文脈の調査フローをまとめて扱う |
@@ -259,7 +261,7 @@ stdio トランスポートは、改行区切り形式と `Content-Length` フ
259
261
  | `analyze-mod` | Mod メタデータの要約、Mod コードのデコンパイル / 検索、クラスソース確認、リマップのプレビュー / 実行を扱う |
260
262
  | `validate-project` | ワークスペース要約と、Mixin / Access Widener / Access Transformer の直接検証を行う |
261
263
  | `manage-cache` | キャッシュの一覧、検証、クリーンアップ / 再構築のプレビュー / 実行を行う |
262
- <!-- END GENERATED TOOL TABLE: v3-entry-tools -->
264
+ <!-- END GENERATED TOOL TABLE: top-level-workflow-tools -->
263
265
 
264
266
  ### ソース探索
265
267
 
@@ -38,6 +38,7 @@ Start here when you are not sure which tool to reach for. In every row, the left
38
38
  - When a parameter has a fixed safe default, `tools/list` exposes it through the JSON Schema `default` field so clients can rely on schema metadata instead of prose notes.
39
39
  - Retryable `suggestedCall` payloads omit parameters when the supplied value already matches the tool default, keeping recovery calls smaller without changing behavior.
40
40
  - Source-oriented tools expose `artifactContents` so callers can tell whether the backing artifact is a `source-jar` or a `decompiled-binary`. `get-class-source`, `get-class-members`, `search-class-source`, and `get-artifact-file` also expose `returnedNamespace`.
41
+ - Cache-backed source, mapping, validation, batch, and workflow tools accept `gradleUserHome?: string` when they need Loom cache data. Use it for builds that used an isolated `GRADLE_USER_HOME`; the server searches `<gradleUserHome>/loom-cache` and `<gradleUserHome>/caches/fabric-loom` before the MCP process default. The value selects a Gradle User Home, not arbitrary Loom cache roots.
41
42
  - `get-class-members` returns `decompiledFallback` (with `constructors`, `fields`, `methods`, each entry is `{ name, line, kind }`) and `decompiledMemberCounts` whenever bytecode enumeration yields zero but the decompiled source for the class is already indexed. The bytecode-derived `members` / `counts` are preserved as-is; the fallback is additive and carries no descriptor or access modifier. `qualityFlags` gains `"members-from-decompiled-source"` in that case. Use `get-class-source` for descriptors and full context.
42
43
  - `get-class-members` also returns an additive `status: "ok" | "members_unavailable" | "partial"` field so callers can distinguish "really 0 members" from "extraction unavailable":
43
44
 
@@ -91,6 +92,7 @@ Workspace detection is memoised in a process-resident `WorkspaceContextCache` (1
91
92
  - `validate-mixin` summary-first workflows should combine `includeIssues=false`, `reportMode="compact"`, and `warningMode="aggregated"`.
92
93
  - `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.
93
94
  - `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.
95
+ - `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.
94
96
  - `validate-mixin` runs each stage (`resolve` / `mapping-health` / `parse` / `target-lookup`) against an independent soft-deadline. When the `target-lookup` stage exhausts its budget mid-loop, completed targets stay in `targetOutcomes` with `status: "ok"` (and `slowTarget: true` plus `elapsedMs` when the per-target soft cap was exceeded) while remaining targets land as `status: "deferred-budget"`. The summary then carries `targetsDeferredBudget` and `degradedReason: "stage-budget"`, and `validationStatus` is promoted to `"partial"`. If the budget is exhausted before the first iteration, `targetOutcomes` stays empty, `targetsDeferredBudget` is omitted, and `degradedReason: "stage-budget-pre-target"`.
95
97
  - Empty Mixin configs are treated as warning-only discovery results with `summary.total=0` instead of invalid input; malformed JSON still returns `ERR_INVALID_INPUT`.
96
98
 
@@ -148,6 +150,8 @@ Common input fields:
148
150
  - `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.
149
151
  - Per-tool shared inputs (`target`, `mapping`, `projectPath`, `version`, etc.) follow the same shape as the matching single tool.
150
152
 
153
+ 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.
154
+
151
155
  Common output:
152
156
 
153
157
  ```json
@@ -271,15 +275,15 @@ These environment variables are read once at worker startup and provide rollback
271
275
  | --- | --- | --- | --- |
272
276
  | `workspace.detected` | A `gradle.properties`, `settings.gradle{,.kts}`, or `build.gradle{,.kts}` file exists at `subject.projectPath`. | `evidence: ["gradle.properties", ...]` lists the gradle files that were found. | `missing` when no gradle files exist; `error` when the filesystem read itself failed. |
273
277
  | `gradle.readable` | `gradle.properties` can be read and the workspace's gradle build scripts are enumerable. | `propertiesPath` and `buildScripts[]` (relative paths). | `skipped` when `workspace.detected` is not `ok`; `missing` when no gradle files at all; `error` on parse / read failure. |
274
- | `loom.cache.found` | A Loom (Fabric / Quilt) cache directory under the workspace or `GRADLE_USER_HOME` exists. Independent of `workspace.detected` so callers can detect a global Loom cache even on non-gradle workspaces. | `cachePath` of the first matching directory. | `missing` when none of the candidate roots exist; `error` on filesystem failure. |
275
- | `minecraft.artifact.resolved` | `resolve-artifact` with `target: { kind: "version", value: <resolvedVersion> }` succeeds against the workspace context. | `artifactId` and `mappingApplied`. | `skipped` when `workspace.detected` or `gradle.readable` is not `ok`; `error` when `resolve-artifact` throws (carries `error.code` and `error.detail`). |
276
- | `mixins.validated` | At least one `*.mixins.json` file was discovered AND every per-config validation completed without throwing. | `counts: { ok, partial, invalid }` (validation outcomes from `validate-mixin`). | `skipped` when any upstream probe is non-`ok`; `missing` when discovery returned 0 paths; `error` when one or more per-config validations threw. |
277
- | `accessWideners.validated` | At least one Access Widener file was discovered AND every validation completed without throwing. | `counts: { ok, invalid }`. | `skipped` / `missing` / `error` follow the same rules as `mixins.validated`. |
278
- | `accessTransformers.validated` | At least one Access Transformer file was discovered AND every validation completed without throwing. | `counts: { ok, invalid }`. | Same as `mixins.validated`. |
278
+ | `loom.cache.found` | A Loom (Fabric / Quilt) cache directory exists under the workspace, `gradleUserHome`, or the process `GRADLE_USER_HOME`. It is independent of `workspace.detected`, so callers can detect a global Loom cache even on non-Gradle workspaces. | `cachePath` of the first matching directory. | `missing` when none of the candidate roots exist; `error` on filesystem failure. |
279
+ | `minecraft.artifact.resolved` | A lightweight artifact metadata probe can locate `target: { kind: "version", value: <resolvedVersion> }` against the workspace context. The probe does not decompile Minecraft or rebuild the source index. | `artifactId` and `mappingApplied`. | `skipped` when `workspace.detected` or `gradle.readable` is not `ok`; `error` when the lightweight probe cannot verify the artifact or requested mapping without full resolution (carries `error.code` and `error.detail`). |
280
+ | `mixins.validated` | At least one `*.mixins.json` file was discovered AND every per-config validation completed without throwing. | `counts: { ok, partial, invalid }` (validation outcomes from `validate-mixin`). | `error` when any per-config validation threw (still emits `counts`); `skipped` when discovery was empty AND `workspace.detected` / `gradle.readable` blocked; `missing` when discovery returned 0 paths and upstream probes were `ok`. A failed `minecraft.artifact.resolved` does not flip executed validators to `skipped`. |
281
+ | `accessWideners.validated` | At least one Access Widener file was discovered AND every validation completed without throwing. | `counts: { ok, invalid }`. | Same rules as `mixins.validated`. |
282
+ | `accessTransformers.validated` | At least one Access Transformer file was discovered AND every validation completed without throwing. | `counts: { ok, invalid }`. | Same rules as `mixins.validated`. |
279
283
 
280
- Status precedence (top wins): `skipped` (upstream blocked) > `missing` (no items) > `error` (item-level caught) > `ok`.
284
+ Status precedence (top wins): `error` (item-level caught) > `ok` (validators ran) > `skipped` (upstream env blocked AND no items ran) > `missing` (no items, upstream `ok`).
281
285
 
282
- Output projection: with `detail: "summary"` (or when `include` does not contain `"workspace"`), each `tasks[*]` entry is slimmed to `status`, `error?`, and `warnings?` only — `evidence` / `buildScripts` / `counts` / `propertiesPath` / `cachePath` / `artifactId` / `mapping` / `durationMs` are stripped. With `detail: "full"` (or `"standard"`) AND `include` containing `"workspace"`, every sub-field is preserved. Set `VALIDATE_PROJECT_TASKS_OFF=1` at process start to omit the field entirely (legacy shape).
286
+ Output projection: with `detail: "summary"` (or when `include` does not contain `"workspace"`), each `tasks[*]` entry is slimmed to `status`, `error?`, and `warnings?` only — `evidence` / `buildScripts` / `counts` / `propertiesPath` / `cachePath` / `artifactId` / `mapping` / `durationMs` are stripped. With `detail: "full"` (or `"standard"`) AND `include` containing `"workspace"`, every sub-field is preserved. Set `VALIDATE_PROJECT_TASKS_OFF=1` at process start to omit the field entirely (legacy shape). Use `resolve-artifact` directly when a follow-up source lookup needs a fully indexed artifact.
283
287
  - `validate-access-widener` keeps vanilla validation when `projectPath`, `scope`, and `preferProjectVersion` are omitted. Supplying Loom workspace context switches it into runtime-aware mode, which returns `provenance` and per-entry runtime access evidence without changing the existing summary shape.
284
288
  - `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"`.
285
289
  - Start with `manage-cache` for cache inventory and safe cleanup. Use `executionMode="preview"` before `executionMode="apply"`.
@@ -385,6 +389,8 @@ Use `resolve-workspace-symbol` when you need compile-visible names from actual G
385
389
 
386
390
  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.
387
391
 
392
+ `gradleUserHome` is a per-call path option, not an environment variable. It takes precedence over the MCP process `GRADLE_USER_HOME` for Loom source jars, Loom Tiny mappings, loader/runtime jars, and `validate-project` Loom cache probes. `projectPath` search roots still apply for workspace-local caches.
393
+
388
394
  ### Core and Repository Discovery
389
395
 
390
396
  | Variable | Default | Description |
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@adhisang/minecraft-modding-mcp",
3
- "version": "4.1.0",
4
- "description": "MCP server with utilities for Minecraft modding workflows",
3
+ "version": "4.2.0",
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",
7
7
  "types": "dist/index.d.ts",
@@ -36,9 +36,21 @@
36
36
  "validate": "npm run check && npm test && npm run test:coverage && npm run test:perf"
37
37
  },
38
38
  "keywords": [
39
+ "claude",
40
+ "fabric",
41
+ "forge",
39
42
  "mcp",
43
+ "mcp-server",
40
44
  "minecraft",
41
- "modding"
45
+ "minecraft-modding",
46
+ "mixin",
47
+ "modding",
48
+ "model-context-protocol",
49
+ "mojang-mappings",
50
+ "neoforge",
51
+ "nodejs",
52
+ "typescript",
53
+ "yarn-mappings"
42
54
  ],
43
55
  "author": "adhi-jp",
44
56
  "license": "MIT",