@4da/mcp-server 6.0.0 → 6.0.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,87 @@
1
1
  # Changelog
2
2
 
3
+ ## 6.0.2 — 2026-10-04
4
+
5
+ ### `--setup` writes the files editors actually read
6
+
7
+ Three of the four editors `--setup` reported as configured were configured in
8
+ files those editors never read, so nothing happened:
9
+
10
+ | Editor | Before | Now |
11
+ |---|---|---|
12
+ | VS Code | `~/.vscode/mcp.json` | the user profile's `mcp.json`: `%APPDATA%\Code\User\` (Windows), `~/Library/Application Support/Code/User/` (macOS), `$XDG_CONFIG_HOME/Code/User/` (Linux, default `~/.config`), key `servers`, `"type": "stdio"` |
13
+ | Windsurf | `~/.windsurf/mcp.json` | `~/.codeium/windsurf/mcp_config.json`, key `mcpServers` |
14
+ | Claude Code | `mcpServers` in the project's `.claude/settings.json` (or, outside a project, rewrote `~/.claude.json`) | prints `claude mcp add --scope user 4da -- npx @4da/mcp-server`; `~/.claude.json` is never edited |
15
+
16
+ Added: VS Code Insiders, Claude Desktop (`claude_desktop_config.json`) and
17
+ Devin Desktop / Devin CLI (`~/.config/devin/mcp_config.json`,
18
+ `%APPDATA%\devin\` on Windows), Windsurf's successor. Cursor
19
+ (`~/.cursor/mcp.json`) was already right.
20
+
21
+ - **A config file setup cannot parse is left untouched.** It used to be read
22
+ as `{}`, so a VS Code `mcp.json` with a comment or a trailing comma (both
23
+ legal there) was replaced by our entry alone, deleting every other server.
24
+ Files are now parsed as JSONC and edited in place with `jsonc-parser`
25
+ (Microsoft's, the parser VS Code uses; no dependencies of its own), which
26
+ keeps comments, formatting, other servers and other keys. A file that does
27
+ not parse is reported with the entry to add by hand.
28
+ - An existing `4da` entry is updated, not duplicated, and keeps its other
29
+ fields (`env`); an identical one is left alone, so a second run writes
30
+ nothing.
31
+ - Every modified file is backed up first (`<file>.bak`; an earlier backup is
32
+ never overwritten) and replaced atomically (temp file, then rename).
33
+ - `--setup --dry-run` wrote anyway when run through `npx @4da/mcp-server`
34
+ (only the `4da-mcp-setup` entry honoured the flag). It now writes nothing on
35
+ either, and prints each file and the exact entry it would add.
36
+
37
+ ### Clearer answers when the database cannot help
38
+
39
+ - A desktop-only tool (`get_relevant_content`, `get_actionable_signals`,
40
+ `knowledge_gaps`, `record_feedback`, `developer_dna`) called without the
41
+ desktop app's database answered `[]`, which reads as "nothing relevant". It
42
+ now carries a `desktop_app_note` saying it needs the app.
43
+ - A database file that is damaged or not SQLite answered every call with
44
+ SQLite's bare "file is not a database". The message now names the file and
45
+ what to do, and never advises deleting it (`--doctor`'s integrity check used
46
+ to say "Try deleting data/4da.db"). The handle a failed open left behind is
47
+ closed, so on Windows the file can be moved aside while the server runs.
48
+ - The database lookup no longer checks `data/4da.db` two directories above the
49
+ server's own files, a leftover from when the server was a folder of the app
50
+ repository; installed, it pointed into `node_modules/@4da/`.
51
+
52
+ - Dependencies: `@modelcontextprotocol/server` ^2.2.0, `hono` ^4.13.12; dev: `@types/node` ^26.6.3, `vitest` ^5.0.3 (#2).
53
+
54
+ ## 6.0.1 — 2026-10-04
55
+
56
+ ### The server has its own repository
57
+
58
+ `@4da/mcp-server` now lives at
59
+ [github.com/4DA-Systems/4da-mcp-server](https://github.com/4DA-Systems/4da-mcp-server),
60
+ with its full history, instead of a folder of the 4DA desktop app's monorepo.
61
+ Issues, releases and the Claude Code plugin marketplace move with it:
62
+
63
+ ```bash
64
+ claude plugin marketplace add 4DA-Systems/4da-mcp-server
65
+ claude plugin install 4da@4da
66
+ ```
67
+
68
+ The package, its name in the MCP Registry (`io.github.4DA-Systems/4da-mcp-server`)
69
+ and every tool are unchanged.
70
+
71
+ - **Published with provenance.** Releases are built and published from this
72
+ repository's `release.yml` through npm trusted publishing, so each version
73
+ carries a SLSA provenance attestation tying it to the commit it was built from.
74
+ - **App-schema contract.** The server reads the desktop app's database, which
75
+ is now maintained in a different repository. `pnpm run contract` checks every
76
+ statement the server issues, and every column it probes for, against the
77
+ schema the app's migrations produce (`contract/app-schema.sql`, generated in
78
+ the app's CI). The app's CI runs the same check before a migration merges.
79
+ - **Removed dead code.** `explainRelevance`, `getSourceItem`,
80
+ `recordAgentFeedback` and `getAgentFeedbackStats` had no callers since their
81
+ tools were removed; the standalone schema no longer creates the unused
82
+ `agent_feedback` table.
83
+ - The Claude Code plugin pins the exact server version it was released with.
84
+
3
85
  ## 6.0.0 — 2026-10-02
4
86
 
5
87
  ### New: `upgrade_impact`
package/README.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@4da/mcp-server?color=gold)](https://www.npmjs.com/package/@4da/mcp-server)
4
4
  [![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](LICENSE)
5
- [![Node](https://img.shields.io/badge/Node-%3E%3D20-brightgreen)](https://nodejs.org/)
6
- [![smithery badge](https://smithery.ai/badge/@4da/mcp-server)](https://smithery.ai/server/@4da/mcp-server)
5
+ [![Node](https://img.shields.io/badge/Node-%3E%3D22-brightgreen)](https://nodejs.org/)
6
+ [![CI](https://github.com/4DA-Systems/4da-mcp-server/actions/workflows/ci.yml/badge.svg)](https://github.com/4DA-Systems/4da-mcp-server/actions/workflows/ci.yml)
7
7
 
8
8
  **Upgrade intelligence for AI coding agents.** Before your agent bumps a dependency it learns what changes between the version you run and the one you want, which of your files that touches, and which vulnerabilities the move fixes, from your own lockfiles, on your machine. Plus vulnerability scanning at osv-scanner parity, ranked upgrade plans and decision memory. Zero config, no account.
9
9
 
@@ -38,16 +38,16 @@ claude mcp add 4da -- npx @4da/mcp-server
38
38
  **As a Claude Code plugin** (the MCP server plus a hook):
39
39
 
40
40
  ```bash
41
- claude plugin marketplace add 4DA-Systems/4DA --sparse .claude-plugin mcp-4da-server
41
+ claude plugin marketplace add 4DA-Systems/4da-mcp-server
42
42
  claude plugin install 4da@4da
43
43
  ```
44
44
 
45
45
  The hook: when your agent edits a dependency's version in `package.json`, `Cargo.toml`, `pyproject.toml`, `requirements.txt` or `go.mod`, it is told which packages moved and given the exact `dependency_check` and `upgrade_impact` calls to make before it installs and builds. The hook is plain Node, contacts nothing, and stays silent for every other edit.
46
46
 
47
47
  <details>
48
- <summary><b>Cursor / Windsurf</b></summary>
48
+ <summary><b>Cursor / Windsurf / Devin Desktop</b></summary>
49
49
 
50
- Add to `~/.cursor/mcp.json` or `~/.windsurf/mcp.json`:
50
+ Add to `~/.cursor/mcp.json` (Cursor), `~/.codeium/windsurf/mcp_config.json` (Windsurf), or `~/.config/devin/mcp_config.json` (Devin Desktop and Devin CLI; `%APPDATA%devinmcp_config.json` on Windows):
51
51
  ```json
52
52
  {
53
53
  "mcpServers": {
@@ -63,7 +63,7 @@ Add to `~/.cursor/mcp.json` or `~/.windsurf/mcp.json`:
63
63
  <details>
64
64
  <summary><b>VS Code (Copilot)</b></summary>
65
65
 
66
- Add to `~/.vscode/mcp.json`:
66
+ Run **MCP: Open User Configuration** and add the entry, or edit the file directly: `%APPDATA%CodeUsermcp.json` (Windows), `~/Library/Application Support/Code/User/mcp.json` (macOS), `~/.config/Code/User/mcp.json` (Linux). VS Code uses `servers`, not `mcpServers`:
67
67
  ```json
68
68
  {
69
69
  "servers": {
@@ -97,8 +97,11 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
97
97
  <summary><b>Auto-setup</b> (detects all installed editors)</summary>
98
98
 
99
99
  ```bash
100
+ npx @4da/mcp-server --setup --dry-run # show each file and entry, write nothing
100
101
  npx @4da/mcp-server --setup
101
102
  ```
103
+
104
+ Writes Cursor, VS Code (and Insiders), Windsurf, Devin Desktop and Claude Desktop configs it finds, merging into what is there: other servers, settings and comments are kept, a backup (`.bak`) is written first, and a file it cannot parse is left untouched with the entry to add by hand. For Claude Code it prints the `claude mcp add` command instead of editing `~/.claude.json`.
102
105
  </details>
103
106
 
104
107
  Then ask your AI: **"What changes if I upgrade X to Y?"**, **"Scan for vulnerabilities"** or **"What should I upgrade first?"**
@@ -268,11 +271,11 @@ Any tool that supports [MCP](https://modelcontextprotocol.io): Claude Code, Clau
268
271
  ## Build from Source
269
272
 
270
273
  ```bash
271
- git clone https://github.com/4DA-Systems/4DA.git
272
- cd 4DA/mcp-4da-server
274
+ git clone https://github.com/4DA-Systems/4da-mcp-server.git
275
+ cd 4da-mcp-server
273
276
  pnpm install
274
277
  pnpm build
275
- pnpm test # 662 tests, offline
278
+ pnpm test # offline
276
279
  ```
277
280
 
278
281
  ## License
package/dist/db.d.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  import type BetterSqlite3 from "better-sqlite3";
8
8
  /** Null when better-sqlite3 can open a database here; otherwise why not, with the fix. */
9
9
  export declare function nativeBindingProblem(): string | null;
10
- import type { SourceItem, RelevantItem, UserContext, RelevanceExplanation, FeedbackAction, FeedbackResult } from "./types.js";
10
+ import type { RelevantItem, UserContext, FeedbackAction, FeedbackResult } from "./types.js";
11
11
  import type { ProjectScanResult } from "./project-scanner.js";
12
12
  /**
13
13
  * Where the deployed desktop app keeps its database, mirroring
@@ -30,6 +30,20 @@ export declare function desktopAppDbPaths(platform?: NodeJS.Platform, env?: Node
30
30
  * in, so agent memory and decisions did not follow the user between projects.
31
31
  */
32
32
  export declare function standaloneDbPath(): string;
33
+ /**
34
+ * Whether an error says the database file itself is unreadable: not SQLite at
35
+ * all, or damaged. better-sqlite3 reports these as SQLITE_NOTADB ("file is not
36
+ * a database") and SQLITE_CORRUPT ("database disk image is malformed").
37
+ */
38
+ export declare function isUnreadableDbError(error: unknown): boolean;
39
+ /**
40
+ * What to tell the user about an unreadable database. Every tool call used to
41
+ * answer with the bare SQLite text ("file is not a database"), with no way
42
+ * out. Nothing is deleted or moved automatically: the desktop app's database
43
+ * can be the user's whole corpus, and the standalone one holds their recorded
44
+ * decisions and agent memory.
45
+ */
46
+ export declare function unreadableDbMessage(absolutePath: string, error: unknown): string;
33
47
  export interface DatabaseValidationResult {
34
48
  valid: boolean;
35
49
  error?: string;
@@ -98,6 +112,8 @@ export declare const DEPENDENCY_GROUP_QUERY = "SELECT DISTINCT package_name, lan
98
112
  export declare class FourDADatabase {
99
113
  private db;
100
114
  private _isStandalone;
115
+ /** Absolute path of the open database file. */
116
+ readonly dbPath: string;
101
117
  constructor(dbPath?: string);
102
118
  /**
103
119
  * Whether this database was freshly created in standalone mode
@@ -193,10 +209,6 @@ export declare class FourDADatabase {
193
209
  * Fallback: TypeScript keyword scoring for standalone mode (no Rust pipeline).
194
210
  */
195
211
  private getRelevantContentFallback;
196
- /**
197
- * Get a single source item by ID and type
198
- */
199
- getSourceItem(itemId: number, sourceType: string): SourceItem | null;
200
212
  /**
201
213
  * Look up persisted necessity scores for an item (written by Rust analysis pipeline).
202
214
  * Returns defaults (0.0/null) if no necessity data exists yet.
@@ -206,10 +218,6 @@ export declare class FourDADatabase {
206
218
  * Get the user's context (what 4DA knows about them)
207
219
  */
208
220
  getUserContext(includeAce?: boolean, includeLearned?: boolean): UserContext;
209
- /**
210
- * Explain why an item was considered relevant
211
- */
212
- explainRelevance(itemId: number, sourceType: string): RelevanceExplanation | null;
213
221
  /**
214
222
  * Record user feedback on an item
215
223
  */
@@ -221,54 +229,6 @@ export declare class FourDADatabase {
221
229
  * so against the desktop database this is a no-op.
222
230
  */
223
231
  private ensureFeedbackTable;
224
- /**
225
- * Ensure the agent_feedback table exists.
226
- * Called on first use so existing databases (created before this feature)
227
- * get the table added without requiring a migration.
228
- */
229
- private ensureAgentFeedbackTable;
230
- /**
231
- * Record agent feedback on recommended content items
232
- */
233
- recordAgentFeedback(itemIds: string[], outcome: string, context?: string, sessionTask?: string): {
234
- success: boolean;
235
- message: string;
236
- recorded_count: number;
237
- };
238
- /**
239
- * Get agent feedback statistics for the given period
240
- */
241
- getAgentFeedbackStats(days?: number): {
242
- period_days: number;
243
- outcomes: {
244
- used: number;
245
- rejected: number;
246
- partially_used: number;
247
- total: number;
248
- };
249
- by_source: Array<{
250
- source_type: string;
251
- used: number;
252
- rejected: number;
253
- partially_used: number;
254
- total: number;
255
- usefulness_rate: number;
256
- }>;
257
- top_used_items: Array<{
258
- item_id: string;
259
- title: string | null;
260
- source_type: string | null;
261
- used_count: number;
262
- rejected_count: number;
263
- }>;
264
- recent_feedback: Array<{
265
- item_id: string;
266
- outcome: string;
267
- context: string | null;
268
- session_task: string | null;
269
- recorded_at: string;
270
- }>;
271
- };
272
232
  /**
273
233
  * Compute relevance score for an item based on user context
274
234
  */