@adhisang/minecraft-modding-mcp 1.2.1 → 2.1.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 (51) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +184 -64
  3. package/dist/cli.js +31 -4
  4. package/dist/compat-stdio-transport.d.ts +2 -7
  5. package/dist/compat-stdio-transport.js +12 -154
  6. package/dist/index.js +537 -202
  7. package/dist/json-rpc-framing.d.ts +22 -0
  8. package/dist/json-rpc-framing.js +168 -0
  9. package/dist/mapping-pipeline-service.d.ts +1 -1
  10. package/dist/mapping-pipeline-service.js +13 -5
  11. package/dist/mapping-service.d.ts +12 -4
  12. package/dist/mapping-service.js +222 -105
  13. package/dist/mcp-helpers.d.ts +10 -2
  14. package/dist/mcp-helpers.js +59 -5
  15. package/dist/minecraft-explorer-service.d.ts +1 -2
  16. package/dist/minecraft-explorer-service.js +120 -24
  17. package/dist/mixin-validator.d.ts +24 -2
  18. package/dist/mixin-validator.js +228 -103
  19. package/dist/mod-decompile-service.d.ts +5 -0
  20. package/dist/mod-decompile-service.js +40 -5
  21. package/dist/mod-remap-service.js +142 -30
  22. package/dist/mojang-tiny-mapping-service.js +26 -26
  23. package/dist/path-resolver.js +41 -4
  24. package/dist/registry-service.d.ts +10 -1
  25. package/dist/registry-service.js +154 -22
  26. package/dist/resources.js +7 -7
  27. package/dist/search-hit-accumulator.d.ts +0 -3
  28. package/dist/search-hit-accumulator.js +27 -6
  29. package/dist/source-jar-reader.js +16 -2
  30. package/dist/source-resolver.d.ts +1 -0
  31. package/dist/source-resolver.js +93 -2
  32. package/dist/source-service.d.ts +76 -47
  33. package/dist/source-service.js +1344 -763
  34. package/dist/stdio-supervisor.d.ts +46 -0
  35. package/dist/stdio-supervisor.js +349 -0
  36. package/dist/storage/files-repo.d.ts +3 -0
  37. package/dist/storage/files-repo.js +66 -1
  38. package/dist/storage/migrations.d.ts +1 -1
  39. package/dist/storage/migrations.js +6 -2
  40. package/dist/storage/schema.d.ts +1 -0
  41. package/dist/storage/schema.js +7 -0
  42. package/dist/symbols/symbol-extractor.js +6 -4
  43. package/dist/tool-execution-gate.d.ts +15 -0
  44. package/dist/tool-execution-gate.js +58 -0
  45. package/dist/tool-input.d.ts +6 -0
  46. package/dist/tool-input.js +64 -0
  47. package/dist/types.d.ts +1 -1
  48. package/dist/version-diff-service.js +10 -5
  49. package/dist/version-service.js +7 -2
  50. package/dist/workspace-mapping-service.js +12 -0
  51. package/package.json +4 -1
@@ -0,0 +1,22 @@
1
+ import { type JSONRPCMessage } from "@modelcontextprotocol/sdk/types.js";
2
+ export type FramingMode = "unknown" | "line" | "content-length";
3
+ export type ConcreteFramingMode = Exclude<FramingMode, "unknown">;
4
+ export type ParsedJsonRpcFrame = {
5
+ message: JSONRPCMessage;
6
+ mode: ConcreteFramingMode;
7
+ };
8
+ export declare function encodeJsonRpcMessage(message: JSONRPCMessage, mode: ConcreteFramingMode): Buffer;
9
+ export declare class JsonRpcFrameReader {
10
+ private mode;
11
+ private buffer;
12
+ get currentMode(): FramingMode;
13
+ reset(): void;
14
+ clear(): void;
15
+ processChunk(chunk: Buffer, handlers: {
16
+ onFrame: (frame: ParsedJsonRpcFrame) => void;
17
+ onError: (error: Error) => void;
18
+ }): void;
19
+ private detectMode;
20
+ private readLineDelimitedMessage;
21
+ private readContentLengthMessage;
22
+ }
@@ -0,0 +1,168 @@
1
+ import { JSONRPCMessageSchema } from "@modelcontextprotocol/sdk/types.js";
2
+ function findHeaderBoundary(buffer) {
3
+ const crlfBoundary = buffer.indexOf("\r\n\r\n");
4
+ if (crlfBoundary !== -1) {
5
+ return { index: crlfBoundary, delimiterBytes: 4 };
6
+ }
7
+ const lfBoundary = buffer.indexOf("\n\n");
8
+ if (lfBoundary !== -1) {
9
+ return { index: lfBoundary, delimiterBytes: 2 };
10
+ }
11
+ return undefined;
12
+ }
13
+ function parseJsonRpcMessage(json) {
14
+ return JSONRPCMessageSchema.parse(JSON.parse(json));
15
+ }
16
+ function asError(value) {
17
+ return value instanceof Error ? value : new Error(String(value));
18
+ }
19
+ export function encodeJsonRpcMessage(message, mode) {
20
+ const json = JSON.stringify(message);
21
+ return Buffer.from(mode === "content-length"
22
+ ? `Content-Length: ${Buffer.byteLength(json, "utf8")}\r\n\r\n${json}`
23
+ : `${json}\n`, "utf8");
24
+ }
25
+ export class JsonRpcFrameReader {
26
+ mode = "unknown";
27
+ buffer = Buffer.alloc(0);
28
+ get currentMode() {
29
+ return this.mode;
30
+ }
31
+ reset() {
32
+ this.mode = "unknown";
33
+ }
34
+ clear() {
35
+ this.mode = "unknown";
36
+ this.buffer = Buffer.alloc(0);
37
+ }
38
+ processChunk(chunk, handlers) {
39
+ if (chunk.length === 0) {
40
+ return;
41
+ }
42
+ this.buffer = Buffer.concat([this.buffer, chunk]);
43
+ while (true) {
44
+ try {
45
+ if (this.mode === "unknown") {
46
+ const detected = this.detectMode();
47
+ if (!detected) {
48
+ return;
49
+ }
50
+ this.mode = detected;
51
+ continue;
52
+ }
53
+ const modeBefore = this.mode;
54
+ const message = this.mode === "content-length"
55
+ ? this.readContentLengthMessage()
56
+ : this.readLineDelimitedMessage();
57
+ if (!message) {
58
+ if (this.mode !== modeBefore) {
59
+ continue;
60
+ }
61
+ return;
62
+ }
63
+ handlers.onFrame({
64
+ message,
65
+ mode: this.mode
66
+ });
67
+ }
68
+ catch (caughtError) {
69
+ this.mode = "unknown";
70
+ handlers.onError(asError(caughtError));
71
+ }
72
+ }
73
+ }
74
+ detectMode() {
75
+ while (this.buffer.length > 0) {
76
+ if (this.buffer[0] === 0x0a) {
77
+ this.buffer = this.buffer.subarray(1);
78
+ continue;
79
+ }
80
+ if (this.buffer.length >= 2 && this.buffer[0] === 0x0d && this.buffer[1] === 0x0a) {
81
+ this.buffer = this.buffer.subarray(2);
82
+ continue;
83
+ }
84
+ break;
85
+ }
86
+ if (this.buffer.length === 0) {
87
+ return undefined;
88
+ }
89
+ const prefix = this.buffer
90
+ .subarray(0, Math.min(this.buffer.length, 32))
91
+ .toString("utf8")
92
+ .toLowerCase();
93
+ if (prefix.startsWith("content-length")) {
94
+ return "content-length";
95
+ }
96
+ const firstNewline = this.buffer.indexOf(0x0a);
97
+ if (firstNewline === -1) {
98
+ return undefined;
99
+ }
100
+ const firstLine = this.buffer.subarray(0, firstNewline).toString("utf8").replace(/\r$/, "");
101
+ if (/^\s*content-length\s*:/i.test(firstLine)) {
102
+ return "content-length";
103
+ }
104
+ return "line";
105
+ }
106
+ readLineDelimitedMessage() {
107
+ while (true) {
108
+ const newlineIndex = this.buffer.indexOf(0x0a);
109
+ if (newlineIndex === -1) {
110
+ return undefined;
111
+ }
112
+ const line = this.buffer.subarray(0, newlineIndex).toString("utf8").replace(/\r$/, "");
113
+ this.buffer = this.buffer.subarray(newlineIndex + 1);
114
+ if (line.trim().length === 0) {
115
+ continue;
116
+ }
117
+ if (/^\s*content-length\s*:/i.test(line)) {
118
+ const separator = this.buffer.length > 0 && this.buffer[0] === 0x0d ? "\r\n" : "\n";
119
+ this.buffer = Buffer.concat([Buffer.from(`${line}${separator}`, "utf8"), this.buffer]);
120
+ this.mode = "content-length";
121
+ return undefined;
122
+ }
123
+ return parseJsonRpcMessage(line);
124
+ }
125
+ }
126
+ readContentLengthMessage() {
127
+ const headerBoundary = findHeaderBoundary(this.buffer);
128
+ if (!headerBoundary) {
129
+ return undefined;
130
+ }
131
+ const headersRaw = this.buffer.subarray(0, headerBoundary.index).toString("utf8");
132
+ const headerLines = headersRaw
133
+ .split(/\r?\n/)
134
+ .map((line) => line.trim())
135
+ .filter((line) => line.length > 0);
136
+ let contentLength;
137
+ for (const headerLine of headerLines) {
138
+ const separatorIndex = headerLine.indexOf(":");
139
+ if (separatorIndex === -1) {
140
+ this.buffer = this.buffer.subarray(headerBoundary.index + headerBoundary.delimiterBytes);
141
+ throw new Error(`Malformed header line: ${headerLine}`);
142
+ }
143
+ const headerName = headerLine.slice(0, separatorIndex).trim().toLowerCase();
144
+ const headerValue = headerLine.slice(separatorIndex + 1).trim();
145
+ if (headerName === "content-length") {
146
+ const parsed = Number.parseInt(headerValue, 10);
147
+ if (!Number.isFinite(parsed) || parsed < 0) {
148
+ this.buffer = this.buffer.subarray(headerBoundary.index + headerBoundary.delimiterBytes);
149
+ throw new Error(`Invalid Content-Length header value: ${headerValue}`);
150
+ }
151
+ contentLength = parsed;
152
+ }
153
+ }
154
+ if (contentLength === undefined) {
155
+ this.buffer = this.buffer.subarray(headerBoundary.index + headerBoundary.delimiterBytes);
156
+ throw new Error("Missing Content-Length header.");
157
+ }
158
+ const messageStart = headerBoundary.index + headerBoundary.delimiterBytes;
159
+ const frameEnd = messageStart + contentLength;
160
+ if (this.buffer.length < frameEnd) {
161
+ return undefined;
162
+ }
163
+ const body = this.buffer.subarray(messageStart, frameEnd).toString("utf8");
164
+ this.buffer = this.buffer.subarray(frameEnd);
165
+ return parseJsonRpcMessage(body);
166
+ }
167
+ }
168
+ //# sourceMappingURL=json-rpc-framing.js.map
@@ -12,7 +12,7 @@ export interface MappingPipelineResult {
12
12
  /**
13
13
  * Mapping pipeline for v0.3.
14
14
  * Current implementation enforces explicit guarantees:
15
- * - official: always pass-through
15
+ * - obfuscated: always pass-through
16
16
  * - mojang: requires source-backed artifact; decompile-only artifacts are rejected
17
17
  */
18
18
  export declare function applyMappingPipeline(input: MappingPipelineInput): MappingPipelineResult;
@@ -2,14 +2,14 @@ import { createError, ERROR_CODES } from "./errors.js";
2
2
  /**
3
3
  * Mapping pipeline for v0.3.
4
4
  * Current implementation enforces explicit guarantees:
5
- * - official: always pass-through
5
+ * - obfuscated: always pass-through
6
6
  * - mojang: requires source-backed artifact; decompile-only artifacts are rejected
7
7
  */
8
8
  export function applyMappingPipeline(input) {
9
9
  const transformChain = [];
10
10
  const qualityFlags = [];
11
- if (input.requestedMapping === "official") {
12
- transformChain.push("mapping:official-pass-through");
11
+ if (input.requestedMapping === "obfuscated") {
12
+ transformChain.push("mapping:obfuscated-pass-through");
13
13
  if (input.resolved.isDecompiled) {
14
14
  qualityFlags.push("decompiled");
15
15
  }
@@ -17,7 +17,7 @@ export function applyMappingPipeline(input) {
17
17
  qualityFlags.push("source-backed");
18
18
  }
19
19
  return {
20
- mappingApplied: "official",
20
+ mappingApplied: "obfuscated",
21
21
  qualityFlags,
22
22
  transformChain
23
23
  };
@@ -43,9 +43,17 @@ export function applyMappingPipeline(input) {
43
43
  requestedMapping: input.requestedMapping,
44
44
  target: input.target,
45
45
  origin: input.resolved.origin,
46
+ artifactOrigin: input.resolved.origin,
46
47
  binaryJarPath: input.resolved.binaryJarPath,
47
48
  sourceJarPath: input.resolved.sourceJarPath,
48
- nextAction: "Provide a source-backed artifact (source jar) or use mapping=official."
49
+ nextAction: "Provide a source-backed artifact (source jar) or use mapping=obfuscated.",
50
+ suggestedCall: {
51
+ tool: "resolve-artifact",
52
+ params: {
53
+ target: input.target,
54
+ mapping: "obfuscated"
55
+ }
56
+ }
49
57
  }
50
58
  });
51
59
  }
@@ -46,6 +46,8 @@ export type SymbolResolutionOutput = {
46
46
  status: SymbolResolutionStatus;
47
47
  resolvedSymbol?: SymbolReference;
48
48
  candidates: Array<SymbolReference & Pick<MappingLookupCandidate, "matchKind" | "confidence">>;
49
+ candidateCount: number;
50
+ candidatesTruncated?: boolean;
49
51
  warnings: string[];
50
52
  provenance?: MappingLookupProvenance;
51
53
  ambiguityReasons?: string[];
@@ -56,6 +58,7 @@ export type FindMappingInput = {
56
58
  name: string;
57
59
  owner?: string;
58
60
  descriptor?: string;
61
+ signatureMode?: "exact" | "name-only";
59
62
  sourceMapping: SourceMapping;
60
63
  targetMapping: SourceMapping;
61
64
  sourcePriority?: MappingSourcePriority;
@@ -63,6 +66,7 @@ export type FindMappingInput = {
63
66
  ownerHint?: string;
64
67
  descriptorHint?: string;
65
68
  };
69
+ maxCandidates?: number;
66
70
  };
67
71
  export type FindMappingOutput = SymbolResolutionOutput;
68
72
  export type EnsureMappingAvailableInput = {
@@ -78,13 +82,13 @@ export type EnsureMappingAvailableOutput = {
78
82
  };
79
83
  export type ResolveMethodMappingExactInput = {
80
84
  version: string;
81
- kind: SymbolQueryKind;
82
85
  name: string;
83
- owner?: string;
84
- descriptor?: string;
86
+ owner: string;
87
+ descriptor: string;
85
88
  sourceMapping: SourceMapping;
86
89
  targetMapping: SourceMapping;
87
90
  sourcePriority?: MappingSourcePriority;
91
+ maxCandidates?: number;
88
92
  };
89
93
  export type ResolveMethodMappingExactOutput = SymbolResolutionOutput;
90
94
  export type ClassApiMatrixKind = "class" | "field" | "method";
@@ -94,6 +98,7 @@ export type ClassApiMatrixInput = {
94
98
  classNameMapping: SourceMapping;
95
99
  sourcePriority?: MappingSourcePriority;
96
100
  includeKinds?: ClassApiMatrixKind[];
101
+ maxRows?: number;
97
102
  };
98
103
  export type ClassApiMatrixEntry = {
99
104
  symbol: string;
@@ -104,7 +109,7 @@ export type ClassApiMatrixEntry = {
104
109
  export type ClassApiMatrixRow = {
105
110
  kind: ClassApiMatrixKind;
106
111
  descriptor?: string;
107
- official?: ClassApiMatrixEntry;
112
+ obfuscated?: ClassApiMatrixEntry;
108
113
  mojang?: ClassApiMatrixEntry;
109
114
  intermediary?: ClassApiMatrixEntry;
110
115
  yarn?: ClassApiMatrixEntry;
@@ -116,6 +121,8 @@ export type ClassApiMatrixOutput = {
116
121
  classNameMapping: SourceMapping;
117
122
  classIdentity: Partial<Record<SourceMapping, string>>;
118
123
  rows: ClassApiMatrixRow[];
124
+ rowCount: number;
125
+ rowsTruncated?: boolean;
119
126
  warnings: string[];
120
127
  ambiguousRowCount?: number;
121
128
  };
@@ -129,6 +136,7 @@ export type SymbolExistenceInput = {
129
136
  sourcePriority?: MappingSourcePriority;
130
137
  nameMode?: "fqcn" | "auto";
131
138
  signatureMode?: "exact" | "name-only";
139
+ maxCandidates?: number;
132
140
  };
133
141
  export type SymbolExistenceOutput = SymbolResolutionOutput;
134
142
  export declare class MappingService {