mcp-code-context 2.1.3 โ†’ 2.2.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.
Files changed (35) hide show
  1. package/CHANGELOG.md +44 -71
  2. package/CONTRIBUTING.md +243 -0
  3. package/MEJORAS_PROPUESTAS.md +324 -0
  4. package/README.md +31 -7
  5. package/RELEASE_NOTES_v2.2.0.md +286 -0
  6. package/dist/src/index.d.ts +36 -0
  7. package/dist/src/index.js +198 -2
  8. package/dist/src/index.js.map +1 -1
  9. package/dist/src/tools/readFileLines.d.ts +26 -0
  10. package/dist/src/tools/readFileLines.js +77 -0
  11. package/dist/src/tools/readFileLines.js.map +1 -0
  12. package/dist/src/tools/searchCodePattern.d.ts +32 -0
  13. package/dist/src/tools/searchCodePattern.js +80 -0
  14. package/dist/src/tools/searchCodePattern.js.map +1 -0
  15. package/dist/src/utils/backupManager.d.ts +13 -6
  16. package/dist/src/utils/backupManager.js +73 -8
  17. package/dist/src/utils/backupManager.js.map +1 -1
  18. package/dist/src/utils/projectRoot.d.ts +10 -0
  19. package/dist/src/utils/projectRoot.js +40 -0
  20. package/dist/src/utils/projectRoot.js.map +1 -0
  21. package/dist/tests/test-backup-system.d.ts +7 -0
  22. package/dist/tests/test-backup-system.js +152 -0
  23. package/dist/tests/test-backup-system.js.map +1 -0
  24. package/dist/tests/test-new-tools.d.ts +4 -0
  25. package/dist/tests/test-new-tools.js +147 -0
  26. package/dist/tests/test-new-tools.js.map +1 -0
  27. package/llms.txt +62 -7
  28. package/package.json +2 -2
  29. package/src/index.ts +233 -2
  30. package/src/tools/readFileLines.ts +104 -0
  31. package/src/tools/searchCodePattern.ts +129 -0
  32. package/src/utils/backupManager.ts +83 -8
  33. package/src/utils/projectRoot.ts +44 -0
  34. package/tests/test-backup-system.ts +174 -0
  35. package/tests/test-new-tools.ts +165 -0
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Tests for Centralized Backup System
3
+ * - Backup creation in project root
4
+ * - Folder structure preservation
5
+ * - clean_backups functionality
6
+ */
7
+ export {};
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Tests for Centralized Backup System
3
+ * - Backup creation in project root
4
+ * - Folder structure preservation
5
+ * - clean_backups functionality
6
+ */
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ import { createBackup, cleanAllBackups } from '../src/utils/backupManager.js';
10
+ import { findProjectRoot } from '../src/utils/projectRoot.js';
11
+ const TEST_DIR = path.join(process.cwd(), 'tests', 'fixtures', 'backup-test-project');
12
+ const TEST_FILE = path.join(TEST_DIR, 'src', 'components', 'Button.tsx');
13
+ function setupTestProject() {
14
+ // Create test project structure
15
+ if (fs.existsSync(TEST_DIR)) {
16
+ fs.rmSync(TEST_DIR, { recursive: true, force: true });
17
+ }
18
+ fs.mkdirSync(path.join(TEST_DIR, 'src', 'components'), { recursive: true });
19
+ fs.writeFileSync(TEST_FILE, 'export const Button = () => <button>Click</button>;');
20
+ // Create package.json to mark as project root
21
+ fs.writeFileSync(path.join(TEST_DIR, 'package.json'), JSON.stringify({ name: 'backup-test-project' }));
22
+ }
23
+ function cleanupTestProject() {
24
+ if (fs.existsSync(TEST_DIR)) {
25
+ fs.rmSync(TEST_DIR, { recursive: true, force: true });
26
+ }
27
+ }
28
+ function runTests() {
29
+ console.log('\n๐Ÿงช Testing Centralized Backup System...\n');
30
+ let passed = 0;
31
+ let failed = 0;
32
+ // Setup
33
+ setupTestProject();
34
+ try {
35
+ // Test 1: Find project root
36
+ console.log('Test 1: Find project root');
37
+ const projectRoot = findProjectRoot(TEST_FILE);
38
+ if (projectRoot === TEST_DIR) {
39
+ console.log('โœ… PASS: Project root found correctly');
40
+ passed++;
41
+ }
42
+ else {
43
+ console.log(`โŒ FAIL: Expected ${TEST_DIR}, got ${projectRoot}`);
44
+ failed++;
45
+ }
46
+ // Test 2: Create backup in centralized location
47
+ console.log('\nTest 2: Create backup in centralized location');
48
+ const backupPath = createBackup(TEST_FILE);
49
+ const expectedBackupDir = path.join(TEST_DIR, '.mcp-backups', 'src', 'components');
50
+ const backupExists = fs.existsSync(backupPath);
51
+ const inCorrectLocation = backupPath.startsWith(expectedBackupDir);
52
+ if (backupExists && inCorrectLocation) {
53
+ console.log('โœ… PASS: Backup created in centralized location');
54
+ console.log(` Location: ${backupPath}`);
55
+ passed++;
56
+ }
57
+ else {
58
+ console.log('โŒ FAIL: Backup not in correct location');
59
+ console.log(` Expected dir: ${expectedBackupDir}`);
60
+ console.log(` Actual path: ${backupPath}`);
61
+ failed++;
62
+ }
63
+ // Test 3: Backup preserves folder structure
64
+ console.log('\nTest 3: Backup preserves folder structure');
65
+ const relativePath = path.relative(TEST_DIR, TEST_FILE);
66
+ const expectedStructure = path.join('.mcp-backups', relativePath);
67
+ const actualStructure = path.relative(TEST_DIR, backupPath.replace(/\.\d+\.backup$/, ''));
68
+ if (actualStructure.startsWith(expectedStructure)) {
69
+ console.log('โœ… PASS: Folder structure preserved');
70
+ console.log(` Structure: ${expectedStructure}`);
71
+ passed++;
72
+ }
73
+ else {
74
+ console.log('โŒ FAIL: Folder structure not preserved');
75
+ console.log(` Expected: ${expectedStructure}`);
76
+ console.log(` Actual: ${actualStructure}`);
77
+ failed++;
78
+ }
79
+ // Test 4: Multiple backups in same location
80
+ console.log('\nTest 4: Multiple backups (rolling system)');
81
+ const backup2 = createBackup(TEST_FILE);
82
+ const backup3 = createBackup(TEST_FILE);
83
+ const allBackups = fs.readdirSync(expectedBackupDir)
84
+ .filter(f => f.startsWith('Button.tsx.') && f.endsWith('.backup'));
85
+ if (allBackups.length === 3) {
86
+ console.log('โœ… PASS: Multiple backups created');
87
+ console.log(` Backups: ${allBackups.join(', ')}`);
88
+ passed++;
89
+ }
90
+ else {
91
+ console.log(`โŒ FAIL: Expected 3 backups, found ${allBackups.length}`);
92
+ failed++;
93
+ }
94
+ // Test 5: clean_backups removes all backups
95
+ console.log('\nTest 5: clean_backups removes all backups');
96
+ const result = cleanAllBackups(TEST_DIR);
97
+ const backupDirExists = fs.existsSync(path.join(TEST_DIR, '.mcp-backups'));
98
+ if (result && !backupDirExists) {
99
+ console.log('โœ… PASS: All backups cleaned');
100
+ console.log(` Backup directory removed successfully`);
101
+ passed++;
102
+ }
103
+ else {
104
+ console.log('โŒ FAIL: Backups not cleaned properly');
105
+ console.log(` Result: ${result}, Dir exists: ${backupDirExists}`);
106
+ failed++;
107
+ }
108
+ // Test 6: clean_backups on non-existent directory
109
+ console.log('\nTest 6: clean_backups on non-existent directory');
110
+ const result2 = cleanAllBackups(TEST_DIR);
111
+ if (!result2) {
112
+ console.log('โœ… PASS: Returns false when backup directory not found');
113
+ passed++;
114
+ }
115
+ else {
116
+ console.log('โŒ FAIL: Should return false when directory not found');
117
+ failed++;
118
+ }
119
+ // Test 7: Backup in nested project structure
120
+ console.log('\nTest 7: Backup in deeply nested file');
121
+ const deepFile = path.join(TEST_DIR, 'src', 'features', 'auth', 'components', 'LoginForm.tsx');
122
+ fs.mkdirSync(path.dirname(deepFile), { recursive: true });
123
+ fs.writeFileSync(deepFile, 'export const LoginForm = () => <form />;');
124
+ const deepBackup = createBackup(deepFile);
125
+ const expectedDeepDir = path.join(TEST_DIR, '.mcp-backups', 'src', 'features', 'auth', 'components');
126
+ if (deepBackup.startsWith(expectedDeepDir)) {
127
+ console.log('โœ… PASS: Deep nesting preserved');
128
+ console.log(` Path: ${path.relative(TEST_DIR, deepBackup)}`);
129
+ passed++;
130
+ }
131
+ else {
132
+ console.log('โŒ FAIL: Deep nesting not preserved');
133
+ failed++;
134
+ }
135
+ }
136
+ catch (error) {
137
+ console.log(`โŒ FAIL: Unexpected error: ${error}`);
138
+ failed++;
139
+ }
140
+ finally {
141
+ // Cleanup
142
+ cleanupTestProject();
143
+ }
144
+ console.log('\nโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•');
145
+ console.log(`๐Ÿ“Š Results: ${passed} passed, ${failed} failed (${passed + failed} total)`);
146
+ console.log('โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•\n');
147
+ if (failed > 0) {
148
+ process.exit(1);
149
+ }
150
+ }
151
+ runTests();
152
+ //# sourceMappingURL=test-backup-system.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-backup-system.js","sourceRoot":"","sources":["../../tests/test-backup-system.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Test suite for new tools: read_file_lines and search_code_pattern
3
+ */
4
+ export {};
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Test suite for new tools: read_file_lines and search_code_pattern
3
+ */
4
+ import { readFileLines } from "../src/tools/readFileLines.js";
5
+ import { searchCodePattern } from "../src/tools/searchCodePattern.js";
6
+ import * as fs from "node:fs";
7
+ import * as path from "node:path";
8
+ import { fileURLToPath } from "node:url";
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = path.dirname(__filename);
11
+ // Create test file
12
+ const testDir = path.join(__dirname, "test-data");
13
+ const testFile = path.join(testDir, "sample.ts");
14
+ if (!fs.existsSync(testDir)) {
15
+ fs.mkdirSync(testDir, { recursive: true });
16
+ }
17
+ const testContent = `// Sample TypeScript file
18
+ export class Calculator {
19
+ add(a: number, b: number): number {
20
+ return a + b;
21
+ }
22
+
23
+ subtract(a: number, b: number): number {
24
+ return a - b;
25
+ }
26
+
27
+ multiply(a: number, b: number): number {
28
+ return a * b;
29
+ }
30
+
31
+ divide(a: number, b: number): number {
32
+ if (b === 0) throw new Error("Division by zero");
33
+ return a / b;
34
+ }
35
+ }
36
+
37
+ export function greet(name: string): string {
38
+ return \`Hello, \${name}!\`;
39
+ }
40
+ `;
41
+ fs.writeFileSync(testFile, testContent, "utf-8");
42
+ console.log("๐Ÿงช Testing read_file_lines...\n");
43
+ // Test 1: Read exact line range
44
+ console.log("Test 1: Read lines 3-7");
45
+ const result1 = readFileLines({
46
+ filePath: testFile,
47
+ startLine: 3,
48
+ endLine: 7,
49
+ });
50
+ if (result1.success && result1.content?.includes("add")) {
51
+ console.log("โœ… PASS: Exact line range");
52
+ }
53
+ else {
54
+ console.error("โŒ FAIL: Exact line range");
55
+ console.error(result1);
56
+ }
57
+ // Test 2: Read around pattern
58
+ console.log("\nTest 2: Read around pattern 'multiply'");
59
+ const result2 = readFileLines({
60
+ filePath: testFile,
61
+ aroundPattern: "multiply",
62
+ contextLines: 2,
63
+ });
64
+ if (result2.success && result2.content?.includes("multiply")) {
65
+ console.log("โœ… PASS: Pattern search");
66
+ }
67
+ else {
68
+ console.error("โŒ FAIL: Pattern search");
69
+ console.error(result2);
70
+ }
71
+ // Test 3: Invalid line range
72
+ console.log("\nTest 3: Invalid line range (should fail)");
73
+ const result3 = readFileLines({
74
+ filePath: testFile,
75
+ startLine: 100,
76
+ endLine: 200,
77
+ });
78
+ if (!result3.success && result3.error?.includes("Invalid line range")) {
79
+ console.log("โœ… PASS: Error handling for invalid range");
80
+ }
81
+ else {
82
+ console.error("โŒ FAIL: Should have failed with invalid range");
83
+ }
84
+ // Test 4: Pattern not found
85
+ console.log("\nTest 4: Pattern not found (should fail)");
86
+ const result4 = readFileLines({
87
+ filePath: testFile,
88
+ aroundPattern: "nonexistent_pattern_xyz",
89
+ });
90
+ if (!result4.success && result4.error?.includes("not found")) {
91
+ console.log("โœ… PASS: Error handling for pattern not found");
92
+ }
93
+ else {
94
+ console.error("โŒ FAIL: Should have failed with pattern not found");
95
+ }
96
+ console.log("\n๐Ÿงช Testing search_code_pattern...\n");
97
+ // Test 5: Search for pattern
98
+ console.log("Test 5: Search for 'Calculator'");
99
+ const result5 = searchCodePattern({
100
+ rootDir: testDir,
101
+ pattern: "Calculator",
102
+ fileExtensions: [".ts"],
103
+ maxResults: 10,
104
+ });
105
+ if (result5.success && result5.matches && result5.matches.length > 0) {
106
+ console.log(`โœ… PASS: Found ${result5.totalMatches} matches`);
107
+ }
108
+ else {
109
+ console.error("โŒ FAIL: Should have found matches");
110
+ console.error(result5);
111
+ }
112
+ // Test 6: Search with no matches
113
+ console.log("\nTest 6: Search for non-existent pattern");
114
+ const result6 = searchCodePattern({
115
+ rootDir: testDir,
116
+ pattern: "NonExistentClass123",
117
+ fileExtensions: [".ts"],
118
+ });
119
+ if (result6.success && result6.totalMatches === 0) {
120
+ console.log("โœ… PASS: No matches found (as expected)");
121
+ }
122
+ else {
123
+ console.error("โŒ FAIL: Should have found no matches");
124
+ }
125
+ // Test 7: Search with context
126
+ console.log("\nTest 7: Search with context lines");
127
+ const result7 = searchCodePattern({
128
+ rootDir: testDir,
129
+ pattern: "divide",
130
+ fileExtensions: [".ts"],
131
+ showContext: true,
132
+ contextLines: 2,
133
+ });
134
+ if (result7.success &&
135
+ result7.matches &&
136
+ result7.matches[0]?.context &&
137
+ result7.matches[0].context.length > 0) {
138
+ console.log("โœ… PASS: Context lines included");
139
+ }
140
+ else {
141
+ console.error("โŒ FAIL: Context lines not included");
142
+ console.error(result7);
143
+ }
144
+ // Cleanup
145
+ fs.rmSync(testDir, { recursive: true, force: true });
146
+ console.log("\nโœจ All tests completed!");
147
+ //# sourceMappingURL=test-new-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-new-tools.js","sourceRoot":"","sources":["../../tests/test-new-tools.ts"],"names":[],"mappings":"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"}
package/llms.txt CHANGED
@@ -57,24 +57,79 @@ This MCP server solves two problems:
57
57
 
58
58
  **Best used when:** You're about to modify a file and need to understand the blast radius.
59
59
 
60
- #### 4. `rollback_file`
60
+ #### 4. `read_file_lines`
61
+ **Purpose:** Read specific line ranges from a file without loading the entire content.
62
+
63
+ **Input:**
64
+ - `filePath` (required): Absolute path to the source file.
65
+ - `startLine` (optional): Starting line number (1-indexed).
66
+ - `endLine` (optional): Ending line number (1-indexed).
67
+ - `aroundPattern` (optional): Search pattern to find and return surrounding lines.
68
+ - `contextLines` (optional): Number of lines before/after pattern (default: 5).
69
+
70
+ **What it does:**
71
+ - **Mode 1 (Exact Range)**: When `startLine` and `endLine` are provided, returns only those lines.
72
+ - **Mode 2 (Pattern Search)**: When `aroundPattern` is provided, finds the first occurrence and returns surrounding lines with context.
73
+ - Validates line ranges and provides clear error messages.
74
+ - 90% token savings compared to reading full files for small fragments.
75
+
76
+ **Best used when:**
77
+ - Debugging specific code blocks when you know the line numbers
78
+ - Viewing context around error messages or logs
79
+ - Extracting small fragments without AST parsing overhead
80
+
81
+ **Example use cases:**
82
+ - "Show me lines 120-135 of coordinator.dart"
83
+ - "Show me the code around 'HeroBannerWidget' in hero_banner_widget.dart"
84
+
85
+ #### 5. `search_code_pattern`
86
+ **Purpose:** Search for code patterns across multiple files in a repository.
87
+
88
+ **Input:**
89
+ - `rootDir` (required): Absolute path to the repository root.
90
+ - `pattern` (required): Regular expression pattern to search for.
91
+ - `fileExtensions` (optional): Array of extensions to search (e.g., `[".ts", ".dart"]`). Defaults to common code extensions.
92
+ - `excludeDirs` (optional): Directories to exclude (default: `["node_modules", "dist", "build"]`).
93
+ - `showContext` (optional): Include surrounding lines (default: true).
94
+ - `contextLines` (optional): Number of context lines before/after (default: 3).
95
+ - `maxResults` (optional): Maximum matches to return (default: 50).
96
+
97
+ **What it does:**
98
+ - Walks the repository respecting `.gitignore` rules.
99
+ - Searches for regex patterns across all matching files.
100
+ - Returns structured results with file paths, line numbers, and optional context.
101
+ - Highlights the matching line with a `>` marker in context output.
102
+ - 85% more efficient than manual grep + analysis workflows.
103
+
104
+ **Best used when:**
105
+ - Finding all usages of a function or variable
106
+ - Locating specific log statements or debug markers
107
+ - Discovering patterns across the codebase
108
+ - Understanding how a feature is implemented across files
109
+
110
+ **Example use cases:**
111
+ - "Find all occurrences of 'widget.height' in the Flutter project"
112
+ - "Search for '๐ŸŽฏ \[BUILDER\]' logs in .dart files"
113
+ - "Find all files that call 'HeroBannerWidget'"
114
+
115
+ #### 6. `rollback_file`
61
116
  **Purpose:** Restores a file to a previous state from the automated backup system.
62
117
  **Input:**
63
118
  - `filePath` (required): Absolute path.
64
119
  - `steps` (optional): Number of versions to go back (1-5, default: 1).
65
120
  **What it does:** Reverts the file to the state it was in before the last 1-5 modifications.
66
121
 
67
- ### Write Tools (v2.1.3 Mandatory Workflow)
122
+ ### Write Tools (v2.2.0 Mandatory Workflow)
68
123
 
69
124
  All write tools follow a **Two-Phase Workflow**:
70
125
  1. **Phase 1 (Preview)**: Call without a token to get a unified `diff` and a `confirmationToken`.
71
126
  2. **Phase 2 (Apply)**: Call with `confirmationToken` and `confirm: true` to apply the changes.
72
127
 
73
- **Important Notes (v2.1.3):**
128
+ **Important Notes (v2.2.0):**
74
129
  - โœ… **Windows CRLF Support**: Fully resolved. All operations work correctly on Windows files with CRLF line endings.
75
130
  - โœ… **Parameter Brace Handling**: Methods with braces in parameters (e.g., `{int? cart}`) are now handled correctly.
76
131
 
77
- #### 5. `write_file_surgical`
132
+ #### 7. `write_file_surgical`
78
133
  **Purpose:** Replace the full source code of a named symbol in a file.
79
134
 
80
135
  **Input:**
@@ -93,7 +148,7 @@ All write tools follow a **Two-Phase Workflow**:
93
148
 
94
149
  **Best used when:** You need to modify a specific function or method without touching the rest of the file.
95
150
 
96
- #### 5. `insert_symbol`
151
+ #### 8. `insert_symbol`
97
152
  **Purpose:** Insert new code at a precise location relative to an existing symbol.
98
153
 
99
154
  **Input:**
@@ -110,7 +165,7 @@ All write tools follow a **Two-Phase Workflow**:
110
165
 
111
166
  **Best used when:** Adding new methods to a class or new functions to a module.
112
167
 
113
- #### 6. `rename_symbol`
168
+ #### 9. `rename_symbol`
114
169
  **Purpose:** Rename a symbol across an entire repository.
115
170
 
116
171
  **Input:**
@@ -129,7 +184,7 @@ All write tools follow a **Two-Phase Workflow**:
129
184
 
130
185
  **Best used when:** Refactoring a class, function, or method name that is used across multiple files.
131
186
 
132
- #### 7. `remove_symbol`
187
+ #### 10. `remove_symbol`
133
188
  **Purpose:** Safely remove a symbol from a file.
134
189
 
135
190
  **Input:**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-code-context",
3
- "version": "2.1.3",
3
+ "version": "2.2.0",
4
4
  "description": "Powerful MCP server for LLM-ready semantic code context and surgical AST-aware editing. Supports TypeScript, JavaScript, PHP, Dart, and Python.",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -11,7 +11,7 @@
11
11
  "build": "tsc",
12
12
  "start": "node dist/src/index.js",
13
13
  "dev": "tsc && node dist/src/index.js",
14
- "test": "npm run build && node dist/tests/test-dart.js && node dist/tests/test-php.js && node dist/tests/writers/test-write-smoke.js",
14
+ "test": "npm run build && node dist/tests/test-dart.js && node dist/tests/test-php.js && node dist/tests/writers/test-write-smoke.js && node dist/tests/test-new-tools.js && node dist/tests/test-backup-system.js",
15
15
  "clean": "rimraf dist",
16
16
  "rebuild": "npm run clean && npm run build"
17
17
  },