@debugai/mcp 2.3.0 → 2.4.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.
- package/README.md +41 -4
- package/dist/backend.d.ts +11 -1
- package/dist/cli/commands.js +22 -4
- package/dist/cli/install.d.ts +38 -1
- package/dist/cli/install.js +22 -6
- package/dist/server.js +6 -0
- package/dist/tools/reportOutcome.d.ts +36 -0
- package/dist/tools/reportOutcome.js +79 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -133,6 +133,8 @@ call report_outcome so the project's error memory stays accurate.
|
|
|
133
133
|
|
|
134
134
|
You do not need this package. The [DebugAI extension](https://marketplace.visualstudio.com/items?itemName=debugai.debugai) registers the MCP server automatically (VS Code 1.101+) and adds one-click fix apply, proactive scan, and codebase indexing on top. It is on [Open VSX](https://open-vsx.org/extension/debugai/debugai) too, for Cursor, Windsurf, and VSCodium.
|
|
135
135
|
|
|
136
|
+
The two servers are the same protocol surface and are kept in step by a test that reads both copies as text, because a comment saying "keep these in sync" has failed here before. From extension 2.8.1 the bundled server also does local source resolution, which this package has had since 2.2.0. Until then, an agent on the bundled server that pasted a traceback into a workspace nobody had indexed still got "Insufficient context for specific fix" at 20% confidence, which is the exact answer this feature exists to remove.
|
|
137
|
+
|
|
136
138
|
## Manual setup
|
|
137
139
|
|
|
138
140
|
`setup` covers this, and `install --client=<id>` covers the case where a client is installed somewhere unusual. If you would still rather edit the file yourself, the entry is the same everywhere:
|
|
@@ -150,9 +152,16 @@ You do not need this package. The [DebugAI extension](https://marketplace.visual
|
|
|
150
152
|
|
|
151
153
|
Where it goes:
|
|
152
154
|
|
|
155
|
+
> **On Claude Code, `--scope user` is the part that matters.** `claude mcp add`
|
|
156
|
+
> defaults to `--scope local`, which writes the server under
|
|
157
|
+
> `projects."/your/dir".mcpServers` — it then works in that one directory and
|
|
158
|
+
> nowhere else, which reads exactly like DebugAI needing to be set up per repo.
|
|
159
|
+
> `debugai-mcp install` always writes the user scope. If you already ran the
|
|
160
|
+
> local-scope version, `debugai-mcp doctor` now tells you which one you have.
|
|
161
|
+
|
|
153
162
|
| Client | File |
|
|
154
163
|
|--------|------|
|
|
155
|
-
| Claude Code | `~/.claude.json` (or `claude mcp add debugai -- npx -y @debugai/mcp`) |
|
|
164
|
+
| Claude Code | `~/.claude.json`, top-level `mcpServers` (or `claude mcp add --scope user debugai -- npx -y @debugai/mcp`) |
|
|
156
165
|
| Claude Desktop | macOS `~/Library/Application Support/Claude/claude_desktop_config.json`, Windows `%APPDATA%\Claude\claude_desktop_config.json` |
|
|
157
166
|
| Cursor | `~/.cursor/mcp.json` |
|
|
158
167
|
| Windsurf | `~/.codeium/windsurf/mcp_config.json` |
|
|
@@ -190,6 +199,7 @@ Then run `npx -y @debugai/mcp login` once to store your key. If you would rather
|
|
|
190
199
|
- Simple errors route to a fast model. Ugly cross-file ones route to a stronger one on paid tiers. The `Model:` badge in each response tells you which one answered.
|
|
191
200
|
- Analyses run on DebugAI's servers. The error text, any snippet you pass, and — since 2.2 — the project source files the stack trace names are sent there, and Claude (Anthropic) does the analysis. The response lists every file that was read. Scope and limits are spelled out under [`debug_error`](#it-reads-the-source-the-trace-names-22). Privacy policy: [debugai.io/privacy](https://debugai.io/privacy?src=npm).
|
|
192
201
|
- Errors are remembered per project so a repeat hit starts from a fix that was already confirmed. The project identity is a hash of your repo root path; the path itself is never sent.
|
|
202
|
+
- The VS Code extension reads the project's `requirements.txt`, `pyproject.toml` and `package.json` and the interpreter the editor has selected, which is what lets it tell "not installed" apart from "installed under a different interpreter". This server sends none of that, so on a missing-module error you get the general answer and the check to run, not a verdict. You have a shell and it does not, so the honest division is that you run the check. Reporting those facts back through this server is planned.
|
|
193
203
|
|
|
194
204
|
## Troubleshooting
|
|
195
205
|
|
|
@@ -204,9 +214,36 @@ Run `npx -y @debugai/mcp doctor` first. It checks your Node version, whether a k
|
|
|
204
214
|
|
|
205
215
|
**Note on updates**: the analysis runs on DebugAI's servers, so improvements to
|
|
206
216
|
error parsing, retrieval and root-cause quality reach you without upgrading this
|
|
207
|
-
package.
|
|
208
|
-
|
|
209
|
-
|
|
217
|
+
package. Client releases are only for things that change on your machine.
|
|
218
|
+
|
|
219
|
+
Recent server-side work, all of it live for agents already:
|
|
220
|
+
|
|
221
|
+
- `ModuleNotFoundError` no longer opens with an install command. A read of every
|
|
222
|
+
one we had answered found five of eight rejected by the agent that received
|
|
223
|
+
them, for three different causes needing three different fixes: the package
|
|
224
|
+
was installed under another interpreter, the name was a local file, or the
|
|
225
|
+
import line was malformed. Rank 1 is now the check that tells those apart.
|
|
226
|
+
- A Python `SyntaxError` is no longer diagnosed as a JavaScript one, and the
|
|
227
|
+
framework is read from the error text rather than from what the repository
|
|
228
|
+
contains.
|
|
229
|
+
- Operating-system errors (`Access is denied.`, `No space left on device`) are
|
|
230
|
+
recognised as errors. Thirty were probed and twenty-eight had been refused.
|
|
231
|
+
- Credentials in the text you send are replaced before anything is stored or
|
|
232
|
+
reaches a model.
|
|
233
|
+
- pytest, unittest, jest, vitest and mocha output yields real file paths, so a
|
|
234
|
+
failing test gets cross-file context instead of none.
|
|
235
|
+
|
|
236
|
+
**2.4.0**: `report_outcome` gains `unused`. An agent that solved the problem its
|
|
237
|
+
own way had to report `failed`, which marks a fix as tried and beaten when
|
|
238
|
+
nothing of ours was ever run. Both tool surfaces, the npm server and the one
|
|
239
|
+
bundled in the VS Code extension, now take the same fields.
|
|
240
|
+
|
|
241
|
+
**2.3.0**: agents get the same four memory states the editor panel does.
|
|
242
|
+
`debug_error` had two branches, and a fix that had been tried and kept failing
|
|
243
|
+
read identically to one nobody had tried. To an agent those are the same
|
|
244
|
+
sentence, so the natural next move is to propose the fix that already did not
|
|
245
|
+
work. The four states now match the panel: confirmed and verified, confirmed,
|
|
246
|
+
unproven, and anti-pattern.
|
|
210
247
|
|
|
211
248
|
**2.2.0**: two things that were advertised but not delivered.
|
|
212
249
|
|
package/dist/backend.d.ts
CHANGED
|
@@ -56,9 +56,19 @@ export interface DebugResponse {
|
|
|
56
56
|
}
|
|
57
57
|
export interface OutcomeRequest {
|
|
58
58
|
debug_log_id: string;
|
|
59
|
-
|
|
59
|
+
/**
|
|
60
|
+
* 'unused' joined on 2026-08-26. An agent that read the fixes, used none of
|
|
61
|
+
* them and solved it another way previously had to report 'failed', which
|
|
62
|
+
* marks a fix as tried and beaten when nothing of ours was ever run.
|
|
63
|
+
*/
|
|
64
|
+
result: 'worked' | 'failed' | 'unused';
|
|
60
65
|
fix_rank?: number;
|
|
66
|
+
/** An error message observed after a failed fix. Not an explanation. */
|
|
61
67
|
new_error?: string;
|
|
68
|
+
/** What actually resolved it, when our answer was not what worked. */
|
|
69
|
+
actual_fix?: string;
|
|
70
|
+
/** What would have made the tool more useful here. About the tool, not the bug. */
|
|
71
|
+
tool_feedback?: string;
|
|
62
72
|
source: 'agent';
|
|
63
73
|
}
|
|
64
74
|
export interface OutcomeResponse {
|
package/dist/cli/commands.js
CHANGED
|
@@ -17,7 +17,7 @@ import { clearStoredKey, configPath, loadFileConfig, maskKey, resolveSettings, w
|
|
|
17
17
|
import { DeviceLinkError, startDeviceLink, waitForDeviceLink } from '../deviceLink.js';
|
|
18
18
|
import { DEFAULT_API_BASE } from '../constants.js';
|
|
19
19
|
import { detectedClients, findClient, isDetected, knownClients, } from './clients.js';
|
|
20
|
-
import { applyToClient,
|
|
20
|
+
import { applyToClient, findInstall } from './install.js';
|
|
21
21
|
import { FAIL, INFO, OK, WARN, bold, codeBox, dim, heading, openBrowser, say, yellow } from './ui.js';
|
|
22
22
|
// ── shared helpers ───────────────────────────────────────────────────────────
|
|
23
23
|
function flag(argv, name) {
|
|
@@ -215,7 +215,12 @@ function listClients(env) {
|
|
|
215
215
|
heading('Known MCP clients');
|
|
216
216
|
for (const c of knownClients(env)) {
|
|
217
217
|
const mark = isDetected(c) ? OK() : INFO();
|
|
218
|
-
const
|
|
218
|
+
const site = isDetected(c) ? findInstall(c) : null;
|
|
219
|
+
const state = !isDetected(c)
|
|
220
|
+
? 'not found'
|
|
221
|
+
: site?.scope === 'user' ? 'detected · debugai configured'
|
|
222
|
+
: site?.scope === 'project' ? 'detected · debugai configured (one directory only)'
|
|
223
|
+
: 'detected';
|
|
219
224
|
say(` ${mark} ${bold(c.id.padEnd(15))} ${c.label.padEnd(22)} ${dim(state)}`);
|
|
220
225
|
say(` ${dim(c.configPath ?? 'no config path on this OS')}`);
|
|
221
226
|
if (c.note)
|
|
@@ -329,10 +334,23 @@ export async function cmdDoctor(_argv, env = process.env) {
|
|
|
329
334
|
say(` ${INFO()} None detected. "debugai-mcp install --list" shows every supported client.`);
|
|
330
335
|
}
|
|
331
336
|
for (const c of detected) {
|
|
332
|
-
|
|
337
|
+
const site = findInstall(c);
|
|
338
|
+
if (site?.scope === 'user') {
|
|
333
339
|
pass(`${c.label} — debugai configured`, c.configPath ?? undefined);
|
|
334
|
-
|
|
340
|
+
}
|
|
341
|
+
else if (site?.scope === 'project') {
|
|
342
|
+
// Working, but only in one directory, and somebody who does not know that
|
|
343
|
+
// concludes DebugAI has to be set up per repo. That belief is what makes
|
|
344
|
+
// an MCP server not worth installing, so this is a warning with the exact
|
|
345
|
+
// command to widen it rather than a quiet pass.
|
|
346
|
+
say(` ${WARN()} ${yellow(`${c.label} — debugai configured for ONE directory only`)}`);
|
|
347
|
+
say(` ${dim(site.projectPath ?? '')}`);
|
|
348
|
+
say(` ${dim('`claude mcp add` defaults to --scope local. To use DebugAI in every repo:')}`);
|
|
349
|
+
say(` ${dim(`debugai-mcp install --client=${c.id}`)}`);
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
335
352
|
say(` ${WARN()} ${yellow(`${c.label} — installed but DebugAI is not in its config`)}\n ${dim(`fix: debugai-mcp install --client=${c.id}`)}`);
|
|
353
|
+
}
|
|
336
354
|
}
|
|
337
355
|
say();
|
|
338
356
|
if (hardFailures) {
|
package/dist/cli/install.d.ts
CHANGED
|
@@ -17,5 +17,42 @@ export interface InstallOptions {
|
|
|
17
17
|
remove?: boolean;
|
|
18
18
|
}
|
|
19
19
|
export declare function applyToClient(client: McpClient, opts?: InstallOptions): InstallResult;
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Where a client's config points at this server, if anywhere.
|
|
22
|
+
*
|
|
23
|
+
* ## Why this is not a boolean any more
|
|
24
|
+
*
|
|
25
|
+
* Claude Code stores MCP servers in two places in one file, and the difference
|
|
26
|
+
* decides whether DebugAI works in every repo or exactly one:
|
|
27
|
+
*
|
|
28
|
+
* ~/.claude.json
|
|
29
|
+
* ├── mcpServers ← user scope. Every directory, every session.
|
|
30
|
+
* └── projects
|
|
31
|
+
* └── /home/me/thing
|
|
32
|
+
* └── mcpServers ← local scope. That one directory only.
|
|
33
|
+
*
|
|
34
|
+
* `claude mcp add` writes the SECOND one, because `--scope local` is its
|
|
35
|
+
* default. This function used to read only the first, so the officially
|
|
36
|
+
* documented install path produced a config that `doctor` then reported as
|
|
37
|
+
* missing — a diagnostic contradicting a working install, which is worse than
|
|
38
|
+
* no diagnostic, because it sends somebody to re-run an installer that then
|
|
39
|
+
* creates a duplicate entry in the other scope.
|
|
40
|
+
*
|
|
41
|
+
* Reported by an agent running a real build on 2026-08-24, who lost a whole
|
|
42
|
+
* session to it. Their words: "two documented paths disagree, and the
|
|
43
|
+
* diagnostic sides with the wrong one."
|
|
44
|
+
*
|
|
45
|
+
* The scope is returned rather than flattened away because the two are not
|
|
46
|
+
* equally good. A local-scope install is the thing that makes somebody think
|
|
47
|
+
* they have to reconfigure DebugAI per directory, and telling them where it
|
|
48
|
+
* actually is turns that into a one-line fix.
|
|
49
|
+
*/
|
|
50
|
+
export interface InstallSite {
|
|
51
|
+
/** 'user' works everywhere. 'project' works in `projectPath` only. */
|
|
52
|
+
scope: 'user' | 'project';
|
|
53
|
+
/** Which directory it is scoped to, for 'project'. */
|
|
54
|
+
projectPath?: string;
|
|
55
|
+
}
|
|
56
|
+
export declare function findInstall(client: McpClient): InstallSite | null;
|
|
57
|
+
/** True when the client's config points at this server in ANY scope. */
|
|
21
58
|
export declare function isInstalled(client: McpClient): boolean;
|
package/dist/cli/install.js
CHANGED
|
@@ -135,16 +135,32 @@ export function applyToClient(client, opts = {}) {
|
|
|
135
135
|
warning,
|
|
136
136
|
};
|
|
137
137
|
}
|
|
138
|
-
|
|
139
|
-
export function isInstalled(client) {
|
|
138
|
+
export function findInstall(client) {
|
|
140
139
|
if (!client.configPath || !existsSync(client.configPath))
|
|
141
|
-
return
|
|
140
|
+
return null;
|
|
141
|
+
const has = (v) => Boolean(v && typeof v === 'object' && SERVER_NAME in v);
|
|
142
142
|
try {
|
|
143
143
|
const parsed = parseJsonc(readFileSync(client.configPath, 'utf8'));
|
|
144
|
-
const
|
|
145
|
-
|
|
144
|
+
const root = parsed.value;
|
|
145
|
+
if (has(root?.[serversKey(client.shape)]))
|
|
146
|
+
return { scope: 'user' };
|
|
147
|
+
// Claude Code's per-directory scope. Other clients have no `projects` key,
|
|
148
|
+
// so this loop simply never runs for them rather than needing a special case.
|
|
149
|
+
const projects = root?.projects;
|
|
150
|
+
if (projects && typeof projects === 'object') {
|
|
151
|
+
for (const [dir, cfg] of Object.entries(projects)) {
|
|
152
|
+
if (cfg && typeof cfg === 'object' && has(cfg.mcpServers)) {
|
|
153
|
+
return { scope: 'project', projectPath: dir };
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
146
158
|
}
|
|
147
159
|
catch {
|
|
148
|
-
return
|
|
160
|
+
return null;
|
|
149
161
|
}
|
|
150
162
|
}
|
|
163
|
+
/** True when the client's config points at this server in ANY scope. */
|
|
164
|
+
export function isInstalled(client) {
|
|
165
|
+
return findInstall(client) !== null;
|
|
166
|
+
}
|
package/dist/server.js
CHANGED
|
@@ -26,6 +26,12 @@ yourself only when you already know the relevant code is somewhere the trace
|
|
|
26
26
|
does not name.
|
|
27
27
|
|
|
28
28
|
After you apply or abandon a fix, call report_outcome with the debug_log_id.
|
|
29
|
+
Report it even when you ignored the answer and fixed it your own way: pass
|
|
30
|
+
result "unused" and put what actually worked in actualFix. A case DebugAI got
|
|
31
|
+
wrong is worth more to it than one it got right, and "unused" is not the same
|
|
32
|
+
as "failed" — reporting a fix as failed when you never ran it buries it for the
|
|
33
|
+
next person. If the tool could have served you better here, say so in
|
|
34
|
+
toolFeedback; that reaches the people who build it.
|
|
29
35
|
That is what turns a one-off answer into memory for the next person who hits
|
|
30
36
|
the same error. Skipping it costs the user the feature they are paying for.
|
|
31
37
|
|
|
@@ -1,3 +1,39 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import type { BackendConfig } from '../backend.js';
|
|
3
|
+
/**
|
|
4
|
+
* The channel back.
|
|
5
|
+
*
|
|
6
|
+
* ## Why this tool grew on 2026-08-26
|
|
7
|
+
*
|
|
8
|
+
* An external user's agent reported an outcome and wrote this into `newError`,
|
|
9
|
+
* a field described to it as "the error observed AFTER applying the fix":
|
|
10
|
+
*
|
|
11
|
+
* "The first corrected node -e command was still rewritten by PowerShell
|
|
12
|
+
* quoting; a separate PowerShell HTTP verification was used successfully
|
|
13
|
+
* instead."
|
|
14
|
+
*
|
|
15
|
+
* That is not an error. It is a post-mortem: our answer was aimed at the wrong
|
|
16
|
+
* layer, and here is what actually worked. It is the most useful thing anybody
|
|
17
|
+
* has ever sent this system, and the agent had to force it through the wrong
|
|
18
|
+
* slot because nothing here asked for it.
|
|
19
|
+
*
|
|
20
|
+
* So the schema now asks. Three changes, each closing a case an honest agent
|
|
21
|
+
* could not previously report:
|
|
22
|
+
*
|
|
23
|
+
* 'unused' — you read the fixes, used none of them, and solved it your
|
|
24
|
+
* own way. Previously only 'worked' and 'failed' existed, so
|
|
25
|
+
* this had to be misreported as a failure or not reported.
|
|
26
|
+
* Reporting it as a failure is actively harmful: it marks a
|
|
27
|
+
* fix as tried and beaten when nothing of ours was run.
|
|
28
|
+
* actualFix — what actually resolved it. Ground truth on a case we got
|
|
29
|
+
* wrong, which is worth more than a case we got right.
|
|
30
|
+
* toolFeedback — what would have made this tool more useful here. About the
|
|
31
|
+
* tool, not the bug, and kept separate for exactly that
|
|
32
|
+
* reason: a complaint about DebugAI must never end up
|
|
33
|
+
* promoted into somebody's project memory as a fix.
|
|
34
|
+
*
|
|
35
|
+
* A field on a tool agents already call beats a new tool they would have to be
|
|
36
|
+
* told about. This one has a measured ~50% attach rate; a new `send_feedback`
|
|
37
|
+
* starts at zero and competes for the same attention.
|
|
38
|
+
*/
|
|
3
39
|
export declare function registerReportOutcome(server: McpServer, config: BackendConfig): void;
|
|
@@ -2,41 +2,98 @@ import { z } from 'zod';
|
|
|
2
2
|
import { callOutcomeBackend } from '../backend.js';
|
|
3
3
|
import { mapBackendErrorToToolResult } from '../errors.js';
|
|
4
4
|
import { resolveAuth } from './authGate.js';
|
|
5
|
+
/**
|
|
6
|
+
* The channel back.
|
|
7
|
+
*
|
|
8
|
+
* ## Why this tool grew on 2026-08-26
|
|
9
|
+
*
|
|
10
|
+
* An external user's agent reported an outcome and wrote this into `newError`,
|
|
11
|
+
* a field described to it as "the error observed AFTER applying the fix":
|
|
12
|
+
*
|
|
13
|
+
* "The first corrected node -e command was still rewritten by PowerShell
|
|
14
|
+
* quoting; a separate PowerShell HTTP verification was used successfully
|
|
15
|
+
* instead."
|
|
16
|
+
*
|
|
17
|
+
* That is not an error. It is a post-mortem: our answer was aimed at the wrong
|
|
18
|
+
* layer, and here is what actually worked. It is the most useful thing anybody
|
|
19
|
+
* has ever sent this system, and the agent had to force it through the wrong
|
|
20
|
+
* slot because nothing here asked for it.
|
|
21
|
+
*
|
|
22
|
+
* So the schema now asks. Three changes, each closing a case an honest agent
|
|
23
|
+
* could not previously report:
|
|
24
|
+
*
|
|
25
|
+
* 'unused' — you read the fixes, used none of them, and solved it your
|
|
26
|
+
* own way. Previously only 'worked' and 'failed' existed, so
|
|
27
|
+
* this had to be misreported as a failure or not reported.
|
|
28
|
+
* Reporting it as a failure is actively harmful: it marks a
|
|
29
|
+
* fix as tried and beaten when nothing of ours was run.
|
|
30
|
+
* actualFix — what actually resolved it. Ground truth on a case we got
|
|
31
|
+
* wrong, which is worth more than a case we got right.
|
|
32
|
+
* toolFeedback — what would have made this tool more useful here. About the
|
|
33
|
+
* tool, not the bug, and kept separate for exactly that
|
|
34
|
+
* reason: a complaint about DebugAI must never end up
|
|
35
|
+
* promoted into somebody's project memory as a fix.
|
|
36
|
+
*
|
|
37
|
+
* A field on a tool agents already call beats a new tool they would have to be
|
|
38
|
+
* told about. This one has a measured ~50% attach rate; a new `send_feedback`
|
|
39
|
+
* starts at zero and competes for the same attention.
|
|
40
|
+
*/
|
|
5
41
|
export function registerReportOutcome(server, config) {
|
|
6
42
|
server.registerTool('report_outcome', {
|
|
7
43
|
title: 'Report Fix Outcome',
|
|
8
|
-
description: 'Report
|
|
9
|
-
'Call this ONCE
|
|
10
|
-
'
|
|
11
|
-
'
|
|
12
|
-
'
|
|
44
|
+
description: 'Report what happened after DebugAI answered — including when you did not use its fix. ' +
|
|
45
|
+
'Call this ONCE per debug_error response, passing the debug_log_id from it. ' +
|
|
46
|
+
'If you solved the problem another way, say so with result "unused" and put the real ' +
|
|
47
|
+
'fix in actualFix: a case DebugAI got wrong is worth more to it than one it got right. ' +
|
|
48
|
+
'If the tool could have helped you more here, say that in toolFeedback. ' +
|
|
49
|
+
'Confirmed rank-1 fixes are remembered for this project and returned to whoever hits ' +
|
|
50
|
+
'the same error next.',
|
|
13
51
|
inputSchema: {
|
|
14
52
|
debugLogId: z
|
|
15
53
|
.string()
|
|
16
54
|
.min(1)
|
|
17
55
|
.describe('The debug_log_id value from the debug_error response you are reporting on.'),
|
|
18
56
|
result: z
|
|
19
|
-
.enum(['worked', 'failed'])
|
|
20
|
-
.describe('"worked" =
|
|
57
|
+
.enum(['worked', 'failed', 'unused'])
|
|
58
|
+
.describe('"worked" = you applied a DebugAI fix and the error stopped. ' +
|
|
59
|
+
'"failed" = you applied one and it did not help (or made things worse). ' +
|
|
60
|
+
'"unused" = you did not apply any of them and resolved it another way. ' +
|
|
61
|
+
'Use "unused" rather than "failed" when nothing of ours was actually run. ' +
|
|
62
|
+
'They are different facts and reporting the wrong one buries a fix nobody tried.'),
|
|
21
63
|
fixRank: z
|
|
22
64
|
.number()
|
|
23
65
|
.int()
|
|
24
66
|
.min(1)
|
|
25
67
|
.max(3)
|
|
26
68
|
.optional()
|
|
27
|
-
.describe('Which ranked fix you applied (1-3). Rank 1 outcomes feed team error memory.'),
|
|
69
|
+
.describe('Which ranked fix you applied (1-3). Rank 1 outcomes feed team error memory. Omit for "unused".'),
|
|
28
70
|
newError: z
|
|
29
71
|
.string()
|
|
30
72
|
.max(4000)
|
|
31
73
|
.optional()
|
|
32
|
-
.describe('If result is "failed": the error observed AFTER applying the fix.'),
|
|
74
|
+
.describe('If result is "failed": the error observed AFTER applying the fix. An error message, not an explanation.'),
|
|
75
|
+
actualFix: z
|
|
76
|
+
.string()
|
|
77
|
+
.max(4000)
|
|
78
|
+
.optional()
|
|
79
|
+
.describe('What actually resolved the error, when it was not the fix DebugAI suggested. ' +
|
|
80
|
+
'Free text. Say what the real cause turned out to be and what you changed, ' +
|
|
81
|
+
'especially if the cause was in a different layer than the answer addressed ' +
|
|
82
|
+
'(the shell, the runtime version, the environment, a missing package).'),
|
|
83
|
+
toolFeedback: z
|
|
84
|
+
.string()
|
|
85
|
+
.max(2000)
|
|
86
|
+
.optional()
|
|
87
|
+
.describe('What would have made DebugAI more useful on THIS call. About the tool, not the bug: ' +
|
|
88
|
+
'context it lacked, a question it should have asked, an input shape it rejected, ' +
|
|
89
|
+
'a wrong assumption in its reasoning. This reaches the people who build it.'),
|
|
33
90
|
},
|
|
34
91
|
annotations: {
|
|
35
92
|
title: 'Report Fix Outcome',
|
|
36
93
|
// Deliberately NO readOnlyHint — this records telemetry server-side.
|
|
37
94
|
idempotentHint: true,
|
|
38
95
|
},
|
|
39
|
-
}, async ({ debugLogId, result, fixRank, newError }) => {
|
|
96
|
+
}, async ({ debugLogId, result, fixRank, newError, actualFix, toolFeedback }) => {
|
|
40
97
|
const gate = await resolveAuth(config);
|
|
41
98
|
if (!gate.ok)
|
|
42
99
|
return gate.result;
|
|
@@ -46,11 +103,22 @@ export function registerReportOutcome(server, config) {
|
|
|
46
103
|
result,
|
|
47
104
|
fix_rank: fixRank,
|
|
48
105
|
new_error: newError,
|
|
106
|
+
actual_fix: actualFix,
|
|
107
|
+
tool_feedback: toolFeedback,
|
|
49
108
|
source: 'agent',
|
|
50
109
|
}, gate.config);
|
|
110
|
+
// The acknowledgement is the only thing that tells an agent its report
|
|
111
|
+
// landed somewhere real. An 'unused' report especially: an agent that
|
|
112
|
+
// says "I ignored you and did it myself" and gets a generic thank-you
|
|
113
|
+
// learns that the field is decorative, and stops filling it.
|
|
51
114
|
const ack = result === 'worked'
|
|
52
115
|
? 'Outcome recorded: fix worked. Rank-1 confirmations are remembered for this project, so the next hit on this error starts from the confirmed fix.'
|
|
53
|
-
:
|
|
116
|
+
: result === 'unused'
|
|
117
|
+
? 'Outcome recorded: our fix was not used.' +
|
|
118
|
+
(actualFix
|
|
119
|
+
? ' The fix that actually worked was logged — that is the most useful thing this tool receives, because it is a case we got wrong.'
|
|
120
|
+
: ' If you know what actually resolved it, send it in actualFix: a wrong answer we can see is worth more than a right one we cannot.')
|
|
121
|
+
: 'Outcome recorded: fix failed. The follow-up error was logged and feeds directly into improving future answers. If you are still stuck, call debug_error again with the NEW error text.';
|
|
54
122
|
return {
|
|
55
123
|
content: [{ type: 'text', text: ack }],
|
|
56
124
|
structuredContent: { recorded: true, result },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@debugai/mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"mcpName": "io.github.1shizaan/debugai-mcp",
|
|
5
5
|
"description": "DebugAI MCP server. One command sets it up in Claude Desktop, Claude Code, Cursor, Zed, Windsurf, Cline or any MCP client: browser sign-in, no key pasting, no config editing.",
|
|
6
6
|
"license": "MIT",
|