@adhisang/minecraft-modding-mcp 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +62 -0
- package/README.md +139 -30
- package/dist/cache-registry.d.ts +95 -0
- package/dist/cache-registry.js +541 -0
- package/dist/cli.js +31 -4
- package/dist/compat-stdio-transport.d.ts +2 -7
- package/dist/compat-stdio-transport.js +12 -154
- package/dist/entry-tools/analyze-mod-service.d.ts +207 -0
- package/dist/entry-tools/analyze-mod-service.js +253 -0
- package/dist/entry-tools/analyze-symbol-service.d.ts +209 -0
- package/dist/entry-tools/analyze-symbol-service.js +304 -0
- package/dist/entry-tools/compare-minecraft-service.d.ts +210 -0
- package/dist/entry-tools/compare-minecraft-service.js +397 -0
- package/dist/entry-tools/entry-tool-schema.d.ts +6 -0
- package/dist/entry-tools/entry-tool-schema.js +10 -0
- package/dist/entry-tools/inspect-minecraft-service.d.ts +1953 -0
- package/dist/entry-tools/inspect-minecraft-service.js +876 -0
- package/dist/entry-tools/manage-cache-service.d.ts +130 -0
- package/dist/entry-tools/manage-cache-service.js +229 -0
- package/dist/entry-tools/request-normalizers.d.ts +10 -0
- package/dist/entry-tools/request-normalizers.js +36 -0
- package/dist/entry-tools/response-contract.d.ts +44 -0
- package/dist/entry-tools/response-contract.js +96 -0
- package/dist/entry-tools/validate-project-service.d.ts +543 -0
- package/dist/entry-tools/validate-project-service.js +381 -0
- package/dist/index.js +495 -42
- package/dist/json-rpc-framing.d.ts +22 -0
- package/dist/json-rpc-framing.js +168 -0
- package/dist/mapping-pipeline-service.js +9 -1
- package/dist/mapping-service.d.ts +9 -0
- package/dist/mapping-service.js +183 -60
- package/dist/minecraft-explorer-service.d.ts +0 -1
- package/dist/minecraft-explorer-service.js +119 -23
- package/dist/mixin-validator.d.ts +24 -2
- package/dist/mixin-validator.js +223 -98
- package/dist/mod-decompile-service.d.ts +5 -0
- package/dist/mod-decompile-service.js +40 -5
- package/dist/mod-remap-service.js +142 -30
- package/dist/path-resolver.js +41 -4
- package/dist/registry-service.d.ts +10 -1
- package/dist/registry-service.js +154 -22
- package/dist/search-hit-accumulator.js +23 -2
- package/dist/source-jar-reader.js +16 -2
- package/dist/source-resolver.js +6 -7
- package/dist/source-service.d.ts +42 -4
- package/dist/source-service.js +781 -127
- package/dist/stdio-supervisor.d.ts +46 -0
- package/dist/stdio-supervisor.js +349 -0
- package/dist/storage/files-repo.d.ts +3 -9
- package/dist/storage/files-repo.js +66 -43
- package/dist/symbols/symbol-extractor.js +6 -4
- package/dist/tool-execution-gate.d.ts +15 -0
- package/dist/tool-execution-gate.js +58 -0
- package/dist/version-diff-service.js +10 -5
- package/dist/version-service.js +7 -2
- package/dist/workspace-mapping-service.js +12 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12,6 +12,16 @@ import { analyzeModJar } from "./mod-analyzer.js";
|
|
|
12
12
|
import { remapModJar } from "./mod-remap-service.js";
|
|
13
13
|
import { registerResources } from "./resources.js";
|
|
14
14
|
import { SourceService } from "./source-service.js";
|
|
15
|
+
import { ToolExecutionGate } from "./tool-execution-gate.js";
|
|
16
|
+
import { WorkspaceMappingService } from "./workspace-mapping-service.js";
|
|
17
|
+
import { InspectMinecraftService, inspectMinecraftSchema, inspectMinecraftShape } from "./entry-tools/inspect-minecraft-service.js";
|
|
18
|
+
import { AnalyzeSymbolService, analyzeSymbolSchema, analyzeSymbolShape } from "./entry-tools/analyze-symbol-service.js";
|
|
19
|
+
import { CompareMinecraftService, compareMinecraftSchema, compareMinecraftShape } from "./entry-tools/compare-minecraft-service.js";
|
|
20
|
+
import { AnalyzeModService, analyzeModSchema, analyzeModShape } from "./entry-tools/analyze-mod-service.js";
|
|
21
|
+
import { ValidateProjectService, validateProjectSchema, validateProjectShape, discoverWorkspaceAccessWideners, discoverWorkspaceMixins } from "./entry-tools/validate-project-service.js";
|
|
22
|
+
import { ManageCacheService, manageCacheSchema, manageCacheShape } from "./entry-tools/manage-cache-service.js";
|
|
23
|
+
import { createCacheRegistry } from "./cache-registry.js";
|
|
24
|
+
import { buildEntryToolMeta } from "./entry-tools/response-contract.js";
|
|
15
25
|
if (!process.env.NODE_ENV) {
|
|
16
26
|
process.env.NODE_ENV = "production";
|
|
17
27
|
}
|
|
@@ -28,6 +38,24 @@ const SOURCE_MODES = ["metadata", "snippet", "full"];
|
|
|
28
38
|
const ARTIFACT_SCOPES = ["vanilla", "merged", "loader"];
|
|
29
39
|
const DECODE_COMPRESSIONS = ["none", "gzip", "auto"];
|
|
30
40
|
const ENCODE_COMPRESSIONS = ["none", "gzip"];
|
|
41
|
+
const HEAVY_TOOL_NAMES = new Set([
|
|
42
|
+
"trace-symbol-lifecycle",
|
|
43
|
+
"diff-class-signatures",
|
|
44
|
+
"compare-versions",
|
|
45
|
+
"find-mapping",
|
|
46
|
+
"resolve-method-mapping-exact",
|
|
47
|
+
"get-class-api-matrix",
|
|
48
|
+
"get-registry-data"
|
|
49
|
+
]);
|
|
50
|
+
const ENTRY_TOOL_NAMES = new Set([
|
|
51
|
+
"inspect-minecraft",
|
|
52
|
+
"analyze-symbol",
|
|
53
|
+
"compare-minecraft",
|
|
54
|
+
"analyze-mod",
|
|
55
|
+
"validate-project",
|
|
56
|
+
"manage-cache"
|
|
57
|
+
]);
|
|
58
|
+
const heavyToolExecutionGate = new ToolExecutionGate({ maxConcurrent: 1, maxQueue: 2 });
|
|
31
59
|
const nonEmptyString = z.string().trim().min(1);
|
|
32
60
|
const optionalNonEmptyString = z.string().trim().min(1).optional();
|
|
33
61
|
const optionalPositiveInt = z.number().int().positive().optional();
|
|
@@ -59,6 +87,9 @@ const sourceLookupTargetSchema = z.discriminatedUnion("type", [
|
|
|
59
87
|
value: nonEmptyString
|
|
60
88
|
})
|
|
61
89
|
]);
|
|
90
|
+
const RESOLVE_ARTIFACT_TARGET_DESCRIPTION = "Object with kind and value. Example: {\"kind\":\"version\",\"value\":\"1.21.10\"}. Must be an object, not a string.";
|
|
91
|
+
const SOURCE_LOOKUP_TARGET_DESCRIPTION = "Object: {\"type\":\"resolve\",\"kind\":\"version\",\"value\":\"1.21.10\"} or {\"type\":\"artifact\",\"artifactId\":\"...\"}. Must be an object, not a string.";
|
|
92
|
+
const SOURCE_SCOPE_DESCRIPTION = 'vanilla = Mojang client jar only; merged = Loom cache discovery (default); loader = currently behaves the same as "merged".';
|
|
62
93
|
const listVersionsShape = {
|
|
63
94
|
includeSnapshots: z.boolean().optional().describe("default false"),
|
|
64
95
|
limit: optionalPositiveInt.describe("default 20, max 200")
|
|
@@ -68,12 +99,12 @@ const resolveArtifactShape = {
|
|
|
68
99
|
target: z.object({
|
|
69
100
|
kind: targetKindSchema,
|
|
70
101
|
value: nonEmptyString
|
|
71
|
-
}).describe(
|
|
102
|
+
}).describe(RESOLVE_ARTIFACT_TARGET_DESCRIPTION),
|
|
72
103
|
mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
|
|
73
104
|
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
|
|
74
105
|
allowDecompile: z.boolean().optional().describe("default true"),
|
|
75
106
|
projectPath: optionalNonEmptyString.describe("Optional workspace root path for Loom cache-assisted source resolution"),
|
|
76
|
-
scope: artifactScopeSchema.optional().describe(
|
|
107
|
+
scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
|
|
77
108
|
preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override target.value"),
|
|
78
109
|
strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false.")
|
|
79
110
|
};
|
|
@@ -81,12 +112,12 @@ const resolveArtifactSchema = z.object(resolveArtifactShape);
|
|
|
81
112
|
const getClassSourceShape = {
|
|
82
113
|
className: nonEmptyString,
|
|
83
114
|
mode: sourceModeSchema.optional().describe("metadata (default) = symbol outline only; snippet = source with default maxLines=200; full = entire source"),
|
|
84
|
-
target: sourceLookupTargetSchema.describe(
|
|
115
|
+
target: sourceLookupTargetSchema.describe(SOURCE_LOOKUP_TARGET_DESCRIPTION),
|
|
85
116
|
mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
|
|
86
117
|
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
|
|
87
118
|
allowDecompile: z.boolean().optional().describe("default true"),
|
|
88
119
|
projectPath: optionalNonEmptyString.describe("Optional workspace root path for Loom cache-assisted source resolution"),
|
|
89
|
-
scope: artifactScopeSchema.optional().describe(
|
|
120
|
+
scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
|
|
90
121
|
preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override target.value"),
|
|
91
122
|
strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false."),
|
|
92
123
|
startLine: optionalPositiveInt,
|
|
@@ -110,7 +141,7 @@ const getClassSourceSchema = z
|
|
|
110
141
|
});
|
|
111
142
|
const getClassMembersShape = {
|
|
112
143
|
className: nonEmptyString,
|
|
113
|
-
target: sourceLookupTargetSchema.describe(
|
|
144
|
+
target: sourceLookupTargetSchema.describe(SOURCE_LOOKUP_TARGET_DESCRIPTION),
|
|
114
145
|
mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn (default obfuscated)"),
|
|
115
146
|
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
|
|
116
147
|
allowDecompile: z.boolean().optional().describe("default true"),
|
|
@@ -120,7 +151,7 @@ const getClassMembersShape = {
|
|
|
120
151
|
memberPattern: optionalNonEmptyString,
|
|
121
152
|
maxMembers: optionalPositiveInt.describe("default 500, max 5000"),
|
|
122
153
|
projectPath: optionalNonEmptyString,
|
|
123
|
-
scope: artifactScopeSchema.optional().describe(
|
|
154
|
+
scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
|
|
124
155
|
preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override version"),
|
|
125
156
|
strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false.")
|
|
126
157
|
};
|
|
@@ -176,7 +207,8 @@ const diffClassSignaturesShape = {
|
|
|
176
207
|
fromVersion: nonEmptyString,
|
|
177
208
|
toVersion: nonEmptyString,
|
|
178
209
|
mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn (default obfuscated)"),
|
|
179
|
-
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first")
|
|
210
|
+
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
|
|
211
|
+
includeFullDiff: z.boolean().optional().describe("When false, omit from/to snapshots from modified entries and keep only key+changed")
|
|
180
212
|
};
|
|
181
213
|
const diffClassSignaturesSchema = z.object(diffClassSignaturesShape);
|
|
182
214
|
const findMappingShape = {
|
|
@@ -194,7 +226,8 @@ const findMappingShape = {
|
|
|
194
226
|
descriptorHint: optionalNonEmptyString
|
|
195
227
|
})
|
|
196
228
|
.partial()
|
|
197
|
-
.optional()
|
|
229
|
+
.optional(),
|
|
230
|
+
maxCandidates: optionalPositiveInt.describe("Limit returned candidates (default 200, max 200)")
|
|
198
231
|
};
|
|
199
232
|
const findMappingSchema = z.object(findMappingShape).superRefine((value, ctx) => {
|
|
200
233
|
if (value.kind === "class") {
|
|
@@ -260,7 +293,8 @@ const resolveMethodMappingExactShape = {
|
|
|
260
293
|
descriptor: nonEmptyString.describe("required JVM descriptor"),
|
|
261
294
|
sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
|
|
262
295
|
targetMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
|
|
263
|
-
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first")
|
|
296
|
+
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
|
|
297
|
+
maxCandidates: optionalPositiveInt.describe("Limit returned candidates (default 200, max 200)")
|
|
264
298
|
};
|
|
265
299
|
const resolveMethodMappingExactSchema = z
|
|
266
300
|
.object(resolveMethodMappingExactShape)
|
|
@@ -298,7 +332,8 @@ const getClassApiMatrixShape = {
|
|
|
298
332
|
className: nonEmptyString,
|
|
299
333
|
classNameMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
|
|
300
334
|
includeKinds: classApiKindsSchema.optional().describe("comma-separated: class,field,method"),
|
|
301
|
-
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first")
|
|
335
|
+
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
|
|
336
|
+
maxRows: optionalPositiveInt.describe("Limit returned rows (max 5000)")
|
|
302
337
|
};
|
|
303
338
|
const getClassApiMatrixSchema = z.object(getClassApiMatrixShape);
|
|
304
339
|
const resolveWorkspaceSymbolShape = {
|
|
@@ -309,7 +344,8 @@ const resolveWorkspaceSymbolShape = {
|
|
|
309
344
|
owner: optionalNonEmptyString,
|
|
310
345
|
descriptor: optionalNonEmptyString,
|
|
311
346
|
sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
|
|
312
|
-
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first")
|
|
347
|
+
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
|
|
348
|
+
maxCandidates: optionalPositiveInt.describe("Limit returned candidates for field/method lookups (default 200, max 200)")
|
|
313
349
|
};
|
|
314
350
|
const resolveWorkspaceSymbolSchema = z
|
|
315
351
|
.object(resolveWorkspaceSymbolShape)
|
|
@@ -380,7 +416,8 @@ const checkSymbolExistsShape = {
|
|
|
380
416
|
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
|
|
381
417
|
nameMode: classNameModeSchema.optional().describe("fqcn | auto (default fqcn)"),
|
|
382
418
|
signatureMode: z.enum(["exact", "name-only"]).optional()
|
|
383
|
-
.describe("exact (default): require descriptor for methods; name-only: match by owner+name only")
|
|
419
|
+
.describe("exact (default): require descriptor for methods; name-only: match by owner+name only"),
|
|
420
|
+
maxCandidates: optionalPositiveInt.describe("Limit returned candidates (default 200, max 200)")
|
|
384
421
|
};
|
|
385
422
|
const checkSymbolExistsSchema = z.object(checkSymbolExistsShape).superRefine((value, ctx) => {
|
|
386
423
|
if (value.kind === "class") {
|
|
@@ -483,14 +520,18 @@ const validateMixinShape = {
|
|
|
483
520
|
z.object({
|
|
484
521
|
mode: z.literal("config"),
|
|
485
522
|
configPaths: z.array(nonEmptyString).min(1).describe("Path array to mixin config JSON files (e.g. modid.mixins.json)")
|
|
523
|
+
}),
|
|
524
|
+
z.object({
|
|
525
|
+
mode: z.literal("project"),
|
|
526
|
+
path: nonEmptyString.describe("Workspace root path used to discover *.mixins.json files automatically")
|
|
486
527
|
})
|
|
487
|
-
]),
|
|
528
|
+
]).describe("One of { mode: 'inline', source }, { mode: 'path', path }, { mode: 'paths', paths[] }, { mode: 'config', configPaths[] }, or { mode: 'project', path }."),
|
|
488
529
|
sourceRoots: z.array(z.string().min(1)).optional()
|
|
489
530
|
.describe("Array of source roots for multi-module projects (e.g. ['common/src/main/java', 'neoforge/src/main/java'])"),
|
|
490
531
|
version: nonEmptyString.describe("Minecraft version"),
|
|
491
532
|
mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
|
|
492
533
|
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
|
|
493
|
-
scope: artifactScopeSchema.optional().describe(
|
|
534
|
+
scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
|
|
494
535
|
projectPath: optionalNonEmptyString.describe("Optional workspace root path for Loom cache-assisted source resolution"),
|
|
495
536
|
preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override version"),
|
|
496
537
|
minSeverity: z.enum(["error", "warning", "all"]).optional()
|
|
@@ -503,12 +544,14 @@ const validateMixinShape = {
|
|
|
503
544
|
.describe("'full'=all warnings (default), 'aggregated'=group warnings by category with counts and samples"),
|
|
504
545
|
preferProjectMapping: z.boolean().optional()
|
|
505
546
|
.describe("When true, auto-detect mapping from project config even if mapping is explicitly provided"),
|
|
506
|
-
reportMode: z.enum(["compact", "full"]).optional()
|
|
507
|
-
.describe("'compact' omits
|
|
547
|
+
reportMode: z.enum(["compact", "full", "summary-first"]).optional()
|
|
548
|
+
.describe("'compact' omits heavy per-result detail, 'summary-first' hoists shared provenance/warnings/incomplete reasons, 'full'=everything (default)"),
|
|
508
549
|
warningCategoryFilter: z.array(z.enum(["mapping", "configuration", "validation", "resolution", "parse"])).optional()
|
|
509
550
|
.describe("Only include warnings/issues matching these categories (default: all)"),
|
|
510
551
|
treatInfoAsWarning: z.boolean().optional()
|
|
511
|
-
.describe("When false, suppress info-severity structured warnings from output (default true)")
|
|
552
|
+
.describe("When false, suppress info-severity structured warnings from output (default true)"),
|
|
553
|
+
includeIssues: z.boolean().optional()
|
|
554
|
+
.describe("When false, keep summary fields but omit per-result issues[] payloads")
|
|
512
555
|
};
|
|
513
556
|
const validateMixinSchema = z.object(validateMixinShape);
|
|
514
557
|
const validateAccessWidenerShape = {
|
|
@@ -525,7 +568,9 @@ const analyzeModJarShape = {
|
|
|
525
568
|
const analyzeModJarSchema = z.object(analyzeModJarShape);
|
|
526
569
|
const getRegistryDataShape = {
|
|
527
570
|
version: nonEmptyString.describe("Minecraft version (e.g. 1.21)"),
|
|
528
|
-
registry: optionalNonEmptyString.describe('Optional registry name (e.g. "block", "item", "minecraft:biome"). Omit to list all registries.')
|
|
571
|
+
registry: optionalNonEmptyString.describe('Optional registry name (e.g. "block", "item", "minecraft:biome"). Omit to list all registries.'),
|
|
572
|
+
includeData: z.boolean().optional().describe("When false, return registry names/counts without full entry bodies"),
|
|
573
|
+
maxEntriesPerRegistry: optionalPositiveInt.describe("Limit returned entries per registry body")
|
|
529
574
|
};
|
|
530
575
|
const getRegistryDataSchema = z.object(getRegistryDataShape);
|
|
531
576
|
const COMPARE_VERSIONS_CATEGORIES = ["classes", "registry", "all"];
|
|
@@ -540,7 +585,9 @@ const compareVersionsShape = {
|
|
|
540
585
|
const compareVersionsSchema = z.object(compareVersionsShape);
|
|
541
586
|
const decompileModJarShape = {
|
|
542
587
|
jarPath: nonEmptyString.describe("Local path to the mod JAR file"),
|
|
543
|
-
className: optionalNonEmptyString.describe("Optional fully-qualified class name to view source. Omit to list all classes.")
|
|
588
|
+
className: optionalNonEmptyString.describe("Optional fully-qualified class name to view source. Omit to list all classes."),
|
|
589
|
+
includeFiles: z.boolean().optional().describe("When false, omit the full class list and return counts only"),
|
|
590
|
+
maxFiles: optionalPositiveInt.describe("Limit returned class names when files are included")
|
|
544
591
|
};
|
|
545
592
|
const decompileModJarSchema = z.object(decompileModJarShape);
|
|
546
593
|
const getModClassSourceShape = {
|
|
@@ -588,6 +635,9 @@ const server = new McpServer({
|
|
|
588
635
|
name: "@adhisang/minecraft-modding-mcp",
|
|
589
636
|
version: SERVER_VERSION
|
|
590
637
|
});
|
|
638
|
+
// The SDK validates tool args before invoking handlers and returns generic InvalidParams text.
|
|
639
|
+
// Bypass that layer so runTool() remains the single source of truth for validation and error envelopes.
|
|
640
|
+
server.validateToolInput = async (_tool, args) => args;
|
|
591
641
|
const config = loadConfig();
|
|
592
642
|
const nbtLimits = {
|
|
593
643
|
maxInputBytes: config.maxNbtInputBytes,
|
|
@@ -606,6 +656,50 @@ const sourceService = new Proxy({}, {
|
|
|
606
656
|
return typeof value === "function" ? value.bind(service) : value;
|
|
607
657
|
}
|
|
608
658
|
});
|
|
659
|
+
const workspaceMappingService = new WorkspaceMappingService();
|
|
660
|
+
const inspectMinecraftService = new InspectMinecraftService({
|
|
661
|
+
listVersions: (input) => sourceService.listVersions(input),
|
|
662
|
+
resolveArtifact: (input) => sourceService.resolveArtifact(input),
|
|
663
|
+
findClass: (input) => Promise.resolve(sourceService.findClass(input)),
|
|
664
|
+
getClassSource: (input) => sourceService.getClassSource(input),
|
|
665
|
+
getClassMembers: (input) => sourceService.getClassMembers(input),
|
|
666
|
+
searchClassSource: (input) => sourceService.searchClassSource(input),
|
|
667
|
+
getArtifactFile: (input) => sourceService.getArtifactFile(input),
|
|
668
|
+
listArtifactFiles: (input) => sourceService.listArtifactFiles(input),
|
|
669
|
+
detectProjectMinecraftVersion: (projectPath) => workspaceMappingService.detectProjectMinecraftVersion(projectPath)
|
|
670
|
+
});
|
|
671
|
+
const analyzeSymbolService = new AnalyzeSymbolService({
|
|
672
|
+
checkSymbolExists: (input) => sourceService.checkSymbolExists(input),
|
|
673
|
+
findMapping: (input) => sourceService.findMapping(input),
|
|
674
|
+
resolveMethodMappingExact: (input) => sourceService.resolveMethodMappingExact(input),
|
|
675
|
+
traceSymbolLifecycle: (input) => sourceService.traceSymbolLifecycle(input),
|
|
676
|
+
resolveWorkspaceSymbol: (input) => sourceService.resolveWorkspaceSymbol(input),
|
|
677
|
+
getClassApiMatrix: (input) => sourceService.getClassApiMatrix(input)
|
|
678
|
+
});
|
|
679
|
+
const compareMinecraftService = new CompareMinecraftService({
|
|
680
|
+
compareVersions: (input) => sourceService.compareVersions(input),
|
|
681
|
+
diffClassSignatures: (input) => sourceService.diffClassSignatures(input),
|
|
682
|
+
getRegistryData: (input) => sourceService.getRegistryData(input)
|
|
683
|
+
});
|
|
684
|
+
const analyzeModService = new AnalyzeModService({
|
|
685
|
+
analyzeModJar: (jarPath, options) => analyzeModJar(jarPath, options),
|
|
686
|
+
decompileModJar: (input) => sourceService.decompileModJar(input),
|
|
687
|
+
getModClassSource: (input) => sourceService.getModClassSource(input),
|
|
688
|
+
searchModSource: (input) => sourceService.searchModSource(input),
|
|
689
|
+
remapModJar: (input) => remapModJar(input, config)
|
|
690
|
+
});
|
|
691
|
+
const validateProjectService = new ValidateProjectService({
|
|
692
|
+
validateMixin: (input) => sourceService.validateMixin(input),
|
|
693
|
+
validateAccessWidener: (input) => sourceService.validateAccessWidener(input),
|
|
694
|
+
discoverMixins: discoverWorkspaceMixins,
|
|
695
|
+
discoverAccessWideners: discoverWorkspaceAccessWideners
|
|
696
|
+
});
|
|
697
|
+
const manageCacheService = new ManageCacheService({
|
|
698
|
+
registry: createCacheRegistry({
|
|
699
|
+
cacheDir: config.cacheDir,
|
|
700
|
+
sqlitePath: config.sqlitePath
|
|
701
|
+
})
|
|
702
|
+
});
|
|
609
703
|
registerResources(server, sourceService);
|
|
610
704
|
let processHandlersAttached = false;
|
|
611
705
|
let serverStarted = false;
|
|
@@ -768,8 +862,314 @@ function extractFieldErrorsFromDetails(details) {
|
|
|
768
862
|
.filter((entry) => entry != null);
|
|
769
863
|
return normalized.length > 0 ? normalized : undefined;
|
|
770
864
|
}
|
|
771
|
-
function
|
|
865
|
+
function asObjectRecord(value) {
|
|
866
|
+
return typeof value === "object" && value != null && !Array.isArray(value)
|
|
867
|
+
? value
|
|
868
|
+
: undefined;
|
|
869
|
+
}
|
|
870
|
+
function asNonEmptyString(value) {
|
|
871
|
+
return typeof value === "string" && value.trim() ? value : undefined;
|
|
872
|
+
}
|
|
873
|
+
function asStringArray(value) {
|
|
874
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "string" && entry.trim())
|
|
875
|
+
? value
|
|
876
|
+
: undefined;
|
|
877
|
+
}
|
|
878
|
+
function truncateSuggestionText(value, maxLength = 500) {
|
|
879
|
+
return value.length > maxLength
|
|
880
|
+
? `${value.slice(0, maxLength)}...`
|
|
881
|
+
: value;
|
|
882
|
+
}
|
|
883
|
+
function parseJsonObjectString(value) {
|
|
884
|
+
if (!value.trim().startsWith("{")) {
|
|
885
|
+
return undefined;
|
|
886
|
+
}
|
|
887
|
+
try {
|
|
888
|
+
const parsed = JSON.parse(value);
|
|
889
|
+
return asObjectRecord(parsed);
|
|
890
|
+
}
|
|
891
|
+
catch {
|
|
892
|
+
return undefined;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
function inferTargetKindFromString(value) {
|
|
896
|
+
if (/[\\/]/.test(value) || /\.jar$/i.test(value)) {
|
|
897
|
+
return "jar";
|
|
898
|
+
}
|
|
899
|
+
if (value.split(":").length >= 3) {
|
|
900
|
+
return "coordinate";
|
|
901
|
+
}
|
|
902
|
+
return "version";
|
|
903
|
+
}
|
|
904
|
+
function copySourceLookupSuggestionFields(tool, source) {
|
|
905
|
+
const result = {};
|
|
906
|
+
const stringFields = tool === "get-class-source"
|
|
907
|
+
? ["className", "mode", "mapping", "sourcePriority", "projectPath", "scope", "outputFile"]
|
|
908
|
+
: ["className", "mapping", "sourcePriority", "projectPath", "scope", "access", "memberPattern"];
|
|
909
|
+
for (const field of stringFields) {
|
|
910
|
+
const value = source[field];
|
|
911
|
+
if (typeof value === "string" && value.trim()) {
|
|
912
|
+
result[field] = value;
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
const numericFields = tool === "get-class-source"
|
|
916
|
+
? ["startLine", "endLine", "maxLines", "maxChars"]
|
|
917
|
+
: ["maxMembers"];
|
|
918
|
+
for (const field of numericFields) {
|
|
919
|
+
const value = source[field];
|
|
920
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
921
|
+
result[field] = value;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
const booleanFields = tool === "get-class-source"
|
|
925
|
+
? ["allowDecompile", "preferProjectVersion", "strictVersion"]
|
|
926
|
+
: ["allowDecompile", "preferProjectVersion", "strictVersion", "includeSynthetic", "includeInherited"];
|
|
927
|
+
for (const field of booleanFields) {
|
|
928
|
+
const value = source[field];
|
|
929
|
+
if (typeof value === "boolean") {
|
|
930
|
+
result[field] = value;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
return result;
|
|
934
|
+
}
|
|
935
|
+
function copyValidateMixinSharedParams(source) {
|
|
936
|
+
const result = {};
|
|
937
|
+
const stringFields = [
|
|
938
|
+
"version",
|
|
939
|
+
"mapping",
|
|
940
|
+
"sourcePriority",
|
|
941
|
+
"scope",
|
|
942
|
+
"projectPath",
|
|
943
|
+
"minSeverity",
|
|
944
|
+
"warningMode",
|
|
945
|
+
"reportMode"
|
|
946
|
+
];
|
|
947
|
+
for (const field of stringFields) {
|
|
948
|
+
const value = source[field];
|
|
949
|
+
if (typeof value === "string" && value.trim()) {
|
|
950
|
+
result[field] = value;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
const booleanFields = [
|
|
954
|
+
"preferProjectVersion",
|
|
955
|
+
"hideUncertain",
|
|
956
|
+
"explain",
|
|
957
|
+
"preferProjectMapping",
|
|
958
|
+
"treatInfoAsWarning",
|
|
959
|
+
"includeIssues"
|
|
960
|
+
];
|
|
961
|
+
for (const field of booleanFields) {
|
|
962
|
+
const value = source[field];
|
|
963
|
+
if (typeof value === "boolean") {
|
|
964
|
+
result[field] = value;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
const sourceRoots = asStringArray(source.sourceRoots);
|
|
968
|
+
if (sourceRoots) {
|
|
969
|
+
result.sourceRoots = sourceRoots;
|
|
970
|
+
}
|
|
971
|
+
const warningCategoryFilter = asStringArray(source.warningCategoryFilter);
|
|
972
|
+
if (warningCategoryFilter) {
|
|
973
|
+
result.warningCategoryFilter = warningCategoryFilter;
|
|
974
|
+
}
|
|
975
|
+
return result;
|
|
976
|
+
}
|
|
977
|
+
function buildValidateMixinSuggestedParams(normalizedInput) {
|
|
978
|
+
const record = asObjectRecord(normalizedInput);
|
|
979
|
+
if (!record) {
|
|
980
|
+
return {
|
|
981
|
+
input: {
|
|
982
|
+
mode: "inline",
|
|
983
|
+
source: "<Mixin Java source>"
|
|
984
|
+
},
|
|
985
|
+
version: "<minecraft-version>"
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
const inputRecord = asObjectRecord(record.input);
|
|
989
|
+
const shared = copyValidateMixinSharedParams(record);
|
|
990
|
+
const version = asNonEmptyString(record.version) ?? "<minecraft-version>";
|
|
991
|
+
const inlineSource = asNonEmptyString(record.input) ??
|
|
992
|
+
asNonEmptyString(inputRecord?.source) ??
|
|
993
|
+
asNonEmptyString(record.source);
|
|
994
|
+
if (inlineSource) {
|
|
995
|
+
const parsedInlineObject = parseJsonObjectString(inlineSource);
|
|
996
|
+
if (parsedInlineObject && typeof parsedInlineObject.mode === "string") {
|
|
997
|
+
return {
|
|
998
|
+
...shared,
|
|
999
|
+
input: parsedInlineObject,
|
|
1000
|
+
version
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
return {
|
|
1004
|
+
...shared,
|
|
1005
|
+
input: {
|
|
1006
|
+
mode: "inline",
|
|
1007
|
+
source: truncateSuggestionText(inlineSource)
|
|
1008
|
+
},
|
|
1009
|
+
version
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
const path = asNonEmptyString(inputRecord?.path) ??
|
|
1013
|
+
asNonEmptyString(record.sourcePath);
|
|
1014
|
+
if (path) {
|
|
1015
|
+
return {
|
|
1016
|
+
...shared,
|
|
1017
|
+
input: {
|
|
1018
|
+
mode: "path",
|
|
1019
|
+
path
|
|
1020
|
+
},
|
|
1021
|
+
version
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1024
|
+
const paths = asStringArray(inputRecord?.paths) ??
|
|
1025
|
+
asStringArray(record.sourcePaths);
|
|
1026
|
+
if (paths) {
|
|
1027
|
+
return {
|
|
1028
|
+
...shared,
|
|
1029
|
+
input: {
|
|
1030
|
+
mode: "paths",
|
|
1031
|
+
paths
|
|
1032
|
+
},
|
|
1033
|
+
version
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
const configPaths = asStringArray(inputRecord?.configPaths) ??
|
|
1037
|
+
(asNonEmptyString(record.mixinConfigPath) ? [record.mixinConfigPath] : undefined);
|
|
1038
|
+
if (configPaths) {
|
|
1039
|
+
return {
|
|
1040
|
+
...shared,
|
|
1041
|
+
input: {
|
|
1042
|
+
mode: "config",
|
|
1043
|
+
configPaths
|
|
1044
|
+
},
|
|
1045
|
+
version
|
|
1046
|
+
};
|
|
1047
|
+
}
|
|
1048
|
+
const projectPath = asNonEmptyString(record.projectPath) ??
|
|
1049
|
+
(inputRecord?.mode === "project" ? asNonEmptyString(inputRecord.path) : undefined);
|
|
1050
|
+
if (projectPath) {
|
|
1051
|
+
return {
|
|
1052
|
+
...shared,
|
|
1053
|
+
input: {
|
|
1054
|
+
mode: "project",
|
|
1055
|
+
path: projectPath
|
|
1056
|
+
},
|
|
1057
|
+
version
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
return {
|
|
1061
|
+
...shared,
|
|
1062
|
+
input: {
|
|
1063
|
+
mode: "inline",
|
|
1064
|
+
source: "<Mixin Java source>"
|
|
1065
|
+
},
|
|
1066
|
+
version
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
function buildResolveArtifactSuggestedParams(normalizedInput) {
|
|
1070
|
+
const record = asObjectRecord(normalizedInput);
|
|
1071
|
+
if (!record) {
|
|
1072
|
+
return {
|
|
1073
|
+
target: {
|
|
1074
|
+
kind: "version",
|
|
1075
|
+
value: "<minecraft-version>"
|
|
1076
|
+
}
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
const targetValue = asNonEmptyString(record.target);
|
|
1080
|
+
const result = {
|
|
1081
|
+
target: targetValue
|
|
1082
|
+
? {
|
|
1083
|
+
kind: inferTargetKindFromString(targetValue),
|
|
1084
|
+
value: targetValue
|
|
1085
|
+
}
|
|
1086
|
+
: {
|
|
1087
|
+
kind: "version",
|
|
1088
|
+
value: "<minecraft-version>"
|
|
1089
|
+
}
|
|
1090
|
+
};
|
|
1091
|
+
const stringFields = ["mapping", "sourcePriority", "projectPath", "scope"];
|
|
1092
|
+
for (const field of stringFields) {
|
|
1093
|
+
const value = record[field];
|
|
1094
|
+
if (typeof value === "string" && value.trim()) {
|
|
1095
|
+
result[field] = value;
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
const booleanFields = ["allowDecompile", "preferProjectVersion", "strictVersion"];
|
|
1099
|
+
for (const field of booleanFields) {
|
|
1100
|
+
const value = record[field];
|
|
1101
|
+
if (typeof value === "boolean") {
|
|
1102
|
+
result[field] = value;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
return result;
|
|
1106
|
+
}
|
|
1107
|
+
function buildSourceLookupSuggestedParams(tool, normalizedInput) {
|
|
1108
|
+
const record = asObjectRecord(normalizedInput);
|
|
1109
|
+
const result = record ? copySourceLookupSuggestionFields(tool, record) : {};
|
|
1110
|
+
const targetValue = asNonEmptyString(record?.target);
|
|
1111
|
+
result.target = targetValue
|
|
1112
|
+
? {
|
|
1113
|
+
type: "resolve",
|
|
1114
|
+
kind: inferTargetKindFromString(targetValue),
|
|
1115
|
+
value: targetValue
|
|
1116
|
+
}
|
|
1117
|
+
: {
|
|
1118
|
+
type: "resolve",
|
|
1119
|
+
kind: "version",
|
|
1120
|
+
value: "<minecraft-version>"
|
|
1121
|
+
};
|
|
1122
|
+
if (!asNonEmptyString(result.className)) {
|
|
1123
|
+
result.className = "<fully-qualified-class-name>";
|
|
1124
|
+
}
|
|
1125
|
+
return result;
|
|
1126
|
+
}
|
|
1127
|
+
function buildInvalidInputGuidance(tool, normalizedInput) {
|
|
1128
|
+
if (tool === "validate-mixin") {
|
|
1129
|
+
const hints = [
|
|
1130
|
+
"validate-mixin.input must be an object with input.mode = \"inline\" | \"path\" | \"paths\" | \"config\" | \"project\".",
|
|
1131
|
+
"Whole-project example: {\"input\":{\"mode\":\"project\",\"path\":\"/workspace\"},\"version\":\"1.21.10\",\"preferProjectVersion\":true,\"preferProjectMapping\":true}.",
|
|
1132
|
+
"Legacy top-level source/sourcePath/sourcePaths/mixinConfigPath fields are no longer accepted; wrap them under input.mode instead."
|
|
1133
|
+
];
|
|
1134
|
+
return {
|
|
1135
|
+
hints,
|
|
1136
|
+
suggestedCall: {
|
|
1137
|
+
tool,
|
|
1138
|
+
params: buildValidateMixinSuggestedParams(normalizedInput)
|
|
1139
|
+
}
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1142
|
+
if (tool === "resolve-artifact") {
|
|
1143
|
+
return {
|
|
1144
|
+
hints: [
|
|
1145
|
+
"resolve-artifact.target must be an object: {\"kind\":\"version|jar|coordinate\",\"value\":\"...\"}.",
|
|
1146
|
+
"Bare string targets are not accepted; wrap the value under target.kind and target.value."
|
|
1147
|
+
],
|
|
1148
|
+
suggestedCall: {
|
|
1149
|
+
tool,
|
|
1150
|
+
params: buildResolveArtifactSuggestedParams(normalizedInput)
|
|
1151
|
+
}
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
if (tool === "get-class-source" || tool === "get-class-members") {
|
|
1155
|
+
return {
|
|
1156
|
+
hints: [
|
|
1157
|
+
`${tool}.target must be an object: {"type":"resolve","kind":"version|jar|coordinate","value":"..."} or {"type":"artifact","artifactId":"..."}.`,
|
|
1158
|
+
"Bare string targets are not accepted; wrap the value under target.type/target.kind/target.value."
|
|
1159
|
+
],
|
|
1160
|
+
suggestedCall: {
|
|
1161
|
+
tool,
|
|
1162
|
+
params: buildSourceLookupSuggestedParams(tool, normalizedInput)
|
|
1163
|
+
}
|
|
1164
|
+
};
|
|
1165
|
+
}
|
|
1166
|
+
return undefined;
|
|
1167
|
+
}
|
|
1168
|
+
function mapErrorToProblem(caughtError, requestId, context) {
|
|
772
1169
|
if (caughtError instanceof ZodError) {
|
|
1170
|
+
const guidance = context?.tool
|
|
1171
|
+
? buildInvalidInputGuidance(context.tool, context.normalizedInput)
|
|
1172
|
+
: undefined;
|
|
773
1173
|
return {
|
|
774
1174
|
type: "https://minecraft-modding-mcp.dev/problems/invalid-input",
|
|
775
1175
|
title: "Invalid input",
|
|
@@ -778,7 +1178,8 @@ function mapErrorToProblem(caughtError, requestId) {
|
|
|
778
1178
|
code: ERROR_CODES.INVALID_INPUT,
|
|
779
1179
|
instance: requestId,
|
|
780
1180
|
fieldErrors: toFieldErrorsFromZod(caughtError),
|
|
781
|
-
hints: ["Check fieldErrors and submit a valid tool argument payload."]
|
|
1181
|
+
hints: guidance?.hints ?? ["Check fieldErrors and submit a valid tool argument payload."],
|
|
1182
|
+
...(guidance?.suggestedCall ? { suggestedCall: guidance.suggestedCall } : {})
|
|
782
1183
|
};
|
|
783
1184
|
}
|
|
784
1185
|
if (isAppError(caughtError)) {
|
|
@@ -806,25 +1207,37 @@ function mapErrorToProblem(caughtError, requestId) {
|
|
|
806
1207
|
}
|
|
807
1208
|
function splitWarnings(data) {
|
|
808
1209
|
const result = { ...data };
|
|
1210
|
+
const warnings = [];
|
|
809
1211
|
const maybeWarnings = result.warnings;
|
|
810
|
-
if (
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
1212
|
+
if (Array.isArray(maybeWarnings)) {
|
|
1213
|
+
warnings.push(...maybeWarnings.filter((entry) => typeof entry === "string"));
|
|
1214
|
+
delete result.warnings;
|
|
1215
|
+
}
|
|
1216
|
+
let meta = {};
|
|
1217
|
+
const maybeMeta = result.meta;
|
|
1218
|
+
if (maybeMeta && typeof maybeMeta === "object" && !Array.isArray(maybeMeta)) {
|
|
1219
|
+
meta = { ...maybeMeta };
|
|
1220
|
+
delete result.meta;
|
|
1221
|
+
const metaWarnings = meta.warnings;
|
|
1222
|
+
if (Array.isArray(metaWarnings)) {
|
|
1223
|
+
warnings.push(...metaWarnings.filter((entry) => typeof entry === "string"));
|
|
1224
|
+
delete meta.warnings;
|
|
1225
|
+
}
|
|
815
1226
|
}
|
|
816
|
-
const warnings = maybeWarnings.filter((entry) => typeof entry === "string");
|
|
817
|
-
delete result.warnings;
|
|
818
1227
|
return {
|
|
819
1228
|
result,
|
|
820
|
-
warnings
|
|
1229
|
+
warnings: [...new Set(warnings)],
|
|
1230
|
+
meta
|
|
821
1231
|
};
|
|
822
1232
|
}
|
|
823
1233
|
async function runTool(tool, rawInput, schema, action) {
|
|
824
1234
|
const requestId = buildRequestId();
|
|
825
1235
|
const startedAt = Date.now();
|
|
1236
|
+
let normalizedInput = rawInput;
|
|
826
1237
|
try {
|
|
827
|
-
const
|
|
1238
|
+
const preparedInput = prepareToolInput(rawInput);
|
|
1239
|
+
normalizedInput = preparedInput.normalizedInput;
|
|
1240
|
+
const { removedOfficialPaths, suggestedReplacementInput } = preparedInput;
|
|
828
1241
|
if (removedOfficialPaths.length > 0) {
|
|
829
1242
|
throw createError({
|
|
830
1243
|
code: ERROR_CODES.INVALID_INPUT,
|
|
@@ -846,11 +1259,31 @@ async function runTool(tool, rawInput, schema, action) {
|
|
|
846
1259
|
});
|
|
847
1260
|
}
|
|
848
1261
|
const parsedInput = schema.parse(normalizedInput);
|
|
849
|
-
const payload = await
|
|
850
|
-
|
|
1262
|
+
const payload = await (HEAVY_TOOL_NAMES.has(tool)
|
|
1263
|
+
? heavyToolExecutionGate.run(tool, () => action(parsedInput))
|
|
1264
|
+
: action(parsedInput));
|
|
1265
|
+
const { result, warnings, meta: resultMeta } = splitWarnings(payload);
|
|
1266
|
+
const entryMeta = ENTRY_TOOL_NAMES.has(tool)
|
|
1267
|
+
? buildEntryToolMeta({
|
|
1268
|
+
detail: normalizedInput &&
|
|
1269
|
+
typeof normalizedInput === "object" &&
|
|
1270
|
+
!Array.isArray(normalizedInput) &&
|
|
1271
|
+
typeof normalizedInput.detail === "string"
|
|
1272
|
+
? normalizedInput.detail ?? "summary"
|
|
1273
|
+
: "summary",
|
|
1274
|
+
include: normalizedInput &&
|
|
1275
|
+
typeof normalizedInput === "object" &&
|
|
1276
|
+
!Array.isArray(normalizedInput) &&
|
|
1277
|
+
Array.isArray(normalizedInput.include)
|
|
1278
|
+
? normalizedInput.include
|
|
1279
|
+
: undefined
|
|
1280
|
+
})
|
|
1281
|
+
: undefined;
|
|
851
1282
|
return objectResult({
|
|
852
1283
|
result,
|
|
853
1284
|
meta: {
|
|
1285
|
+
...(entryMeta ?? {}),
|
|
1286
|
+
...resultMeta,
|
|
854
1287
|
requestId,
|
|
855
1288
|
tool,
|
|
856
1289
|
durationMs: Date.now() - startedAt,
|
|
@@ -859,7 +1292,10 @@ async function runTool(tool, rawInput, schema, action) {
|
|
|
859
1292
|
});
|
|
860
1293
|
}
|
|
861
1294
|
catch (caughtError) {
|
|
862
|
-
const problem = mapErrorToProblem(caughtError, requestId
|
|
1295
|
+
const problem = mapErrorToProblem(caughtError, requestId, {
|
|
1296
|
+
tool,
|
|
1297
|
+
normalizedInput
|
|
1298
|
+
});
|
|
863
1299
|
if (isAppError(caughtError)) {
|
|
864
1300
|
const isSevere = caughtError.code === ERROR_CODES.DB_FAILURE ||
|
|
865
1301
|
caughtError.code === ERROR_CODES.REPO_FETCH_FAILED ||
|
|
@@ -905,6 +1341,12 @@ server.tool("list-versions", "List available Minecraft versions from Mojang mani
|
|
|
905
1341
|
includeSnapshots: input.includeSnapshots,
|
|
906
1342
|
limit: input.limit
|
|
907
1343
|
})));
|
|
1344
|
+
server.tool("inspect-minecraft", "High-level v3 entry tool for version discovery, artifact resolution, class inspection, source search, file reads, and file listings.", inspectMinecraftShape, { readOnlyHint: true }, async (args) => runTool("inspect-minecraft", args, inspectMinecraftSchema, async (input) => inspectMinecraftService.execute(input)));
|
|
1345
|
+
server.tool("analyze-symbol", "High-level v3 entry tool for symbol existence, mapping, lifecycle, workspace analysis, and API overview.", analyzeSymbolShape, { readOnlyHint: true }, async (args) => runTool("analyze-symbol", args, analyzeSymbolSchema, async (input) => analyzeSymbolService.execute(input)));
|
|
1346
|
+
server.tool("compare-minecraft", "High-level v3 entry tool for version comparisons, class diffs, registry diffs, and migration overviews.", compareMinecraftShape, { readOnlyHint: true }, async (args) => runTool("compare-minecraft", args, compareMinecraftSchema, async (input) => compareMinecraftService.execute(input)));
|
|
1347
|
+
server.tool("analyze-mod", "High-level v3 entry tool for mod metadata inspection, decompile/search flows, class source, and safe remap previews/applies.", analyzeModShape, { readOnlyHint: false }, async (args) => runTool("analyze-mod", args, analyzeModSchema, async (input) => analyzeModService.execute(input)));
|
|
1348
|
+
server.tool("validate-project", "High-level v3 entry tool for project summary, direct mixin validation, and access widener validation.", validateProjectShape, { readOnlyHint: true }, async (args) => runTool("validate-project", args, validateProjectSchema, async (input) => validateProjectService.execute(input)));
|
|
1349
|
+
server.tool("manage-cache", "High-level v3 entry tool for cache summaries, listing, verification, previewed mutation, and explicit apply operations.", manageCacheShape, { readOnlyHint: false }, async (args) => runTool("manage-cache", args, manageCacheSchema, async (input) => manageCacheService.execute(input)));
|
|
908
1350
|
server.tool("resolve-artifact", "Resolve source artifact from a target object ({ kind, value }) and return artifact metadata. For target.kind=jar, only <basename>-sources.jar is auto-adopted; other adjacent *-sources.jar files are informational.", resolveArtifactShape, { readOnlyHint: true }, async (args) => runTool("resolve-artifact", args, resolveArtifactSchema, async (input) => sourceService.resolveArtifact({
|
|
909
1351
|
target: input.target,
|
|
910
1352
|
mapping: input.mapping,
|
|
@@ -1008,7 +1450,8 @@ server.tool("diff-class-signatures", "Compare one class signature between two Mi
|
|
|
1008
1450
|
fromVersion: input.fromVersion,
|
|
1009
1451
|
toVersion: input.toVersion,
|
|
1010
1452
|
mapping: input.mapping,
|
|
1011
|
-
sourcePriority: input.sourcePriority
|
|
1453
|
+
sourcePriority: input.sourcePriority,
|
|
1454
|
+
includeFullDiff: input.includeFullDiff
|
|
1012
1455
|
})));
|
|
1013
1456
|
server.tool("find-mapping", "Find symbol mapping candidates between namespaces using structured symbol inputs for a specific Minecraft version.", findMappingShape, { readOnlyHint: true }, async (args) => runTool("find-mapping", args, findMappingSchema, async (input) => sourceService.findMapping({
|
|
1014
1457
|
version: input.version,
|
|
@@ -1019,7 +1462,8 @@ server.tool("find-mapping", "Find symbol mapping candidates between namespaces u
|
|
|
1019
1462
|
sourceMapping: input.sourceMapping,
|
|
1020
1463
|
targetMapping: input.targetMapping,
|
|
1021
1464
|
sourcePriority: input.sourcePriority,
|
|
1022
|
-
disambiguation: input.disambiguation
|
|
1465
|
+
disambiguation: input.disambiguation,
|
|
1466
|
+
maxCandidates: input.maxCandidates
|
|
1023
1467
|
})));
|
|
1024
1468
|
server.tool("resolve-method-mapping-exact", "Resolve one method mapping exactly by owner+name+descriptor between namespaces and report resolved/not_found/ambiguous.", resolveMethodMappingExactShape, { readOnlyHint: true }, async (args) => runTool("resolve-method-mapping-exact", args, resolveMethodMappingExactSchema, async (input) => sourceService.resolveMethodMappingExact({
|
|
1025
1469
|
version: input.version,
|
|
@@ -1028,14 +1472,16 @@ server.tool("resolve-method-mapping-exact", "Resolve one method mapping exactly
|
|
|
1028
1472
|
descriptor: input.descriptor,
|
|
1029
1473
|
sourceMapping: input.sourceMapping,
|
|
1030
1474
|
targetMapping: input.targetMapping,
|
|
1031
|
-
sourcePriority: input.sourcePriority
|
|
1475
|
+
sourcePriority: input.sourcePriority,
|
|
1476
|
+
maxCandidates: input.maxCandidates
|
|
1032
1477
|
})));
|
|
1033
1478
|
server.tool("get-class-api-matrix", "List class/member API rows across obfuscated/mojang/intermediary/yarn mappings for one class and Minecraft version.", getClassApiMatrixShape, { readOnlyHint: true }, async (args) => runTool("get-class-api-matrix", args, getClassApiMatrixSchema, async (input) => sourceService.getClassApiMatrix({
|
|
1034
1479
|
version: input.version,
|
|
1035
1480
|
className: input.className,
|
|
1036
1481
|
classNameMapping: input.classNameMapping,
|
|
1037
1482
|
includeKinds: parseClassApiKinds(input.includeKinds),
|
|
1038
|
-
sourcePriority: input.sourcePriority
|
|
1483
|
+
sourcePriority: input.sourcePriority,
|
|
1484
|
+
maxRows: input.maxRows
|
|
1039
1485
|
})));
|
|
1040
1486
|
server.tool("resolve-workspace-symbol", "Resolve class/field/method names as seen at compile time for a workspace by reading Gradle Loom mapping settings.", resolveWorkspaceSymbolShape, { readOnlyHint: true }, async (args) => runTool("resolve-workspace-symbol", args, resolveWorkspaceSymbolSchema, async (input) => sourceService.resolveWorkspaceSymbol({
|
|
1041
1487
|
projectPath: input.projectPath,
|
|
@@ -1045,7 +1491,8 @@ server.tool("resolve-workspace-symbol", "Resolve class/field/method names as see
|
|
|
1045
1491
|
owner: input.owner,
|
|
1046
1492
|
descriptor: input.descriptor,
|
|
1047
1493
|
sourceMapping: input.sourceMapping,
|
|
1048
|
-
sourcePriority: input.sourcePriority
|
|
1494
|
+
sourcePriority: input.sourcePriority,
|
|
1495
|
+
maxCandidates: input.maxCandidates
|
|
1049
1496
|
})));
|
|
1050
1497
|
server.tool("check-symbol-exists", "Check whether a class/field/method symbol exists in a specific mapping namespace for one Minecraft version.", checkSymbolExistsShape, { readOnlyHint: true }, async (args) => runTool("check-symbol-exists", args, checkSymbolExistsSchema, async (input) => sourceService.checkSymbolExists({
|
|
1051
1498
|
version: input.version,
|
|
@@ -1056,7 +1503,8 @@ server.tool("check-symbol-exists", "Check whether a class/field/method symbol ex
|
|
|
1056
1503
|
sourceMapping: input.sourceMapping,
|
|
1057
1504
|
sourcePriority: input.sourcePriority,
|
|
1058
1505
|
nameMode: input.nameMode,
|
|
1059
|
-
signatureMode: input.signatureMode
|
|
1506
|
+
signatureMode: input.signatureMode,
|
|
1507
|
+
maxCandidates: input.maxCandidates
|
|
1060
1508
|
})));
|
|
1061
1509
|
server.tool("nbt-to-json", "Decode Java Edition NBT binary payload (base64) into typed JSON.", nbtToJsonShape, { readOnlyHint: true }, async (args) => runTool("nbt-to-json", args, nbtToJsonSchema, async (input) => Promise.resolve(nbtBase64ToTypedJson({
|
|
1062
1510
|
nbtBase64: input.nbtBase64,
|
|
@@ -1091,7 +1539,8 @@ server.tool("validate-mixin", "Validate Mixin source against Minecraft bytecode
|
|
|
1091
1539
|
preferProjectMapping: input.preferProjectMapping,
|
|
1092
1540
|
reportMode: input.reportMode,
|
|
1093
1541
|
warningCategoryFilter: input.warningCategoryFilter,
|
|
1094
|
-
treatInfoAsWarning: input.treatInfoAsWarning
|
|
1542
|
+
treatInfoAsWarning: input.treatInfoAsWarning,
|
|
1543
|
+
includeIssues: input.includeIssues
|
|
1095
1544
|
})));
|
|
1096
1545
|
server.tool("validate-access-widener", "Validate Access Widener file entries against Minecraft bytecode signatures for a given version.", validateAccessWidenerShape, { readOnlyHint: true }, async (args) => runTool("validate-access-widener", args, validateAccessWidenerSchema, async (input) => sourceService.validateAccessWidener({
|
|
1097
1546
|
content: input.content,
|
|
@@ -1107,7 +1556,9 @@ server.tool("analyze-mod-jar", "Analyze a Minecraft mod JAR to extract loader ty
|
|
|
1107
1556
|
}));
|
|
1108
1557
|
server.tool("get-registry-data", "Get Minecraft registry data (blocks, items, biomes, etc.) for a specific version by running the server data generator.", getRegistryDataShape, { readOnlyHint: true }, async (args) => runTool("get-registry-data", args, getRegistryDataSchema, async (input) => sourceService.getRegistryData({
|
|
1109
1558
|
version: input.version,
|
|
1110
|
-
registry: input.registry
|
|
1559
|
+
registry: input.registry,
|
|
1560
|
+
includeData: input.includeData,
|
|
1561
|
+
maxEntriesPerRegistry: input.maxEntriesPerRegistry
|
|
1111
1562
|
})));
|
|
1112
1563
|
server.tool("compare-versions", "Compare two Minecraft versions to find added/removed classes and registry entry changes. Useful for understanding what changed between versions during mod migration.", compareVersionsShape, { readOnlyHint: true }, async (args) => runTool("compare-versions", args, compareVersionsSchema, async (input) => sourceService.compareVersions({
|
|
1113
1564
|
fromVersion: input.fromVersion,
|
|
@@ -1118,7 +1569,9 @@ server.tool("compare-versions", "Compare two Minecraft versions to find added/re
|
|
|
1118
1569
|
})));
|
|
1119
1570
|
server.tool("decompile-mod-jar", "Decompile a Minecraft mod JAR using Vineflower and list available classes, or view a specific class source. Builds on analyze-mod-jar by exposing the actual source code.", decompileModJarShape, { readOnlyHint: true }, async (args) => runTool("decompile-mod-jar", args, decompileModJarSchema, async (input) => sourceService.decompileModJar({
|
|
1120
1571
|
jarPath: input.jarPath,
|
|
1121
|
-
className: input.className
|
|
1572
|
+
className: input.className,
|
|
1573
|
+
includeFiles: input.includeFiles,
|
|
1574
|
+
maxFiles: input.maxFiles
|
|
1122
1575
|
})));
|
|
1123
1576
|
server.tool("get-mod-class-source", "Get decompiled source code for a specific class in a mod JAR. The mod JAR will be decompiled if not already cached.", getModClassSourceShape, { readOnlyHint: true }, async (args) => runTool("get-mod-class-source", args, getModClassSourceSchema, async (input) => sourceService.getModClassSource({
|
|
1124
1577
|
jarPath: input.jarPath,
|