@adhisang/minecraft-modding-mcp 3.1.1 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +20 -8
  3. package/dist/access-transformer-parser.d.ts +17 -0
  4. package/dist/access-transformer-parser.js +97 -0
  5. package/dist/concurrency.d.ts +1 -0
  6. package/dist/concurrency.js +24 -0
  7. package/dist/decompiler/vineflower.js +22 -21
  8. package/dist/entry-tools/analyze-mod-service.d.ts +4 -4
  9. package/dist/entry-tools/analyze-symbol-service.d.ts +20 -20
  10. package/dist/entry-tools/inspect-minecraft-service.d.ts +148 -148
  11. package/dist/entry-tools/validate-project-service.d.ts +153 -16
  12. package/dist/entry-tools/validate-project-service.js +360 -23
  13. package/dist/gradle-paths.d.ts +4 -0
  14. package/dist/gradle-paths.js +57 -0
  15. package/dist/index.js +65 -13
  16. package/dist/mapping-pipeline-service.d.ts +3 -1
  17. package/dist/mapping-pipeline-service.js +16 -1
  18. package/dist/mapping-service.d.ts +4 -0
  19. package/dist/mapping-service.js +155 -60
  20. package/dist/minecraft-explorer-service.d.ts +13 -0
  21. package/dist/minecraft-explorer-service.js +8 -4
  22. package/dist/mixin-validator.d.ts +33 -2
  23. package/dist/mixin-validator.js +197 -11
  24. package/dist/mod-analyzer.d.ts +1 -0
  25. package/dist/mod-analyzer.js +17 -1
  26. package/dist/mod-decompile-service.js +4 -4
  27. package/dist/mod-remap-service.js +1 -54
  28. package/dist/mod-search-service.d.ts +1 -0
  29. package/dist/mod-search-service.js +84 -51
  30. package/dist/response-utils.d.ts +35 -0
  31. package/dist/response-utils.js +113 -0
  32. package/dist/source-jar-reader.d.ts +16 -0
  33. package/dist/source-jar-reader.js +103 -1
  34. package/dist/source-resolver.js +9 -10
  35. package/dist/source-service.d.ts +22 -2
  36. package/dist/source-service.js +914 -105
  37. package/dist/tool-contract-manifest.js +8 -6
  38. package/dist/types.d.ts +17 -0
  39. package/dist/workspace-mapping-service.d.ts +13 -0
  40. package/dist/workspace-mapping-service.js +146 -14
  41. package/package.json +1 -1
@@ -15,7 +15,7 @@ const SECTION_ROWS = {
15
15
  "| `analyze-symbol` | Handle symbol existence checks, namespace mapping, lifecycle tracing, workspace symbol resolution, and API overviews |",
16
16
  "| `compare-minecraft` | Compare version pairs, class diffs, registry diffs, and migration-oriented summaries |",
17
17
  "| `analyze-mod` | Summarize mod metadata, decompile and search mod code, inspect class source, and preview or apply remaps |",
18
- "| `validate-project` | Summarize workspaces and run direct Mixin or Access Widener validation |",
18
+ "| `validate-project` | Summarize workspaces and run direct Mixin, Access Widener, or Access Transformer validation |",
19
19
  "| `manage-cache` | List, verify, and preview or apply cache cleanup and rebuild operations |"
20
20
  ],
21
21
  ja: [
@@ -23,7 +23,7 @@ const SECTION_ROWS = {
23
23
  "| `analyze-symbol` | シンボル存在確認、名前空間変換、ライフサイクル追跡、ワークスペースシンボル解決、API 概要をまとめて扱う |",
24
24
  "| `compare-minecraft` | バージョン差分、クラス差分、レジストリ差分、移行向け概要を比較する |",
25
25
  "| `analyze-mod` | Mod メタデータの要約、Mod コードのデコンパイル / 検索、クラスソース確認、リマップのプレビュー / 実行を扱う |",
26
- "| `validate-project` | ワークスペース要約と、Mixin / Access Widener の直接検証を行う |",
26
+ "| `validate-project` | ワークスペース要約と、Mixin / Access Widener / Access Transformer の直接検証を行う |",
27
27
  "| `manage-cache` | キャッシュの一覧、検証、クリーンアップ / 再構築のプレビュー / 実行を行う |"
28
28
  ]
29
29
  },
@@ -93,14 +93,14 @@ const SECTION_ROWS = {
93
93
  },
94
94
  "mod-analysis": {
95
95
  en: [
96
- "| `analyze-mod-jar` | Extract mod metadata, dependencies, entrypoints, and mixin config info from a JAR |",
96
+ "| `analyze-mod-jar` | Extract mod metadata, dependencies, entrypoints, mixin config info, and packaged access transformer paths from a JAR |",
97
97
  "| `decompile-mod-jar` | Decompile a mod JAR and optionally return one class source |",
98
98
  "| `get-mod-class-source` | Read one class source from the decompiled mod cache |",
99
99
  "| `search-mod-source` | Search decompiled mod source by class, method, field, or content |",
100
100
  "| `remap-mod-jar` | Remap a Fabric or Quilt mod JAR to `yarn` or `mojang` names |"
101
101
  ],
102
102
  ja: [
103
- "| `analyze-mod-jar` | JAR から Mod メタデータ、依存関係、エントリポイント、Mixin 設定情報を抽出する |",
103
+ "| `analyze-mod-jar` | JAR から Mod メタデータ、依存関係、エントリポイント、Mixin 設定情報、同梱 Access Transformer パスを抽出する |",
104
104
  "| `decompile-mod-jar` | Mod JAR をデコンパイルし、必要に応じて 1 つのクラスソースを返す |",
105
105
  "| `get-mod-class-source` | デコンパイル済み Mod キャッシュから 1 つのクラスソースを読み取る |",
106
106
  "| `search-mod-source` | デコンパイル済み Mod ソースを class、method、field、content で検索する |",
@@ -110,11 +110,13 @@ const SECTION_ROWS = {
110
110
  "validation": {
111
111
  en: [
112
112
  "| `validate-mixin` | Validate Mixin source against a target Minecraft version |",
113
- "| `validate-access-widener` | Validate Access Widener content against a target Minecraft version |"
113
+ "| `validate-access-widener` | Validate Access Widener content against a target Minecraft version, optionally using runtime-aware Loom artifacts |",
114
+ "| `validate-access-transformer` | Validate Access Transformer content against a target Minecraft version, optionally using Forge/NeoForge runtime artifacts |"
114
115
  ],
115
116
  ja: [
116
117
  "| `validate-mixin` | 対象 Minecraft バージョンに対して Mixin ソースを検証する |",
117
- "| `validate-access-widener` | 対象 Minecraft バージョンに対して Access Widener の内容を検証する |"
118
+ "| `validate-access-widener` | 対象 Minecraft バージョンに対して Access Widener の内容を検証し、必要に応じて Loom runtime artifact も使う |",
119
+ "| `validate-access-transformer` | 対象 Minecraft バージョンに対して Access Transformer の内容を検証し、必要に応じて Forge / NeoForge runtime artifact も使う |"
118
120
  ]
119
121
  },
120
122
  "registry-diagnostics": {
package/dist/types.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  export type SourceOrigin = "local-jar" | "local-m2" | "remote-repo" | "decompiled";
2
2
  export type SourceMapping = "obfuscated" | "mojang" | "intermediary" | "yarn";
3
+ export type AccessTransformerNamespace = "srg" | "mojang" | "obfuscated";
4
+ export type RuntimeValidationNamespace = SourceMapping | AccessTransformerNamespace;
3
5
  export type MappingSourcePriority = "loom-first" | "maven-first";
4
6
  export type ArtifactTargetKind = "version" | "jar" | "coordinate";
5
7
  export type ArtifactScope = "vanilla" | "merged" | "loader";
@@ -37,6 +39,21 @@ export interface ArtifactProvenance {
37
39
  };
38
40
  transformChain: string[];
39
41
  }
42
+ export interface RuntimeValidationProvenance<TMapping extends RuntimeValidationNamespace = RuntimeValidationNamespace> {
43
+ version: string;
44
+ jarPath: string;
45
+ requestedScope?: ArtifactScope;
46
+ appliedScope?: ArtifactScope;
47
+ requestedMapping: TMapping;
48
+ mappingApplied: TMapping;
49
+ origin: SourceOrigin | "loom-cache" | "version-jar";
50
+ resolutionNotes?: string[];
51
+ scopeFallback?: {
52
+ requested: string;
53
+ applied: string;
54
+ reason: string;
55
+ };
56
+ }
40
57
  export interface ErrorEnvelope {
41
58
  code: string;
42
59
  message: string;
@@ -13,7 +13,20 @@ export type WorkspaceCompileMappingOutput = {
13
13
  evidence: WorkspaceMappingEvidence[];
14
14
  warnings: string[];
15
15
  };
16
+ export type WorkspaceProjectLoader = "fabric" | "quilt" | "forge" | "neoforge" | "unknown";
17
+ export type WorkspaceLoaderEvidence = {
18
+ filePath: string;
19
+ loader: WorkspaceProjectLoader;
20
+ reason: string;
21
+ };
22
+ export type WorkspaceProjectLoaderOutput = {
23
+ resolved: boolean;
24
+ loader?: WorkspaceProjectLoader;
25
+ evidence: WorkspaceLoaderEvidence[];
26
+ warnings: string[];
27
+ };
16
28
  export declare class WorkspaceMappingService {
17
29
  detectCompileMapping(input: WorkspaceCompileMappingInput): Promise<WorkspaceCompileMappingOutput>;
18
30
  detectProjectMinecraftVersion(projectPath: string): Promise<string | undefined>;
31
+ detectProjectLoader(projectPath: string): Promise<WorkspaceProjectLoaderOutput>;
19
32
  }
@@ -1,7 +1,9 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { resolve } from "node:path";
3
3
  import fastGlob from "fast-glob";
4
+ import { mapWithConcurrencyLimit } from "./concurrency.js";
4
5
  import { createError, ERROR_CODES } from "./errors.js";
6
+ const WORKSPACE_FILE_READ_CONCURRENCY = 4;
5
7
  function detectMappingsFromContent(content) {
6
8
  const detections = [];
7
9
  if (/officialMojangMappings\s*\(/i.test(content)) {
@@ -36,6 +38,46 @@ function detectMappingsFromContent(content) {
36
38
  }
37
39
  return detections;
38
40
  }
41
+ function detectLoadersFromContent(content) {
42
+ const detections = [];
43
+ if (/\bid\s*(?:\(\s*)?["']net\.neoforged\.moddev["']\s*\)?/i.test(content)) {
44
+ detections.push({
45
+ loader: "neoforge",
46
+ reason: "net.neoforged.moddev plugin"
47
+ });
48
+ }
49
+ if (/\bid\s*(?:\(\s*)?["']net\.minecraftforge\.gradle["']\s*\)?/i.test(content)) {
50
+ detections.push({
51
+ loader: "forge",
52
+ reason: "net.minecraftforge.gradle plugin"
53
+ });
54
+ }
55
+ if (/\bid\s*(?:\(\s*)?["']org\.quiltmc\.loom["']\s*\)?/i.test(content)) {
56
+ detections.push({
57
+ loader: "quilt",
58
+ reason: "org.quiltmc.loom plugin"
59
+ });
60
+ }
61
+ if (/\bid\s*(?:\(\s*)?["']fabric-loom["']\s*\)?/i.test(content) || /\bid\s*(?:\(\s*)?["']dev\.architectury\.loom["']\s*\)?/i.test(content)) {
62
+ detections.push({
63
+ loader: "fabric",
64
+ reason: "fabric/dev.architectury loom plugin"
65
+ });
66
+ }
67
+ if (/\bminecraft\s*\{[\s\S]*?\baccessTransformer\b/i.test(content)) {
68
+ detections.push({
69
+ loader: "forge",
70
+ reason: "minecraft { accessTransformer ... } block"
71
+ });
72
+ }
73
+ if (/\bneoForge\s*\{[\s\S]*?\baccessTransformers\b/i.test(content)) {
74
+ detections.push({
75
+ loader: "neoforge",
76
+ reason: "neoForge { accessTransformers ... } block"
77
+ });
78
+ }
79
+ return detections;
80
+ }
39
81
  export class WorkspaceMappingService {
40
82
  async detectCompileMapping(input) {
41
83
  const projectPath = input.projectPath?.trim();
@@ -49,30 +91,26 @@ export class WorkspaceMappingService {
49
91
  });
50
92
  }
51
93
  const root = resolve(projectPath);
52
- const files = fastGlob.sync(["build.gradle", "build.gradle.kts", "**/build.gradle", "**/build.gradle.kts"], {
94
+ const files = (await fastGlob.glob(["build.gradle", "build.gradle.kts", "**/build.gradle", "**/build.gradle.kts"], {
53
95
  cwd: root,
54
96
  absolute: true,
55
97
  onlyFiles: true,
56
98
  ignore: ["**/.git/**", "**/.gradle/**", "**/build/**", "**/out/**", "**/node_modules/**"]
57
- });
58
- const evidence = [];
59
- for (const filePath of files.sort((left, right) => left.localeCompare(right))) {
99
+ })).sort((left, right) => left.localeCompare(right));
100
+ const evidence = (await mapWithConcurrencyLimit(files, WORKSPACE_FILE_READ_CONCURRENCY, async (filePath) => {
60
101
  let content;
61
102
  try {
62
103
  content = await readFile(filePath, "utf8");
63
104
  }
64
105
  catch {
65
- continue;
106
+ return [];
66
107
  }
67
- const detections = detectMappingsFromContent(content);
68
- for (const detection of detections) {
69
- evidence.push({
70
- filePath,
71
- mapping: detection.mapping,
72
- reason: detection.reason
73
- });
74
- }
75
- }
108
+ return detectMappingsFromContent(content).map((detection) => ({
109
+ filePath,
110
+ mapping: detection.mapping,
111
+ reason: detection.reason
112
+ }));
113
+ })).flat();
76
114
  if (evidence.length === 0) {
77
115
  return {
78
116
  resolved: false,
@@ -121,5 +159,99 @@ export class WorkspaceMappingService {
121
159
  }
122
160
  return undefined;
123
161
  }
162
+ async detectProjectLoader(projectPath) {
163
+ const root = resolve(projectPath);
164
+ const buildFiles = (await fastGlob.glob(["build.gradle", "build.gradle.kts", "**/build.gradle", "**/build.gradle.kts"], {
165
+ cwd: root,
166
+ absolute: true,
167
+ onlyFiles: true,
168
+ ignore: ["**/.git/**", "**/.gradle/**", "**/build/**", "**/out/**", "**/node_modules/**"]
169
+ })).sort((left, right) => left.localeCompare(right));
170
+ const descriptorFiles = (await fastGlob.glob([
171
+ "fabric.mod.json",
172
+ "quilt.mod.json",
173
+ "META-INF/mods.toml",
174
+ "META-INF/neoforge.mods.toml",
175
+ "**/fabric.mod.json",
176
+ "**/quilt.mod.json",
177
+ "**/META-INF/mods.toml",
178
+ "**/META-INF/neoforge.mods.toml"
179
+ ], {
180
+ cwd: root,
181
+ absolute: true,
182
+ onlyFiles: true,
183
+ ignore: ["**/.git/**", "**/.gradle/**", "**/build/**", "**/out/**", "**/node_modules/**"]
184
+ })).sort((left, right) => left.localeCompare(right));
185
+ const evidence = (await mapWithConcurrencyLimit(buildFiles, WORKSPACE_FILE_READ_CONCURRENCY, async (filePath) => {
186
+ let content;
187
+ try {
188
+ content = await readFile(filePath, "utf8");
189
+ }
190
+ catch {
191
+ return [];
192
+ }
193
+ return detectLoadersFromContent(content).map((detection) => ({
194
+ filePath,
195
+ loader: detection.loader,
196
+ reason: detection.reason
197
+ }));
198
+ })).flat();
199
+ for (const descriptorPath of descriptorFiles) {
200
+ const normalized = descriptorPath.replaceAll("\\", "/");
201
+ if (normalized.endsWith("fabric.mod.json")) {
202
+ evidence.push({
203
+ filePath: descriptorPath,
204
+ loader: "fabric",
205
+ reason: "fabric.mod.json"
206
+ });
207
+ }
208
+ else if (normalized.endsWith("quilt.mod.json")) {
209
+ evidence.push({
210
+ filePath: descriptorPath,
211
+ loader: "quilt",
212
+ reason: "quilt.mod.json"
213
+ });
214
+ }
215
+ else if (normalized.endsWith("META-INF/neoforge.mods.toml")) {
216
+ evidence.push({
217
+ filePath: descriptorPath,
218
+ loader: "neoforge",
219
+ reason: "META-INF/neoforge.mods.toml"
220
+ });
221
+ }
222
+ else if (normalized.endsWith("META-INF/mods.toml")) {
223
+ evidence.push({
224
+ filePath: descriptorPath,
225
+ loader: "forge",
226
+ reason: "META-INF/mods.toml"
227
+ });
228
+ }
229
+ }
230
+ if (evidence.length === 0) {
231
+ return {
232
+ resolved: false,
233
+ evidence,
234
+ warnings: ["No workspace loader declaration was detected from build.gradle(.kts) files or mod descriptors."]
235
+ };
236
+ }
237
+ const loaderSet = new Set(evidence
238
+ .map((entry) => entry.loader)
239
+ .filter((loader) => loader !== "unknown"));
240
+ if (loaderSet.size !== 1) {
241
+ return {
242
+ resolved: false,
243
+ evidence,
244
+ warnings: [
245
+ `Multiple or ambiguous workspace loaders were detected: ${[...loaderSet].join(", ") || "unknown"}.`
246
+ ]
247
+ };
248
+ }
249
+ return {
250
+ resolved: true,
251
+ loader: [...loaderSet][0],
252
+ evidence,
253
+ warnings: []
254
+ };
255
+ }
124
256
  }
125
257
  //# sourceMappingURL=workspace-mapping-service.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhisang/minecraft-modding-mcp",
3
- "version": "3.1.1",
3
+ "version": "3.2.0",
4
4
  "description": "MCP server with utilities for Minecraft modding workflows",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",