@debugai/mcp 2.0.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.
package/README.md CHANGED
@@ -1,110 +1,69 @@
1
1
  # @debugai/mcp
2
2
 
3
- DebugAI as an MCP server. Your agent hands an error to `debug_error` and gets
4
- back the root cause plus up to 3 ranked fixes with code patches. Works in
5
- Claude Desktop, Claude Code, Cursor, Zed, Windsurf, and any other MCP client.
3
+ <p align="center">
4
+ <a href="https://www.npmjs.com/package/@debugai/mcp"><img src="https://img.shields.io/npm/v/@debugai/mcp?color=0A0A0F&label=npm" alt="npm version"></a>
5
+ <img src="https://img.shields.io/badge/node-%3E%3D18-0A0A0F" alt="Node 18+">
6
+ <img src="https://img.shields.io/badge/license-MIT-0A0A0F" alt="MIT license">
7
+ </p>
6
8
 
7
- Until now this server only shipped inside the
8
- [DebugAI VS Code extension](https://marketplace.visualstudio.com/items?itemName=debugai.debugai).
9
- This package is the same server, standalone. No VS Code required.
9
+ Give your coding agent a debugger instead of a grep loop.
10
10
 
11
- ## Setup
12
-
13
- 1. Create a free account at [debugai.io](https://debugai.io) (10 debugs/day, no card).
14
- 2. Copy your API key (`dbg_...`) from [debugai.io/dashboard](https://debugai.io/dashboard).
15
- 3. Add the server to your MCP client (snippets below). Node 18+ required.
11
+ Your agent hands an error to `debug_error` and gets back the root cause, the exact file and line, and up to 3 ranked fixes as ready-to-apply edits. Each fix is labeled with whether a mechanical check actually passed, so the agent knows which ones were checked and which are the model's own estimate.
16
12
 
17
- ### Set the key once for every client (optional)
13
+ Auto-configures Claude Code, Claude Desktop, Cursor, Windsurf, Zed, Gemini CLI, and Cline. Works in any other MCP client with a manual entry. Node 18 or later.
18
14
 
19
- Instead of repeating the key in each client's `env` block, write it to
20
- `~/.debugai/config.json`:
15
+ ## Setup
21
16
 
22
- ```json
23
- { "api_key": "dbg_your_key_here" }
17
+ ```bash
18
+ npx -y @debugai/mcp setup
24
19
  ```
25
20
 
26
- Every MCP client launching `npx -y @debugai/mcp` picks it up you can then
27
- drop the `env` block from the snippets below entirely. An explicit
28
- `DEBUGAI_API_KEY` env var still wins over the file.
21
+ That is the whole thing. It signs you in through your browser (no key to find or copy), writes the config for every MCP client it finds on this machine, then checks that all of it actually works.
29
22
 
30
- ### Claude Code
23
+ Restart the clients it names and your agent has the tools.
31
24
 
32
- ```bash
33
- claude mcp add debugai --env DEBUGAI_API_KEY=dbg_your_key_here -- npx -y @debugai/mcp
34
- ```
35
-
36
- ### Claude Desktop
25
+ Prefer to read first? [debugai.io/start?src=npm](https://debugai.io/start?src=npm) walks the same thing per client.
37
26
 
38
- `claude_desktop_config.json` (Settings, Developer, Edit Config):
27
+ ### What that command does to your machine
39
28
 
40
- ```json
41
- {
42
- "mcpServers": {
43
- "debugai": {
44
- "command": "npx",
45
- "args": ["-y", "@debugai/mcp"],
46
- "env": { "DEBUGAI_API_KEY": "dbg_your_key_here" }
47
- }
48
- }
49
- }
50
- ```
29
+ Worth knowing before you run something that edits your editor config:
51
30
 
52
- ### Cursor
31
+ - Signs you in with a short code you confirm in the browser. Free account, 10 debugs a day, no card.
32
+ - Stores your key in `~/.debugai/config.json` with `0600` permissions. That is the only file that ever holds it.
33
+ - Adds a `debugai` entry to the config of each MCP client it detects. Every file is backed up first (`<file>.debugai-backup-<timestamp>`), every other setting in the file is preserved, and a file it cannot parse is left alone and reported instead. One caveat stated plainly: if your config contains comments, the rewrite drops them, because JSON has nowhere to put them. You get a warning before it happens and the backup still has them.
34
+ - Skips VS Code by default, because the [DebugAI extension](https://marketplace.visualstudio.com/items?itemName=debugai.debugai) already registers this server there and a second entry would show every tool twice. `install --client=vscode` does it anyway if you want the server without the extension.
35
+ - Never writes your key into a client config. Client configs get committed to repos. Keys should not.
53
36
 
54
- `~/.cursor/mcp.json` (or `.cursor/mcp.json` per project):
37
+ Preview it without writing anything:
55
38
 
56
- ```json
57
- {
58
- "mcpServers": {
59
- "debugai": {
60
- "command": "npx",
61
- "args": ["-y", "@debugai/mcp"],
62
- "env": { "DEBUGAI_API_KEY": "dbg_your_key_here" }
63
- }
64
- }
65
- }
39
+ ```bash
40
+ npx -y @debugai/mcp install --dry-run
66
41
  ```
67
42
 
68
- ### Zed
69
-
70
- `settings.json`:
43
+ Undo all of it:
71
44
 
72
- ```json
73
- {
74
- "context_servers": {
75
- "debugai": {
76
- "command": {
77
- "path": "npx",
78
- "args": ["-y", "@debugai/mcp"],
79
- "env": { "DEBUGAI_API_KEY": "dbg_your_key_here" }
80
- }
81
- }
82
- }
83
- }
45
+ ```bash
46
+ npx -y @debugai/mcp uninstall # removes the entry from every client config
47
+ npx -y @debugai/mcp logout # removes the stored key
84
48
  ```
85
49
 
86
- ### Windsurf
50
+ ### Commands
87
51
 
88
- `~/.codeium/windsurf/mcp_config.json`:
52
+ | Command | What it does |
53
+ |---------|--------------|
54
+ | `setup` | `login` then `install`, then verifies. The one you want. |
55
+ | `login` | Browser sign-in. `--key dbg_…` to paste a key instead (CI, air-gapped boxes). `--force` to re-link. |
56
+ | `logout` | Removes the stored key. |
57
+ | `status` | Which key and account are active right now. |
58
+ | `install` | Writes client configs. `--list`, `--client=cursor`, `--all`, `--dry-run`, `--remove`. |
59
+ | `uninstall` | Removes the entry from every client config. |
60
+ | `doctor` | Diagnoses a broken setup: key, API reachability, per-client wiring. |
89
61
 
90
- ```json
91
- {
92
- "mcpServers": {
93
- "debugai": {
94
- "command": "npx",
95
- "args": ["-y", "@debugai/mcp"],
96
- "env": { "DEBUGAI_API_KEY": "dbg_your_key_here" }
97
- }
98
- }
99
- }
100
- ```
62
+ `npx -y @debugai/mcp install --list` prints every supported client, where its config lives on your OS, and whether DebugAI is already in it.
101
63
 
102
- ### VS Code
64
+ ### Signing in from inside a chat
103
65
 
104
- You don't need this package. The
105
- [DebugAI extension](https://marketplace.visualstudio.com/items?itemName=debugai.debugai)
106
- registers the MCP server automatically (VS Code 1.101+) and adds one-click
107
- fix apply, proactive scan, and codebase indexing on top.
66
+ If your agent calls a DebugAI tool before you have signed in, the tool answers with a short code and a URL instead of an error. Confirm it in the browser, tell the agent to try again, and the call goes through. No config editing, and no client restart, because the key is re-read on every call.
108
67
 
109
68
  ## The tools
110
69
 
@@ -119,18 +78,9 @@ Give it an error, get an analysis.
119
78
  | `codeSnippet` | no | Code around the failing line, if the agent has it. |
120
79
  | `filePath` | no | Path to the file that threw. |
121
80
 
122
- Returns the root cause, up to 3 fixes ranked by confidence, the detected
123
- framework, and whether the answer came from cache. Since 2.0 each fix also
124
- carries, where derivable: `edits` (exact old/new strings your agent's edit
125
- tool can apply directly), `unified_diff`, and `verify_with` (a syntax-level
126
- check command to run after applying). Read-only: it never touches your
127
- files. Applying a fix is your agent's (and your) call.
81
+ Returns the root cause, up to 3 fixes ranked by confidence, the detected framework, and whether the answer came from cache. Since 2.0 each fix also carries, where derivable: `edits` (exact old/new strings your agent's edit tool can apply directly), `unified_diff`, and `verify_with` (a syntax-level check command to run after applying). Read-only: it never touches your files. Applying a fix is your agent's call, and yours.
128
82
 
129
- Every fix is labeled with its verification state, and there are three of
130
- them, not two: **verified** (a mechanical check passed — currently
131
- parse/import classes), **failed check** (confidence capped hard), or **not
132
- verified** (the confidence number is the model's own estimate — nothing
133
- checked it). We label the third case instead of hiding it.
83
+ Every fix is labeled with its verification state, and there are three of them, not two: **verified** (a mechanical check passed, currently parse and import classes), **failed check** (confidence capped hard), or **not verified** (the confidence number is the model's own estimate, nothing checked it). We label the third case instead of hiding it.
134
84
 
135
85
  ### `report_outcome`
136
86
 
@@ -143,11 +93,7 @@ Tell DebugAI whether an applied fix actually worked.
143
93
  | `fixRank` | no | Which ranked fix was applied (1-3). |
144
94
  | `newError` | no | If it failed: the error you saw after applying. |
145
95
 
146
- Confirmed rank-1 fixes are remembered per project (the next hit on the same
147
- error starts from the confirmed fix); failed-fix follow-ups are the
148
- feedback that improves future answers. Agents are asked to call this once
149
- per applied fix — same pipeline human feedback flows through in the VS Code
150
- extension.
96
+ Confirmed rank-1 fixes are remembered per project, so the next hit on the same error starts from the confirmed fix. Failed-fix follow-ups are the feedback that improves future answers. Agents are asked to call this once per applied fix, through the same pipeline human feedback flows through in the VS Code extension.
151
97
 
152
98
  Example, in Claude Code:
153
99
 
@@ -157,11 +103,66 @@ Example, in Claude Code:
157
103
  > **Root cause:** `db.session` is used after the request context closed.
158
104
  > **Fix 1 (94% confidence):** move the query inside the request handler...
159
105
 
106
+ ### Making your agent reach for it
107
+
108
+ The server tells connecting agents what it is for, but a rule in your project file is the deterministic version. Add this to `CLAUDE.md`, `.cursorrules`, or whatever your agent reads:
109
+
110
+ ```
111
+ On any runtime error, exception, or failing test, call the debugai
112
+ debug_error tool before attempting your own fix. After applying a fix,
113
+ call report_outcome so the project's error memory stays accurate.
114
+ ```
115
+
116
+ ## VS Code
117
+
118
+ 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.
119
+
120
+ ## Manual setup
121
+
122
+ `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:
123
+
124
+ ```json
125
+ {
126
+ "mcpServers": {
127
+ "debugai": {
128
+ "command": "npx",
129
+ "args": ["-y", "@debugai/mcp"]
130
+ }
131
+ }
132
+ }
133
+ ```
134
+
135
+ Where it goes:
136
+
137
+ | Client | File |
138
+ |--------|------|
139
+ | Claude Code | `~/.claude.json` (or `claude mcp add debugai -- npx -y @debugai/mcp`) |
140
+ | Claude Desktop | macOS `~/Library/Application Support/Claude/claude_desktop_config.json`, Windows `%APPDATA%\Claude\claude_desktop_config.json` |
141
+ | Cursor | `~/.cursor/mcp.json` |
142
+ | Windsurf | `~/.codeium/windsurf/mcp_config.json` |
143
+ | Gemini CLI | `~/.gemini/settings.json` |
144
+ | Cline | VS Code globalStorage, `saoudrizwan.claude-dev/settings/cline_mcp_settings.json` |
145
+
146
+ Zed uses a different key and a nested command:
147
+
148
+ ```json
149
+ {
150
+ "context_servers": {
151
+ "debugai": {
152
+ "source": "custom",
153
+ "command": { "path": "npx", "args": ["-y", "@debugai/mcp"] }
154
+ }
155
+ }
156
+ }
157
+ ```
158
+
159
+ Then run `npx -y @debugai/mcp login` once to store your key. If you would rather set the key per client, `DEBUGAI_API_KEY` in that client's `env` block still works and still wins over the stored one.
160
+
160
161
  ## Environment variables
161
162
 
162
163
  | Variable | Default | Description |
163
164
  |----------|---------|-------------|
164
- | `DEBUGAI_API_KEY` | (none) | Your API key. Falls back to `api_key` in the config file. |
165
+ | `DEBUGAI_API_KEY` | (none) | Your API key. Overrides `api_key` in the config file. |
165
166
  | `DEBUGAI_API_BASE` | DebugAI production | Override for self-hosted or staging setups. Falls back to `api_base` in the config file. |
166
167
  | `DEBUGAI_TIMEOUT_MS` | `150000` | Per-request deadline. Deep analyses can take 30-90s. |
167
168
  | `DEBUGAI_CONFIG_PATH` | `~/.debugai/config.json` | Alternate config file location. Rarely needed. |
@@ -170,22 +171,23 @@ Example, in Claude Code:
170
171
 
171
172
  - Free tier: 10 debugs/day. Pro ($12/mo): 1,000/mo soft cap, never hard-blocked at it.
172
173
  - When you hit the daily cap the tool says so and stops. It will not silently retry.
173
- - Simple errors route to a fast model; ugly cross-file ones route to a
174
- stronger one on paid tiers. The `Model:` badge in each response tells you
175
- which one answered.
176
- - Analyses run on DebugAI's servers. The error text and any snippet you pass
177
- are sent there. Privacy policy: [debugai.io/privacy](https://debugai.io/privacy).
174
+ - 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.
175
+ - Analyses run on DebugAI's servers. The error text and any snippet you pass are sent there, and Claude (Anthropic) does the analysis. Privacy policy: [debugai.io/privacy](https://debugai.io/privacy?src=npm).
178
176
 
179
177
  ## Troubleshooting
180
178
 
181
- - **"authentication failed"**: key missing or wrong. Check the `env` block in
182
- your client config or `~/.debugai/config.json`, restart the client. Keys
183
- start with `dbg_`.
184
- - **Nothing happens on `npx @debugai/mcp`**: correct. It's a stdio server that
185
- waits for an MCP client to speak first. Run `npx @debugai/mcp --help` to
186
- verify the install.
187
- - **Timeouts**: deep analyses can take up to 90s. If your client has its own
188
- tool timeout, raise it above that.
179
+ Run `npx -y @debugai/mcp doctor` first. It checks your Node version, whether a key is stored and where it came from, whether that key still authenticates against the API, the permissions on the config file, and which detected clients are missing the DebugAI entry. Most answers are in that output.
180
+
181
+ - **"authentication failed"**: the key was rotated or revoked. Run `npx -y @debugai/mcp login --force`.
182
+ - **Tools do not appear in the client**: the client was not restarted, or it reads a different config file. `install --list` shows which file was written.
183
+ - **Nothing happens on `npx @debugai/mcp`**: correct. It is a stdio server waiting for an MCP client to speak first. Use `--help` to verify the install.
184
+ - **Timeouts**: deep analyses can take up to 90s. If your client has its own tool timeout, raise it above that.
185
+
186
+ ## Changelog
187
+
188
+ **2.1.0**: one-command setup. Browser sign-in over a device link (no key pasting), automatic client config writing with backups, `doctor` for diagnosing a broken setup, and in-conversation sign-in when an agent calls a tool before you have an account.
189
+
190
+ **2.0.0**: `report_outcome` tool, ready-to-apply `edits` per fix, and the three-state verification label.
189
191
 
190
192
  ## Development
191
193
 
package/dist/auth.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ export interface AuthProviderOptions {
2
+ apiBase: string;
3
+ env?: NodeJS.ProcessEnv;
4
+ clientLabel?: string;
5
+ /** Injected in tests. */
6
+ now?: () => number;
7
+ fetchImpl?: typeof fetch;
8
+ }
9
+ export type EnsureAuth = {
10
+ ok: true;
11
+ apiKey: string;
12
+ } | {
13
+ ok: false;
14
+ reason: 'link_pending';
15
+ text: string;
16
+ userCode: string;
17
+ verificationUri: string;
18
+ } | {
19
+ ok: false;
20
+ reason: 'link_unavailable';
21
+ text: string;
22
+ };
23
+ export declare class AuthProvider {
24
+ private readonly opts;
25
+ private pending;
26
+ private pendingStartedAt;
27
+ private lastPollAt;
28
+ private readonly env;
29
+ private readonly now;
30
+ constructor(opts: AuthProviderOptions);
31
+ /** Env wins over file, re-read every call — see the header note. */
32
+ currentKey(): string;
33
+ /**
34
+ * Returns a usable key, or the exact words the agent should say to the user.
35
+ * Never throws: a failure to reach the link endpoint degrades to printed
36
+ * instructions, it does not take the tool call down with it.
37
+ */
38
+ ensure(): Promise<EnsureAuth>;
39
+ private pendingResult;
40
+ }
package/dist/auth.js ADDED
@@ -0,0 +1,115 @@
1
+ // Live auth for the running server.
2
+ //
3
+ // Two problems this solves, both of which used to end the funnel:
4
+ //
5
+ // 1. The key used to be read ONCE at process start. A user who fixed their
6
+ // setup while the client was running still got auth errors until they
7
+ // restarted the whole MCP client. Now the key is re-read from env + the
8
+ // config file on every tool call, so `debugai-mcp login` in another
9
+ // terminal takes effect on the next call — no restart, no reconnect.
10
+ //
11
+ // 2. A user with no key at all used to get a dead-end error. Now the server
12
+ // starts a device link itself and hands the agent a short code plus a URL
13
+ // to read out. The human approves in a browser; the agent retries; the
14
+ // second call finds the key and does the real work. Signup happens inside
15
+ // the conversation instead of in a config file the user never opens.
16
+ import { loadFileConfig, writeFileConfig } from './config.js';
17
+ import { DeviceLinkError, pollDeviceLink, startDeviceLink, } from './deviceLink.js';
18
+ /** Minimum gap between in-session polls: one poll per tool call, at most. */
19
+ const MIN_POLL_GAP_MS = 3_000;
20
+ export class AuthProvider {
21
+ opts;
22
+ pending = null;
23
+ pendingStartedAt = 0;
24
+ lastPollAt = 0;
25
+ env;
26
+ now;
27
+ constructor(opts) {
28
+ this.opts = opts;
29
+ this.env = opts.env ?? process.env;
30
+ this.now = opts.now ?? Date.now;
31
+ }
32
+ /** Env wins over file, re-read every call — see the header note. */
33
+ currentKey() {
34
+ const envKey = (this.env.DEBUGAI_API_KEY ?? '').trim();
35
+ if (envKey)
36
+ return envKey;
37
+ return loadFileConfig(this.env, () => { }).apiKey ?? '';
38
+ }
39
+ /**
40
+ * Returns a usable key, or the exact words the agent should say to the user.
41
+ * Never throws: a failure to reach the link endpoint degrades to printed
42
+ * instructions, it does not take the tool call down with it.
43
+ */
44
+ async ensure() {
45
+ const existing = this.currentKey();
46
+ if (existing)
47
+ return { ok: true, apiKey: existing };
48
+ // A link already in flight — poll it once before minting another code, so
49
+ // an agent retrying in a loop doesn't spray fresh codes at the user.
50
+ if (this.pending && this.now() - this.pendingStartedAt < this.pending.expiresIn * 1000) {
51
+ if (this.now() - this.lastPollAt >= MIN_POLL_GAP_MS) {
52
+ this.lastPollAt = this.now();
53
+ try {
54
+ const result = await pollDeviceLink(this.pending.deviceCode, {
55
+ apiBase: this.opts.apiBase,
56
+ fetchImpl: this.opts.fetchImpl,
57
+ });
58
+ if (result.status === 'linked') {
59
+ writeFileConfig({ apiKey: result.apiKey }, this.env);
60
+ this.pending = null;
61
+ return { ok: true, apiKey: result.apiKey };
62
+ }
63
+ if (result.status === 'expired' || result.status === 'denied') {
64
+ this.pending = null; // fall through and mint a fresh code below
65
+ }
66
+ }
67
+ catch {
68
+ // Network hiccup mid-link: keep the pending code, repeat instructions.
69
+ }
70
+ }
71
+ if (this.pending)
72
+ return this.pendingResult(this.pending);
73
+ }
74
+ try {
75
+ const start = await startDeviceLink({
76
+ apiBase: this.opts.apiBase,
77
+ clientLabel: this.opts.clientLabel,
78
+ fetchImpl: this.opts.fetchImpl,
79
+ });
80
+ this.pending = start;
81
+ this.pendingStartedAt = this.now();
82
+ this.lastPollAt = this.now();
83
+ return this.pendingResult(start);
84
+ }
85
+ catch (err) {
86
+ const detail = err instanceof DeviceLinkError ? ` (${err.message})` : '';
87
+ return {
88
+ ok: false,
89
+ reason: 'link_unavailable',
90
+ text: 'DebugAI is not connected to an account yet, and the automatic link could not be ' +
91
+ `started${detail}. Tell the user to run this in a terminal, which signs them in and ` +
92
+ 'stores the key for every MCP client at once:\n\n' +
93
+ ' npx -y @debugai/mcp login\n\n' +
94
+ 'It opens a browser, takes about 20 seconds, and needs no config editing. ' +
95
+ 'Then retry this tool call. No client restart needed.',
96
+ };
97
+ }
98
+ }
99
+ pendingResult(start) {
100
+ return {
101
+ ok: false,
102
+ reason: 'link_pending',
103
+ userCode: start.userCode,
104
+ verificationUri: start.verificationUri,
105
+ text: 'DebugAI is not connected to an account yet. This takes about 20 seconds and needs no ' +
106
+ 'config file editing.\n\n' +
107
+ 'Tell the user, verbatim:\n' +
108
+ ` 1. Open ${start.verificationUriComplete}\n` +
109
+ ` 2. Sign in (free, 10 debugs/day, no card) and confirm the code ${start.userCode}\n\n` +
110
+ 'Then call this tool again with the same arguments. The key is picked up automatically ' +
111
+ 'on the next call. The MCP client does NOT need restarting. ' +
112
+ `The code expires in ${Math.round(start.expiresIn / 60)} minutes.`,
113
+ };
114
+ }
115
+ }
package/dist/backend.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { AuthProvider } from './auth.js';
1
2
  export interface DebugRequest {
2
3
  error_message: string;
3
4
  code_snippet?: string;
@@ -54,11 +55,19 @@ export interface OutcomeResponse {
54
55
  success: boolean;
55
56
  }
56
57
  export interface BackendConfig {
58
+ /** Key resolved at process start. Present for direct/test use; live calls prefer `auth`. */
57
59
  apiKey: string;
58
60
  apiBase: string;
59
61
  version: string;
60
62
  /** Whole-request deadline in ms. Claude analysis runs 30-90s; nginx cuts at 120s. */
61
63
  timeoutMs?: number;
64
+ /**
65
+ * Live auth. When set, tools resolve the key through it on every call (so a
66
+ * key added while the client is running works without a restart) and can
67
+ * start a browser sign-in mid-conversation. Absent in unit tests, which pass
68
+ * a fixed apiKey.
69
+ */
70
+ auth?: AuthProvider;
62
71
  }
63
72
  export interface BackendError extends Error {
64
73
  status: number;
@@ -0,0 +1,36 @@
1
+ export type ConfigShape = 'mcpServers' | 'context_servers' | 'vscode_servers';
2
+ export interface McpClient {
3
+ id: string;
4
+ label: string;
5
+ shape: ConfigShape;
6
+ /** Absolute path to the config file, or null when this OS isn't supported. */
7
+ configPath: string | null;
8
+ /** Directories that prove the app is installed even before any MCP config exists. */
9
+ probes: string[];
10
+ /** What the user must do after we write the file. */
11
+ afterInstall: string;
12
+ /**
13
+ * True for clients `install` skips unless named explicitly — currently only
14
+ * VS Code, where the DebugAI extension already registers the server and a
15
+ * second manual entry would show the same tools twice.
16
+ */
17
+ optIn?: boolean;
18
+ note?: string;
19
+ }
20
+ export declare function knownClients(env?: NodeJS.ProcessEnv): McpClient[];
21
+ export declare function findClient(id: string, env?: NodeJS.ProcessEnv): McpClient | undefined;
22
+ /** A client counts as present when its config file OR its app directory exists. */
23
+ export declare function isDetected(client: McpClient): boolean;
24
+ export declare function detectedClients(env?: NodeJS.ProcessEnv): McpClient[];
25
+ /**
26
+ * The server entry itself. `npx -y` is deliberate: it self-updates on each
27
+ * launch and needs no global install, which is the only variant that works
28
+ * identically on a laptop, a devcontainer, and CI.
29
+ *
30
+ * No `env` block, ever — the key lives in ~/.debugai/config.json (see
31
+ * config.ts). Client configs get committed to repos; keys should not.
32
+ */
33
+ export declare function serverEntry(client: McpClient): Record<string, unknown>;
34
+ /** Top-level key in that client's config file where servers are listed. */
35
+ export declare function serversKey(shape: ConfigShape): string;
36
+ export declare const SERVER_NAME = "debugai";
@@ -0,0 +1,143 @@
1
+ // Where every MCP client keeps its config, and what shape it wants.
2
+ //
3
+ // This registry is the thing that replaces "copy this JSON blob into the
4
+ // right file" in the README. Adding a client = one entry here; the install
5
+ // command, doctor, and `--print` output all read from it.
6
+ //
7
+ // Two config shapes exist in the wild:
8
+ // mcpServers { command, args, env? } (most clients)
9
+ // context_servers { source, command: { path, args, env? } } (Zed)
10
+ // servers { type: "stdio", command, args } (VS Code native)
11
+ import { existsSync } from 'node:fs';
12
+ import { homedir, platform } from 'node:os';
13
+ import { join } from 'node:path';
14
+ function appDataDir(env) {
15
+ const home = homedir();
16
+ if (platform() === 'win32')
17
+ return env.APPDATA ?? join(home, 'AppData', 'Roaming');
18
+ if (platform() === 'darwin')
19
+ return join(home, 'Library', 'Application Support');
20
+ return env.XDG_CONFIG_HOME ?? join(home, '.config');
21
+ }
22
+ /** VS Code's per-user directory — Cline stores its MCP config under it too. */
23
+ function vscodeUserDir(env) {
24
+ return join(appDataDir(env), 'Code', 'User');
25
+ }
26
+ export function knownClients(env = process.env) {
27
+ const home = homedir();
28
+ const appData = appDataDir(env);
29
+ return [
30
+ {
31
+ id: 'claude-code',
32
+ label: 'Claude Code',
33
+ shape: 'mcpServers',
34
+ configPath: join(home, '.claude.json'),
35
+ probes: [join(home, '.claude'), join(home, '.claude.json')],
36
+ afterInstall: 'Start a new Claude Code session (or run /mcp to reconnect).',
37
+ },
38
+ {
39
+ id: 'claude-desktop',
40
+ label: 'Claude Desktop',
41
+ shape: 'mcpServers',
42
+ configPath: join(appData, 'Claude', 'claude_desktop_config.json'),
43
+ probes: [join(appData, 'Claude')],
44
+ afterInstall: 'Quit Claude Desktop completely and reopen it (closing the window is not enough).',
45
+ },
46
+ {
47
+ id: 'cursor',
48
+ label: 'Cursor',
49
+ shape: 'mcpServers',
50
+ configPath: join(home, '.cursor', 'mcp.json'),
51
+ probes: [join(home, '.cursor')],
52
+ afterInstall: 'Cursor picks this up on its own — check Settings, MCP for a green dot.',
53
+ },
54
+ {
55
+ id: 'windsurf',
56
+ label: 'Windsurf',
57
+ shape: 'mcpServers',
58
+ configPath: join(home, '.codeium', 'windsurf', 'mcp_config.json'),
59
+ probes: [join(home, '.codeium', 'windsurf'), join(home, '.codeium')],
60
+ afterInstall: 'Open Windsurf, Settings, MCP and hit refresh.',
61
+ },
62
+ {
63
+ id: 'zed',
64
+ label: 'Zed',
65
+ shape: 'context_servers',
66
+ configPath: platform() === 'win32'
67
+ ? join(appData, 'Zed', 'settings.json')
68
+ : join(env.XDG_CONFIG_HOME ?? join(home, '.config'), 'zed', 'settings.json'),
69
+ probes: [
70
+ join(env.XDG_CONFIG_HOME ?? join(home, '.config'), 'zed'),
71
+ join(appData, 'Zed'),
72
+ ],
73
+ afterInstall: 'Zed reloads settings on save — the server appears in the agent panel.',
74
+ },
75
+ {
76
+ id: 'gemini-cli',
77
+ label: 'Gemini CLI',
78
+ shape: 'mcpServers',
79
+ configPath: join(home, '.gemini', 'settings.json'),
80
+ probes: [join(home, '.gemini')],
81
+ afterInstall: 'Restart the Gemini CLI session.',
82
+ },
83
+ {
84
+ id: 'cline',
85
+ label: 'Cline (VS Code)',
86
+ shape: 'mcpServers',
87
+ configPath: join(vscodeUserDir(env), 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'),
88
+ probes: [join(vscodeUserDir(env), 'globalStorage', 'saoudrizwan.claude-dev')],
89
+ afterInstall: 'Open the Cline panel, MCP Servers — it reconnects without a VS Code restart.',
90
+ },
91
+ {
92
+ id: 'vscode',
93
+ label: 'VS Code (native MCP)',
94
+ shape: 'vscode_servers',
95
+ configPath: join(vscodeUserDir(env), 'mcp.json'),
96
+ probes: [vscodeUserDir(env)],
97
+ optIn: true,
98
+ note: 'The DebugAI VS Code extension already registers this server (VS Code 1.101+), '
99
+ + 'plus one-click fix apply and proactive scan. Only install here if you do not want the extension.',
100
+ afterInstall: 'Run "MCP: List Servers" from the command palette to confirm.',
101
+ },
102
+ ];
103
+ }
104
+ export function findClient(id, env = process.env) {
105
+ return knownClients(env).find((c) => c.id === id.toLowerCase());
106
+ }
107
+ /** A client counts as present when its config file OR its app directory exists. */
108
+ export function isDetected(client) {
109
+ if (client.configPath && existsSync(client.configPath))
110
+ return true;
111
+ return client.probes.some((p) => existsSync(p));
112
+ }
113
+ export function detectedClients(env = process.env) {
114
+ return knownClients(env).filter(isDetected);
115
+ }
116
+ /**
117
+ * The server entry itself. `npx -y` is deliberate: it self-updates on each
118
+ * launch and needs no global install, which is the only variant that works
119
+ * identically on a laptop, a devcontainer, and CI.
120
+ *
121
+ * No `env` block, ever — the key lives in ~/.debugai/config.json (see
122
+ * config.ts). Client configs get committed to repos; keys should not.
123
+ */
124
+ export function serverEntry(client) {
125
+ const command = 'npx';
126
+ const args = ['-y', '@debugai/mcp'];
127
+ if (client.shape === 'context_servers') {
128
+ return { source: 'custom', command: { path: command, args } };
129
+ }
130
+ if (client.shape === 'vscode_servers') {
131
+ return { type: 'stdio', command, args };
132
+ }
133
+ return { command, args };
134
+ }
135
+ /** Top-level key in that client's config file where servers are listed. */
136
+ export function serversKey(shape) {
137
+ if (shape === 'context_servers')
138
+ return 'context_servers';
139
+ if (shape === 'vscode_servers')
140
+ return 'servers';
141
+ return 'mcpServers';
142
+ }
143
+ export const SERVER_NAME = 'debugai';
@@ -0,0 +1,7 @@
1
+ export declare function cmdLogin(argv: string[], env?: NodeJS.ProcessEnv): Promise<number>;
2
+ export declare function cmdLogout(_argv: string[], env?: NodeJS.ProcessEnv): number;
3
+ export declare function cmdStatus(_argv: string[], env?: NodeJS.ProcessEnv): Promise<number>;
4
+ export declare function cmdInstall(argv: string[], env?: NodeJS.ProcessEnv): number;
5
+ export declare function cmdUninstall(argv: string[], env?: NodeJS.ProcessEnv): number;
6
+ export declare function cmdDoctor(_argv: string[], env?: NodeJS.ProcessEnv): Promise<number>;
7
+ export declare function cmdSetup(argv: string[], env?: NodeJS.ProcessEnv): Promise<number>;