@adhisang/minecraft-modding-mcp 5.0.0 → 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 (72) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/access-widener-parser.d.ts +1 -0
  3. package/dist/access-widener-parser.js +6 -3
  4. package/dist/cache-registry.js +35 -31
  5. package/dist/decompiler/vineflower.js +8 -2
  6. package/dist/entry-tools/analyze-mod-service.js +2 -1
  7. package/dist/entry-tools/analyze-symbol-service.js +18 -9
  8. package/dist/entry-tools/compare-minecraft-service.js +1 -1
  9. package/dist/entry-tools/inspect-minecraft/handlers/class-members.js +2 -1
  10. package/dist/entry-tools/inspect-minecraft/handlers/file.js +26 -1
  11. package/dist/entry-tools/inspect-minecraft/handlers/versions.js +2 -1
  12. package/dist/entry-tools/inspect-minecraft/internal.js +2 -0
  13. package/dist/entry-tools/response-contract.d.ts +2 -0
  14. package/dist/entry-tools/response-contract.js +2 -2
  15. package/dist/entry-tools/validate-project-service.d.ts +4 -4
  16. package/dist/entry-tools/verify-mixin-target-service.js +7 -7
  17. package/dist/index.js +20 -16
  18. package/dist/java-process.js +1 -1
  19. package/dist/json-rpc-framing.d.ts +4 -0
  20. package/dist/json-rpc-framing.js +23 -1
  21. package/dist/mapping/internal-types.d.ts +17 -0
  22. package/dist/mapping/loaders/tiny-maven.js +46 -20
  23. package/dist/mapping/lookup.d.ts +12 -1
  24. package/dist/mapping/lookup.js +53 -1
  25. package/dist/mapping-service.js +36 -21
  26. package/dist/mixin/annotation-validators.js +21 -3
  27. package/dist/mixin/parsed-validator.js +1 -0
  28. package/dist/mixin-parser.js +71 -3
  29. package/dist/mod-decompile-service.d.ts +2 -0
  30. package/dist/mod-decompile-service.js +19 -2
  31. package/dist/mod-remap-service.js +6 -5
  32. package/dist/mojang-tiny-mapping-service.js +5 -2
  33. package/dist/nbt/java-nbt-codec.js +40 -16
  34. package/dist/nbt/json-patch.js +51 -12
  35. package/dist/nbt/typed-json.d.ts +1 -0
  36. package/dist/nbt/typed-json.js +12 -2
  37. package/dist/nbt/types.d.ts +2 -2
  38. package/dist/path-converter.js +10 -3
  39. package/dist/registry-service.d.ts +2 -0
  40. package/dist/registry-service.js +16 -1
  41. package/dist/repo-downloader.js +4 -3
  42. package/dist/source/artifact-resolver.js +1 -1
  43. package/dist/source/class-source/snippet-builder.js +6 -0
  44. package/dist/source/class-source-helpers.d.ts +4 -4
  45. package/dist/source/class-source-helpers.js +12 -11
  46. package/dist/source/class-source.d.ts +19 -0
  47. package/dist/source/class-source.js +48 -21
  48. package/dist/source/file-access.js +3 -2
  49. package/dist/source/indexer.js +24 -7
  50. package/dist/source/lifecycle/mapping-helpers.js +28 -3
  51. package/dist/source/lifecycle/runtime-check.js +20 -6
  52. package/dist/source/search.js +23 -8
  53. package/dist/source/validate-mixin/pipeline/resolve.js +23 -3
  54. package/dist/source/workspace-target.js +2 -1
  55. package/dist/source-resolver.js +2 -2
  56. package/dist/source-service.js +9 -1
  57. package/dist/stdio-supervisor.d.ts +2 -2
  58. package/dist/stdio-supervisor.js +29 -9
  59. package/dist/storage/db.js +24 -1
  60. package/dist/storage/files-repo.d.ts +3 -0
  61. package/dist/storage/files-repo.js +43 -37
  62. package/dist/storage/symbols-repo.d.ts +9 -0
  63. package/dist/storage/symbols-repo.js +47 -19
  64. package/dist/symbols/symbol-extractor.js +1 -1
  65. package/dist/tool-guidance.d.ts +2 -1
  66. package/dist/tool-guidance.js +26 -1
  67. package/dist/tool-schemas.d.ts +4 -4
  68. package/dist/tool-schemas.js +91 -91
  69. package/dist/warning-details.d.ts +12 -0
  70. package/dist/warning-details.js +17 -0
  71. package/dist/workspace-mapping-service.js +9 -0
  72. package/package.json +1 -1
@@ -1,12 +1,12 @@
1
- import { isAbsolute as pathIsAbsolute, resolve as pathResolve } from "node:path";
1
+ import { resolve as pathResolve } from "node:path";
2
2
  import { z } from "zod";
3
3
  import { DETAIL_LEVELS, CANONICAL_INCLUDE_GROUPS } from "./entry-tools/response-contract.js";
4
4
  // Shared response-shape controls for the expert + batch tools (replacing the old
5
5
  // per-tool `compact` boolean). detail: summary|standard|full + include[] mirrors the
6
6
  // entry-tool contract. Defaults are per-tool (see DEFAULT_DETAIL_BY_TOOL in response-utils):
7
7
  // resolution/mapping tools + batch default "summary"; source/file tools default "standard".
8
- const DETAIL_DESCRIPTION = "Response detail: 'summary' (terse: drops diagnostics/empties, slims candidates), 'standard' (default for source/file tools: keeps fields but drops heavy diagnostics), 'full' (everything). Replaces the old `compact` flag.";
9
- const RESPONSE_INCLUDE_DESCRIPTION = "Opt specific field groups back in regardless of detail, e.g. [\"provenance\"], [\"candidates\"], [\"samples\"], [\"artifact\"], [\"descriptors\"].";
8
+ const DETAIL_DESCRIPTION = "summary = terse (drops diagnostics/empties, slims candidates); standard = keeps fields, drops heavy diagnostics; full = everything.";
9
+ const RESPONSE_INCLUDE_DESCRIPTION = 'Field groups to include regardless of detail, e.g. ["provenance"].';
10
10
  function detailParam(defaultLevel) {
11
11
  return z.enum(DETAIL_LEVELS).default(defaultLevel).describe(DETAIL_DESCRIPTION);
12
12
  }
@@ -30,7 +30,7 @@ export const ENCODE_COMPRESSIONS = ["none", "gzip"];
30
30
  export const nonEmptyString = z.string().trim().min(1);
31
31
  export const optionalNonEmptyString = z.string().trim().min(1).optional();
32
32
  export const optionalPositiveInt = z.number().int().positive().optional();
33
- export const gradleUserHomeSchema = optionalNonEmptyString.describe("Gradle User Home to use for Loom/Gradle cache lookups instead of the MCP process GRADLE_USER_HOME.");
33
+ export const gradleUserHomeSchema = optionalNonEmptyString.describe("Gradle user home for Loom cache lookups (overrides GRADLE_USER_HOME).");
34
34
  // Optional descriptor: "" and whitespace-only strings are normalized to undefined so that
35
35
  // tools with signatureMode="name-only" can accept "caller omitted descriptor" inputs whether
36
36
  // the caller passed an empty string or omitted the field entirely. Malformed descriptors are
@@ -89,13 +89,13 @@ export const sourceLookupTargetSchema = z.discriminatedUnion("kind", [
89
89
  dependencyTargetSchema,
90
90
  z.object({ kind: z.literal("artifact"), artifactId: nonEmptyString })
91
91
  ]);
92
- export const RESOLVE_ARTIFACT_TARGET_DESCRIPTION = 'Object with kind. Examples: {"kind":"version","value":"1.21.10"}, {"kind":"workspace"} (uses projectPath), or {"kind":"dependency","group":"dev.architectury","name":"architectury"}. Must be an object, not a string.';
93
- export const SOURCE_LOOKUP_TARGET_DESCRIPTION = 'Object with kind (same shape as resolve-artifact). Examples: {"kind":"version","value":"1.21.10"}, {"kind":"workspace"} (uses projectPath), {"kind":"dependency","group":"...","name":"..."}, or {"kind":"artifact","artifactId":"..."} to reuse an already-resolved artifact. Must be an object, not a string.';
94
- export const SOURCE_SCOPE_DESCRIPTION = "vanilla = Mojang client jar only; merged = source-oriented merged runtime discovery; loader = loader/runtime artifact discovery when the workspace exposes transformed runtime jars.";
92
+ export const RESOLVE_ARTIFACT_TARGET_DESCRIPTION = 'Object, not string. e.g. {"kind":"version","value":"1.21.10"}, {"kind":"workspace"}, {"kind":"dependency","group":"g","name":"n"}.';
93
+ export const SOURCE_LOOKUP_TARGET_DESCRIPTION = 'Same shape as resolve-artifact target, plus {"kind":"artifact","artifactId":"..."} to reuse a resolved artifact. Object, not string.';
94
+ export const SOURCE_SCOPE_DESCRIPTION = "vanilla = Mojang client jar only; merged = merged runtime discovery; loader = loader-transformed runtime jars.";
95
95
  // Shared describe() text reused by every symbol-lookup tool so the contract reads
96
96
  // identically on find-mapping and check-symbol-exists (and any future sibling).
97
97
  export const SIGNATURE_MODE_DESCRIPTION = "exact: descriptor required for kind=method; name-only (default): match by owner+name only.";
98
- export const NAME_MODE_DESCRIPTION = "auto (default): accept a fully-qualified name, or a dotless name where the tool allows it; fqcn: require a fully-qualified name.";
98
+ export const NAME_MODE_DESCRIPTION = "auto (default): FQCN, or dotless name where allowed; fqcn: require FQCN.";
99
99
  export const listVersionsShape = {
100
100
  includeSnapshots: z.boolean().default(false),
101
101
  limit: optionalPositiveInt.default(20).describe("max 200")
@@ -103,14 +103,14 @@ export const listVersionsShape = {
103
103
  export const listVersionsSchema = z.object(listVersionsShape);
104
104
  export const resolveArtifactShape = {
105
105
  target: resolveArtifactTargetSchema.describe(RESOLVE_ARTIFACT_TARGET_DESCRIPTION),
106
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
107
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
106
+ mapping: sourceMappingSchema.optional(),
107
+ sourcePriority: mappingSourcePrioritySchema.optional(),
108
108
  allowDecompile: z.boolean().default(true),
109
- projectPath: optionalNonEmptyString.describe("Optional workspace root path for Loom cache-assisted source resolution"),
109
+ projectPath: optionalNonEmptyString.describe("Workspace root for Loom cache-assisted resolution"),
110
110
  gradleUserHome: gradleUserHomeSchema,
111
111
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
112
- preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override target.value"),
113
- strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false."),
112
+ preferProjectVersion: z.boolean().optional().describe("Detect MC version from gradle.properties and override target.value"),
113
+ strictVersion: z.boolean().optional().describe("Reject version-approximated results (default false)"),
114
114
  detail: detailParam("summary"),
115
115
  include: responseIncludeParam
116
116
  };
@@ -119,14 +119,14 @@ export const getClassSourceShape = {
119
119
  className: nonEmptyString,
120
120
  mode: sourceModeSchema.default("metadata").describe("metadata = symbol outline only; snippet = source with default maxLines=200; full = entire source"),
121
121
  target: sourceLookupTargetSchema.describe(SOURCE_LOOKUP_TARGET_DESCRIPTION),
122
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
123
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
122
+ mapping: sourceMappingSchema.optional(),
123
+ sourcePriority: mappingSourcePrioritySchema.optional(),
124
124
  allowDecompile: z.boolean().default(true),
125
- projectPath: optionalNonEmptyString.describe("Optional workspace root path for Loom cache-assisted source resolution"),
125
+ projectPath: optionalNonEmptyString.describe("Workspace root for Loom cache-assisted resolution"),
126
126
  gradleUserHome: gradleUserHomeSchema,
127
127
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
128
- preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override target.value"),
129
- strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false."),
128
+ preferProjectVersion: z.boolean().optional().describe("Detect MC version from gradle.properties and override target.value"),
129
+ strictVersion: z.boolean().optional().describe("Reject version-approximated results (default false)"),
130
130
  startLine: optionalPositiveInt,
131
131
  endLine: optionalPositiveInt,
132
132
  maxLines: optionalPositiveInt,
@@ -134,7 +134,7 @@ export const getClassSourceShape = {
134
134
  outputFile: optionalNonEmptyString.describe("Write source to this file path and return metadata-only response"),
135
135
  detail: detailParam("standard"),
136
136
  include: responseIncludeParam,
137
- includeProvenance: z.boolean().default(false).describe("Alias for include:[\"provenance\"]. When true, include diagnostic metadata (provenance, qualityFlags, artifactContents). Default false — omitted to keep the common path lean.")
137
+ includeProvenance: z.boolean().default(false).describe('Alias for include:["provenance"] (diagnostic metadata). Default false.')
138
138
  };
139
139
  export const getClassSourceSchema = z
140
140
  .object(getClassSourceShape)
@@ -152,24 +152,24 @@ export const getClassSourceSchema = z
152
152
  export const getClassMembersShape = {
153
153
  className: nonEmptyString,
154
154
  target: sourceLookupTargetSchema.describe(SOURCE_LOOKUP_TARGET_DESCRIPTION),
155
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn (default obfuscated)"),
156
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
155
+ mapping: sourceMappingSchema.optional().describe("default obfuscated"),
156
+ sourcePriority: mappingSourcePrioritySchema.optional(),
157
157
  allowDecompile: z.boolean().default(true),
158
- access: memberAccessSchema.default("public").describe("public | all"),
158
+ access: memberAccessSchema.default("public"),
159
159
  includeSynthetic: z.boolean().default(false),
160
160
  includeInherited: z.boolean().default(false),
161
161
  memberPattern: optionalNonEmptyString,
162
162
  maxMembers: optionalPositiveInt.describe("default 150, max 5000. Page beyond the first 150 with cursor."),
163
- cursor: optionalNonEmptyString.describe("Continuation cursor from a previous response's nextCursor; resumes the member list after the last returned page."),
163
+ cursor: optionalNonEmptyString.describe("nextCursor from the previous response."),
164
164
  projectPath: optionalNonEmptyString,
165
165
  gradleUserHome: gradleUserHomeSchema,
166
166
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
167
- preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override version"),
168
- strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false."),
167
+ preferProjectVersion: z.boolean().optional().describe("Detect MC version from gradle.properties and override version"),
168
+ strictVersion: z.boolean().optional().describe("Reject version-approximated results (default false)"),
169
169
  detail: detailParam("standard"),
170
170
  include: responseIncludeParam,
171
- includeProvenance: z.boolean().default(false).describe("Alias for include:[\"provenance\"]. When true, include diagnostic metadata (provenance, qualityFlags, artifactContents). Default false — omitted to keep the common path lean."),
172
- includeDescriptors: z.boolean().default(false).describe("Alias for include:[\"descriptors\"]. When true, also emit jvmDescriptor on FIELD members. Default false: field descriptors are omitted (the type is already in javaSignature). Method/constructor descriptors are always present for overload disambiguation.")
171
+ includeProvenance: z.boolean().default(false).describe('Alias for include:["provenance"] (diagnostic metadata). Default false.'),
172
+ includeDescriptors: z.boolean().default(false).describe('Alias for include:["descriptors"]: also emit jvmDescriptor on FIELD members (method/constructor descriptors are always present). Default false.')
173
173
  };
174
174
  export const getClassMembersSchema = z.object(getClassMembersShape);
175
175
  export const verifyMixinTargetMemberSchema = z.discriminatedUnion("kind", [
@@ -185,18 +185,18 @@ export const verifyMixinTargetMemberSchema = z.discriminatedUnion("kind", [
185
185
  })
186
186
  ]);
187
187
  export const verifyMixinTargetShape = {
188
- owner: nonEmptyString.describe("Fully-qualified class name of the target owner (e.g. net.minecraft.world.entity.LivingEntity)."),
189
- member: verifyMixinTargetMemberSchema.describe('Member to verify. Object with kind. Examples: {"kind":"method","name":"tick","descriptor":"()V"} or {"kind":"field","name":"airSupply"}.'),
190
- mixinMemberName: optionalNonEmptyString.describe("Optional caller-authored mixin field/method name. Drives @Accessor (getXxx/setXxx) and @Invoker (invokeXxx/callXxx) advice when the target is private."),
191
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
192
- autoRemap: z.boolean().optional().describe("When true and mapping differs from the artifact namespace, translate owner+member via find-mapping instead of failing ERR_NAMESPACE_MISMATCH. Requires a version-based target."),
193
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
188
+ owner: nonEmptyString.describe("Fully-qualified target owner class name."),
189
+ member: verifyMixinTargetMemberSchema.describe('e.g. {"kind":"method","name":"tick","descriptor":"()V"} or {"kind":"field","name":"airSupply"}.'),
190
+ mixinMemberName: optionalNonEmptyString.describe("Caller-authored mixin member name; drives @Accessor/@Invoker advice when the target is private."),
191
+ mapping: sourceMappingSchema.optional(),
192
+ autoRemap: z.boolean().optional().describe("Translate owner+member via find-mapping when mapping differs from the artifact namespace (requires a version-based target)."),
193
+ sourcePriority: mappingSourcePrioritySchema.optional(),
194
194
  projectPath: optionalNonEmptyString.describe("Workspace root path for target.kind=workspace and Loom cache assistance."),
195
195
  gradleUserHome: gradleUserHomeSchema,
196
196
  target: resolveArtifactTargetSchema.describe(RESOLVE_ARTIFACT_TARGET_DESCRIPTION),
197
197
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
198
- preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override target.value"),
199
- strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false.")
198
+ preferProjectVersion: z.boolean().optional().describe("Detect MC version from gradle.properties and override target.value"),
199
+ strictVersion: z.boolean().optional().describe("Reject version-approximated results (default false)")
200
200
  };
201
201
  export const verifyMixinTargetSchema = z.object(verifyMixinTargetShape);
202
202
  export const batchSymbolKindSchema = z.enum(["class", "field", "method"]);
@@ -211,7 +211,7 @@ export const batchClassSourceEntrySchema = z.object({
211
211
  });
212
212
  export const batchClassSourceShape = {
213
213
  target: resolveArtifactTargetSchema.describe(RESOLVE_ARTIFACT_TARGET_DESCRIPTION),
214
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
214
+ mapping: sourceMappingSchema.optional(),
215
215
  sourcePriority: mappingSourcePrioritySchema.optional(),
216
216
  allowDecompile: z.boolean().optional(),
217
217
  projectPath: optionalNonEmptyString,
@@ -233,8 +233,8 @@ export const batchClassSourceSchema = z.object(batchClassSourceShape).superRefin
233
233
  // Per-entry `outputFile` is forwarded into the concurrently-dispatched
234
234
  // `getClassSource` calls; two entries resolving to the same physical file
235
235
  // would race on `writeFile`. Normalize via `path.resolve` so aliases like
236
- // `out.java` / `./out.java` / `dir/../out.java` collide as expected,
237
- // matching the writer's `isAbsolute(p) ? p : resolvePath(p)` rule.
236
+ // `out.java` / `./out.java` / `dir/../out.java` / `/tmp/dir/../out.java`
237
+ // collide as expected, covering relative and absolute spellings alike.
238
238
  const seen = new Map();
239
239
  for (let i = 0; i < value.entries.length; i += 1) {
240
240
  const entry = value.entries[i];
@@ -243,7 +243,7 @@ export const batchClassSourceSchema = z.object(batchClassSourceShape).superRefin
243
243
  const trimmed = entry.outputFile.trim();
244
244
  if (trimmed.length === 0)
245
245
  continue;
246
- const canonical = pathIsAbsolute(trimmed) ? trimmed : pathResolve(trimmed);
246
+ const canonical = pathResolve(trimmed);
247
247
  const previous = seen.get(canonical);
248
248
  if (previous !== undefined) {
249
249
  ctx.addIssue({
@@ -285,7 +285,7 @@ export const batchClassMembersSchema = z.object(batchClassMembersShape);
285
285
  export const batchSymbolExistsTargetSchema = z.discriminatedUnion("kind", [
286
286
  z.object({ kind: z.literal("version"), value: nonEmptyString }),
287
287
  workspaceTargetSchema
288
- ]).describe('Object with kind. Only kind="version" or kind="workspace" is accepted; dependency/jar/coordinate targets carry library versions, not Minecraft versions, and would corrupt the mapping query.');
288
+ ]).describe('Only kind="version" or kind="workspace"; other kinds carry library versions, not MC versions.');
289
289
  export const batchSymbolExistsEntrySchema = z.object({
290
290
  kind: batchSymbolKindSchema,
291
291
  name: nonEmptyString,
@@ -332,7 +332,7 @@ export const batchMappingsEntrySchema = z
332
332
  })
333
333
  .strict();
334
334
  export const batchMappingsShape = {
335
- version: nonEmptyString.describe("Minecraft version shared by every entry. Per-entry version is rejected; this batch shape is intentionally single-version."),
335
+ version: nonEmptyString.describe("Minecraft version shared by every entry (single-version batch)."),
336
336
  sourcePriority: mappingSourcePrioritySchema.optional(),
337
337
  projectPath: optionalNonEmptyString,
338
338
  gradleUserHome: gradleUserHomeSchema,
@@ -346,16 +346,16 @@ export const batchMappingsSchema = z.object(batchMappingsShape);
346
346
  export const searchClassSourceShape = {
347
347
  artifactId: nonEmptyString,
348
348
  query: nonEmptyString,
349
- intent: searchIntentSchema.optional().describe("symbol | text | path"),
350
- match: searchMatchSchema.optional().describe("exact | prefix | contains | regex"),
349
+ intent: searchIntentSchema.optional(),
350
+ match: searchMatchSchema.optional(),
351
351
  packagePrefix: optionalNonEmptyString,
352
352
  fileGlob: optionalNonEmptyString,
353
- symbolKind: searchSymbolKindSchema.optional().describe("class | interface | enum | record | method | field"),
354
- queryMode: z.enum(["auto", "token", "literal"]).default("auto").describe("auto: indexed search, including separator queries like foo.bar; token: indexed-only; literal: explicit substring scan only"),
353
+ symbolKind: searchSymbolKindSchema.optional(),
354
+ queryMode: z.enum(["auto", "token", "literal"]).default("auto").describe("auto: indexed search incl. separator queries like foo.bar; token: indexed-only; literal: substring scan only"),
355
355
  limit: optionalPositiveInt.default(20),
356
356
  cursor: optionalNonEmptyString,
357
- 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)."),
358
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first. Used only when queryNamespace triggers translation."),
357
+ queryNamespace: sourceMappingSchema.optional().describe("Query namespace; symbol-intent FQCN queries are translated via find-mapping first. Ignored for text/path intents."),
358
+ sourcePriority: mappingSourcePrioritySchema.optional().describe("Used only when queryNamespace triggers translation."),
359
359
  gradleUserHome: gradleUserHomeSchema,
360
360
  detail: detailParam("standard"),
361
361
  include: responseIncludeParam
@@ -389,8 +389,8 @@ export const traceSymbolLifecycleShape = {
389
389
  descriptor: optionalDescriptorString.describe('optional JVM descriptor, e.g. "(I)V". Empty strings are treated as omitted.'),
390
390
  fromVersion: optionalNonEmptyString,
391
391
  toVersion: optionalNonEmptyString,
392
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn (default obfuscated)"),
393
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
392
+ mapping: sourceMappingSchema.optional().describe("default obfuscated"),
393
+ sourcePriority: mappingSourcePrioritySchema.optional(),
394
394
  gradleUserHome: gradleUserHomeSchema,
395
395
  includeSnapshots: z.boolean().default(false),
396
396
  maxVersions: optionalPositiveInt.default(120).describe("max 400"),
@@ -401,21 +401,21 @@ export const diffClassSignaturesShape = {
401
401
  className: nonEmptyString,
402
402
  fromVersion: nonEmptyString,
403
403
  toVersion: nonEmptyString,
404
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn (default obfuscated)"),
405
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
404
+ mapping: sourceMappingSchema.optional().describe("default obfuscated"),
405
+ sourcePriority: mappingSourcePrioritySchema.optional(),
406
406
  gradleUserHome: gradleUserHomeSchema,
407
407
  includeFullDiff: z.boolean().default(true).describe("When false, omit from/to snapshots from modified entries and keep only key+changed")
408
408
  };
409
409
  export const diffClassSignaturesSchema = z.object(diffClassSignaturesShape);
410
410
  export const findMappingShape = {
411
411
  version: nonEmptyString,
412
- kind: workspaceSymbolKindSchema.describe("class | field | method"),
412
+ kind: workspaceSymbolKindSchema,
413
413
  name: nonEmptyString,
414
414
  owner: optionalNonEmptyString,
415
- descriptor: optionalDescriptorString.describe("JVM descriptor. Optional when signatureMode='name-only' (default). Empty strings are treated as omitted."),
416
- sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
417
- targetMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
418
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
415
+ descriptor: optionalDescriptorString.describe("JVM descriptor; optional when signatureMode='name-only'. Empty = omitted."),
416
+ sourceMapping: sourceMappingSchema,
417
+ targetMapping: sourceMappingSchema,
418
+ sourcePriority: mappingSourcePrioritySchema.optional(),
419
419
  gradleUserHome: gradleUserHomeSchema,
420
420
  nameMode: classNameModeSchema.default("auto").describe(NAME_MODE_DESCRIPTION),
421
421
  signatureMode: z.enum(["exact", "name-only"]).default("name-only").describe(SIGNATURE_MODE_DESCRIPTION),
@@ -426,7 +426,7 @@ export const findMappingShape = {
426
426
  })
427
427
  .partial()
428
428
  .optional(),
429
- maxCandidates: optionalPositiveInt.default(5).describe("Limit returned candidates (default 5, max 200). Raise when you need the full candidate list."),
429
+ maxCandidates: optionalPositiveInt.default(5).describe("default 5, max 200"),
430
430
  detail: detailParam("summary"),
431
431
  include: responseIncludeParam
432
432
  };
@@ -496,11 +496,11 @@ export const resolveMethodMappingExactShape = {
496
496
  name: nonEmptyString,
497
497
  owner: nonEmptyString,
498
498
  descriptor: nonEmptyString.describe("required JVM descriptor"),
499
- sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
500
- targetMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
501
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
499
+ sourceMapping: sourceMappingSchema,
500
+ targetMapping: sourceMappingSchema,
501
+ sourcePriority: mappingSourcePrioritySchema.optional(),
502
502
  gradleUserHome: gradleUserHomeSchema,
503
- maxCandidates: optionalPositiveInt.default(5).describe("Limit returned candidates (default 5, max 200). Raise when you need the full candidate list."),
503
+ maxCandidates: optionalPositiveInt.default(5).describe("default 5, max 200"),
504
504
  detail: detailParam("summary"),
505
505
  include: responseIncludeParam
506
506
  };
@@ -538,25 +538,25 @@ export const classApiKindsSchema = z.string().superRefine((value, ctx) => {
538
538
  export const getClassApiMatrixShape = {
539
539
  version: nonEmptyString,
540
540
  className: nonEmptyString,
541
- classNameMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
541
+ classNameMapping: sourceMappingSchema,
542
542
  includeKinds: classApiKindsSchema.optional().describe("comma-separated: class,field,method"),
543
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
543
+ sourcePriority: mappingSourcePrioritySchema.optional(),
544
544
  gradleUserHome: gradleUserHomeSchema,
545
545
  maxRows: optionalPositiveInt.describe("Limit returned rows (max 5000)"),
546
- cursor: optionalNonEmptyString.describe("Continuation cursor from a previous response's nextCursor; resumes after the last returned row.")
546
+ cursor: optionalNonEmptyString.describe("nextCursor from the previous response.")
547
547
  };
548
548
  export const getClassApiMatrixSchema = z.object(getClassApiMatrixShape);
549
549
  export const resolveWorkspaceSymbolShape = {
550
550
  projectPath: nonEmptyString,
551
551
  version: nonEmptyString,
552
- kind: workspaceSymbolKindSchema.describe("class | field | method"),
552
+ kind: workspaceSymbolKindSchema,
553
553
  name: nonEmptyString,
554
554
  owner: optionalNonEmptyString,
555
555
  descriptor: optionalDescriptorString.describe("JVM descriptor. Empty strings are treated as omitted."),
556
- sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
557
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
556
+ sourceMapping: sourceMappingSchema,
557
+ sourcePriority: mappingSourcePrioritySchema.optional(),
558
558
  gradleUserHome: gradleUserHomeSchema,
559
- maxCandidates: optionalPositiveInt.default(5).describe("Limit returned candidates for field/method lookups (default 5, max 200). Raise when you need the full candidate list."),
559
+ maxCandidates: optionalPositiveInt.default(5).describe("default 5, max 200 (field/method lookups)"),
560
560
  detail: detailParam("summary"),
561
561
  include: responseIncludeParam
562
562
  };
@@ -621,16 +621,16 @@ export const resolveWorkspaceSymbolSchema = z
621
621
  });
622
622
  export const checkSymbolExistsShape = {
623
623
  version: nonEmptyString,
624
- kind: workspaceSymbolKindSchema.describe("class | field | method"),
624
+ kind: workspaceSymbolKindSchema,
625
625
  owner: optionalNonEmptyString,
626
626
  name: nonEmptyString,
627
- descriptor: optionalDescriptorString.describe("JVM descriptor. Optional when signatureMode='name-only' (default). Empty strings are treated as omitted."),
628
- sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
629
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
627
+ descriptor: optionalDescriptorString.describe("JVM descriptor; optional when signatureMode='name-only'. Empty = omitted."),
628
+ sourceMapping: sourceMappingSchema,
629
+ sourcePriority: mappingSourcePrioritySchema.optional(),
630
630
  gradleUserHome: gradleUserHomeSchema,
631
631
  nameMode: classNameModeSchema.default("auto").describe(NAME_MODE_DESCRIPTION),
632
632
  signatureMode: z.enum(["exact", "name-only"]).default("name-only").describe(SIGNATURE_MODE_DESCRIPTION),
633
- maxCandidates: optionalPositiveInt.default(5).describe("Limit returned candidates (default 5, max 200). Raise when you need the full candidate list."),
633
+ maxCandidates: optionalPositiveInt.default(5).describe("default 5, max 200"),
634
634
  detail: detailParam("summary"),
635
635
  include: responseIncludeParam
636
636
  };
@@ -693,7 +693,7 @@ export const checkSymbolExistsSchema = z.object(checkSymbolExistsShape).superRef
693
693
  });
694
694
  export const nbtToJsonShape = {
695
695
  nbtBase64: nonEmptyString,
696
- compression: decodeCompressionSchema.default("auto").describe("none | gzip | auto")
696
+ compression: decodeCompressionSchema.default("auto")
697
697
  };
698
698
  export const nbtToJsonSchema = z.object(nbtToJsonShape);
699
699
  const nbtPatchOperationSchema = z
@@ -710,7 +710,7 @@ export const nbtApplyJsonPatchShape = {
710
710
  export const nbtApplyJsonPatchSchema = z.object(nbtApplyJsonPatchShape);
711
711
  export const jsonToNbtShape = {
712
712
  typedJson: z.unknown(),
713
- compression: encodeCompressionSchema.default("none").describe("none | gzip")
713
+ compression: encodeCompressionSchema.default("none")
714
714
  };
715
715
  export const jsonToNbtSchema = z.object(jsonToNbtShape);
716
716
  export const indexArtifactShape = {
@@ -740,16 +740,16 @@ export const validateMixinShape = {
740
740
  mode: z.literal("project"),
741
741
  path: nonEmptyString.describe("Workspace root path used to discover *.mixins.json files automatically")
742
742
  })
743
- ]).describe("One of { mode: 'inline', source }, { mode: 'path', path }, { mode: 'paths', paths[] }, { mode: 'config', configPaths[] }, or { mode: 'project', path }."),
743
+ ]).describe("mode = inline | path | paths | config | project"),
744
744
  sourceRoots: z.array(z.string().min(1)).optional()
745
- .describe("Array of source roots for multi-module projects (e.g. ['common/src/main/java', 'neoforge/src/main/java'])"),
746
- version: optionalNonEmptyString.describe("Minecraft version. Optional when input.mode='project' (detected from the workspace) or preferProjectVersion=true with projectPath set; required otherwise."),
747
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
748
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
745
+ .describe("Source roots for multi-module projects (e.g. ['common/src/main/java'])"),
746
+ version: optionalNonEmptyString.describe("Minecraft version. Optional when input.mode='project' or preferProjectVersion=true with projectPath; required otherwise."),
747
+ mapping: sourceMappingSchema.optional(),
748
+ sourcePriority: mappingSourcePrioritySchema.optional(),
749
749
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
750
- projectPath: optionalNonEmptyString.describe("Optional workspace root path for Loom cache-assisted source resolution"),
750
+ projectPath: optionalNonEmptyString.describe("Workspace root for Loom cache-assisted resolution"),
751
751
  gradleUserHome: gradleUserHomeSchema,
752
- preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override version"),
752
+ preferProjectVersion: z.boolean().optional().describe("Detect MC version from gradle.properties and override version"),
753
753
  minSeverity: z.enum(["error", "warning", "all"]).default("all")
754
754
  .describe("'error'=errors only, 'warning'=errors+warnings, 'all'=everything"),
755
755
  hideUncertain: z.boolean().default(false)
@@ -761,7 +761,7 @@ export const validateMixinShape = {
761
761
  preferProjectMapping: z.boolean().default(false)
762
762
  .describe("When true, auto-detect mapping from project config even if mapping is explicitly provided"),
763
763
  reportMode: z.enum(["compact", "full", "summary-first"]).default("summary-first")
764
- .describe("Default 'summary-first': hoists shared provenance/warnings/incomplete reasons and drops per-result resolvedMembers/toolHealth/structuredWarnings. 'compact' omits heavy per-result detail; 'full'=everything. resolvedMembers/per-result toolHealth/resolutionTrace require reportMode='full' or explain=true."),
764
+ .describe("summary-first (default) hoists shared provenance/warnings, drops per-result heavy detail; compact omits heavy per-result detail; full = everything (required for resolvedMembers/toolHealth/resolutionTrace unless explain=true)."),
765
765
  warningCategoryFilter: z.array(z.enum(["mapping", "configuration", "validation", "resolution", "parse"])).optional()
766
766
  .describe("Only include warnings/issues matching these categories (default: all)"),
767
767
  treatInfoAsWarning: z.boolean().default(true)
@@ -785,8 +785,8 @@ export const validateMixinSchema = z.object(validateMixinShape).superRefine((val
785
785
  export const validateAccessWidenerShape = {
786
786
  content: nonEmptyString.describe("Access Widener file content"),
787
787
  version: nonEmptyString.describe("Minecraft version"),
788
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
789
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
788
+ mapping: sourceMappingSchema.optional(),
789
+ sourcePriority: mappingSourcePrioritySchema.optional(),
790
790
  projectPath: optionalNonEmptyString.describe("Optional workspace root path for Loom cache-assisted runtime validation"),
791
791
  gradleUserHome: gradleUserHomeSchema,
792
792
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
@@ -797,8 +797,8 @@ export const validateAccessWidenerSchema = z.object(validateAccessWidenerShape);
797
797
  export const validateAccessTransformerShape = {
798
798
  content: nonEmptyString.describe("Access Transformer file content"),
799
799
  version: nonEmptyString.describe("Minecraft version"),
800
- atNamespace: z.enum(["srg", "mojang", "obfuscated"]).optional().describe("srg | mojang | obfuscated"),
801
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
800
+ atNamespace: z.enum(["srg", "mojang", "obfuscated"]).optional(),
801
+ sourcePriority: mappingSourcePrioritySchema.optional(),
802
802
  projectPath: optionalNonEmptyString.describe("Optional workspace root path for Forge/NeoForge runtime validation"),
803
803
  gradleUserHome: gradleUserHomeSchema,
804
804
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
@@ -814,7 +814,7 @@ export const analyzeModJarSchema = z.object(analyzeModJarShape);
814
814
  export const getRegistryDataShape = {
815
815
  version: nonEmptyString.describe("Minecraft version (e.g. 1.21)"),
816
816
  registry: optionalNonEmptyString.describe('Optional registry name (e.g. "block", "item", "minecraft:biome"). Omit to list all registries.'),
817
- includeData: z.boolean().default(true).describe("When false, return registry names/counts only. To discover which registries exist without pulling every entry body, pass includeData:false (omitting registry with the default includeData:true returns the full data for every registry)."),
817
+ includeData: z.boolean().default(true).describe("false = registry names/counts only (cheap discovery); true (default) = full entry bodies."),
818
818
  maxEntriesPerRegistry: optionalPositiveInt.describe("Limit returned entries per registry body")
819
819
  };
820
820
  export const getRegistryDataSchema = z.object(getRegistryDataShape);
@@ -823,7 +823,7 @@ export const compareVersionsCategorySchema = z.enum(COMPARE_VERSIONS_CATEGORIES)
823
823
  export const compareVersionsShape = {
824
824
  fromVersion: nonEmptyString.describe("Older Minecraft version (e.g. 1.20.4)"),
825
825
  toVersion: nonEmptyString.describe("Newer Minecraft version (e.g. 1.21)"),
826
- category: compareVersionsCategorySchema.default("all").describe("classes | registry | all"),
826
+ category: compareVersionsCategorySchema.default("all"),
827
827
  packageFilter: optionalNonEmptyString.describe("Filter classes to a package prefix (e.g. net.minecraft.world.item)"),
828
828
  maxClassResults: optionalPositiveInt.default(500).describe("Max class results per direction (max 5000)")
829
829
  };
@@ -848,7 +848,7 @@ export const modSearchTypeSchema = z.enum(MOD_SEARCH_TYPES);
848
848
  export const searchModSourceShape = {
849
849
  jarPath: nonEmptyString.describe("Local path to the mod JAR file"),
850
850
  query: nonEmptyString.describe("Search pattern (regex or literal string)"),
851
- searchType: modSearchTypeSchema.default("all").describe("class | method | field | content | all"),
851
+ searchType: modSearchTypeSchema.default("all"),
852
852
  limit: optionalPositiveInt.default(50).describe("Max results (max 200)")
853
853
  };
854
854
  export const searchModSourceSchema = z.object(searchModSourceShape);
@@ -858,7 +858,7 @@ export const remapModJarShape = {
858
858
  inputJar: nonEmptyString.describe("Path to the mod JAR file"),
859
859
  outputJar: optionalNonEmptyString.describe("Output path for remapped JAR (auto-generated if omitted)"),
860
860
  mcVersion: optionalNonEmptyString.describe("Minecraft version (auto-detected from mod metadata if omitted)"),
861
- targetMapping: remapTargetSchema.describe("yarn | mojang"),
861
+ targetMapping: remapTargetSchema,
862
862
  forceRemap: z
863
863
  .boolean()
864
864
  .optional()
@@ -16,3 +16,15 @@ export type WarningDetail = {
16
16
  * position and dereferences the text via `warnings[index]`.
17
17
  */
18
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[];
@@ -60,4 +60,21 @@ function classifyWarning(message, index) {
60
60
  export function classifyWarnings(warnings) {
61
61
  return warnings.map((message, index) => classifyWarning(message, index));
62
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
+ }
63
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhisang/minecraft-modding-mcp",
3
- "version": "5.0.0",
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",