@debugai/mcp 1.1.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,29 @@
1
+ export async function resolveAuth(config) {
2
+ if (!config.auth) {
3
+ return { ok: true, config }; // tests and direct embedders pass a fixed key
4
+ }
5
+ const state = await config.auth.ensure();
6
+ if (state.ok) {
7
+ return {
8
+ ok: true,
9
+ config: state.apiKey === config.apiKey ? config : { ...config, apiKey: state.apiKey },
10
+ };
11
+ }
12
+ return {
13
+ ok: false,
14
+ result: {
15
+ isError: true,
16
+ content: [{ type: 'text', text: state.text }],
17
+ structuredContent: state.reason === 'link_pending'
18
+ ? {
19
+ error_type: 'not_linked',
20
+ user_code: state.userCode,
21
+ verification_uri: state.verificationUri,
22
+ // Retryable on purpose: the SAME call succeeds once the human
23
+ // confirms. Agents should retry after telling the user, not give up.
24
+ retryable: true,
25
+ }
26
+ : { error_type: 'not_linked', retryable: true },
27
+ },
28
+ };
29
+ }
@@ -1,4 +1,5 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import type { BackendConfig, DebugFix } from '../backend.js';
3
+ export declare function formatVerification(fix: DebugFix): string;
3
4
  export declare function formatFix(fix: DebugFix, index: number): string;
4
5
  export declare function registerDebugError(server: McpServer, config: BackendConfig): void;
@@ -1,9 +1,23 @@
1
1
  import { z } from 'zod';
2
2
  import { callDebugBackend } from '../backend.js';
3
3
  import { mapBackendErrorToToolResult } from '../errors.js';
4
+ import { resolveAuth } from './authGate.js';
5
+ // Tri-state verification labeling (docs/plan-v2-contract-phase1.md §1).
6
+ // The null case is rendered ON PURPOSE: a confidence number nothing checked
7
+ // must never look the same as one that was mechanically verified.
8
+ export function formatVerification(fix) {
9
+ if (fix.verified === true) {
10
+ return `✓ Verified — ${fix.verification_reason ?? 'mechanical check passed'}`;
11
+ }
12
+ if (fix.verified === false) {
13
+ return `✗ Failed mechanical check (confidence capped) — ${fix.verification_reason ?? 'check failed'}`;
14
+ }
15
+ return '· Not verified — confidence is the model\'s own estimate; nothing checked this fix.';
16
+ }
4
17
  export function formatFix(fix, index) {
5
18
  const lines = [
6
19
  `\n**Fix ${index} (${fix.confidence}% confidence)** — ${fix.title}`,
20
+ formatVerification(fix),
7
21
  fix.description,
8
22
  ];
9
23
  if (fix.code) {
@@ -12,6 +26,15 @@ export function formatFix(fix, index) {
12
26
  if (fix.line_hint) {
13
27
  lines.push(`_Location: ${fix.line_hint}_`);
14
28
  }
29
+ if (fix.edits?.length) {
30
+ lines.push('_Machine-applicable edit available: `edits` on this fix in structuredContent carries the exact old/new strings (apply with your Edit/replace tool)._');
31
+ }
32
+ if (fix.unified_diff) {
33
+ lines.push('```diff', fix.unified_diff.trimEnd(), '```');
34
+ }
35
+ if (fix.verify_with) {
36
+ lines.push(`_Syntax-level check after applying: \`${fix.verify_with}\`_`);
37
+ }
15
38
  return lines.join('\n');
16
39
  }
17
40
  export function registerDebugError(server, config) {
@@ -22,7 +45,8 @@ export function registerDebugError(server, config) {
22
45
  '"debug this stack trace", "fix this exception", "analyze this traceback", or shows a ' +
23
46
  'Traceback / TypeError / ReferenceError / AttributeError. ' +
24
47
  'Works for Python, JavaScript, TypeScript, Go, Rust. ' +
25
- 'Returns root cause explanation plus up to 3 ranked fixes with code patches.',
48
+ 'Returns root cause explanation plus up to 3 ranked fixes with machine-applicable code edits. ' +
49
+ 'After applying a fix, report whether it worked via the report_outcome tool.',
26
50
  inputSchema: {
27
51
  errorText: z
28
52
  .string()
@@ -46,6 +70,9 @@ export function registerDebugError(server, config) {
46
70
  title: 'Debug Error',
47
71
  },
48
72
  }, async ({ errorText, language, codeSnippet, filePath }) => {
73
+ const gate = await resolveAuth(config);
74
+ if (!gate.ok)
75
+ return gate.result;
49
76
  try {
50
77
  const result = await callDebugBackend({
51
78
  error_message: errorText,
@@ -55,7 +82,7 @@ export function registerDebugError(server, config) {
55
82
  // framework_hint deliberately omitted: a language ('python') is not a
56
83
  // framework ('fastapi'), and sending it bypasses the engine's
57
84
  // framework detection — FastAPI/React errors lose their expert hints.
58
- }, config);
85
+ }, gate.config);
59
86
  const sections = ['## Root Cause', result.root_cause ?? '(no root cause returned)'];
60
87
  if (result.fixes?.length) {
61
88
  sections.push('\n## Fixes');
@@ -79,16 +106,23 @@ export function registerDebugError(server, config) {
79
106
  if (badges.length) {
80
107
  sections.push(`\n---\n_${badges.join(' · ')}_`);
81
108
  }
109
+ if (result.debug_log_id) {
110
+ sections.push(`\nAfter applying a fix, call report_outcome with debugLogId "${result.debug_log_id}", ` +
111
+ 'the fixRank you applied, and result "worked" or "failed" (include newError text if it failed).');
112
+ }
82
113
  const text = sections.join('\n');
83
114
  return {
84
115
  content: [{ type: 'text', text }],
85
116
  structuredContent: {
117
+ schema_version: result.schema_version ?? '1.0',
86
118
  root_cause: result.root_cause,
87
119
  fixes: result.fixes,
88
120
  framework_detected: result.framework_detected,
89
121
  model_used: result.model_used,
90
122
  cached: result.cached ?? false,
91
123
  has_project_context: result.has_project_context ?? false,
124
+ debug_log_id: result.debug_log_id ?? null,
125
+ error_signature: result.error_signature ?? null,
92
126
  },
93
127
  };
94
128
  }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { BackendConfig } from '../backend.js';
3
+ export declare function registerReportOutcome(server: McpServer, config: BackendConfig): void;
@@ -0,0 +1,63 @@
1
+ import { z } from 'zod';
2
+ import { callOutcomeBackend } from '../backend.js';
3
+ import { mapBackendErrorToToolResult } from '../errors.js';
4
+ import { resolveAuth } from './authGate.js';
5
+ export function registerReportOutcome(server, config) {
6
+ server.registerTool('report_outcome', {
7
+ title: 'Report Fix Outcome',
8
+ description: 'Report whether a DebugAI fix actually worked after you applied it. ' +
9
+ 'Call this ONCE after applying (or abandoning) a fix from debug_error, passing the ' +
10
+ 'debug_log_id from that response. If the fix failed, include the new error text — ' +
11
+ 'failed-fix follow-ups directly improve future answers for this codebase, and ' +
12
+ 'confirmed rank-1 fixes are remembered for the whole team.',
13
+ inputSchema: {
14
+ debugLogId: z
15
+ .string()
16
+ .min(1)
17
+ .describe('The debug_log_id value from the debug_error response you are reporting on.'),
18
+ result: z
19
+ .enum(['worked', 'failed'])
20
+ .describe('"worked" = the fix resolved the error; "failed" = it did not (or made things worse).'),
21
+ fixRank: z
22
+ .number()
23
+ .int()
24
+ .min(1)
25
+ .max(3)
26
+ .optional()
27
+ .describe('Which ranked fix you applied (1-3). Rank 1 outcomes feed team error memory.'),
28
+ newError: z
29
+ .string()
30
+ .max(4000)
31
+ .optional()
32
+ .describe('If result is "failed": the error observed AFTER applying the fix.'),
33
+ },
34
+ annotations: {
35
+ title: 'Report Fix Outcome',
36
+ // Deliberately NO readOnlyHint — this records telemetry server-side.
37
+ idempotentHint: true,
38
+ },
39
+ }, async ({ debugLogId, result, fixRank, newError }) => {
40
+ const gate = await resolveAuth(config);
41
+ if (!gate.ok)
42
+ return gate.result;
43
+ try {
44
+ await callOutcomeBackend({
45
+ debug_log_id: debugLogId,
46
+ result,
47
+ fix_rank: fixRank,
48
+ new_error: newError,
49
+ source: 'agent',
50
+ }, gate.config);
51
+ const ack = result === 'worked'
52
+ ? '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
+ : '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
+ return {
55
+ content: [{ type: 'text', text: ack }],
56
+ structuredContent: { recorded: true, result },
57
+ };
58
+ }
59
+ catch (err) {
60
+ return mapBackendErrorToToolResult(err);
61
+ }
62
+ });
63
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@debugai/mcp",
3
- "version": "1.1.0",
4
- "description": "DebugAI MCP server hand any error to DebugAI from Claude Desktop, Claude Code, Cursor, Zed, or any MCP client and get root cause + ranked fixes.",
3
+ "version": "2.1.0",
4
+ "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.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "bin": {