fast-context-mcp 1.0.0 → 1.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fast-context-mcp",
3
- "version": "1.0.0",
4
- "description": "AI-driven semantic code search via reverse-engineered Windsurf protocol (Node.js)",
3
+ "version": "1.1.0",
4
+ "description": "AI-driven semantic code search MCP server (Node.js)",
5
5
  "type": "module",
6
6
  "main": "src/server.mjs",
7
7
  "bin": {
@@ -21,7 +21,7 @@
21
21
  "dependencies": {
22
22
  "@modelcontextprotocol/sdk": "^1.0.0",
23
23
  "@vscode/ripgrep": "^1.15.9",
24
- "better-sqlite3": "^11.0.0",
24
+ "sql.js": "^1.14.0",
25
25
  "tree-node-cli": "^1.6.0",
26
26
  "zod": "^3.23.0"
27
27
  },
package/src/core.mjs CHANGED
@@ -12,7 +12,7 @@
12
12
  */
13
13
 
14
14
  import { readdirSync, existsSync, statSync } from "node:fs";
15
- import { resolve, join, relative } from "node:path";
15
+ import { resolve, join, relative, sep } from "node:path";
16
16
  import { gzipSync } from "node:zlib";
17
17
  import { randomUUID } from "node:crypto";
18
18
  import { platform, arch, release, version as osVersion, hostname, cpus, totalmem } from "node:os";
@@ -361,11 +361,11 @@ function getToolDefinitions(maxCommands = 8) {
361
361
 
362
362
  /**
363
363
  * Auto-discover Windsurf API key from local installation.
364
- * @returns {string|null}
364
+ * @returns {Promise<string|null>}
365
365
  */
366
- function autoDiscoverApiKey() {
366
+ async function autoDiscoverApiKey() {
367
367
  try {
368
- const result = extractKey();
368
+ const result = await extractKey();
369
369
  if (result.api_key && result.api_key.startsWith("sk-")) {
370
370
  return result.api_key;
371
371
  }
@@ -377,12 +377,12 @@ function autoDiscoverApiKey() {
377
377
 
378
378
  /**
379
379
  * Get API key from env var or auto-discovery.
380
- * @returns {string}
380
+ * @returns {Promise<string>}
381
381
  */
382
- function getApiKey() {
382
+ async function getApiKey() {
383
383
  const key = process.env.WINDSURF_API_KEY;
384
384
  if (key) return key;
385
- const discovered = autoDiscoverApiKey();
385
+ const discovered = await autoDiscoverApiKey();
386
386
  if (discovered) return discovered;
387
387
  throw new Error(
388
388
  "Windsurf API Key not found. Set WINDSURF_API_KEY env var or ensure Windsurf is logged in. " +
@@ -933,7 +933,7 @@ function _parseAnswer(xmlText, projectRoot) {
933
933
 
934
934
  // Path safety: reject traversal attempts (../) and paths outside project root
935
935
  const fullPath = resolve(projectRoot, rel);
936
- if (!fullPath.startsWith(resolvedRoot + "/") && fullPath !== resolvedRoot) {
936
+ if (!fullPath.startsWith(resolvedRoot + sep) && fullPath !== resolvedRoot) {
937
937
  continue;
938
938
  }
939
939
 
@@ -984,7 +984,7 @@ export async function search({
984
984
 
985
985
  // Get credentials
986
986
  if (!apiKey) {
987
- apiKey = getApiKey();
987
+ apiKey = await getApiKey();
988
988
  }
989
989
  if (!jwt) {
990
990
  log("Fetching JWT...");
@@ -1199,8 +1199,8 @@ export async function searchWithContent({
1199
1199
 
1200
1200
  /**
1201
1201
  * Extract Windsurf API Key info (for MCP tool use).
1202
- * @returns {Object}
1202
+ * @returns {Promise<Object>}
1203
1203
  */
1204
- export function extractKeyInfo() {
1204
+ export async function extractKeyInfo() {
1205
1205
  return extractKey();
1206
1206
  }
@@ -2,13 +2,13 @@
2
2
  * Windsurf API Key extraction from local installation.
3
3
  *
4
4
  * Cross-platform: macOS / Windows / Linux.
5
- * Uses better-sqlite3 to read state.vscdb.
5
+ * Uses sql.js (pure JS/WASM) to read state.vscdb — no native compilation needed.
6
6
  */
7
7
 
8
- import { existsSync } from "node:fs";
8
+ import { existsSync, readFileSync } from "node:fs";
9
9
  import { join } from "node:path";
10
10
  import { homedir, platform } from "node:os";
11
- import Database from "better-sqlite3";
11
+ import initSqlJs from "sql.js";
12
12
 
13
13
  /**
14
14
  * Get the platform-specific path to Windsurf's state.vscdb.
@@ -34,9 +34,9 @@ export function getDbPath() {
34
34
  /**
35
35
  * Extract API Key from Windsurf state.vscdb.
36
36
  * @param {string} [dbPath]
37
- * @returns {{ api_key?: string, db_path: string, error?: string, hint?: string }}
37
+ * @returns {Promise<{ api_key?: string, db_path: string, error?: string, hint?: string }>}
38
38
  */
39
- export function extractKey(dbPath) {
39
+ export async function extractKey(dbPath) {
40
40
  if (!dbPath) {
41
41
  dbPath = getDbPath();
42
42
  }
@@ -49,34 +49,45 @@ export function extractKey(dbPath) {
49
49
  };
50
50
  }
51
51
 
52
- let row;
52
+ let db;
53
53
  try {
54
- const db = new Database(dbPath, { readonly: true });
55
- row = db.prepare("SELECT value FROM ItemTable WHERE key = 'windsurfAuthStatus'").get();
56
- db.close();
54
+ const SQL = await initSqlJs();
55
+ const buf = readFileSync(dbPath);
56
+ db = new SQL.Database(buf);
57
57
  } catch (e) {
58
- return { error: `Failed to read database: ${e.message}`, db_path: dbPath };
58
+ return { error: `Failed to open database: ${e.message}`, db_path: dbPath };
59
59
  }
60
60
 
61
- if (!row) {
62
- return {
63
- error: "windsurfAuthStatus record not found",
64
- hint: "Ensure Windsurf is logged in.",
65
- db_path: dbPath,
66
- };
67
- }
68
-
69
- let data;
70
61
  try {
71
- data = JSON.parse(row.value);
72
- } catch {
73
- return { error: "windsurfAuthStatus data parse failed", db_path: dbPath };
74
- }
62
+ const stmt = db.prepare("SELECT value FROM ItemTable WHERE key = 'windsurfAuthStatus'");
63
+ if (!stmt.step()) {
64
+ stmt.free();
65
+ return {
66
+ error: "windsurfAuthStatus record not found",
67
+ hint: "Ensure Windsurf is logged in.",
68
+ db_path: dbPath,
69
+ };
70
+ }
75
71
 
76
- const apiKey = data.apiKey || "";
77
- if (!apiKey) {
78
- return { error: "apiKey field is empty", db_path: dbPath };
79
- }
72
+ const row = stmt.getAsObject();
73
+ stmt.free();
74
+
75
+ let data;
76
+ try {
77
+ data = JSON.parse(row.value);
78
+ } catch {
79
+ return { error: "windsurfAuthStatus data parse failed", db_path: dbPath };
80
+ }
81
+
82
+ const apiKey = data.apiKey || "";
83
+ if (!apiKey) {
84
+ return { error: "apiKey field is empty", db_path: dbPath };
85
+ }
80
86
 
81
- return { api_key: apiKey, db_path: dbPath };
87
+ return { api_key: apiKey, db_path: dbPath };
88
+ } catch (e) {
89
+ return { error: `Extraction failed: ${e.message}`, db_path: dbPath };
90
+ } finally {
91
+ db.close();
92
+ }
82
93
  }
package/src/server.mjs CHANGED
@@ -174,7 +174,7 @@ server.tool(
174
174
  "Windsurf's local database. Set the result as WINDSURF_API_KEY env var.",
175
175
  {},
176
176
  async () => {
177
- const result = extractKeyInfo();
177
+ const result = await extractKeyInfo();
178
178
 
179
179
  if (result.error) {
180
180
  const text = `Error: ${result.error}\n${result.hint || ""}\nDB path: ${result.db_path || "N/A"}`;