New:Socket for Asana Is Now Available.Learn more
Get Started

@debugai/mcp

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@debugai/mcp - npm Package Compare versions

Comparing version
2.3.0
to
2.4.0
+11
-1
dist/backend.d.ts

@@ -59,5 +59,15 @@ import type { AuthProvider } from './auth.js';

debug_log_id: string;
result: 'worked' | 'failed';
/**
* 'unused' joined on 2026-08-26. An agent that read the fixes, used none of
* them and solved it another way previously had to report 'failed', which
* marks a fix as tried and beaten when nothing of ours was ever run.
*/
result: 'worked' | 'failed' | 'unused';
fix_rank?: number;
/** An error message observed after a failed fix. Not an explanation. */
new_error?: string;
/** What actually resolved it, when our answer was not what worked. */
actual_fix?: string;
/** What would have made the tool more useful here. About the tool, not the bug. */
tool_feedback?: string;
source: 'agent';

@@ -64,0 +74,0 @@ }

@@ -20,3 +20,3 @@ // The subcommands. Every one of these exists to delete a step a human used

import { detectedClients, findClient, isDetected, knownClients, } from './clients.js';
import { applyToClient, isInstalled } from './install.js';
import { applyToClient, findInstall } from './install.js';
import { FAIL, INFO, OK, WARN, bold, codeBox, dim, heading, openBrowser, say, yellow } from './ui.js';

@@ -219,3 +219,8 @@ // ── shared helpers ───────────────────────────────────────────────────────────

const mark = isDetected(c) ? OK() : INFO();
const state = isDetected(c) ? (isInstalled(c) ? 'detected · debugai configured' : 'detected') : 'not found';
const site = isDetected(c) ? findInstall(c) : null;
const state = !isDetected(c)
? 'not found'
: site?.scope === 'user' ? 'detected · debugai configured'
: site?.scope === 'project' ? 'detected · debugai configured (one directory only)'
: 'detected';
say(` ${mark} ${bold(c.id.padEnd(15))} ${c.label.padEnd(22)} ${dim(state)}`);

@@ -334,6 +339,19 @@ say(` ${dim(c.configPath ?? 'no config path on this OS')}`);

for (const c of detected) {
if (isInstalled(c))
const site = findInstall(c);
if (site?.scope === 'user') {
pass(`${c.label} — debugai configured`, c.configPath ?? undefined);
else
}
else if (site?.scope === 'project') {
// Working, but only in one directory, and somebody who does not know that
// concludes DebugAI has to be set up per repo. That belief is what makes
// an MCP server not worth installing, so this is a warning with the exact
// command to widen it rather than a quiet pass.
say(` ${WARN()} ${yellow(`${c.label} — debugai configured for ONE directory only`)}`);
say(` ${dim(site.projectPath ?? '')}`);
say(` ${dim('`claude mcp add` defaults to --scope local. To use DebugAI in every repo:')}`);
say(` ${dim(`debugai-mcp install --client=${c.id}`)}`);
}
else {
say(` ${WARN()} ${yellow(`${c.label} — installed but DebugAI is not in its config`)}\n ${dim(`fix: debugai-mcp install --client=${c.id}`)}`);
}
}

@@ -340,0 +358,0 @@ say();

@@ -20,3 +20,40 @@ import { type McpClient } from './clients.js';

export declare function applyToClient(client: McpClient, opts?: InstallOptions): InstallResult;
/** True when the client's config already points at this server. */
/**
* Where a client's config points at this server, if anywhere.
*
* ## Why this is not a boolean any more
*
* Claude Code stores MCP servers in two places in one file, and the difference
* decides whether DebugAI works in every repo or exactly one:
*
* ~/.claude.json
* ├── mcpServers ← user scope. Every directory, every session.
* └── projects
* └── /home/me/thing
* └── mcpServers ← local scope. That one directory only.
*
* `claude mcp add` writes the SECOND one, because `--scope local` is its
* default. This function used to read only the first, so the officially
* documented install path produced a config that `doctor` then reported as
* missing — a diagnostic contradicting a working install, which is worse than
* no diagnostic, because it sends somebody to re-run an installer that then
* creates a duplicate entry in the other scope.
*
* Reported by an agent running a real build on 2026-08-24, who lost a whole
* session to it. Their words: "two documented paths disagree, and the
* diagnostic sides with the wrong one."
*
* The scope is returned rather than flattened away because the two are not
* equally good. A local-scope install is the thing that makes somebody think
* they have to reconfigure DebugAI per directory, and telling them where it
* actually is turns that into a one-line fix.
*/
export interface InstallSite {
/** 'user' works everywhere. 'project' works in `projectPath` only. */
scope: 'user' | 'project';
/** Which directory it is scoped to, for 'project'. */
projectPath?: string;
}
export declare function findInstall(client: McpClient): InstallSite | null;
/** True when the client's config points at this server in ANY scope. */
export declare function isInstalled(client: McpClient): boolean;
+22
-6

@@ -138,14 +138,30 @@ // Writes the DebugAI server into MCP client config files.

}
/** True when the client's config already points at this server. */
export function isInstalled(client) {
export function findInstall(client) {
if (!client.configPath || !existsSync(client.configPath))
return false;
return null;
const has = (v) => Boolean(v && typeof v === 'object' && SERVER_NAME in v);
try {
const parsed = parseJsonc(readFileSync(client.configPath, 'utf8'));
const servers = parsed.value?.[serversKey(client.shape)];
return Boolean(servers && typeof servers === 'object' && SERVER_NAME in servers);
const root = parsed.value;
if (has(root?.[serversKey(client.shape)]))
return { scope: 'user' };
// Claude Code's per-directory scope. Other clients have no `projects` key,
// so this loop simply never runs for them rather than needing a special case.
const projects = root?.projects;
if (projects && typeof projects === 'object') {
for (const [dir, cfg] of Object.entries(projects)) {
if (cfg && typeof cfg === 'object' && has(cfg.mcpServers)) {
return { scope: 'project', projectPath: dir };
}
}
}
return null;
}
catch {
return false;
return null;
}
}
/** True when the client's config points at this server in ANY scope. */
export function isInstalled(client) {
return findInstall(client) !== null;
}

@@ -29,2 +29,8 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';

After you apply or abandon a fix, call report_outcome with the debug_log_id.
Report it even when you ignored the answer and fixed it your own way: pass
result "unused" and put what actually worked in actualFix. A case DebugAI got
wrong is worth more to it than one it got right, and "unused" is not the same
as "failed" — reporting a fix as failed when you never ran it buries it for the
next person. If the tool could have served you better here, say so in
toolFeedback; that reaches the people who build it.
That is what turns a one-off answer into memory for the next person who hits

@@ -31,0 +37,0 @@ the same error. Skipping it costs the user the feature they are paying for.

import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import type { BackendConfig } from '../backend.js';
/**
* The channel back.
*
* ## Why this tool grew on 2026-08-26
*
* An external user's agent reported an outcome and wrote this into `newError`,
* a field described to it as "the error observed AFTER applying the fix":
*
* "The first corrected node -e command was still rewritten by PowerShell
* quoting; a separate PowerShell HTTP verification was used successfully
* instead."
*
* That is not an error. It is a post-mortem: our answer was aimed at the wrong
* layer, and here is what actually worked. It is the most useful thing anybody
* has ever sent this system, and the agent had to force it through the wrong
* slot because nothing here asked for it.
*
* So the schema now asks. Three changes, each closing a case an honest agent
* could not previously report:
*
* 'unused' — you read the fixes, used none of them, and solved it your
* own way. Previously only 'worked' and 'failed' existed, so
* this had to be misreported as a failure or not reported.
* Reporting it as a failure is actively harmful: it marks a
* fix as tried and beaten when nothing of ours was run.
* actualFix — what actually resolved it. Ground truth on a case we got
* wrong, which is worth more than a case we got right.
* toolFeedback — what would have made this tool more useful here. About the
* tool, not the bug, and kept separate for exactly that
* reason: a complaint about DebugAI must never end up
* promoted into somebody's project memory as a fix.
*
* A field on a tool agents already call beats a new tool they would have to be
* told about. This one has a measured ~50% attach rate; a new `send_feedback`
* starts at zero and competes for the same attention.
*/
export declare function registerReportOutcome(server: McpServer, config: BackendConfig): void;

@@ -5,10 +5,48 @@ import { z } from 'zod';

import { resolveAuth } from './authGate.js';
/**
* The channel back.
*
* ## Why this tool grew on 2026-08-26
*
* An external user's agent reported an outcome and wrote this into `newError`,
* a field described to it as "the error observed AFTER applying the fix":
*
* "The first corrected node -e command was still rewritten by PowerShell
* quoting; a separate PowerShell HTTP verification was used successfully
* instead."
*
* That is not an error. It is a post-mortem: our answer was aimed at the wrong
* layer, and here is what actually worked. It is the most useful thing anybody
* has ever sent this system, and the agent had to force it through the wrong
* slot because nothing here asked for it.
*
* So the schema now asks. Three changes, each closing a case an honest agent
* could not previously report:
*
* 'unused' — you read the fixes, used none of them, and solved it your
* own way. Previously only 'worked' and 'failed' existed, so
* this had to be misreported as a failure or not reported.
* Reporting it as a failure is actively harmful: it marks a
* fix as tried and beaten when nothing of ours was run.
* actualFix — what actually resolved it. Ground truth on a case we got
* wrong, which is worth more than a case we got right.
* toolFeedback — what would have made this tool more useful here. About the
* tool, not the bug, and kept separate for exactly that
* reason: a complaint about DebugAI must never end up
* promoted into somebody's project memory as a fix.
*
* A field on a tool agents already call beats a new tool they would have to be
* told about. This one has a measured ~50% attach rate; a new `send_feedback`
* starts at zero and competes for the same attention.
*/
export function registerReportOutcome(server, config) {
server.registerTool('report_outcome', {
title: 'Report Fix Outcome',
description: 'Report whether a DebugAI fix actually worked after you applied it. ' +
'Call this ONCE after applying (or abandoning) a fix from debug_error, passing the ' +
'debug_log_id from that response. If the fix failed, include the new error text — ' +
'failed-fix follow-ups directly improve future answers for this codebase, and ' +
'confirmed rank-1 fixes are remembered for the whole team.',
description: 'Report what happened after DebugAI answered — including when you did not use its fix. ' +
'Call this ONCE per debug_error response, passing the debug_log_id from it. ' +
'If you solved the problem another way, say so with result "unused" and put the real ' +
'fix in actualFix: a case DebugAI got wrong is worth more to it than one it got right. ' +
'If the tool could have helped you more here, say that in toolFeedback. ' +
'Confirmed rank-1 fixes are remembered for this project and returned to whoever hits ' +
'the same error next.',
inputSchema: {

@@ -20,4 +58,8 @@ debugLogId: z

result: z
.enum(['worked', 'failed'])
.describe('"worked" = the fix resolved the error; "failed" = it did not (or made things worse).'),
.enum(['worked', 'failed', 'unused'])
.describe('"worked" = you applied a DebugAI fix and the error stopped. ' +
'"failed" = you applied one and it did not help (or made things worse). ' +
'"unused" = you did not apply any of them and resolved it another way. ' +
'Use "unused" rather than "failed" when nothing of ours was actually run — ' +
'they are different facts and reporting the wrong one buries a fix nobody tried.'),
fixRank: z

@@ -29,3 +71,3 @@ .number()

.optional()
.describe('Which ranked fix you applied (1-3). Rank 1 outcomes feed team error memory.'),
.describe('Which ranked fix you applied (1-3). Rank 1 outcomes feed team error memory. Omit for "unused".'),
newError: z

@@ -35,3 +77,18 @@ .string()

.optional()
.describe('If result is "failed": the error observed AFTER applying the fix.'),
.describe('If result is "failed": the error observed AFTER applying the fix. An error message, not an explanation.'),
actualFix: z
.string()
.max(4000)
.optional()
.describe('What actually resolved the error, when it was not the fix DebugAI suggested. ' +
'Free text. Say what the real cause turned out to be and what you changed — ' +
'especially if the cause was in a different layer than the answer addressed ' +
'(the shell, the runtime version, the environment, a missing package).'),
toolFeedback: z
.string()
.max(2000)
.optional()
.describe('What would have made DebugAI more useful on THIS call. About the tool, not the bug: ' +
'context it lacked, a question it should have asked, an input shape it rejected, ' +
'a wrong assumption in its reasoning. This reaches the people who build it.'),
},

@@ -43,3 +100,3 @@ annotations: {

},
}, async ({ debugLogId, result, fixRank, newError }) => {
}, async ({ debugLogId, result, fixRank, newError, actualFix, toolFeedback }) => {
const gate = await resolveAuth(config);

@@ -54,7 +111,18 @@ if (!gate.ok)

new_error: newError,
actual_fix: actualFix,
tool_feedback: toolFeedback,
source: 'agent',
}, gate.config);
// The acknowledgement is the only thing that tells an agent its report
// landed somewhere real. An 'unused' report especially: an agent that
// says "I ignored you and did it myself" and gets a generic thank-you
// learns that the field is decorative, and stops filling it.
const ack = result === 'worked'
? 'Outcome recorded: fix worked. Rank-1 confirmations are remembered for this project, so the next hit on this error starts from the confirmed fix.'
: '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.';
: result === 'unused'
? 'Outcome recorded: our fix was not used.' +
(actualFix
? ' The fix that actually worked was logged — that is the most useful thing this tool receives, because it is a case we got wrong.'
: ' 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.')
: '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.';
return {

@@ -61,0 +129,0 @@ content: [{ type: 'text', text: ack }],

{
"name": "@debugai/mcp",
"version": "2.3.0",
"version": "2.4.0",
"mcpName": "io.github.1shizaan/debugai-mcp",

@@ -5,0 +5,0 @@ "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.",

@@ -153,5 +153,12 @@ # @debugai/mcp

> **On Claude Code, `--scope user` is the part that matters.** `claude mcp add`
> defaults to `--scope local`, which writes the server under
> `projects."/your/dir".mcpServers` — it then works in that one directory and
> nowhere else, which reads exactly like DebugAI needing to be set up per repo.
> `debugai-mcp install` always writes the user scope. If you already ran the
> local-scope version, `debugai-mcp doctor` now tells you which one you have.
| Client | File |
|--------|------|
| Claude Code | `~/.claude.json` (or `claude mcp add debugai -- npx -y @debugai/mcp`) |
| Claude Code | `~/.claude.json`, top-level `mcpServers` (or `claude mcp add --scope user debugai -- npx -y @debugai/mcp`) |
| Claude Desktop | macOS `~/Library/Application Support/Claude/claude_desktop_config.json`, Windows `%APPDATA%\Claude\claude_desktop_config.json` |

@@ -158,0 +165,0 @@ | Cursor | `~/.cursor/mcp.json` |