@philau2512/fast-context-mcp 1.5.4 → 1.5.6
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 +2 -2
- package/src/project-path.mjs +33 -15
- package/src/server.mjs +25 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@philau2512/fast-context-mcp",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.6",
|
|
4
4
|
"description": "AI-driven semantic code search MCP server (Node.js) — Windsurf/Devin protocol",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/server.mjs",
|
|
@@ -53,4 +53,4 @@
|
|
|
53
53
|
"access": "public"
|
|
54
54
|
},
|
|
55
55
|
"license": "MIT"
|
|
56
|
-
}
|
|
56
|
+
}
|
package/src/project-path.mjs
CHANGED
|
@@ -1,43 +1,61 @@
|
|
|
1
1
|
import { statSync } from "node:fs";
|
|
2
|
-
import { isAbsolute } from "node:path";
|
|
2
|
+
import { isAbsolute, resolve } from "node:path";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
5
5
|
export const PROJECT_PATH_REQUIRED_MESSAGE =
|
|
6
|
-
"project_path is
|
|
6
|
+
"project_path is optional. Pass the absolute or relative path to the project root directory, or omit to use current working directory.";
|
|
7
7
|
|
|
8
8
|
export const projectPathSchema = z
|
|
9
9
|
.string()
|
|
10
10
|
.trim()
|
|
11
|
-
.
|
|
11
|
+
.nullish()
|
|
12
|
+
.transform((val) => val ?? "")
|
|
13
|
+
.default("");
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Resolve project path to an absolute path.
|
|
17
|
+
* If empty, null, or ".", defaults to cwd (process.cwd()).
|
|
18
|
+
* If relative, resolves against cwd.
|
|
19
|
+
*
|
|
20
|
+
* @param {string|null|undefined} projectPath
|
|
21
|
+
* @param {string} [cwd]
|
|
22
|
+
* @returns {string}
|
|
23
|
+
*/
|
|
24
|
+
export function resolveProjectPath(projectPath, cwd = process.cwd()) {
|
|
25
|
+
const trimmed = typeof projectPath === "string" ? projectPath.trim() : "";
|
|
26
|
+
if (!trimmed || trimmed === "." || trimmed === "./" || trimmed === ".\\") {
|
|
27
|
+
return cwd;
|
|
28
|
+
}
|
|
29
|
+
if (isAbsolute(trimmed)) {
|
|
30
|
+
return trimmed;
|
|
31
|
+
}
|
|
32
|
+
return resolve(cwd, trimmed);
|
|
33
|
+
}
|
|
12
34
|
|
|
13
35
|
/**
|
|
14
36
|
* Validate the project root path provided to fast_context_search.
|
|
37
|
+
* Automatically resolves relative paths or empty/omitted paths against cwd.
|
|
15
38
|
* Returns null when valid, otherwise an MCP-friendly error string.
|
|
16
39
|
*
|
|
17
40
|
* @param {string} projectPath
|
|
18
41
|
* @param {(path: string) => import("node:fs").Stats} [statFn]
|
|
42
|
+
* @param {string} [cwd]
|
|
19
43
|
* @returns {string|null}
|
|
20
44
|
*/
|
|
21
|
-
export function validateProjectPath(projectPath, statFn = statSync) {
|
|
22
|
-
|
|
23
|
-
return `Error: ${PROJECT_PATH_REQUIRED_MESSAGE}`;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (!isAbsolute(projectPath)) {
|
|
27
|
-
return `Error: project_path must be an absolute path, got: ${projectPath}`;
|
|
28
|
-
}
|
|
45
|
+
export function validateProjectPath(projectPath, statFn = statSync, cwd = process.cwd()) {
|
|
46
|
+
const resolved = resolveProjectPath(projectPath, cwd);
|
|
29
47
|
|
|
30
48
|
try {
|
|
31
|
-
const st = statFn(
|
|
49
|
+
const st = statFn(resolved);
|
|
32
50
|
if (!st.isDirectory()) {
|
|
33
|
-
return `Error: project_path is not a directory: ${
|
|
51
|
+
return `Error: project_path is not a directory: ${resolved}`;
|
|
34
52
|
}
|
|
35
53
|
} catch (error) {
|
|
36
54
|
if (error?.code === "ENOENT") {
|
|
37
|
-
return `Error: project_path does not exist: ${
|
|
55
|
+
return `Error: project_path does not exist: ${resolved}`;
|
|
38
56
|
}
|
|
39
57
|
if (error?.code === "EACCES" || error?.code === "EPERM") {
|
|
40
|
-
return `Error: cannot access project_path (${error.code}): ${
|
|
58
|
+
return `Error: cannot access project_path (${error.code}): ${resolved}`;
|
|
41
59
|
}
|
|
42
60
|
const reason = error?.message ? `${error.code || "UNKNOWN"}: ${error.message}` : String(error);
|
|
43
61
|
return `Error: failed to validate project_path: ${reason}`;
|
package/src/server.mjs
CHANGED
|
@@ -22,7 +22,11 @@ import { fileURLToPath } from "node:url";
|
|
|
22
22
|
import { z } from "zod";
|
|
23
23
|
|
|
24
24
|
import { searchWithContent, extractKeyInfo } from "./core.mjs";
|
|
25
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
projectPathSchema,
|
|
27
|
+
resolveProjectPath,
|
|
28
|
+
validateProjectPath,
|
|
29
|
+
} from "./project-path.mjs";
|
|
26
30
|
|
|
27
31
|
const PACKAGE_JSON = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
28
32
|
export const SERVER_VERSION = PACKAGE_JSON.version;
|
|
@@ -91,16 +95,23 @@ export function buildFastContextSearchTool({
|
|
|
91
95
|
const runSearchWithContent = deps.searchWithContent || searchWithContent;
|
|
92
96
|
const validatePath = deps.validateProjectPath || validateProjectPath;
|
|
93
97
|
const description =
|
|
94
|
-
"
|
|
95
|
-
"Locates relevant files, exact line ranges, and code regions from natural language
|
|
98
|
+
"Primary tool for semantic codebase search, context discovery, and verifying logic existence. " +
|
|
99
|
+
"Locates relevant files, exact line ranges, and code regions from natural language or domain concepts in a single step, " +
|
|
96
100
|
"without needing manual grep trials or knowing exact filenames.\n\n" +
|
|
97
|
-
"
|
|
98
|
-
"-
|
|
99
|
-
"
|
|
100
|
-
"-
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
101
|
+
"MANDATORY REQUIREMENT:\n" +
|
|
102
|
+
"- 'project_path' is strictly REQUIRED. You MUST provide the absolute path to the project root directory when calling this tool.\n\n" +
|
|
103
|
+
"RECOMMENDED FOR:\n" +
|
|
104
|
+
"- Verifying feature/data existence: Checking whether a business rule, model, seed data, configuration, or API already exists (e.g. 'check if warrior coefficient seed data exists', 'has rate limiting been added').\n" +
|
|
105
|
+
"- Finding conceptual business logic: Locating where behavior lives across the codebase without guessing file names.\n" +
|
|
106
|
+
"- Tracing multi-file flows: Getting high-relevance entry points, line ranges, and suggested grep keywords before reading code.\n\n" +
|
|
107
|
+
"DO NOT USE WHEN (Avoid Overuse):\n" +
|
|
108
|
+
"- Target file is already known, opened, or specified by the user (use view_file / read_file directly).\n" +
|
|
109
|
+
"- Exact symbol search: Searching for an exact, known function/class/variable name (use grep instead).\n" +
|
|
110
|
+
"- Directory exploration: Simply listing files in a directory (use list_dir/glob instead).\n" +
|
|
111
|
+
"- Single-file localized edits or lint fixes.\n\n" +
|
|
112
|
+
"QUERY TIPS:\n" +
|
|
113
|
+
"- For best semantic search quality, write the query primarily in English; keep local-language domain terms when needed (e.g. 'seed data for sale he so chien binh').\n" +
|
|
114
|
+
"- Use tree_depth/max_turns/max_results for task-level tuning; use exclude_paths to reduce payload or noise.\n" +
|
|
104
115
|
(config.includeSnippetsExplicitlySet
|
|
105
116
|
? `- include_code_snippets: Server-configured default is ${config.includeSnippets}. Do NOT override unless explicitly asked by the user.\n`
|
|
106
117
|
: "- include_code_snippets: Default false (lightweight mode, ~2-5KB output). " +
|
|
@@ -115,8 +126,9 @@ export function buildFastContextSearchTool({
|
|
|
115
126
|
'Add local-language business terms only when needed.'
|
|
116
127
|
),
|
|
117
128
|
project_path: projectPathSchema.describe(
|
|
118
|
-
"
|
|
119
|
-
"
|
|
129
|
+
"Optional path to project root directory (absolute or relative). " +
|
|
130
|
+
"Defaults to current workspace directory if omitted. " +
|
|
131
|
+
"Example: /Users/username/projects/myproject or C:/Users/username/projects/myproject or ."
|
|
120
132
|
),
|
|
121
133
|
tree_depth: z
|
|
122
134
|
.number()
|
|
@@ -184,7 +196,7 @@ export function buildFastContextSearchTool({
|
|
|
184
196
|
exclude_paths,
|
|
185
197
|
include_code_snippets,
|
|
186
198
|
}) => {
|
|
187
|
-
const projectPath = project_path;
|
|
199
|
+
const projectPath = resolveProjectPath(project_path);
|
|
188
200
|
const validationError = validatePath(projectPath);
|
|
189
201
|
if (validationError) {
|
|
190
202
|
return { content: [{ type: "text", text: validationError }] };
|