@adhisang/minecraft-modding-mcp 2.1.0 → 3.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 (32) hide show
  1. package/CHANGELOG.md +38 -1
  2. package/README.md +224 -802
  3. package/dist/cache-registry.d.ts +95 -0
  4. package/dist/cache-registry.js +541 -0
  5. package/dist/entry-tools/analyze-mod-service.d.ts +207 -0
  6. package/dist/entry-tools/analyze-mod-service.js +309 -0
  7. package/dist/entry-tools/analyze-symbol-service.d.ts +209 -0
  8. package/dist/entry-tools/analyze-symbol-service.js +359 -0
  9. package/dist/entry-tools/compare-minecraft-service.d.ts +210 -0
  10. package/dist/entry-tools/compare-minecraft-service.js +429 -0
  11. package/dist/entry-tools/entry-tool-schema.d.ts +6 -0
  12. package/dist/entry-tools/entry-tool-schema.js +10 -0
  13. package/dist/entry-tools/inspect-minecraft-service.d.ts +1954 -0
  14. package/dist/entry-tools/inspect-minecraft-service.js +1030 -0
  15. package/dist/entry-tools/manage-cache-service.d.ts +130 -0
  16. package/dist/entry-tools/manage-cache-service.js +264 -0
  17. package/dist/entry-tools/request-normalizers.d.ts +10 -0
  18. package/dist/entry-tools/request-normalizers.js +36 -0
  19. package/dist/entry-tools/response-contract.d.ts +45 -0
  20. package/dist/entry-tools/response-contract.js +99 -0
  21. package/dist/entry-tools/validate-project-service.d.ts +543 -0
  22. package/dist/entry-tools/validate-project-service.js +414 -0
  23. package/dist/index.js +183 -59
  24. package/dist/observability.d.ts +18 -2
  25. package/dist/observability.js +47 -10
  26. package/dist/source-service.d.ts +0 -1
  27. package/dist/source-service.js +44 -54
  28. package/dist/storage/files-repo.d.ts +1 -0
  29. package/dist/storage/files-repo.js +29 -5
  30. package/dist/tool-contract-manifest.d.ts +4 -0
  31. package/dist/tool-contract-manifest.js +139 -0
  32. package/package.json +1 -1
package/README.md CHANGED
@@ -9,60 +9,54 @@
9
9
 
10
10
  ---
11
11
 
12
- `@adhisang/minecraft-modding-mcp` is an [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that gives AI assistants deep access to Minecraft's source code, mappings, and mod tooling.
12
+ `@adhisang/minecraft-modding-mcp` is an [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that gives AI assistants structured access to Minecraft source code, mappings, mod JARs, registry data, and validation workflows.
13
13
 
14
- It lets you explore decompiled Minecraft source, convert symbol names across four naming namespaces (`obfuscated`, `mojang`, `intermediary`, `yarn`), analyze and decompile Fabric/Forge/NeoForge mod JARs, validate Mixin and Access Widener files, read and patch NBT data, and query generated registry snapshots — all through a structured tool and resource interface designed for Claude Desktop, VS Code, and other MCP-capable clients.
14
+ [MCP](https://modelcontextprotocol.io/) is an open protocol that lets AI assistants call external tools through a structured interface. This server works with Claude Desktop, Claude Code, VS Code, Codex CLI, Gemini CLI, and other MCP-capable clients.
15
15
 
16
- **29 tools** | **7 resources** | **4 namespace mappings** | **SQLite-backed cache**
16
+ **35 tools** (6 entry + 29 expert) | **7 resources** | **4 namespace mappings** | **SQLite-backed cache**
17
17
 
18
18
  ## Features
19
19
 
20
- - **Source Exploration** Browse and search decompiled Minecraft source code with line-level precision and cursor-paginated file listing
21
- - **Multi-Mapping Conversion** Translate class, field, and method names between `obfuscated`, `mojang`, `intermediary`, and `yarn` namespaces
22
- - **Symbol Lifecycle Tracking** Trace when a method or field first appeared, disappeared, or changed across Minecraft versions
23
- - **Mod JAR Analysis** Extract metadata, dependencies, entrypoints, and Mixin configs from Fabric/Forge/NeoForge mod JARs
24
- - **Mixin & Access Widener Validation** — Parse and validate Mixin source and `.accesswidener` files against a target Minecraft version
25
- - **NBT Round-Trip** Decode NBT binary to typed JSON, apply RFC 6902 patches, and re-encode back to NBT
26
- - **Registry Data** Query generated registry snapshots (blocks, items, entities, etc.) for any Minecraft version
27
- - **Version Comparison** Diff class signatures and registry entries between two Minecraft versions
28
- - **JAR Remapping** — Remap Fabric mod JARs from `intermediary` to `yarn` or `mojang` namespaces
29
- - **MCP Resources** — Access version lists, class source, artifact metadata, and mappings through URI-based resources
20
+ - **Source Exploration**: browse and search decompiled Minecraft source code with line-level precision and cursor-paginated file listing
21
+ - **Multi-Mapping Conversion**: translate class, field, and method names between `obfuscated`, `mojang`, `intermediary`, and `yarn`
22
+ - **Version Comparison**: diff class signatures and registry entries between Minecraft versions
23
+ - **Mod JAR Analysis**: extract metadata, dependencies, entrypoints, and Mixin configs from Fabric, Forge, and NeoForge mod JARs
24
+ - **Mixin and Access Widener Validation**: validate source and `.accesswidener` files against a target Minecraft version
25
+ - **NBT Round-Trip**: decode NBT binary to typed JSON, apply RFC 6902 patches, and encode it back to NBT
26
+ - **Registry Data and Runtime Metrics**: query generated registry snapshots and inspect cache and latency counters
27
+ - **MCP Resources**: expose versions, class source, artifact metadata, and mappings through URI-based resources
30
28
 
31
29
  ## Quick Start
32
30
 
33
- ### Prerequisites
34
- - Node.js 22+
35
- - pnpm
31
+ ### Package Users
36
32
 
37
- ### For Users (Installed Package)
38
- ```bash
39
- npx @adhisang/minecraft-modding-mcp
40
- ```
33
+ Requirements:
41
34
 
42
- ### CLI Agent Tools
35
+ - Node.js 22+
36
+ - Java is only required for `remap-mod-jar` and decompile or remap flows that need Vineflower or tiny-remapper
43
37
 
44
- #### Claude Code
38
+ Start the server locally:
45
39
 
46
40
  ```bash
47
- claude mcp add minecraft-modding -- npx -y @adhisang/minecraft-modding-mcp
48
- claude mcp list
41
+ npx -y @adhisang/minecraft-modding-mcp
49
42
  ```
50
43
 
51
- #### OpenAI Codex CLI
44
+ If automatic JAR downloads are blocked in your environment, set `MCP_VINEFLOWER_JAR_PATH` and `MCP_TINY_REMAPPER_JAR_PATH` in the client configuration.
52
45
 
53
- ```bash
54
- codex mcp add minecraft-modding -- npx -y @adhisang/minecraft-modding-mcp
55
- codex mcp list
56
- ```
46
+ ### Client Setup
57
47
 
58
- The stdio transport auto-detects both newline-delimited and `Content-Length` framing, so Codex and newline-based MCP clients can use the same server command.
48
+ CLI clients:
59
49
 
60
- The server now lazily initializes heavyweight source/index services on first MCP request, reducing initial process startup latency for clients that only perform handshake/tool discovery.
61
- To preserve handshake reliability across clients, startup does not eagerly pre-initialize `SourceService` before tool discovery.
50
+ - `Claude Code`: `claude mcp add minecraft-modding -- npx -y @adhisang/minecraft-modding-mcp`
51
+ - `OpenAI Codex CLI`: `codex mcp add minecraft-modding -- npx -y @adhisang/minecraft-modding-mcp`
62
52
 
63
- #### Gemini CLI
53
+ Run `claude mcp list` or `codex mcp list` after registration to verify the server is available.
64
54
 
65
- Add the following to `~/.gemini/settings.json`:
55
+ The stdio transport auto-detects both newline-delimited and `Content-Length` framing, so the same server command works across Codex and standard MCP clients.
56
+
57
+ #### Claude Desktop
58
+
59
+ Add the following to your `claude_desktop_config.json`:
66
60
 
67
61
  ```json
68
62
  {
@@ -75,59 +69,13 @@ Add the following to `~/.gemini/settings.json`:
75
69
  }
76
70
  ```
77
71
 
78
- Then run this command in Gemini CLI:
79
-
80
- ```text
81
- /mcp list
82
- ```
83
-
84
- ### For Developers (Repository)
85
- ```bash
86
- pnpm install
87
- ```
88
-
89
- ### Run (development)
90
- ```bash
91
- pnpm dev
92
- ```
93
-
94
- ### Build + Run (distribution shape)
95
- ```bash
96
- pnpm build
97
- pnpm start
98
- ```
99
-
100
- ### Validate
101
- ```bash
102
- pnpm check
103
- pnpm test
104
- pnpm test:coverage
105
- ```
106
-
107
- ### Coverage
108
- ```bash
109
- pnpm test:coverage
110
- ```
111
-
112
- Coverage thresholds: `lines=80`, `branches=70`, `functions=80`.
113
-
114
- Generate LCOV output for Codecov upload:
115
-
116
- ```bash
117
- pnpm test:coverage:lcov
118
- ```
119
-
120
- GitHub Actions upload workflow: `.github/workflows/codecov.yml` (temporarily disabled; when enabled, it runs on `v*` tags and manual dispatch).
121
-
122
- ### MCP Client Configuration
123
-
124
- #### Claude Desktop
72
+ #### VS Code
125
73
 
126
- Add the following to your `claude_desktop_config.json`:
74
+ Add the following to `.vscode/mcp.json` in your workspace:
127
75
 
128
76
  ```json
129
77
  {
130
- "mcpServers": {
78
+ "servers": {
131
79
  "minecraft-modding": {
132
80
  "command": "npx",
133
81
  "args": ["-y", "@adhisang/minecraft-modding-mcp"]
@@ -136,13 +84,13 @@ Add the following to your `claude_desktop_config.json`:
136
84
  }
137
85
  ```
138
86
 
139
- #### VS Code
87
+ #### Gemini CLI
140
88
 
141
- Add the following to `.vscode/mcp.json` in your workspace:
89
+ Add the following to `~/.gemini/settings.json`:
142
90
 
143
91
  ```json
144
92
  {
145
- "servers": {
93
+ "mcpServers": {
146
94
  "minecraft-modding": {
147
95
  "command": "npx",
148
96
  "args": ["-y", "@adhisang/minecraft-modding-mcp"]
@@ -151,6 +99,12 @@ Add the following to `.vscode/mcp.json` in your workspace:
151
99
  }
152
100
  ```
153
101
 
102
+ Then run:
103
+
104
+ ```text
105
+ /mcp list
106
+ ```
107
+
154
108
  #### Custom Environment
155
109
 
156
110
  Pass environment variables to override defaults:
@@ -170,38 +124,159 @@ Pass environment variables to override defaults:
170
124
  }
171
125
  ```
172
126
 
127
+ ## Start Here
128
+
129
+ These six top-level workflow tools cover the common workflows and return summary-first results, so they are the best default starting points for agents and MCP clients.
130
+
131
+ | Tool | Start here for |
132
+ | --- | --- |
133
+ | `inspect-minecraft` | versions, artifacts, classes, files, and source search |
134
+ | `analyze-symbol` | symbol existence checks, mapping conversion, lifecycle tracing, and workspace symbol resolution |
135
+ | `compare-minecraft` | version-pair diffs, class diffs, registry diffs, and migration-oriented overviews |
136
+ | `analyze-mod` | mod metadata, decompile/search flows, class source, and safe remap preview/apply |
137
+ | `validate-project` | workspace summaries plus direct Mixin and Access Widener validation |
138
+ | `manage-cache` | cache inventory, verification, and preview/apply cleanup workflows |
139
+
140
+ ### Workflow Notes
141
+
142
+ - These top-level workflow tools return `result.summary` first and include `summary.nextActions` when there is a clear follow-up step.
143
+ - `search-class-source` defaults to `queryMode="auto"` and keeps separator queries such as `foo.bar`, `foo_bar`, and `foo$bar` on the indexed path. Use `queryMode="literal"` for an explicit full substring scan.
144
+ - When a public parameter has a fixed safe default, `tools/list` exposes it through the JSON Schema `default` field.
145
+ - Error recovery `suggestedCall` payloads omit parameters when the supplied value already matches the tool default, keeping retry calls smaller without changing behavior.
146
+
147
+ ### Inspect Minecraft source from a version
148
+
149
+ ```json
150
+ {
151
+ "tool": "inspect-minecraft",
152
+ "arguments": {
153
+ "task": "class-source",
154
+ "subject": {
155
+ "kind": "class",
156
+ "className": "net.minecraft.server.Main",
157
+ "artifact": {
158
+ "type": "resolve-target",
159
+ "target": {
160
+ "kind": "version",
161
+ "value": "1.21.10"
162
+ }
163
+ }
164
+ }
165
+ }
166
+ }
167
+ ```
168
+
169
+ ### Map or check a symbol
170
+
171
+ ```json
172
+ {
173
+ "tool": "analyze-symbol",
174
+ "arguments": {
175
+ "task": "map",
176
+ "subject": {
177
+ "kind": "method",
178
+ "owner": "net.minecraft.server.Main",
179
+ "name": "tickServer"
180
+ },
181
+ "version": "1.21.10",
182
+ "sourceMapping": "mojang",
183
+ "targetMapping": "intermediary",
184
+ "signatureMode": "name-only"
185
+ }
186
+ }
187
+ ```
188
+
189
+ ### Summarize a mod JAR
190
+
191
+ ```json
192
+ {
193
+ "tool": "analyze-mod",
194
+ "arguments": {
195
+ "task": "summary",
196
+ "subject": {
197
+ "kind": "jar",
198
+ "jarPath": "/path/to/mymod-1.0.0.jar"
199
+ }
200
+ }
201
+ }
202
+ ```
203
+
204
+ ### Validate a workspace
205
+
206
+ ```json
207
+ {
208
+ "tool": "validate-project",
209
+ "arguments": {
210
+ "task": "project-summary",
211
+ "subject": {
212
+ "kind": "workspace",
213
+ "projectPath": "/workspace/modid",
214
+ "discover": ["mixins", "access-wideners"]
215
+ },
216
+ "preferProjectVersion": true,
217
+ "preferProjectMapping": true
218
+ }
219
+ }
220
+ ```
221
+
222
+ ## Documentation
223
+
224
+ - [Detailed example requests](docs/examples.md)
225
+ - [Tool and configuration reference](docs/tool-reference.md)
226
+ - [日本語 README](docs/README-ja.md)
227
+
173
228
  ## Tool Surface
174
229
 
230
+ Start with these top-level workflow tools unless you already know the exact specialized operation you want. The lower-level tools remain available for narrow follow-up work and automation.
231
+
232
+ ### Top-Level Workflow Tools
233
+
234
+ <!-- BEGIN GENERATED TOOL TABLE: v3-entry-tools -->
235
+ | Tool | Purpose | Key Inputs | Key Outputs |
236
+ | --- | --- | --- | --- |
237
+ | `inspect-minecraft` | Start from a version, artifact, class, file, search query, or workspace and route to the most relevant Minecraft inspection flow | `task?`, `subject?`, `detail?`, `include?`, `limit?`, `cursor?`, `includeSnapshots?` | `result.summary`, `versions?`, `subject`, `artifact?`, `class?`, `source?`, `members?`, `search?`, `file?`, `files?` |
238
+ | `analyze-symbol` | One entry point for symbol existence checks, namespace mapping, lifecycle tracing, workspace symbol analysis, and API overview | `task`, `subject`, `version?`, `sourceMapping?`, `targetMapping?`, `projectPath?`, `classNameMapping?`, `signatureMode?`, `nameMode?`, `includeKinds?`, `maxRows?`, `maxCandidates?`, `detail?`, `include?` | `result.summary`, `match?`, `candidates?`, `ambiguity?`, `matrix?`, `workspace?` |
239
+ | `compare-minecraft` | Compare version pairs, class signatures, registries, or produce a migration-oriented overview | `task?`, `subject`, `detail?`, `include?`, `subject.kind="class".sourcePriority?`, `maxClassResults?`, `maxEntriesPerRegistry?`, `includeFullDiff?`, `limit?` | `result.summary`, `comparison`, `classes?`, `classDiff?`, `registry?`, `migration?` |
240
+ | `analyze-mod` | Metadata-first entry point for mod summary, decompile/search flows, class source, and safe remap previews/applies | `task`, `subject`, `query?`, `searchType?`, `targetMapping?`, `outputJar?`, `executionMode?`, `includeFiles?`, `maxFiles?`, `maxLines?`, `maxChars?`, `limit?`, `detail?`, `include?` | `result.summary`, `metadata?`, `decompile?`, `hits?`, `source?`, `operation?` |
241
+ | `validate-project` | Project-level validation entry for workspace summaries plus direct Mixin and Access Widener validation | `task`, `subject`, `version?`, `mapping?`, `sourcePriority?`, `scope?`, `preferProjectVersion?`, `preferProjectMapping?`, `sourceRoots?`, `configPaths?`, `minSeverity?`, `hideUncertain?`, `explain?`, `warningMode?`, `warningCategoryFilter?`, `treatInfoAsWarning?`, `includeIssues?`, `detail?`, `include?` | `result.summary`, `project`, `workspace?`, `issues?` |
242
+ | `manage-cache` | User-facing cache summary, listing, verification, previewed deletion/pruning/rebuild, and explicit apply operations | `action`, `cacheKinds?`, `selector?`, `executionMode?`, `detail?`, `include?`, `limit?`, `cursor?` | `result.summary`, `stats?`, `cacheEntries?`, `operation?`, `meta.pagination.nextCursor?` |
243
+ <!-- END GENERATED TOOL TABLE: v3-entry-tools -->
244
+
175
245
  ### Source Exploration
176
246
 
177
- Tools for browsing Minecraft versions, resolving source artifacts, and reading/searching decompiled source code.
247
+ Tools for browsing Minecraft versions, resolving source artifacts, and reading or searching decompiled source code.
178
248
 
249
+ <!-- BEGIN GENERATED TOOL TABLE: source-exploration -->
179
250
  | Tool | Purpose | Key Inputs | Key Outputs |
180
251
  | --- | --- | --- | --- |
181
252
  | `list-versions` | List available Minecraft versions from Mojang manifest + local cache | `includeSnapshots?`, `limit?` | `result.latest`, `result.releases[]`, `meta.warnings[]` |
182
253
  | `resolve-artifact` | Resolve source artifact from `version` / `jar` / `coordinate` | `target`, `mapping?`, `sourcePriority?`, `allowDecompile?`, `projectPath?`, `scope?`, `preferProjectVersion?`, `strictVersion?` | `artifactId`, `origin`, `mappingApplied`, `qualityFlags[]`, `artifactContents`, `adjacentSourceCandidates?`, `sampleEntries?`, `warnings[]` |
183
254
  | `find-class` | Resolve simple or fully-qualified class names inside an artifact | `className`, `artifactId`, `limit?` | `matches[]`, `total`, `warnings[]` |
184
- | `get-class-source` | Get class source by artifact target or resolve target on demand (`mode=metadata` by default) | `className`, `target`, `mode?`, `projectPath?`, `scope?`, `preferProjectVersion?`, `strictVersion?`, `startLine?`, `endLine?`, `maxLines?`, `maxChars?`, `outputFile?` | `mode`, `sourceText`, `returnedRange`, `truncated`, `charsTruncated?`, `outputFile?`, `artifactId`, `returnedNamespace`, `artifactContents`, mapping/provenance metadata |
185
- | `get-class-members` | Get class fields/methods/constructors from bytecode | `className`, `target`, `mapping?`, `access?`, `includeInherited?`, `maxMembers?`, `strictVersion?` | `members.{constructors,fields,methods}`, `counts`, `truncated`, `context`, `returnedNamespace`, `artifactContents`, `warnings[]` |
255
+ | `get-class-source` | Get class source by artifact target or resolve target on demand (`mode=metadata` by default) | `className`, `target`, `mode?`, `mapping?`, `sourcePriority?`, `allowDecompile?`, `projectPath?`, `scope?`, `preferProjectVersion?`, `strictVersion?`, `startLine?`, `endLine?`, `maxLines?`, `maxChars?`, `outputFile?` | `mode`, `sourceText`, `returnedRange`, `truncated`, `charsTruncated?`, `outputFile?`, `artifactId`, `returnedNamespace`, `artifactContents`, mapping/provenance metadata |
256
+ | `get-class-members` | Get class fields/methods/constructors from bytecode | `className`, `target`, `mapping?`, `sourcePriority?`, `allowDecompile?`, `access?`, `includeSynthetic?`, `includeInherited?`, `memberPattern?`, `maxMembers?`, `projectPath?`, `scope?`, `preferProjectVersion?`, `strictVersion?` | `members.{constructors,fields,methods}`, `counts`, `truncated`, `context`, `returnedNamespace`, `artifactContents`, `warnings[]` |
186
257
  | `search-class-source` | Search indexed class source for symbols/text/path | `artifactId`, `query`, `intent?`, `match?`, `packagePrefix?`, `fileGlob?`, `symbolKind?`, `queryMode?`, `limit?`, `cursor?` | `hits[]`, `nextCursor?`, `mappingApplied`, `returnedNamespace`, `artifactContents` |
187
258
  | `get-artifact-file` | Read full source file with byte guard | `artifactId`, `filePath`, `maxBytes?` | `content`, `contentBytes`, `truncated`, `mappingApplied`, `returnedNamespace`, `artifactContents` |
188
259
  | `list-artifact-files` | List indexed source file paths with cursor pagination | `artifactId`, `prefix?`, `limit?`, `cursor?` | `items[]`, `nextCursor?`, `mappingApplied`, `artifactContents`, `warnings[]` |
189
260
  | `index-artifact` | Rebuild index metadata for an existing artifact | `artifactId`, `force?` | `reindexed`, `reason`, `counts`, `indexedAt`, `durationMs` |
261
+ <!-- END GENERATED TOOL TABLE: source-exploration -->
190
262
 
191
263
  ### Version Comparison & Symbol Tracking
192
264
 
193
- Tools for comparing class/registry changes across Minecraft versions and tracing symbol existence over time.
265
+ Tools for comparing class and registry changes across Minecraft versions and tracing symbol existence over time.
194
266
 
267
+ <!-- BEGIN GENERATED TOOL TABLE: version-comparison-symbol-tracking -->
195
268
  | Tool | Purpose | Key Inputs | Key Outputs |
196
269
  | --- | --- | --- | --- |
197
- | `trace-symbol-lifecycle` | Trace when `Class.method` exists across Minecraft versions (`descriptor` omitted = name-only lookup) | `symbol`, `descriptor?`, `fromVersion?`, `toVersion?`, `mapping?`, `sourcePriority?`, `maxVersions?`, `includeTimeline?` | `presence.firstSeen`, `presence.lastSeen`, `presence.missingBetween[]`, `presence.existsNow`, `timeline?`, `warnings[]` |
270
+ | `trace-symbol-lifecycle` | Trace when `Class.method` exists across Minecraft versions (`descriptor` omitted = name-only lookup) | `symbol`, `descriptor?`, `fromVersion?`, `toVersion?`, `mapping?`, `sourcePriority?`, `includeSnapshots?`, `maxVersions?`, `includeTimeline?` | `presence.firstSeen`, `presence.lastSeen`, `presence.missingBetween[]`, `presence.existsNow`, `timeline?`, `warnings[]` |
198
271
  | `diff-class-signatures` | Compare one class between two versions and return member deltas | `className`, `fromVersion`, `toVersion`, `mapping?`, `sourcePriority?`, `includeFullDiff?` | `classChange`, `constructors/methods/fields.{added,removed,modified}`, `modified`, `modified[].{key,changed,from?,to?}`, `summary`, `warnings[]` |
199
272
  | `compare-versions` | Compare class/registry changes between two versions | `fromVersion`, `toVersion`, `category?`, `packageFilter?`, `maxClassResults?` | `classes`, `registry`, `summary`, `warnings[]` |
273
+ <!-- END GENERATED TOOL TABLE: version-comparison-symbol-tracking -->
200
274
 
201
275
  ### Mapping & Symbols
202
276
 
203
277
  Tools for converting symbol names between namespaces and checking symbol existence.
204
278
 
279
+ <!-- BEGIN GENERATED TOOL TABLE: mapping-symbols -->
205
280
  | Tool | Purpose | Key Inputs | Key Outputs |
206
281
  | --- | --- | --- | --- |
207
282
  | `find-mapping` | Find mapping candidates for class/field/method symbols between namespaces | `version`, `kind`, `name`, `owner?`, `descriptor?`, `sourceMapping`, `targetMapping`, `sourcePriority?`, `disambiguation?`, `maxCandidates?` | `querySymbol`, `mappingContext`, `resolved`, `status`, `resolvedSymbol?`, `candidates[]`, `candidateCount`, `candidatesTruncated?`, `ambiguityReasons?`, `provenance?`, `meta.warnings[]` |
@@ -209,21 +284,25 @@ Tools for converting symbol names between namespaces and checking symbol existen
209
284
  | `get-class-api-matrix` | Show one class API as a mapping matrix (`obfuscated/mojang/intermediary/yarn`) | `version`, `className`, `classNameMapping`, `includeKinds?`, `sourcePriority?`, `maxRows?` | `classIdentity`, `rows[]`, `rowCount`, `rowsTruncated?`, `ambiguousRowCount?`, `meta.warnings[]` |
210
285
  | `resolve-workspace-symbol` | Resolve compile-visible symbol names for a Gradle workspace (`build.gradle/.kts`) | `projectPath`, `version`, `kind`, `name`, `owner?`, `descriptor?`, `sourceMapping`, `sourcePriority?`, `maxCandidates?` | `querySymbol`, `mappingContext`, `resolved`, `status`, `resolvedSymbol?`, `candidates[]`, `candidateCount`, `candidatesTruncated?`, `workspaceDetection`, `meta.warnings[]` |
211
286
  | `check-symbol-exists` | Strict symbol presence check for class/field/method | `version`, `kind`, `name`, `owner?`, `descriptor?`, `sourceMapping`, `sourcePriority?`, `nameMode?`, `signatureMode?`, `maxCandidates?` | `querySymbol`, `mappingContext`, `resolved`, `status`, `resolvedSymbol?`, `candidates[]`, `candidateCount`, `candidatesTruncated?`, `meta.warnings[]` |
287
+ <!-- END GENERATED TOOL TABLE: mapping-symbols -->
212
288
 
213
289
  ### NBT Utilities
214
290
 
215
291
  Tools for decoding, patching, and encoding Java Edition NBT binary data using a typed JSON representation.
216
292
 
293
+ <!-- BEGIN GENERATED TOOL TABLE: nbt-utilities -->
217
294
  | Tool | Purpose | Key Inputs | Key Outputs |
218
295
  | --- | --- | --- | --- |
219
296
  | `nbt-to-json` | Decode Java Edition NBT binary (`base64`) to typed JSON | `nbtBase64`, `compression?` (`none`, `gzip`, `auto`) | `typedJson`, `meta.compressionDetected`, `meta.inputBytes` |
220
297
  | `nbt-apply-json-patch` | Apply RFC 6902 patch (`add/remove/replace/test`) to typed NBT JSON | `typedJson`, `patch` | `typedJson`, `meta.appliedOps`, `meta.testOps`, `meta.changed` |
221
298
  | `json-to-nbt` | Encode typed JSON back to Java Edition NBT binary (`base64`) | `typedJson`, `compression?` (`none`, `gzip`) | `nbtBase64`, `meta.outputBytes`, `meta.compressionApplied` |
299
+ <!-- END GENERATED TOOL TABLE: nbt-utilities -->
222
300
 
223
301
  ### Mod Analysis
224
302
 
225
303
  Tools for extracting metadata from mod JARs, decompiling mod source, searching mod code, and remapping mod namespaces.
226
304
 
305
+ <!-- BEGIN GENERATED TOOL TABLE: mod-analysis -->
227
306
  | Tool | Purpose | Key Inputs | Key Outputs |
228
307
  | --- | --- | --- | --- |
229
308
  | `analyze-mod-jar` | Extract mod metadata/dependencies/entrypoints from mod JAR | `jarPath`, `includeClasses?` | `modId`, `loader`, `jarKind`, `dependencies`, `entrypoints`, `mixinConfigs`, class stats |
@@ -231,763 +310,106 @@ Tools for extracting metadata from mod JARs, decompiling mod source, searching m
231
310
  | `get-mod-class-source` | Read one class source from decompiled mod cache | `jarPath`, `className`, `maxLines?`, `maxChars?`, `outputFile?` | `className`, `content`, `totalLines`, `truncated?`, `charsTruncated?`, `outputFilePath?`, `warnings[]` |
232
311
  | `search-mod-source` | Search decompiled mod source by class/method/field/content | `jarPath`, `query`, `searchType?`, `limit?` | `hits[]`, `totalHits`, `truncated`, `warnings[]` |
233
312
  | `remap-mod-jar` | Remap a Fabric/Quilt mod JAR to yarn/mojang names; Mojang-mapped inputs are copied for `targetMapping="mojang"` | `inputJar`, `targetMapping`, `mcVersion?`, `outputJar?` | `outputJar`, `mcVersion`, `fromMapping`, `targetMapping`, `resolvedTargetNamespace`, `warnings[]` |
313
+ <!-- END GENERATED TOOL TABLE: mod-analysis -->
234
314
 
235
315
  ### Validation
236
316
 
237
317
  Tools for validating Mixin source and Access Widener files against a target Minecraft version.
238
318
 
319
+ <!-- BEGIN GENERATED TOOL TABLE: validation -->
239
320
  | Tool | Purpose | Key Inputs | Key Outputs |
240
321
  | --- | --- | --- | --- |
241
322
  | `validate-mixin` | Parse/validate Mixin source against target Minecraft version | `input`, `sourceRoots?`, `version`, `mapping?`, `sourcePriority?`, `projectPath?`, `scope?`, `preferProjectVersion?`, `minSeverity?`, `hideUncertain?`, `warningMode?`, `preferProjectMapping?`, `reportMode?`, `warningCategoryFilter?`, `treatInfoAsWarning?`, `explain?`, `includeIssues?` | `mode`, `results[].validationStatus`, `summary.partial`, `issueSummary?`, `provenance?`, `incompleteReasons?`, `toolHealth?`, `confidenceScore?`, `confidenceBreakdown?` |
242
323
  | `validate-access-widener` | Parse/validate Access Widener content against target version | `content`, `version`, `mapping?`, `sourcePriority?` | `valid`, `issues[]`, `warnings[]`, `summary` |
324
+ <!-- END GENERATED TOOL TABLE: validation -->
243
325
 
244
326
  ### Registry & Diagnostics
245
327
 
246
328
  Tools for querying generated registry data and inspecting server runtime state.
247
329
 
330
+ <!-- BEGIN GENERATED TOOL TABLE: registry-diagnostics -->
248
331
  | Tool | Purpose | Key Inputs | Key Outputs |
249
332
  | --- | --- | --- | --- |
250
333
  | `get-registry-data` | Get generated registry snapshots (blocks/items/entities etc.) | `version`, `registry?`, `includeData?`, `maxEntriesPerRegistry?` | `registries`, `data?`, `entryCount`, `returnedEntryCount?`, `registryEntryCounts?`, `dataTruncated?`, `warnings[]` |
251
334
  | `get-runtime-metrics` | Inspect runtime counters and latency snapshots | none | `result.*` runtime metrics, `meta` envelope |
335
+ <!-- END GENERATED TOOL TABLE: registry-diagnostics -->
252
336
 
253
- ### Tool Constraints
254
-
255
- `resolve-artifact` now takes `target: { kind, value }`.
256
- `get-class-source` requires `target`, where `target.type="artifact"` selects a previously resolved `artifactId` and `target.type="resolve"` supplies `{ kind, value }` directly.
257
- `get-class-members` requires the same `target` object shape and still needs a binary jar (`binaryJarPath`) to read `.class` entries.
258
- `get-class-members` returns `ERR_INVALID_INPUT` when a classfile contains malformed field or method descriptors instead of emitting malformed Java signature text from corrupted bytecode.
259
- Malformed `void` usage outside method return positions is rejected with descriptor-specific errors, so invalid method arguments now report as method descriptor failures instead of field descriptor failures.
260
- Error `suggestedCall` payloads now use the same `target` object schema instead of legacy `targetKind` / `targetValue` fields.
261
- Positive integer tool parameters accept numeric strings such as `"10"` in addition to JSON numbers.
262
- This numeric-string coercion only applies to documented top-level tool arguments; nested `typedJson` payloads and JSON Patch `value` objects are preserved verbatim.
263
- `resolve-artifact`, `get-class-source`, `get-class-members`, `search-class-source`, `get-artifact-file`, and `list-artifact-files` include `artifactContents` so clients can see whether the backing artifact is `source-jar` or `decompiled-binary`, whether resources are indexed (`resourcesIncluded=false` today), and whether source coverage is always `full` or `partial`.
264
- `get-class-source`, `get-class-members`, `search-class-source`, and `get-artifact-file` include `returnedNamespace`; compare it with `mappingApplied` when a tool returns remapped symbols instead of raw indexed source text.
265
- `list-artifact-files` warns when you probe `assets/` or `data/` prefixes because the current index stores Java source only, not non-Java resources.
266
- `get-class-source` and `get-class-members` can infer a missing artifact version from `projectPath` when `preferProjectVersion=true` and artifact metadata does not already contain a version.
267
- Heavy analysis tools (`trace-symbol-lifecycle`, `diff-class-signatures`, `compare-versions`, `find-mapping`, `resolve-method-mapping-exact`, `get-class-api-matrix`, `get-registry-data`) are serialized inside the server to protect stdio transport stability; when the queue is full they fail fast with `ERR_LIMIT_EXCEEDED`.
268
- The CLI stdio entrypoint now runs a supervised worker process. If the worker exits unexpectedly, the wrapper restarts it, replays MCP initialization for the current session, and keeps the same stdio connection usable; any request that was already in flight fails with a retryable JSON-RPC internal error instead of tearing down the whole transport.
269
- `find-mapping`, `resolve-method-mapping-exact`, `resolve-workspace-symbol`, and `check-symbol-exists` accept `maxCandidates` to cap `candidates[]`; `candidateCount` always reports the full pre-truncation candidate total and `candidatesTruncated=true` signals clipping.
270
- `get-class-api-matrix` accepts `maxRows`; `rowCount` reports the full pre-truncation row total and `rowsTruncated=true` signals clipping.
271
- `diff-class-signatures` supports `includeFullDiff=false` to omit `from`/`to` snapshots from `modified[]` entries and keep only `key` plus `changed`.
272
- `validate-mixin` requires `input.mode` to be exactly one of `inline`, `path`, `paths`, `config`, or `project`. `input.path`/`input.paths[]` are normalized for host/WSL path formats before file reads. `input.configPaths[]` reads mixin config JSON files and auto-discovers source files for batch validation (`sourceRoots[]` override lookup roots; otherwise common roots like `src/main/java`, `src/client/java`, `common/src/{main,client}/java`, `fabric/src/{main,client}/java`, `neoforge/src/{main,client}/java`, `forge/src/{main,client}/java`, and `quilt/src/{main,client}/java` are auto-detected from configured mixin classes). `input.mode="project"` recursively discovers `**/*.mixins.json` under `input.path`, then runs the same config-driven batch validation with `projectPath` defaulting to that workspace root.
273
- `validate-mixin` always returns `mode`, `results[]`, and `summary`; single-input modes still use a one-element `results[]` array.
274
- `validate-mixin` supports `includeIssues=false` for summary-first workflows that do not need per-result `issues[]`; combine it with `reportMode=compact` and `warningMode=aggregated` to keep responses small.
275
- `reportMode=summary-first` hoists shared provenance, warnings, and incomplete-reason summaries to the top level while trimming duplicate per-result metadata.
276
- `validate-mixin` per-result responses now include `validationStatus` (`full`, `partial`, `invalid`) plus `summary.membersValidated`, `summary.membersSkipped`, and `summary.membersMissing`; `quickSummary` now includes member coverage counts instead of only issue counts.
277
- `validate-mixin` batch `summary` now includes `partial` so callers can distinguish fully clean results from tool-limited-but-non-failing results.
278
- `validate-mixin` now reports `validation-incomplete` when target metadata cannot be loaded reliably, instead of misclassifying those tool-limited cases as confirmed missing classes.
279
- `validate-mixin` responses now include `confidenceBreakdown` alongside `confidenceScore`, exposing the base score plus the penalties that lowered confidence.
280
- `validate-mixin` per-result responses include `provenance.resolutionNotes?` when mapping fallback occurs.
281
- `validate-mixin` provenance now exposes `requestedScope` / `appliedScope` and `requestedSourcePriority` / `appliedSourcePriority` so fallback and retry behavior is explicit.
282
- `scope="loader"` currently resolves the same artifact class as `scope="merged"`; keep using `scope` to declare intent, but expect the same underlying lookup path today.
283
- For non-vanilla scopes such as `scope="merged"`, `validate-mixin` now performs bytecode lookup in the resolved artifact namespace before remapping members back to the requested namespace, so Mojang-mapped Loom workspaces validate against merged class names instead of reporting false partial results.
284
- `validate-mixin` automatically retries with `sourcePriority="maven-first"` after a partial `loom-first` validation caused by mapping/signature resolution limits, and records that retry in warnings plus provenance notes.
285
- `validate-mixin` validates `@Invoker` targets against methods only and `@Accessor` targets against fields only.
286
- `validate-mixin` parser supports both `.class` literal targets and `targets = "..."` / `targets = {"a", "b"}` string forms.
287
- `validate-mixin` parser handles multi-line annotations between `@Shadow`/`@Accessor` and declarations, and strips inline annotations from declaration lines.
288
- `validate-mixin` distinguishes `target-mapping-failed` (warning, uncertain) from `target-not-found` (error) when class mapping fails.
289
- `validate-mixin` issues and `structuredWarnings` include `category` (`mapping`, `configuration`, `validation`, `resolution`, or `parse`) to distinguish setup/tooling/parser limits from real validation errors.
290
- `validate-mixin` supports post-filtering with `minSeverity`, `hideUncertain`, and `warningCategoryFilter`; `treatInfoAsWarning=false` suppresses info-level entries in `structuredWarnings`.
291
- `validate-mixin` per-result responses include `resolvedMembers?` tracking each member's resolution status (`resolved` or `not-found`).
292
- `validate-mixin` with `explain=true` enriches each issue with `explanation` and `suggestedCall` (tool + params) for agent-driven recovery; generated `check-symbol-exists` recovery payloads now stay within that tool's public schema.
293
- Schema validation failures now also return the standard `ERR_INVALID_INPUT` envelope with `fieldErrors`, `hints`, and a mode-correct `suggestedCall` for common `validate-mixin` mistakes such as passing raw source text directly as `input`.
294
- Bare string `target` values now return `ERR_INVALID_INPUT` with a schema-correct `suggestedCall` wrapper for `resolve-artifact`, `get-class-source`, and `get-class-members`.
295
- `validate-mixin` summary uses `processingErrors`, `totalValidationErrors`, and `totalValidationWarnings`; the deprecated `summary.errors` field was removed.
296
- `check-symbol-exists` suppresses raw `No Loom tiny mapping files matched version ...` noise when Maven tiny mappings successfully satisfy the lookup; successful fallback now reports a single concise warning instead of repeating the Loom miss on every result.
297
- `resolve-artifact` with `target.kind=version` uses Loom cache discovery from `projectPath` only when `mapping=mojang`; mapping failures include `searchedPaths`, `candidateArtifacts`, and `recommendedCommand` in error details.
298
- `resolve-artifact` supports `scope` (`vanilla`/`merged`/`loader`) and optional `preferProjectVersion=true` to override `target.value` from `gradle.properties` (`minecraft_version`, `mc_version`, `minecraftVersion`) when `target.kind=version`.
299
- `resolve-artifact` with `target.kind=coordinate` searches the local Maven repository, the local Gradle `modules-2` cache, and configured `MCP_SOURCE_REPOS` before reporting `ERR_SOURCE_NOT_FOUND`.
300
- `resolve-artifact`, `get-class-source`, and `get-class-members` now preserve `ERR_JAR_NOT_FOUND` for missing or inaccessible `target.kind=jar` paths instead of surfacing raw filesystem exceptions.
301
- `resolve-artifact` includes `sampleEntries` only when a source JAR is resolved; decompile-only paths leave it unset.
302
- `resolve-artifact` adds `qualityFlags=["partial-source-no-net-minecraft"]` and a warning when a merged Loom source candidate does not contain `net.minecraft` sources; only candidates that still look like Minecraft source artifacts are auto-selected, while version-matching mod/library source jars remain diagnostics only. `get-class-source` now bypasses that sibling `*-sources.jar` during binary fallback so the fallback can actually reach the binary artifact.
303
- `find-class` returns type symbols (`class`/`interface`/`enum`/`record`) only; fully-qualified lookups are filtered by exact FQCN/file path to avoid false negatives when many classes share the same simple name.
304
- `find-class` returns an explanatory warning when an `obfuscated` artifact is queried with names that look like deobfuscated Mojang classes.
305
- `find-class` suppresses non-vanilla matches for vanilla-looking queries on artifacts flagged with `partial-source-no-net-minecraft`; in that situation it returns a warning instead of unrelated modded classes.
306
- `search-class-source` uses `limit: 20` by default.
307
- `search-class-source` `queryMode` controls text search strategy: `auto` (default) uses indexed token search with literal fallback for separator queries, `token` keeps indexed token behavior only, and `literal` uses substring scan only.
308
- `search-class-source` with `match=regex` enforces `query.length <= 200` and a strict result cap of `100`.
309
- `search-class-source` now returns compact file hits without snippets, line windows, relation expansion, or `totalApprox`.
310
- Use `get-artifact-file` or `get-class-source` to inspect returned files after search.
311
- `search-class-source` `symbolKind` is only supported when `intent=symbol`.
312
- `get-artifact-file` byte truncation now preserves UTF-8 character boundaries, preventing replacement-character (`�`) corruption when `maxBytes` cuts through multibyte text.
313
- `search-class-source` `fileGlob` supports `*`, `**`, and `?`; recursive patterns such as `net/minecraft/**/*.java` are supported.
314
- `get-class-source` fallback matching enforces package compatibility and returns `ERR_CLASS_NOT_FOUND` when only name-colliding classes from other packages exist.
315
- `get-class-source` now falls back to the sibling binary artifact when a source-backed artifact is only partial (for example, merged Loom sources without `net.minecraft` entries); if that fallback still cannot produce source, the error now carries the partial-source context and suggests `get-class-api-matrix` instead of `find-class`.
316
- `get-class-source` warns when fallback source text is returned in a different namespace than the requested mapping; the source text itself is not remapped.
317
- `get-class-source` mode defaults to `metadata` (symbol outline only); `mode=snippet` auto-sets `maxLines=200` when no line range/max is provided; `mode=full` returns the entire source. `outputFile` writes the selected text and returns the file path in `outputFile`.
318
- Decompile fallback for `resolve-artifact`/`get-class-source` now invokes Vineflower with flags before positional `<input-jar> <output-dir>` arguments to avoid false `ERR_DECOMPILER_FAILED` outcomes on valid jars.
319
- `resolve-artifact` with `target.kind=jar` only auto-adopts the exact sibling `"<jar-basename>-sources.jar"`. Other adjacent `*-sources.jar` files are returned as `adjacentSourceCandidates` info only and are never auto-selected.
320
- When a resolved artifact comes from a `*-sources.jar`, `get-class-members` now keeps the sibling binary jar (for example `minecraft-merged-<version>.jar`) instead of treating the source jar as bytecode, and it now looks up the class in the resolved artifact namespace before remapping member names back to the requested mapping.
321
- For `target.kind=coordinate` with a classifier (`group:artifact:version:classifier`), local Maven source lookup checks `<artifact>-<version>-<classifier>-sources.jar` first and then `<artifact>-<version>-sources.jar`.
322
- Mod tool `jarPath` inputs are normalized to a canonical local `.jar` file path before existence checks, cache keying, and processing.
323
- `search-mod-source` enforces `query.length <= 200` and `limit <= 200`.
324
- `search-mod-source` detects source-only jars and searches `.java` entries directly without decompilation.
325
- `get-mod-class-source` supports `maxLines`, `maxChars`, and `outputFile` with truncation behavior aligned to `get-class-source`; when `outputFile` is set, the written file reflects applied truncation.
326
- `decompile-mod-jar` supports `includeFiles=false` to skip the full class list and `maxFiles` to cap it when you only need counts or a sample. `returnedFileCount`, `filesTruncated`, and `filesOmitted` make the shaping explicit.
327
- `find-mapping` returns `ambiguityReasons` when `status=ambiguous` to explain why candidates could not be uniquely resolved.
328
- `get-class-api-matrix` returns `ambiguousRowCount` when one or more rows required ambiguity fallback.
329
- `check-symbol-exists` defaults to strict FQCN class inputs; set `nameMode=auto` to allow short class names (ambiguous matches return `status=ambiguous`).
330
- `check-symbol-exists` supports `signatureMode=name-only` to match methods by owner+name without requiring a descriptor. Single match returns `resolved`; multiple overloads return `ambiguous` with all candidates.
331
- `check-symbol-exists` always validates input shape first and returns `ERR_INVALID_INPUT` for invalid symbol combinations, even when mapping data is unavailable.
332
- `get-registry-data` now discards corrupt cached `registries.json` files, regenerates them when possible, and returns `ERR_REGISTRY_GENERATION_FAILED` if the regenerated snapshot is still unreadable.
333
- `get-registry-data` supports `includeData=false` to return registry names and counts without full entry bodies. `maxEntriesPerRegistry` caps returned entries per registry while preserving full `entryCount` and `registryEntryCounts`.
334
- Migration notes:
335
- - Replace `resolve-artifact` `targetKind` + `targetValue` with `target: { kind, value }`.
336
- - Replace `get-class-source` / `get-class-members` top-level `artifactId` / `targetKind` / `targetValue` with `target: { type: "artifact", artifactId }` or `target: { type: "resolve", kind, value }`.
337
- - `resolve-method-mapping-exact` is method-only and no longer accepts `kind`.
338
- - Replace `validate-mixin` `source` / `sourcePath` / `sourcePaths` / `mixinConfigPath` / `sourceRoot` with `input.mode` plus `input.source` / `input.path` / `input.paths[]` / `input.configPaths[]` and `sourceRoots[]`. Use `input.mode="project"` when you want to discover `*.mixins.json` automatically from a workspace root. Use `summary.processingErrors` instead of `summary.errors`.
339
- - `search-class-source` removed `snippetLines`, `includeDefinition`, and `includeOneHop`; responses now contain compact `hits[]` plus `nextCursor?` only, and `symbolKind` may only be used with `intent=symbol`.
340
- `remap-mod-jar` requires Java to be installed and only supports Fabric/Quilt mods.
341
- Mojang-mapped inputs can be returned as-is for `targetMapping="mojang"`. `targetMapping="yarn"` still expects an intermediary-built input jar.
337
+ Detailed parameter constraints, migration notes, resource behavior, and the full environment-variable matrix live in [docs/tool-reference.md](docs/tool-reference.md).
342
338
 
343
339
  ## Resources
344
340
 
345
- MCP resources provide URI-based access to Minecraft data, usable by any MCP client that supports the resource protocol.
346
-
347
- ### Fixed Resources
348
-
349
- | Resource | URI | Description |
350
- | --- | --- | --- |
351
- | `versions-list` | `mc://versions/list` | List all available Minecraft versions with their metadata |
352
- | `runtime-metrics` | `mc://metrics` | Runtime metrics and performance counters for the MCP server |
353
-
354
- ### Template Resources
355
-
356
- | Resource | URI Template | Description |
357
- | --- | --- | --- |
358
- | `class-source` | `mc://source/{artifactId}/{className}` | Java source code for a class within a resolved artifact |
359
- | `artifact-file` | `mc://artifact/{artifactId}/files/{filePath}` | Raw content of a file within a resolved artifact |
360
- | `find-mapping` | `mc://mappings/{version}/{sourceMapping}/{targetMapping}/{kind}/{name}` | Look up a mapping between two naming namespaces |
361
- | `class-members` | `mc://artifact/{artifactId}/members/{className}` | List constructors, methods, and fields for a class |
362
- | `artifact-metadata` | `mc://artifact/{artifactId}` | Metadata for a previously resolved artifact |
363
-
364
- `versions-list`, `runtime-metrics`, `find-mapping`, `class-members`, and `artifact-metadata` return structured JSON envelopes on success (`{ result, meta }`) and failure (`{ error, meta }`).
365
- `class-source` and `artifact-file` keep raw text responses on success, but still return structured JSON errors on failure.
366
-
367
- ## Response Envelope
368
-
369
- All tools return exactly one of:
370
-
371
- - Success: `{ result: { ... }, meta: { requestId, tool, durationMs, warnings[] } }`
372
- - Failure: `{ error: { type, title, detail, status, code, instance, fieldErrors?, hints? }, meta: { requestId, tool, durationMs, warnings[] } }`
373
-
374
- JSON resources follow the same `result/error/meta` pattern. Text resources return plain text on success.
375
- The same JSON envelope is mirrored in MCP `structuredContent` for SDK-aware clients, and failures also set `isError=true`.
341
+ Fixed resources:
376
342
 
377
- ## Examples
343
+ - `mc://versions/list`
344
+ - `mc://metrics`
378
345
 
379
- ### Source Exploration
380
-
381
- #### Resolve from Minecraft version
382
- ```json
383
- {
384
- "tool": "resolve-artifact",
385
- "arguments": {
386
- "target": {
387
- "kind": "version",
388
- "value": "1.21.10"
389
- },
390
- "mapping": "obfuscated",
391
- "allowDecompile": true,
392
- "projectPath": "/path/to/mod/workspace"
393
- }
394
- }
395
- ```
396
-
397
- #### Get class source with line window
398
- ```json
399
- {
400
- "tool": "get-class-source",
401
- "arguments": {
402
- "target": {
403
- "type": "artifact",
404
- "artifactId": "<artifact-id>"
405
- },
406
- "className": "net.minecraft.server.Main",
407
- "startLine": 50,
408
- "endLine": 180,
409
- "maxLines": 80
410
- }
411
- }
412
- ```
346
+ Template resources:
413
347
 
414
- #### Search by method symbol
415
- ```json
416
- {
417
- "tool": "search-class-source",
418
- "arguments": {
419
- "artifactId": "<artifact-id>",
420
- "query": "tickServer",
421
- "intent": "symbol",
422
- "match": "exact"
423
- }
424
- }
425
- ```
348
+ - `mc://source/{artifactId}/{className}`
349
+ - `mc://artifact/{artifactId}/files/{filePath}`
350
+ - `mc://mappings/{version}/{sourceMapping}/{targetMapping}/{kind}/{name}`
351
+ - `mc://artifact/{artifactId}/members/{className}`
352
+ - `mc://artifact/{artifactId}`
426
353
 
427
- #### Get class member list
428
- ```json
429
- {
430
- "tool": "get-class-members",
431
- "arguments": {
432
- "artifactId": "<artifact-id>",
433
- "className": "net.minecraft.server.Main",
434
- "mapping": "obfuscated",
435
- "access": "all",
436
- "includeInherited": true,
437
- "maxMembers": 300
438
- }
439
- }
440
- ```
354
+ See [docs/tool-reference.md#resources](docs/tool-reference.md#resources) for the full resource table and response behavior.
441
355
 
442
- #### List artifact files with prefix filter
356
+ ## Response Model
443
357
 
444
- List source files under a specific package to understand project structure:
358
+ Tools and JSON resources return the standard `{ result?, error?, meta }` envelope. Text resources (`class-source` and `artifact-file`) return raw text on success and structured JSON on failure.
445
359
 
446
- ```json
447
- {
448
- "tool": "list-artifact-files",
449
- "arguments": {
450
- "artifactId": "<artifact-id>",
451
- "prefix": "net/minecraft/world/level/",
452
- "limit": 50
453
- }
454
- }
455
- ```
360
+ See [docs/tool-reference.md#response-envelope](docs/tool-reference.md#response-envelope) for the exact envelope fields and error shape.
456
361
 
457
- ### Version Comparison & Symbol Tracking
362
+ ## Common Environment Variables
458
363
 
459
- #### Trace `Class.method` lifecycle
460
- ```json
461
- {
462
- "tool": "trace-symbol-lifecycle",
463
- "arguments": {
464
- "symbol": "net.minecraft.server.Main.tickServer",
465
- "descriptor": "()V",
466
- "fromVersion": "1.20.1",
467
- "toVersion": "1.21.10",
468
- "includeTimeline": true
469
- }
470
- }
471
- ```
364
+ These are the most commonly changed settings. For the full supported list, see [docs/tool-reference.md#environment-variables](docs/tool-reference.md#environment-variables).
472
365
 
473
- #### Diff one class across two versions
474
- ```json
475
- {
476
- "tool": "diff-class-signatures",
477
- "arguments": {
478
- "className": "net.minecraft.server.Main",
479
- "fromVersion": "1.20.1",
480
- "toVersion": "1.21.10",
481
- "mapping": "obfuscated",
482
- "includeFullDiff": false
483
- }
484
- }
485
- ```
486
-
487
- #### Compare two Minecraft versions
488
-
489
- Get a high-level summary of what changed between two releases, including class additions/removals and registry diffs:
490
-
491
- ```json
492
- {
493
- "tool": "compare-versions",
494
- "arguments": {
495
- "fromVersion": "1.20.4",
496
- "toVersion": "1.21.10",
497
- "category": "all",
498
- "packageFilter": "net.minecraft.world",
499
- "maxClassResults": 100
500
- }
501
- }
502
- ```
503
-
504
- Registry deltas are returned under `result.registry` (not `registryDiff`).
505
- When `packageFilter` is provided, `result.classes.addedCount`, `removedCount`, and `unchanged`
506
- are all scoped to that filtered package set.
507
-
508
- ### Mapping & Symbols
509
-
510
- #### Lookup mapping candidates
511
- ```json
512
- {
513
- "tool": "find-mapping",
514
- "arguments": {
515
- "version": "1.21.10",
516
- "kind": "class",
517
- "name": "a.b.C",
518
- "sourceMapping": "obfuscated",
519
- "targetMapping": "mojang",
520
- "sourcePriority": "loom-first",
521
- "maxCandidates": 10,
522
- "disambiguation": {
523
- "ownerHint": "net.minecraft"
524
- }
525
- }
526
- }
527
- ```
528
-
529
- #### Lookup method mapping with descriptor
530
- ```json
531
- {
532
- "tool": "find-mapping",
533
- "arguments": {
534
- "version": "1.21.10",
535
- "kind": "method",
536
- "name": "tick",
537
- "owner": "a.b.C",
538
- "descriptor": "(I)V",
539
- "sourceMapping": "obfuscated",
540
- "targetMapping": "intermediary"
541
- }
542
- }
543
- ```
544
-
545
- #### Resolve exact method mapping
546
- ```json
547
- {
548
- "tool": "resolve-method-mapping-exact",
549
- "arguments": {
550
- "version": "1.21.10",
551
- "name": "f",
552
- "owner": "a.b.C",
553
- "descriptor": "(Ljava/lang/String;)V",
554
- "sourceMapping": "obfuscated",
555
- "targetMapping": "mojang"
556
- }
557
- }
558
- ```
559
-
560
- #### Show class API mapping matrix
561
- ```json
562
- {
563
- "tool": "get-class-api-matrix",
564
- "arguments": {
565
- "version": "1.21.10",
566
- "className": "a.b.C",
567
- "classNameMapping": "obfuscated",
568
- "includeKinds": "class,field,method",
569
- "maxRows": 100
570
- }
571
- }
572
- ```
573
-
574
- Add `maxCandidates` or `maxRows` when you only need the top matches or a bounded API slice.
575
-
576
- #### Resolve workspace compile-visible symbol
577
- ```json
578
- {
579
- "tool": "resolve-workspace-symbol",
580
- "arguments": {
581
- "projectPath": "/path/to/mod/workspace",
582
- "version": "1.21.10",
583
- "kind": "method",
584
- "name": "f",
585
- "owner": "a.b.C",
586
- "descriptor": "(Ljava/lang/String;)V",
587
- "sourceMapping": "obfuscated"
588
- }
589
- }
590
- ```
591
-
592
- #### Check symbol existence
593
- ```json
594
- {
595
- "tool": "check-symbol-exists",
596
- "arguments": {
597
- "version": "1.21.10",
598
- "kind": "method",
599
- "name": "f",
600
- "owner": "a.b.C",
601
- "descriptor": "(I)V",
602
- "sourceMapping": "obfuscated"
603
- }
604
- }
605
- ```
606
-
607
- #### Check class existence by short name (`nameMode=auto`)
608
- ```json
609
- {
610
- "tool": "check-symbol-exists",
611
- "arguments": {
612
- "version": "1.21.10",
613
- "kind": "class",
614
- "name": "Blocks",
615
- "nameMode": "auto",
616
- "sourceMapping": "mojang"
617
- }
618
- }
619
- ```
620
-
621
- ### NBT Utilities
622
-
623
- #### Decode Java NBT base64 to typed JSON
624
- ```json
625
- {
626
- "tool": "nbt-to-json",
627
- "arguments": {
628
- "nbtBase64": "<base64-nbt>",
629
- "compression": "auto"
630
- }
631
- }
632
- ```
633
-
634
- #### Patch typed NBT JSON
635
- ```json
636
- {
637
- "tool": "nbt-apply-json-patch",
638
- "arguments": {
639
- "typedJson": {
640
- "rootName": "Level",
641
- "root": { "type": "compound", "value": {} }
642
- },
643
- "patch": [
644
- { "op": "add", "path": "/root/value/name", "value": { "type": "string", "value": "Alex" } }
645
- ]
646
- }
647
- }
648
- ```
649
-
650
- #### Encode typed JSON back to NBT base64
651
- ```json
652
- {
653
- "tool": "json-to-nbt",
654
- "arguments": {
655
- "typedJson": {
656
- "rootName": "Level",
657
- "root": { "type": "compound", "value": {} }
658
- },
659
- "compression": "gzip"
660
- }
661
- }
662
- ```
663
-
664
- ### Mod Analysis Workflow
665
-
666
- A typical mod analysis workflow progresses through metadata extraction, decompilation, source reading, and search:
667
-
668
- #### 1. Analyze mod metadata
669
-
670
- Extract loader type, mod ID, dependencies, and Mixin configurations from a mod JAR:
671
-
672
- ```json
673
- {
674
- "tool": "analyze-mod-jar",
675
- "arguments": {
676
- "jarPath": "/path/to/mymod-1.0.0.jar",
677
- "includeClasses": true
678
- }
679
- }
680
- ```
681
-
682
- #### 2. Decompile the mod JAR
683
-
684
- Decompile all classes and optionally retrieve a specific class inline:
685
-
686
- ```json
687
- {
688
- "tool": "decompile-mod-jar",
689
- "arguments": {
690
- "jarPath": "/path/to/mymod-1.0.0.jar",
691
- "includeFiles": false,
692
- "className": "com.example.mymod.MyMod"
693
- }
694
- }
695
- ```
696
-
697
- #### 3. Read a specific class from decompiled source
698
-
699
- After decompilation, read any class without re-decompiling:
700
-
701
- ```json
702
- {
703
- "tool": "get-mod-class-source",
704
- "arguments": {
705
- "jarPath": "/path/to/mymod-1.0.0.jar",
706
- "className": "com.example.mymod.mixin.PlayerMixin",
707
- "maxLines": 120
708
- }
709
- }
710
- ```
711
-
712
- #### 4. Search across decompiled mod source
713
-
714
- Find method references, field usages, or text patterns across the entire decompiled mod:
715
-
716
- ```json
717
- {
718
- "tool": "search-mod-source",
719
- "arguments": {
720
- "jarPath": "/path/to/mymod-1.0.0.jar",
721
- "query": "onPlayerTick",
722
- "searchType": "method",
723
- "limit": 50
724
- }
725
- }
726
- ```
727
-
728
- #### 5. Remap mod JAR to readable names
729
-
730
- Remap a Fabric mod from `intermediary` to `yarn` names for easier reading:
731
-
732
- ```json
733
- {
734
- "tool": "remap-mod-jar",
735
- "arguments": {
736
- "inputJar": "/path/to/mymod-1.0.0.jar",
737
- "targetMapping": "yarn",
738
- "mcVersion": "1.21.10"
739
- }
740
- }
741
- ```
742
-
743
- If the input jar was already built with Mojang mappings, use `targetMapping: "mojang"` to get a copied output jar and a `fromMapping: "mojang"` result.
744
-
745
- ### Validation
746
-
747
- #### Validate Mixin source
748
-
749
- Check a Mixin class source for correctness against a target Minecraft version:
750
-
751
- ```json
752
- {
753
- "tool": "validate-mixin",
754
- "arguments": {
755
- "input": {
756
- "mode": "inline",
757
- "source": "@Mixin(PlayerEntity.class)\npublic abstract class PlayerMixin {\n @Inject(method = \"tick\", at = @At(\"HEAD\"))\n private void onTick(CallbackInfo ci) {}\n}"
758
- },
759
- "version": "1.21.10",
760
- "mapping": "yarn",
761
- "reportMode": "compact",
762
- "warningMode": "aggregated",
763
- "includeIssues": false
764
- }
765
- }
766
- ```
767
-
768
- #### Validate all Mixins in a project
769
-
770
- Discover `*.mixins.json` files from a workspace root and validate every referenced Mixin in one call:
771
-
772
- ```json
773
- {
774
- "tool": "validate-mixin",
775
- "arguments": {
776
- "input": {
777
- "mode": "project",
778
- "path": "/workspace/modid"
779
- },
780
- "version": "1.21.10",
781
- "projectPath": "/workspace/modid",
782
- "preferProjectVersion": true,
783
- "preferProjectMapping": true,
784
- "reportMode": "compact",
785
- "warningMode": "aggregated",
786
- "includeIssues": false
787
- }
788
- }
789
- ```
790
-
791
- #### Validate multiple Mixin files (batch)
792
-
793
- Run the same validation settings against multiple Mixin source files:
794
-
795
- ```json
796
- {
797
- "tool": "validate-mixin",
798
- "arguments": {
799
- "input": {
800
- "mode": "paths",
801
- "paths": [
802
- "/path/to/PlayerMixin.java",
803
- "/path/to/WorldMixin.java"
804
- ]
805
- },
806
- "version": "1.21.10",
807
- "mapping": "yarn",
808
- "reportMode": "compact",
809
- "warningMode": "aggregated",
810
- "includeIssues": false
811
- }
812
- }
813
- ```
814
-
815
- #### Validate Access Widener
816
-
817
- Check an Access Widener file for valid entries against the target version:
818
-
819
- ```json
820
- {
821
- "tool": "validate-access-widener",
822
- "arguments": {
823
- "content": "accessWidener v2 named\naccessible class net/minecraft/server/Main\naccessible method net/minecraft/server/Main tick ()V",
824
- "version": "1.21.10",
825
- "mapping": "yarn"
826
- }
827
- }
828
- ```
829
-
830
- ### Registry & Diagnostics
366
+ | Variable | Default | Description |
367
+ | --- | --- | --- |
368
+ | `MCP_CACHE_DIR` | `~/.cache/minecraft-modding-mcp` | Cache root for downloads and SQLite |
369
+ | `MCP_SOURCE_REPOS` | Maven Central + Fabric + Forge + NeoForge | Comma-separated Maven repository URLs |
370
+ | `MCP_MAPPING_SOURCE_PRIORITY` | `loom-first` | Mapping source priority (`loom-first` or `maven-first`) |
371
+ | `MCP_ENABLE_INDEXED_SEARCH` | `true` | Enable indexed search for `search-class-source` |
372
+ | `MCP_VINEFLOWER_JAR_PATH` | unset | Override the Vineflower JAR path |
373
+ | `MCP_TINY_REMAPPER_JAR_PATH` | unset | Override the tiny-remapper JAR path |
374
+ | `MCP_MAX_SEARCH_HITS` | `200` | Maximum search result count |
375
+ | `MCP_MAX_CACHE_BYTES` | `2147483648` | Maximum total cache size in bytes |
831
376
 
832
- #### Get all registries for a version
377
+ ## Development
833
378
 
834
- Retrieve the full set of generated registries (blocks, items, entities, etc.) for a Minecraft version:
379
+ Repository requirements:
835
380
 
836
- ```json
837
- {
838
- "tool": "get-registry-data",
839
- "arguments": {
840
- "version": "1.21.10",
841
- "includeData": false
842
- }
843
- }
844
- ```
845
-
846
- #### Get a single registry
381
+ - Node.js 22+
382
+ - `pnpm`
383
+ - Java when running remap or decompile flows locally
847
384
 
848
- Fetch only a specific registry type:
385
+ Setup and run the repository:
849
386
 
850
- ```json
851
- {
852
- "tool": "get-registry-data",
853
- "arguments": {
854
- "version": "1.21.10",
855
- "registry": "minecraft:block",
856
- "maxEntriesPerRegistry": 50
857
- }
858
- }
387
+ ```bash
388
+ pnpm install
389
+ pnpm dev
859
390
  ```
860
391
 
861
- #### Force reindex an artifact
862
-
863
- Rebuild the search index for an artifact after cache or tooling changes:
392
+ Build the packaged shape:
864
393
 
865
- ```json
866
- {
867
- "tool": "index-artifact",
868
- "arguments": {
869
- "artifactId": "<artifact-id>",
870
- "force": true
871
- }
872
- }
394
+ ```bash
395
+ pnpm build
396
+ pnpm start
873
397
  ```
874
398
 
875
- #### Inspect runtime metrics
876
-
877
- Check server performance counters, cache sizes, and latency snapshots:
399
+ Always run:
878
400
 
879
- ```json
880
- {
881
- "tool": "get-runtime-metrics",
882
- "arguments": {}
883
- }
401
+ ```bash
402
+ pnpm check
403
+ pnpm test
884
404
  ```
885
405
 
886
- Cache entry counts and byte accounting are maintained incrementally during `resolve-artifact`, `index-artifact`, cache hits, and eviction, so `get-runtime-metrics` remains cheap even after repeated artifact loads.
887
- Repeated mapping-heavy workflows such as `find-mapping`, `get-class-api-matrix`, `resolve-workspace-symbol`, `check-symbol-exists`, and `validate-mixin` also reuse hot-path resolution work to keep large batches responsive.
888
-
889
- ## Mapping Policy
890
-
891
- ### Namespace Definitions
892
-
893
- | Namespace | Description |
894
- | --- | --- |
895
- | `obfuscated` | Mojang obfuscated names (e.g. `a`, `b`, `c`) |
896
- | `mojang` | Mojang deobfuscated names from `client_mappings.txt` (e.g. `net.minecraft.server.Main`) |
897
- | `intermediary` | Fabric stable intermediary names (e.g. `net.minecraft.class_1234`, `method_5678`) |
898
- | `yarn` | Fabric community human-readable names (e.g. `net.minecraft.server.MinecraftServer`, `tick`) |
899
-
900
- The legacy public namespace name `official` was removed. Requests that still send `official` now fail validation and should be updated to `obfuscated`.
901
-
902
- ### Lookup Rules
903
-
904
- `find-mapping` supports lookup across `obfuscated`, `mojang`, `intermediary`, and `yarn`.
905
-
906
- Symbol query inputs use `kind` + `name` + optional `owner`/`descriptor`:
907
- - class: `kind=class`, `name=a.b.C` (default FQCN). For existence checks only, `nameMode=auto` allows short names like `C`.
908
- - field: `kind=field`, `owner=a.b.C`, `name=fieldName`
909
- - method: `kind=method`, `owner=a.b.C`, `name=methodName`, `descriptor=(I)V`
910
-
911
- `mapping: "mojang"` requires a source-backed artifact. If only decompile path is available, the server returns `ERR_MAPPING_NOT_APPLIED`.
912
-
913
- `resolve-artifact`, `get-class-members`, `trace-symbol-lifecycle`, and `diff-class-signatures` accept `obfuscated | mojang | intermediary | yarn` with constraints:
914
- - `intermediary` / `yarn` require a resolvable Minecraft version context (for example `target.kind=version` or a versioned coordinate).
915
- - for unobfuscated versions (for example 26.1+), requesting `intermediary` / `yarn` falls back to `obfuscated` with a warning.
916
- - `mojang` requires source-backed artifacts; decompile-only paths are rejected with `ERR_MAPPING_NOT_APPLIED`.
917
-
918
- When `trace-symbol-lifecycle` omits `descriptor`, the server resolves methods by owner+name and warns if overload ambiguity prevents a unique answer.
919
- For decompile-only `ERR_MAPPING_NOT_APPLIED` failures, error details include `artifactOrigin`, `nextAction`, and `suggestedCall` so clients can recover without guessing.
406
+ Run these when relevant:
920
407
 
921
- If `find-class` or `get-class-source` returns no hit on an `obfuscated` artifact for names like `net.minecraft.world.item.Item`, the tool now warns that `obfuscated` means Mojang's obfuscated runtime names and recommends retrying with `mapping="mojang"` or translating via `find-mapping`.
922
-
923
- Method descriptor precision is best on Tiny-backed paths (`intermediary`/`yarn`). For `obfuscated <-> mojang`, Mojang `client_mappings` do not carry JVM descriptors, so descriptor queries may fallback to name matching and emit a warning.
924
-
925
- Use `resolve-method-mapping-exact` when candidate ranking is not enough and the workflow needs strict `owner+name+descriptor` certainty.
926
- Use `find-mapping` `disambiguation.ownerHint` / `disambiguation.descriptorHint` to narrow ambiguous candidate sets.
927
- Use `resolve-workspace-symbol` when you need compile-visible names from actual Gradle Loom mappings in a workspace.
928
-
929
- ## Environment Variables
930
-
931
- ### Core
932
-
933
- | Variable | Default | Description |
934
- | --- | --- | --- |
935
- | `MCP_CACHE_DIR` | `~/.cache/minecraft-modding-mcp` | Cache root for downloads and SQLite |
936
- | `MCP_SQLITE_PATH` | `<cacheDir>/source-cache.db` | SQLite database path |
937
- | `MCP_SOURCE_REPOS` | Maven Central + Fabric + Forge + NeoForge | Comma-separated Maven repository URLs |
938
- | `MCP_LOCAL_M2` | `~/.m2/repository` | Local Maven repository path |
939
- | `MCP_ENABLE_INDEXED_SEARCH` | `true` | Enable indexed query path for `search-class-source` |
940
- | `MCP_MAPPING_SOURCE_PRIORITY` | `loom-first` | Mapping source priority (`loom-first` or `maven-first`) |
941
- | `MCP_VERSION_MANIFEST_URL` | Mojang manifest URL | Override manifest endpoint for testing/private mirrors |
942
-
943
- ### Limits & Tuning
944
-
945
- | Variable | Default | Description |
946
- | --- | --- | --- |
947
- | `MCP_MAX_CONTENT_BYTES` | `1000000` | Maximum bytes for file read operations |
948
- | `MCP_MAX_SEARCH_HITS` | `200` | Maximum search result count |
949
- | `MCP_MAX_ARTIFACTS` | `200` | Maximum cached artifacts |
950
- | `MCP_MAX_CACHE_BYTES` | `2147483648` | Maximum total cache size in bytes |
951
- | `MCP_FETCH_TIMEOUT_MS` | `15000` | HTTP request timeout in milliseconds |
952
- | `MCP_FETCH_RETRIES` | `2` | HTTP request retry count |
953
-
954
- ### Decompilation & Remapping
955
-
956
- | Variable | Default | Description |
957
- | --- | --- | --- |
958
- | `MCP_VINEFLOWER_JAR_PATH` | unset | External Vineflower JAR path (auto-downloaded if unset) |
959
- | `MCP_TINY_REMAPPER_JAR_PATH` | unset | External tiny-remapper JAR path (auto-downloaded if unset) |
960
- | `MCP_REMAP_TIMEOUT_MS` | `600000` | Remap operation timeout in milliseconds |
961
- | `MCP_REMAP_MAX_MEMORY_MB` | `4096` | Maximum JVM heap for remap operations |
962
-
963
- ### NBT
964
-
965
- | Variable | Default | Description |
966
- | --- | --- | --- |
967
- | `MCP_MAX_NBT_INPUT_BYTES` | `4194304` | Maximum decoded NBT input bytes accepted by `nbt-to-json` |
968
- | `MCP_MAX_NBT_INFLATED_BYTES` | `16777216` | Maximum gzip-inflated bytes accepted by `nbt-to-json` |
969
- | `MCP_MAX_NBT_RESPONSE_BYTES` | `8388608` | Maximum response payload bytes for NBT tools |
970
-
971
- ## Architecture
972
-
973
- | Component | Technology |
974
- | --- | --- |
975
- | Runtime | Node.js 22+ (native `node:sqlite`) |
976
- | Transport | stdio (MCP standard, auto-detects newline + `Content-Length` framing) |
977
- | Storage | SQLite — artifact metadata, source index, mapping cache |
978
- | Decompilation | [Vineflower](https://github.com/Vineflower/vineflower) (auto-downloaded) |
979
- | Remapping | [tiny-remapper](https://github.com/FabricMC/tiny-remapper) (requires Java) |
980
- | Mapping Sources | Mojang `client_mappings.txt`, Fabric Loom workspace, Maven Tiny v2 |
981
-
982
- The server runs as a single long-lived process communicating over stdio. Artifacts (source JARs, binary JARs, mapping files) are downloaded on demand and cached in SQLite. The search index is built lazily on first query and persisted for subsequent calls.
983
-
984
- ## Development Notes
985
-
986
- - `SourceService` is the canonical implementation for artifact resolution, ingestion, and source querying.
987
- - `version` resolution downloads Mojang client JARs into cache and routes them through the same ingestion flow as `jar` and `coordinate` targets.
988
- - Tool responses are always wrapped as `{ result?, error?, meta }`.
989
- - Tool responses also mirror that envelope into MCP `structuredContent`, and failures set `isError=true`.
990
- - `meta` includes `requestId`, `tool`, `durationMs`, and `warnings[]`.
408
+ - `pnpm test:manual:stdio-smoke` for MCP transport, registration, or manual workflow changes
409
+ - `pnpm test:manual:package-smoke` when checking packaged install and distribution behavior
410
+ - `pnpm test:perf` for search, index, or performance-sensitive changes
411
+ - `pnpm test:coverage` or `pnpm test:coverage:lcov` for coverage checks (`lines=80`, `branches=70`, `functions=80`)
412
+ - `pnpm validate` for the full local validation suite
991
413
 
992
414
  ## License
993
415