@adhisang/minecraft-modding-mcp 6.3.0 → 7.0.0-rc.1

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 (101) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +13 -3
  3. package/dist/cache-policy.d.ts +71 -0
  4. package/dist/cache-policy.js +83 -0
  5. package/dist/cache-registry.js +45 -8
  6. package/dist/cli.js +74 -3
  7. package/dist/compat-stdio-transport.d.ts +1 -1
  8. package/dist/compat-stdio-transport.js +13 -1
  9. package/dist/config.d.ts +3 -0
  10. package/dist/config.js +8 -2
  11. package/dist/decompiler/vineflower.d.ts +1 -0
  12. package/dist/decompiler/vineflower.js +8 -5
  13. package/dist/entry-tools/analyze-mod-service.d.ts +70 -136
  14. package/dist/entry-tools/analyze-symbol-service.d.ts +112 -150
  15. package/dist/entry-tools/compare-minecraft-service.d.ts +59 -145
  16. package/dist/entry-tools/entry-tool-schema.d.ts +38 -4
  17. package/dist/entry-tools/entry-tool-schema.js +4 -1
  18. package/dist/entry-tools/inspect-minecraft/internal.d.ts +235 -799
  19. package/dist/entry-tools/inspect-minecraft/internal.js +50 -13
  20. package/dist/entry-tools/inspect-minecraft-service.d.ts +372 -1736
  21. package/dist/entry-tools/manage-cache-service.d.ts +81 -91
  22. package/dist/entry-tools/validate-project/cases/mixin.js +26 -6
  23. package/dist/entry-tools/validate-project/cases/project-summary.d.ts +7 -7
  24. package/dist/entry-tools/validate-project-service.d.ts +164 -592
  25. package/dist/entry-tools/verify-mixin-target-service.d.ts +3 -19
  26. package/dist/entry-tools/verify-mixin-target-service.js +19 -1
  27. package/dist/era-classifier.d.ts +161 -0
  28. package/dist/era-classifier.js +292 -0
  29. package/dist/error-mapping.d.ts +76 -0
  30. package/dist/error-mapping.js +116 -8
  31. package/dist/index.d.ts +42 -4
  32. package/dist/index.js +636 -473
  33. package/dist/java-process.d.ts +2 -0
  34. package/dist/java-process.js +22 -2
  35. package/dist/json-rpc-framing.d.ts +77 -1
  36. package/dist/json-rpc-framing.js +249 -13
  37. package/dist/mapping/loaders/tiny-loom-selection.d.ts +88 -0
  38. package/dist/mapping/loaders/tiny-loom-selection.js +223 -0
  39. package/dist/mapping/loaders/tiny-loom.js +45 -33
  40. package/dist/mapping/loaders/tiny-maven.js +6 -11
  41. package/dist/mapping/parsers/tiny.d.ts +57 -0
  42. package/dist/mapping/parsers/tiny.js +99 -22
  43. package/dist/mapping-service.d.ts +19 -0
  44. package/dist/mapping-service.js +93 -9
  45. package/dist/maven-resolver.d.ts +18 -0
  46. package/dist/maven-resolver.js +20 -0
  47. package/dist/mcp-helpers.d.ts +19 -2
  48. package/dist/mcp-helpers.js +58 -9
  49. package/dist/minecraft-explorer-service.d.ts +1 -1
  50. package/dist/mixin/types.d.ts +8 -0
  51. package/dist/mod-analyzer.js +7 -7
  52. package/dist/mod-decompile-service.js +1 -0
  53. package/dist/nbt/java-nbt-codec.js +12 -2
  54. package/dist/nbt/json-patch.js +14 -3
  55. package/dist/nbt/pipeline.js +40 -3
  56. package/dist/nbt/typed-json.js +26 -1
  57. package/dist/registration-adapter.d.ts +32 -0
  58. package/dist/registration-adapter.js +52 -0
  59. package/dist/repo-downloader.d.ts +165 -0
  60. package/dist/repo-downloader.js +568 -10
  61. package/dist/request-context.d.ts +7 -0
  62. package/dist/request-context.js +9 -0
  63. package/dist/resources.d.ts +1 -1
  64. package/dist/resources.js +25 -19
  65. package/dist/server-identity.d.ts +27 -0
  66. package/dist/server-identity.js +26 -0
  67. package/dist/source/access-validate.js +53 -0
  68. package/dist/source/artifact-resolver.d.ts +81 -2
  69. package/dist/source/artifact-resolver.js +227 -15
  70. package/dist/source/class-source.d.ts +36 -0
  71. package/dist/source/class-source.js +222 -38
  72. package/dist/source/did-you-mean.d.ts +12 -1
  73. package/dist/source/did-you-mean.js +6 -2
  74. package/dist/source/file-access.js +150 -46
  75. package/dist/source/indexer.js +1 -0
  76. package/dist/source/shared-utils.d.ts +21 -0
  77. package/dist/source/shared-utils.js +23 -0
  78. package/dist/source-resolver.js +224 -57
  79. package/dist/source-service.d.ts +12 -1
  80. package/dist/stdio-supervisor.d.ts +357 -2
  81. package/dist/stdio-supervisor.js +1031 -80
  82. package/dist/storage/db.d.ts +2 -1
  83. package/dist/storage/db.js +15 -8
  84. package/dist/synthetic-decorator.d.ts +24 -0
  85. package/dist/synthetic-decorator.js +48 -0
  86. package/dist/tool-guidance.d.ts +17 -1
  87. package/dist/tool-guidance.js +323 -18
  88. package/dist/tool-schema-registry.d.ts +2 -0
  89. package/dist/tool-schema-registry.js +4 -0
  90. package/dist/tool-schemas.d.ts +2212 -3919
  91. package/dist/tool-schemas.js +33 -7
  92. package/dist/types.d.ts +35 -0
  93. package/dist/v1-parity-schemas.d.ts +7 -0
  94. package/dist/v1-parity-schemas.js +5584 -0
  95. package/dist/version-diff-service.d.ts +33 -0
  96. package/dist/version-diff-service.js +148 -3
  97. package/dist/version-service.js +36 -14
  98. package/dist/warning-details.js +18 -1
  99. package/docs/README-ja.md +5 -3
  100. package/docs/tool-reference.md +196 -19
  101. package/package.json +13 -8
@@ -17,14 +17,75 @@ export function extractDidYouMean(details) {
17
17
  if (!entry || typeof entry !== "object") {
18
18
  return undefined;
19
19
  }
20
- const { className, matchReason } = entry;
20
+ const { className, matchReason, artifactId } = entry;
21
21
  if (typeof className !== "string" || typeof matchReason !== "string") {
22
22
  return undefined;
23
23
  }
24
- cleaned.push({ className, matchReason });
24
+ // `artifactId` marks a candidate found in an artifact the caller did not name
25
+ // (the internal binary fallback or nested-jar redirect). It is optional and
26
+ // dropped when malformed, so a bad value cannot suppress the whole array.
27
+ cleaned.push({
28
+ className,
29
+ matchReason,
30
+ ...(typeof artifactId === "string" && artifactId ? { artifactId } : {})
31
+ });
25
32
  }
26
33
  return cleaned.slice(0, MAX_DID_YOU_MEAN_ENTRIES);
27
34
  }
35
+ // A shell jar bundles a handful of inner jars, not hundreds; the cap only
36
+ // bounds a pathological inventory, it is not an expected truncation point.
37
+ const MAX_NESTED_JAR_ENTRIES = 64;
38
+ /**
39
+ * Validates and extracts a `nestedJars` inventory from error details.
40
+ * `buildClassSourceNotFoundError` records it whenever the lookup ran against a
41
+ * shell jar, but `context` is primitive-only, so without this the inventory
42
+ * never left the process. Malformed payloads are dropped whole rather than
43
+ * partially published, matching {@link extractDidYouMean}. An empty inventory
44
+ * is dropped too: the producing site omits the key entirely in that case, so an
45
+ * empty array carries no information a caller could act on.
46
+ */
47
+ export function extractNestedJars(details) {
48
+ const raw = details?.nestedJars;
49
+ if (!Array.isArray(raw) || raw.length === 0) {
50
+ return undefined;
51
+ }
52
+ const cleaned = [];
53
+ for (const entry of raw) {
54
+ if (typeof entry !== "string" || !entry) {
55
+ return undefined;
56
+ }
57
+ cleaned.push(entry);
58
+ }
59
+ return cleaned.slice(0, MAX_NESTED_JAR_ENTRIES);
60
+ }
61
+ const ISSUE_ORIGIN_VALUES = new Set([
62
+ "code_issue",
63
+ "tool_issue",
64
+ "environment"
65
+ ]);
66
+ /**
67
+ * Per-throw-site {@link IssueOrigin} override carried on an AppError's
68
+ * `details.issueOrigin`.
69
+ *
70
+ * The default classification is keyed purely on the error CODE, which is right
71
+ * for codes whose every throw site shares one origin. A few codes do not:
72
+ * `ERR_CONTEXT_UNRESOLVED` covers both a caller naming a version no artifact
73
+ * carries (genuinely `code_issue`) and the tool resolving an artifact with no
74
+ * binary jar behind the caller's back (`tool_issue`). Publishing the latter as
75
+ * caller-fixable sends an agent into a retry loop over input it cannot repair.
76
+ *
77
+ * This override is deliberately opt-in and per-error: `issueOriginForErrorCode`
78
+ * and its default sets stay untouched, so the exhaustive classification map in
79
+ * tests/runtime/error-mapping.test.ts keeps forcing a conscious decision for
80
+ * every new code. The key is not in `CONTEXT_ALLOWLIST`, so it cannot leak into
81
+ * the public `context` blob.
82
+ */
83
+ export function extractIssueOriginOverride(details) {
84
+ const raw = details?.issueOrigin;
85
+ return typeof raw === "string" && ISSUE_ORIGIN_VALUES.has(raw)
86
+ ? raw
87
+ : undefined;
88
+ }
28
89
  export function statusForErrorCode(code) {
29
90
  if (code === ERROR_CODES.BATCH_ABORTED) {
30
91
  return 412;
@@ -193,6 +254,51 @@ export function issueOriginForErrorCode(code) {
193
254
  }
194
255
  return "tool_issue";
195
256
  }
257
+ /**
258
+ * The single source of truth for a ProblemDetails classification pair, and the
259
+ * ONLY supported way to compute one for an error the server caught. Every site
260
+ * that turns a caught error into a published envelope spreads this result — the
261
+ * tool envelope (`mapErrorToProblem`), batch entries, the batch-aborted
262
+ * sentinel, and the `mc://` resource read — so one failure always publishes the
263
+ * same `{ retryClass, issueOrigin }` no matter which access path the caller
264
+ * used.
265
+ *
266
+ * KNOWN EXCEPTION — the synthetic supervisor replies in `src/stdio-supervisor.ts`
267
+ * (`buildSupervisorQueueLimitReply`, `buildValidateProjectTimeoutReply`) write
268
+ * the pair as literals and never import this builder. They are not emission
269
+ * sites for a caught error at all: the supervisor answers a request the worker
270
+ * never got to run, so there is no source `AppError` whose `details` could carry
271
+ * an override and nothing to pass as the required `details` argument. Their
272
+ * literals are `transient` / `tool_issue`, which is exactly what this function
273
+ * returns for `ERR_LIMIT_EXCEEDED` and `ERR_TOOL_TIMEOUT` today — but that is a
274
+ * duplicated value held in agreement by hand, not a second call into this
275
+ * classifier. Reclassifying either code here must be mirrored there.
276
+ *
277
+ * It exists because that pair used to be assembled by hand at each site. The
278
+ * `issueOrigin` half has a per-throw-site override (see
279
+ * {@link extractIssueOriginOverride}), and honouring it was copy-pasted into
280
+ * some sites and forgotten in others — which is exactly how one identical
281
+ * AppError came to publish `tool_issue` through a tool call and `code_issue`
282
+ * through a resource read. Composing the pair here removes the opportunity:
283
+ * emission modules import this function and no longer reach the component
284
+ * classifiers at all.
285
+ *
286
+ * `details` is REQUIRED, deliberately without a default. A site that genuinely
287
+ * has no AppError behind it (a ZodError, a sanitized non-AppError, the
288
+ * batch-aborted sentinel) must pass `undefined` explicitly, so skipping the
289
+ * override can only ever be a written-down decision rather than an omission.
290
+ *
291
+ * Only `issueOrigin` is overridable per throw site. `retryClass` stays purely
292
+ * code-derived: it is a documented wire contract, and changing the value an
293
+ * existing code publishes is a Breaking change, so a `retryClass` override seam
294
+ * was deliberately deferred rather than added alongside this one.
295
+ */
296
+ export function problemClassification(code, details) {
297
+ return {
298
+ retryClass: retryClassForErrorCode(code),
299
+ issueOrigin: extractIssueOriginOverride(details) ?? issueOriginForErrorCode(code)
300
+ };
301
+ }
196
302
  // Non-sensitive AppError.details fields that are safe to echo to callers as
197
303
  // machine-readable repair context. Filesystem paths and free-form text are
198
304
  // intentionally excluded.
@@ -275,6 +381,7 @@ export function errorToBatchEntryProblem(caughtError, instance, options) {
275
381
  const fieldErrors = extractFieldErrors(caughtError.details);
276
382
  const context = extractAllowlistedContext(caughtError.details);
277
383
  const didYouMean = extractDidYouMean(caughtError.details);
384
+ const nestedJars = extractNestedJars(caughtError.details);
278
385
  return {
279
386
  type: `https://minecraft-modding-mcp.dev/problems/${caughtError.code.toLowerCase()}`,
280
387
  title: "Tool execution error",
@@ -282,12 +389,12 @@ export function errorToBatchEntryProblem(caughtError, instance, options) {
282
389
  status: statusForErrorCode(caughtError.code),
283
390
  code: caughtError.code,
284
391
  instance,
285
- retryClass: retryClassForErrorCode(caughtError.code),
286
- issueOrigin: issueOriginForErrorCode(caughtError.code),
392
+ ...problemClassification(caughtError.code, caughtError.details),
287
393
  ...(fieldErrors ? { fieldErrors } : {}),
288
394
  ...(baseHints ? { hints: baseHints } : {}),
289
395
  ...(options?.suggestedCall ? { suggestedCall: options.suggestedCall } : {}),
290
396
  ...(didYouMean ? { didYouMean } : {}),
397
+ ...(nestedJars ? { nestedJars } : {}),
291
398
  ...(context ? { context } : {})
292
399
  };
293
400
  }
@@ -307,8 +414,9 @@ export function errorToBatchEntryProblem(caughtError, instance, options) {
307
414
  status: 500,
308
415
  code: ERROR_CODES.INTERNAL,
309
416
  instance,
310
- retryClass: retryClassForErrorCode(ERROR_CODES.INTERNAL),
311
- issueOrigin: issueOriginForErrorCode(ERROR_CODES.INTERNAL),
417
+ // No AppError behind this envelope: the throw was sanitized away, so there
418
+ // is no per-site override to honour.
419
+ ...problemClassification(ERROR_CODES.INTERNAL, undefined),
312
420
  ...(options?.suggestedCall ? { suggestedCall: options.suggestedCall } : {})
313
421
  };
314
422
  }
@@ -320,8 +428,8 @@ export function buildBatchAbortedProblem(instance) {
320
428
  status: 412,
321
429
  code: ERROR_CODES.BATCH_ABORTED,
322
430
  instance,
323
- retryClass: retryClassForErrorCode(ERROR_CODES.BATCH_ABORTED),
324
- issueOrigin: issueOriginForErrorCode(ERROR_CODES.BATCH_ABORTED)
431
+ // Synthesized sentinel, not a caught AppError: no per-site override exists.
432
+ ...problemClassification(ERROR_CODES.BATCH_ABORTED, undefined)
325
433
  };
326
434
  }
327
435
  //# sourceMappingURL=error-mapping.js.map
package/dist/index.d.ts CHANGED
@@ -1,10 +1,48 @@
1
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
1
+ import { McpServer, type McpRequestContext } from "@modelcontextprotocol/server";
2
2
  import { SourceService } from "./source-service.js";
3
+ import { SERVER_VERSION } from "./server-identity.js";
3
4
  import { applyErrorMetaExtensions, mapErrorToProblem } from "./tool-guidance.js";
4
5
  export { mapErrorToProblem, applyErrorMetaExtensions };
5
- declare const SERVER_VERSION: string;
6
- declare const server: McpServer;
7
6
  declare const config: import("./types.js").Config;
8
7
  declare const sourceService: SourceService;
8
+ /**
9
+ * Builds a fully-registered McpServer instance. serveStdio calls its factory
10
+ * PER INSTANCE, not per connection: a modern `server/discover` opening builds
11
+ * a probe instance which a following legacy `initialize` DISCARDS
12
+ * (`product.close()`) before calling the factory again — and the probe path
13
+ * MUTATES the instance (installModernOnlyHandlers adds "2026-07-28" support
14
+ * and a server/discover handler). Every call therefore constructs a FRESH
15
+ * McpServer so probe-instance mutations can never leak onto the re-pinned
16
+ * legacy instance (frozen negotiate-down contract). Module-scope services,
17
+ * config, and helpers stay shared; only the McpServer and its registrations
18
+ * are per-instance.
19
+ *
20
+ * Tool registration ORDER: the CALL-SITE order inside this function is the
21
+ * frozen legacy tools/list order — do not reorder the call sites. The calls
22
+ * are captured as deferred thunks and executed at the bottom of the
23
+ * function: in call-site order for legacy/ctx-less instances (byte-frozen
24
+ * golden contract), and in raw tool-name-ascending order when serveStdio
25
+ * constructs a MODERN-era instance (`ctx.era === "modern"` — the SDK's
26
+ * documented era-parameterized factory seam; the v2 SDK itself emits
27
+ * registration order and never sorts). Each instance serves exactly one era,
28
+ * so the two orders can never mix on one connection. (Adopted ordering
29
+ * policy.)
30
+ *
31
+ * Cache hints (adopted policy, src/cache-policy.ts): the constructor options
32
+ * configure the non-zero resources/list + resources/templates/list rows;
33
+ * per-resource rows live in registerResources(); all hints ride the SDK's
34
+ * never-serialized carrier, so 2025-era responses are unaffected.
35
+ *
36
+ * NOTE: the function body below intentionally keeps the original module-scope
37
+ * indentation of the registration block to preserve a reviewable minimal diff.
38
+ */
39
+ declare function buildServer(ctx?: McpRequestContext): McpServer;
40
+ /**
41
+ * Module-scope singleton: populates the register-once tool-schema registry at
42
+ * load time and serves in-process consumers (tests drive its request handlers
43
+ * directly). The stdio wire path does NOT serve this instance — serveStdio's
44
+ * factory builds a fresh one per pinned/probe instance (see buildServer).
45
+ */
46
+ declare const server: McpServer;
9
47
  export declare function startServer(): Promise<void>;
10
- export { server, sourceService, config, SERVER_VERSION };
48
+ export { server, sourceService, config, SERVER_VERSION, buildServer };