skydeckai-code 0.1.34__py3-none-any.whl → 0.1.35__py3-none-any.whl

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.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skydeckai-code
3
- Version: 0.1.34
4
- Summary: This MCP server provides a comprehensive set of tools for AI-driven Development workflows including file operations, code analysis, code linting, multi-language execution, Git operations, web content fetching with HTML-to-markdown conversion, multi-engine web search, code content searching, and system information retrieval.
3
+ Version: 0.1.35
4
+ Summary: This MCP server provides a comprehensive set of tools for AI-driven Development workflows including file operations, code analysis, multi-language execution, web content fetching with HTML-to-markdown conversion, multi-engine web search, code content searching, and system information retrieval.
5
5
  Project-URL: Homepage, https://github.com/skydeckai/skydeckai-code
6
6
  Project-URL: Repository, https://github.com/skydeckai/skydeckai-code
7
7
  Project-URL: Documentation, https://github.com/skydeckai/skydeckai-code/blob/main/README.md
@@ -11,7 +11,6 @@ License-File: LICENSE
11
11
  Keywords: ai,aidd,code,code-analysis,development,mcp
12
12
  Requires-Python: >=3.11
13
13
  Requires-Dist: beautifulsoup4>=4.13.3
14
- Requires-Dist: gitpython>=3.1.44
15
14
  Requires-Dist: html2text>=2025.4.15
16
15
  Requires-Dist: mcp>=1.6.0
17
16
  Requires-Dist: mss>=10.0.0
@@ -36,7 +35,7 @@ Description-Content-Type: text/markdown
36
35
 
37
36
  # SkyDeckAI Code
38
37
 
39
- An MCP server that provides a comprehensive set of tools for AI-driven development workflows. Features include file system operations, code analysis using tree-sitter for multiple programming languages, Git operations, code execution, web content fetching with HTML-to-markdown conversion, multi-engine web search, code content searching, linting detection, and system information retrieval. Designed to enhance AI's capability to assist in software development tasks by providing direct access to both local and remote resources.
38
+ An MCP server that provides a comprehensive set of tools for AI-driven development workflows. Features include file system operations, code analysis using tree-sitter for multiple programming languages, code execution, web content fetching with HTML-to-markdown conversion, multi-engine web search, code content searching, and system information retrieval. Designed to enhance AI's capability to assist in software development tasks by providing direct access to both local and remote resources.
40
39
 
41
40
  # Formerly Known As MCP-Server-AIDD
42
41
 
@@ -80,7 +79,6 @@ If you're using SkyDeck AI Helper app, you can search for "SkyDeckAI Code" and i
80
79
  - Code linting and issue detection for Python and JavaScript/TypeScript
81
80
  - Code content searching with regex pattern matching
82
81
  - Multi-language code execution with safety measures
83
- - Git operations (status, diff, commit, branch management, cloning)
84
82
  - Web content fetching from APIs and websites with HTML-to-markdown conversion
85
83
  - Multi-engine web search with reliable fallback mechanisms
86
84
  - Batch operations for parallel and serial tool execution
@@ -183,69 +181,6 @@ skydeckai-code-cli --tool list_directory --args '{"path": "."}'
183
181
  skydeckai-code-cli --tool search_files --args '{"pattern": ".py", "path": "src"}'
184
182
  ```
185
183
 
186
- ### Git Operations
187
-
188
- | Tool | Parameters | Returns |
189
- | ----------------- | ------------------------------------------------- | -------------------------------- |
190
- | git_init | path: string, initial_branch?: string | Repository initialization status |
191
- | git_status | repo_path: string | Working directory status |
192
- | git_add | repo_path: string, files: string[] | Staging confirmation |
193
- | git_reset | repo_path: string | Unstaging confirmation |
194
- | git_checkout | repo_path: string, branch_name: string | Branch switch confirmation |
195
- | git_create_branch | repo_path: string, branch_name: string | Branch creation confirmation |
196
- | git_clone | url: string, target_path: string, branch?: string | Clone confirmation |
197
- | git_diff_unstaged | repo_path: string | Unstaged changes diff |
198
- | git_diff_staged | repo_path: string | Staged changes diff |
199
- | git_show | repo_path: string, commit_hash: string | Details of a specific commit |
200
-
201
- #### Complex Git Operations
202
-
203
- ##### git_commit
204
-
205
- ```json
206
- {
207
- "repo_path": ".",
208
- "message": "feat: add new feature"
209
- }
210
- ```
211
-
212
- Returns: Commit hash and confirmation.
213
-
214
- ##### git_diff
215
-
216
- ```json
217
- {
218
- "repo_path": ".",
219
- "target": "main"
220
- }
221
- ```
222
-
223
- Returns: Detailed diff output showing all changes between the current branch and the specified target branch or commit.
224
-
225
- ##### git_log
226
-
227
- ```json
228
- {
229
- "repo_path": ".",
230
- "max_count": 10
231
- }
232
- ```
233
-
234
- Returns: Array of commit entries with hash, author, date, and message.
235
-
236
- Common usage:
237
-
238
- ```bash
239
- # Check status
240
- skydeckai-code-cli --tool git_status --args '{"repo_path": "."}'
241
-
242
- # Clone a repository
243
- skydeckai-code-cli --tool git_clone --args '{"url": "https://github.com/username/repo.git", "target_path": "repo"}'
244
-
245
- # Create and switch to new branch
246
- skydeckai-code-cli --tool git_create_branch --args '{"repo_path": ".", "branch_name": "feature/new-branch"}'
247
- ```
248
-
249
184
  ### Code Analysis
250
185
 
251
186
  #### codebase_mapper
@@ -269,8 +204,8 @@ Returns:
269
204
  Supported Languages:
270
205
 
271
206
  - Python (.py)
272
- - JavaScript (.js, .jsx, .mjs, .cjs)
273
- - TypeScript (.ts, .tsx)
207
+ - JavaScript (.js/.jsx, .mjs, .cjs)
208
+ - TypeScript (.ts/.tsx)
274
209
  - Java (.java)
275
210
  - C++ (.cpp, .hpp, .cc)
276
211
  - Ruby (.rb, .rake)
@@ -280,71 +215,17 @@ Supported Languages:
280
215
  - C# (.cs)
281
216
  - Kotlin (.kt, .kts)
282
217
 
283
- #### check_lint
284
-
285
- Check for linting issues in your codebase using native linting tools:
286
-
287
- ```json
288
- {
289
- "path": "src",
290
- "languages": ["python", "javascript"],
291
- "linters": {
292
- "pylint": "--disable=C0111",
293
- "flake8": true,
294
- "eslint": "--fix"
295
- },
296
- "max_issues": 100
297
- }
298
- ```
299
-
300
- **Parameters:**
301
- | Parameter | Type | Required | Description |
302
- |-----------|------|----------|-------------|
303
- | path | string | No | Directory or file to lint (default: ".") |
304
- | languages | array | No | List of languages to lint (auto-detects if empty) |
305
- | linters | object | No | Configuration for specific linters - can use booleans or CLI arguments |
306
- | max_issues | integer | No | Maximum number of issues to return (default: 100, 0 for unlimited) |
307
-
308
- **Returns:**
309
- A detailed report of linting issues found in the codebase, including file paths, line numbers, issue descriptions, and severity levels. Issues are grouped by file and sorted by severity.
310
-
311
- **Supported Languages and Linters:**
312
-
313
- - Python: pylint, flake8 (automatically uses what's available)
314
- - JavaScript/TypeScript: ESLint
315
- - Dart/Flutter: dart_analyze (also reports compilation errors)
316
-
317
218
  **Example Usage:**
318
219
 
319
220
  ```bash
320
- # Check entire codebase with default settings
321
- skydeckai-code-cli --tool check_lint
322
-
323
- # Check specific directory with custom pylint flags
324
- skydeckai-code-cli --tool check_lint --args '{
325
- "path": "src",
326
- "linters": {
327
- "pylint": "--disable=missing-docstring,invalid-name"
328
- }
329
- }'
221
+ # Map the entire codebase structure
222
+ skydeckai-code-cli --tool codebase_mapper --args '{"path": "."}'
330
223
 
331
- # Check only Python files and disable flake8
332
- skydeckai-code-cli --tool check_lint --args '{
333
- "path": "src",
334
- "languages": ["python"],
335
- "linters": {
336
- "flake8": false
337
- }
338
- }'
224
+ # Map only the source directory
225
+ skydeckai-code-cli --tool codebase_mapper --args '{"path": "src"}'
339
226
 
340
- # Check Dart/Flutter files for linting and compilation errors
341
- skydeckai-code-cli --tool check_lint --args '{
342
- "path": "lib",
343
- "languages": ["dart"],
344
- "linters": {
345
- "dart_analyze": "--fatal-infos"
346
- }
347
- }'
227
+ # Map a specific component or module
228
+ skydeckai-code-cli --tool codebase_mapper --args '{"path": "src/components"}'
348
229
  ```
349
230
 
350
231
  #### search_code
@@ -353,7 +234,7 @@ Fast content search tool using regular expressions:
353
234
 
354
235
  ```json
355
236
  {
356
- "pattern": "function\\s+\\w+",
237
+ "patterns": ["function\\s+\\w+", "class\\s+\\w+"],
357
238
  "include": "*.js",
358
239
  "exclude": "node_modules/**",
359
240
  "max_results": 50,
@@ -365,10 +246,10 @@ Fast content search tool using regular expressions:
365
246
  **Parameters:**
366
247
  | Parameter | Type | Required | Description |
367
248
  |-----------|------|----------|-------------|
368
- | pattern | string | Yes | Regular expression pattern to search in file contents |
249
+ | patterns | array of strings | Yes | List of regular expression patterns to search for in file contents |
369
250
  | include | string | No | File pattern to include (glob syntax, default: "\*") |
370
251
  | exclude | string | No | File pattern to exclude (glob syntax, default: "") |
371
- | max_results | integer | No | Maximum results to return (default: 100) |
252
+ | max_results | integer | No | Maximum results to return per pattern (default: 100) |
372
253
  | case_sensitive | boolean | No | Whether search is case-sensitive (default: false) |
373
254
  | path | string | No | Base directory to search from (default: ".") |
374
255
 
@@ -380,21 +261,21 @@ This tool uses ripgrep when available for optimal performance, with a Python fal
380
261
  **Example Usage:**
381
262
 
382
263
  ```bash
383
- # Find function declarations in JavaScript files
264
+ # Find function and class declarations in JavaScript files
384
265
  skydeckai-code-cli --tool search_code --args '{
385
- "pattern": "function\\s+\\w+",
266
+ "patterns": ["function\\s+\\w+", "class\\s+\\w+"],
386
267
  "include": "*.js"
387
268
  }'
388
269
 
389
- # Find all console.log statements with errors
270
+ # Find all console.log statements with errors or warnings
390
271
  skydeckai-code-cli --tool search_code --args '{
391
- "pattern": "console\\.log.*[eE]rror",
272
+ "patterns": ["console\\.log.*[eE]rror", "console\\.log.*[wW]arning"],
392
273
  "path": "src"
393
274
  }'
394
275
 
395
- # Find import statements in TypeScript files
276
+ # Find import and export statements in TypeScript files
396
277
  skydeckai-code-cli --tool search_code --args '{
397
- "pattern": "import.*from",
278
+ "patterns": ["import.*from", "export.*"],
398
279
  "include": "*.{ts,tsx}",
399
280
  "exclude": "node_modules/**"
400
281
  }'
@@ -692,10 +573,9 @@ Execute multiple tool invocations in a single request with parallel execution wh
692
573
  }
693
574
  },
694
575
  {
695
- "tool": "git_init",
576
+ "tool": "execute_shell_script",
696
577
  "arguments": {
697
- "path": ".",
698
- "initial_branch": "main"
578
+ "script": "git init"
699
579
  }
700
580
  }
701
581
  ]
@@ -2,26 +2,24 @@ src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  src/aidd/__init__.py,sha256=c9HBWxWruCxoAqLCJqltylAwz_7xmaK3g8DKViJZs0Q,222
3
3
  src/aidd/cli.py,sha256=cLtaQJmMBfr7fHkd0dyJqpDrVTIwybL48PotniWGrFM,5031
4
4
  src/aidd/server.py,sha256=kPRyWeWkMCZjabelC65XTmzZG7yw8htMJKSfnUcKnb0,1575
5
- src/aidd/tools/__init__.py,sha256=abFameL2CdSZohi7Sa1tUEOzD2M6bcXSOkRpgxfZ1mo,5429
5
+ src/aidd/tools/__init__.py,sha256=MN4QEu4pvU8v45EtR63y0q5iIgt-kW0OW9soOxzjR88,3880
6
6
  src/aidd/tools/base.py,sha256=wHSAaGGYWM8ECmoYd7KEcmjsZRWesNQFf3zMjCKGMcc,380
7
7
  src/aidd/tools/code_analysis.py,sha256=fDpm2o_If5PsngXzHN2-ezSkPVT0ZxivLuzmHrOAmVU,33188
8
- src/aidd/tools/code_execution.py,sha256=dIPxHBtclsetDZY4jGlSBrw_t-7VlIVrK8mflnZ6c4w,13176
9
- src/aidd/tools/code_tools.py,sha256=3CgkQ78iVKMd5j8aLmolLp4c59seD42Qw6VbdUcg2wA,12628
8
+ src/aidd/tools/code_execution.py,sha256=HRLUR1-q1PiCXKZV5QmTknDJKsfvPvFSWZbTpYFcv7I,13703
9
+ src/aidd/tools/code_tools.py,sha256=DQ6N34Wbz5DwUPzt6RG7jk9HF2SsWFCFn99mencHK1c,14263
10
10
  src/aidd/tools/directory_tools.py,sha256=Hxzge_ziYw_FsjYb5yF0R0dHEdvuWRsg7WsdYDG0AUg,12971
11
- src/aidd/tools/file_tools.py,sha256=-OQHFCL_r1TI16-xBrwKfhzHKFgG965Jr0tAmZ9mKbI,44137
11
+ src/aidd/tools/file_tools.py,sha256=hcqQgkIIisjpcx1sL2rgxar9AFrKLmSATT9F50Y35RE,44276
12
12
  src/aidd/tools/get_active_apps_tool.py,sha256=BjLF7iXSDgyAmm_gfFgAul2Gn3iX-CNVYHM7Sh4jTAI,19427
13
13
  src/aidd/tools/get_available_windows_tool.py,sha256=OVIYhItTn9u_DftOr3vPCT-R0DOFvMEEJXA6tD6gqWQ,15952
14
- src/aidd/tools/git_tools.py,sha256=AgolgrZnpN2NALV7SfIwc6D7U7tdPrPTSFmU2WjPfVE,39846
15
14
  src/aidd/tools/image_tools.py,sha256=wT3EcJAfZWcM0IsXdDfbTNjgFhKZM9nu2wHN6Mk_TTQ,5970
16
- src/aidd/tools/lint_tools.py,sha256=0RYE-cXSbfw1VV_03GiFgYhC9ElhdWc4ecEjfMd9Els,25831
17
15
  src/aidd/tools/other_tools.py,sha256=iG3Sd2FP0M0pRv5esPBAUMvlwxTyAMDUdS77IqA_f5s,10822
18
16
  src/aidd/tools/path_tools.py,sha256=RGoOhqP69eHJzM8tEgn_5-GRaR0gp25fd0XZIJ_RnQE,4045
19
17
  src/aidd/tools/screenshot_tool.py,sha256=NMO5B4UG8qfMEOMRd2YoOjtwz_oQ2y1UAGU22jV1yGU,46337
20
18
  src/aidd/tools/state.py,sha256=RWSw0Jfsui8FqC0xsI7Ik07tAg35hRwLHa5xGBVbiI4,1493
21
19
  src/aidd/tools/system_tools.py,sha256=H4_qveKC2HA7SIbi-j4vxA0W4jYh2wfu9A6ni5wkZyA,7249
22
20
  src/aidd/tools/web_tools.py,sha256=gdsj2DEVYb_oYChItK5I1ugt2w25U7IAa5kEw9q6MVg,35534
23
- skydeckai_code-0.1.34.dist-info/METADATA,sha256=t-8R2yEUD7n3NIKyztRZoxG5TfsDshSa3Su9STh8Ojs,32850
24
- skydeckai_code-0.1.34.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
25
- skydeckai_code-0.1.34.dist-info/entry_points.txt,sha256=ZkU1spOhLEnz5MpUn4dDihVcE0DMUC6ejzbsF-eNth4,88
26
- skydeckai_code-0.1.34.dist-info/licenses/LICENSE,sha256=uHse04vmI6ZjW7TblegFl30X-sDyyF0-QvH8ItPca3c,10865
27
- skydeckai_code-0.1.34.dist-info/RECORD,,
21
+ skydeckai_code-0.1.35.dist-info/METADATA,sha256=phlTiNYpNPCAX8oSmjaI6iuLYM_gjQbDSxQllwnayZI,29047
22
+ skydeckai_code-0.1.35.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
23
+ skydeckai_code-0.1.35.dist-info/entry_points.txt,sha256=ZkU1spOhLEnz5MpUn4dDihVcE0DMUC6ejzbsF-eNth4,88
24
+ skydeckai_code-0.1.35.dist-info/licenses/LICENSE,sha256=uHse04vmI6ZjW7TblegFl30X-sDyyF0-QvH8ItPca3c,10865
25
+ skydeckai_code-0.1.35.dist-info/RECORD,,
@@ -36,36 +36,7 @@ from .file_tools import (
36
36
  )
37
37
  from .get_active_apps_tool import get_active_apps_tool, handle_get_active_apps
38
38
  from .get_available_windows_tool import get_available_windows_tool, handle_get_available_windows
39
- from .git_tools import (
40
- git_add_tool,
41
- git_checkout_tool,
42
- git_clone_tool,
43
- git_commit_tool,
44
- git_create_branch_tool,
45
- git_diff_staged_tool,
46
- git_diff_tool,
47
- git_diff_unstaged_tool,
48
- git_init_tool,
49
- git_log_tool,
50
- git_reset_tool,
51
- git_show_tool,
52
- git_status_tool,
53
- handle_git_add,
54
- handle_git_checkout,
55
- handle_git_clone,
56
- handle_git_commit,
57
- handle_git_create_branch,
58
- handle_git_diff,
59
- handle_git_diff_staged,
60
- handle_git_diff_unstaged,
61
- handle_git_init,
62
- handle_git_log,
63
- handle_git_reset,
64
- handle_git_show,
65
- handle_git_status,
66
- )
67
39
  from .image_tools import read_image_file_tool, handle_read_image_file
68
- from .lint_tools import check_lint_tool, handle_check_lint
69
40
  from .other_tools import batch_tools_tool, handle_batch_tools, think_tool, handle_think
70
41
  from .path_tools import (
71
42
  get_allowed_directory_tool,
@@ -100,24 +71,8 @@ TOOL_DEFINITIONS = [
100
71
  execute_shell_script_tool(),
101
72
  codebase_mapper_tool(),
102
73
  search_code_tool(),
103
- check_lint_tool(),
104
74
  batch_tools_tool(),
105
75
  think_tool(),
106
- # Git tools
107
- git_init_tool(),
108
- git_status_tool(),
109
- git_diff_unstaged_tool(),
110
- git_diff_staged_tool(),
111
- git_diff_tool(),
112
- git_commit_tool(),
113
- git_add_tool(),
114
- git_reset_tool(),
115
- git_log_tool(),
116
- git_create_branch_tool(),
117
- git_checkout_tool(),
118
- git_clone_tool(),
119
- git_show_tool(),
120
- get_system_info_tool(),
121
76
  # Screenshot tools
122
77
  capture_screenshot_tool(),
123
78
  # System context tools
@@ -128,6 +83,8 @@ TOOL_DEFINITIONS = [
128
83
  # Web tools
129
84
  web_fetch_tool(),
130
85
  web_search_tool(),
86
+ # System tools
87
+ get_system_info_tool(),
131
88
  ]
132
89
 
133
90
  # Export all handlers
@@ -144,7 +101,6 @@ TOOL_HANDLERS = {
144
101
  "copy_file": handle_copy_file,
145
102
  "search_files": handle_search_files,
146
103
  "search_code": handle_search_code,
147
- "check_lint": handle_check_lint,
148
104
  "delete_file": handle_delete_file,
149
105
  "get_file_info": handle_get_file_info,
150
106
  "directory_tree": handle_directory_tree,
@@ -153,20 +109,6 @@ TOOL_HANDLERS = {
153
109
  "codebase_mapper": handle_codebase_mapper,
154
110
  "batch_tools": handle_batch_tools,
155
111
  "think": handle_think,
156
- # Git handlers
157
- "git_init": handle_git_init,
158
- "git_status": handle_git_status,
159
- "git_diff_unstaged": handle_git_diff_unstaged,
160
- "git_diff_staged": handle_git_diff_staged,
161
- "git_diff": handle_git_diff,
162
- "git_commit": handle_git_commit,
163
- "git_add": handle_git_add,
164
- "git_reset": handle_git_reset,
165
- "git_log": handle_git_log,
166
- "git_create_branch": handle_git_create_branch,
167
- "git_checkout": handle_git_checkout,
168
- "git_clone": handle_git_clone,
169
- "git_show": handle_git_show,
170
112
  "get_system_info": handle_get_system_info,
171
113
  # Screenshot handlers
172
114
  "capture_screenshot": handle_capture_screenshot,
@@ -100,6 +100,9 @@ def execute_shell_script_tool() -> Dict[str, Any]:
100
100
  "Execute a shell script (bash/sh) on the user's local machine within the current working directory. "
101
101
  "WHEN TO USE: When you need to automate system tasks, run shell commands, interact with the operating system, or perform operations "
102
102
  "that are best expressed as shell commands. Useful for file system operations, system configuration, or running system utilities. "
103
+ "Also ideal when you need to run code linters to check for style issues or potential bugs in the codebase, "
104
+ "or when you need to perform version control operations such as initializing git repositories, checking status, "
105
+ "committing changes, cloning repositories, and other git commands without dedicated tools. "
103
106
  "WHEN NOT TO USE: When you need more structured programming (use execute_code instead), when you need to execute potentially "
104
107
  "dangerous system operations, or when you want to run commands outside the allowed directory. "
105
108
  "RETURNS: Text output including stdout, stderr, and exit code of the execution. The output sections are clearly labeled with "
@@ -110,6 +113,8 @@ def execute_shell_script_tool() -> Dict[str, Any]:
110
113
  "Examples: "
111
114
  "- script='echo \"Current directory:\" && pwd'. "
112
115
  "- script='for i in {1..5}; do echo $i; done'. "
116
+ "- script='eslint src/ --format stylish' (for linting). "
117
+ "- script='git init && git add . && git commit -m \"Initial commit\"' (for git operations)."
113
118
  ),
114
119
  "inputSchema": {
115
120
  "type": "object",
@@ -20,17 +20,19 @@ def search_code_tool():
20
20
  "WHEN NOT TO USE: When you need to find files by name (use search_files instead), when you need "
21
21
  "semantic code understanding (use codebase_mapper instead), or when analyzing individual file "
22
22
  "structure. "
23
- "RETURNS: Lines of code matching the specified pattern, grouped by file with line numbers. "
23
+ "RETURNS: Lines of code matching the specified patterns, grouped by file with line numbers. "
24
24
  "Results are sorted by file modification time with newest files first. Respects file filtering "
25
25
  "and ignores binary files. Search is restricted to the allowed directory.",
26
26
  "inputSchema": {
27
27
  "type": "object",
28
28
  "properties": {
29
- "pattern": {
30
- "type": "string",
31
- "description": "Regular expression pattern to search for in file contents. Supports full regex syntax. "
32
- "Examples: 'function\\s+\\w+' to find function declarations, 'import\\s+.*from' to find "
33
- "import statements, 'console\\.log.*Error' to find error logs."
29
+ "patterns": {
30
+ "type": "array",
31
+ "items": {
32
+ "type": "string"
33
+ },
34
+ "description": "List of regular expression patterns to search for in file contents. Supports full regex syntax. "
35
+ "Examples: ['function\\s+\\w+', 'class\\s+\\w+'] to find both function and class declarations."
34
36
  },
35
37
  "include": {
36
38
  "type": "string",
@@ -47,7 +49,7 @@ def search_code_tool():
47
49
  },
48
50
  "max_results": {
49
51
  "type": "integer",
50
- "description": "Maximum number of matching results to return. Use to limit output size for common patterns. "
52
+ "description": "Maximum number of matching results to return per pattern. Use to limit output size for common patterns. "
51
53
  "Default is 100, which is sufficient for most searches while preventing excessive output.",
52
54
  "default": 100
53
55
  },
@@ -65,22 +67,22 @@ def search_code_tool():
65
67
  "default": "."
66
68
  }
67
69
  },
68
- "required": ["pattern"]
70
+ "required": ["patterns"]
69
71
  }
70
72
  }
71
73
 
72
74
 
73
75
  async def handle_search_code(arguments: dict) -> List[TextContent]:
74
76
  """Handle searching for patterns in code files."""
75
- pattern = arguments.get("pattern")
77
+ patterns = arguments.get("patterns", [])
76
78
  include = arguments.get("include", "*")
77
79
  exclude = arguments.get("exclude", "")
78
80
  max_results = arguments.get("max_results", 100)
79
81
  case_sensitive = arguments.get("case_sensitive", False)
80
82
  path = arguments.get("path", ".")
81
83
 
82
- if not pattern:
83
- raise ValueError("Pattern must be provided")
84
+ if not patterns:
85
+ raise ValueError("At least one pattern must be provided")
84
86
 
85
87
  # Determine full path for search start
86
88
  if os.path.isabs(path):
@@ -97,17 +99,36 @@ async def handle_search_code(arguments: dict) -> List[TextContent]:
97
99
  if not os.path.isdir(full_path):
98
100
  raise ValueError(f"Path is not a directory: {path}")
99
101
 
102
+ # Results from all patterns
103
+ all_results = []
104
+
100
105
  try:
101
- # Use ripgrep if available for faster results
102
- try:
103
- return await _search_with_ripgrep(
104
- pattern, include, exclude, max_results, case_sensitive, full_path
105
- )
106
- except (subprocess.SubprocessError, FileNotFoundError):
107
- # Fallback to Python implementation if ripgrep not available
108
- return await _search_with_python(
109
- pattern, include, exclude, max_results, case_sensitive, full_path
110
- )
106
+ for i, pattern in enumerate(patterns):
107
+ pattern_header = f"\n{'='*30}\nPattern {i+1}: {pattern}\n{'='*30}\n" if len(patterns) > 1 else ""
108
+ try:
109
+ # Use ripgrep if available for faster results
110
+ try:
111
+ result = await _search_with_ripgrep(
112
+ pattern, include, exclude, max_results, case_sensitive, full_path
113
+ )
114
+ except (subprocess.SubprocessError, FileNotFoundError):
115
+ # Fallback to Python implementation if ripgrep not available
116
+ result = await _search_with_python(
117
+ pattern, include, exclude, max_results, case_sensitive, full_path
118
+ )
119
+
120
+ # Add pattern header for multiple patterns
121
+ if len(patterns) > 1 and result and result[0].text != f"No matches found for pattern '{pattern}'.":
122
+ result[0].text = pattern_header + result[0].text
123
+
124
+ all_results.extend(result)
125
+ except Exception as e:
126
+ all_results.append(TextContent(
127
+ type="text",
128
+ text=f"{pattern_header}Error searching for pattern '{pattern}': {str(e)}"
129
+ ))
130
+
131
+ return all_results
111
132
  except Exception as e:
112
133
  raise ValueError(f"Error searching code: {str(e)}")
113
134
 
@@ -193,9 +214,17 @@ async def _search_with_ripgrep(
193
214
 
194
215
  # Format output
195
216
  formatted_output = []
217
+ match_count = 0
196
218
  for file_path, data in sorted_files:
197
219
  formatted_output.append(f"\n{file_path} (modified: {datetime.fromtimestamp(data['mod_time']).strftime('%Y-%m-%d %H:%M:%S')})")
198
220
  formatted_output.extend(data["matches"])
221
+ match_count += len(data["matches"])
222
+
223
+ summary = f"Found {match_count} matches in {len(sorted_files)} files for pattern '{pattern}'"
224
+ if match_count > 0:
225
+ formatted_output.insert(0, summary)
226
+ else:
227
+ formatted_output = [summary]
199
228
 
200
229
  return [TextContent(
201
230
  type="text",
@@ -207,7 +236,7 @@ async def _search_with_ripgrep(
207
236
  # ripgrep returns 1 when no matches are found
208
237
  return [TextContent(
209
238
  type="text",
210
- text="No matches found."
239
+ text=f"No matches found for pattern '{pattern}'."
211
240
  )]
212
241
  raise
213
242
 
@@ -310,7 +339,7 @@ async def _search_with_python(
310
339
  if not files_with_matches:
311
340
  return [TextContent(
312
341
  type="text",
313
- text="No matches found."
342
+ text=f"No matches found for pattern '{pattern}'."
314
343
  )]
315
344
 
316
345
  # Sort files by modification time (newest first)
@@ -322,10 +351,21 @@ async def _search_with_python(
322
351
 
323
352
  # Format output
324
353
  formatted_output = []
354
+ total_matches = 0
355
+ files_with_actual_matches = 0
356
+
325
357
  for file_path, data in sorted_files:
326
358
  if data["matches"]: # Only include files that actually have matches
327
359
  formatted_output.append(f"\n{file_path} (modified: {datetime.fromtimestamp(data['mod_time']).strftime('%Y-%m-%d %H:%M:%S')})")
328
360
  formatted_output.extend(data["matches"])
361
+ total_matches += len(data["matches"])
362
+ files_with_actual_matches += 1
363
+
364
+ summary = f"Found {total_matches} matches in {files_with_actual_matches} files for pattern '{pattern}'"
365
+ if total_matches > 0:
366
+ formatted_output.insert(0, summary)
367
+ else:
368
+ formatted_output = [summary]
329
369
 
330
370
  return [TextContent(
331
371
  type="text",
@@ -24,7 +24,8 @@ def read_file_tool():
24
24
  "(use directory_listing instead), or when you need to read multiple files at once (use read_multiple_files instead). "
25
25
  "RETURNS: The complete text content of the specified file or the requested portion if offset/limit are specified. Binary files or files with unknown encodings will return an error message. "
26
26
  "Handles various text encodings and provides detailed error messages if the file cannot be read. Only works within the allowed directory. "
27
- "Example: Enter 'src/main.py' to read a Python file, or add offset/limit to read specific line ranges.",
27
+ "Example: Enter 'src/main.py' to read a Python file, or add offset/limit to read specific line ranges. "
28
+ "TIP: When analyzing a codebase, it's more efficient to use read_multiple_files instead of reading files one by one.",
28
29
  "inputSchema": {
29
30
  "type": "object",
30
31
  "properties": {