tree-sitter-analyzer 0.9.1__py3-none-any.whl → 0.9.2__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.

Potentially problematic release.


This version of tree-sitter-analyzer might be problematic. Click here for more details.

Files changed (61) hide show
  1. tree_sitter_analyzer/__init__.py +132 -132
  2. tree_sitter_analyzer/__main__.py +11 -11
  3. tree_sitter_analyzer/api.py +533 -533
  4. tree_sitter_analyzer/cli/__init__.py +39 -39
  5. tree_sitter_analyzer/cli/__main__.py +12 -12
  6. tree_sitter_analyzer/cli/commands/__init__.py +26 -26
  7. tree_sitter_analyzer/cli/commands/advanced_command.py +88 -88
  8. tree_sitter_analyzer/cli/commands/base_command.py +182 -178
  9. tree_sitter_analyzer/cli/commands/structure_command.py +138 -138
  10. tree_sitter_analyzer/cli/commands/summary_command.py +101 -101
  11. tree_sitter_analyzer/core/__init__.py +15 -15
  12. tree_sitter_analyzer/core/analysis_engine.py +74 -78
  13. tree_sitter_analyzer/core/cache_service.py +320 -320
  14. tree_sitter_analyzer/core/engine.py +566 -566
  15. tree_sitter_analyzer/core/parser.py +293 -293
  16. tree_sitter_analyzer/encoding_utils.py +459 -459
  17. tree_sitter_analyzer/file_handler.py +210 -210
  18. tree_sitter_analyzer/formatters/__init__.py +1 -1
  19. tree_sitter_analyzer/formatters/base_formatter.py +167 -167
  20. tree_sitter_analyzer/formatters/formatter_factory.py +78 -78
  21. tree_sitter_analyzer/formatters/java_formatter.py +18 -18
  22. tree_sitter_analyzer/formatters/python_formatter.py +19 -19
  23. tree_sitter_analyzer/interfaces/__init__.py +9 -9
  24. tree_sitter_analyzer/interfaces/cli.py +528 -528
  25. tree_sitter_analyzer/interfaces/cli_adapter.py +344 -343
  26. tree_sitter_analyzer/interfaces/mcp_adapter.py +206 -206
  27. tree_sitter_analyzer/language_detector.py +53 -53
  28. tree_sitter_analyzer/languages/__init__.py +10 -10
  29. tree_sitter_analyzer/languages/java_plugin.py +1 -1
  30. tree_sitter_analyzer/languages/javascript_plugin.py +446 -446
  31. tree_sitter_analyzer/languages/python_plugin.py +755 -755
  32. tree_sitter_analyzer/mcp/__init__.py +34 -45
  33. tree_sitter_analyzer/mcp/resources/__init__.py +44 -44
  34. tree_sitter_analyzer/mcp/resources/code_file_resource.py +209 -209
  35. tree_sitter_analyzer/mcp/server.py +623 -568
  36. tree_sitter_analyzer/mcp/tools/__init__.py +30 -30
  37. tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +681 -673
  38. tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +247 -247
  39. tree_sitter_analyzer/mcp/tools/base_tool.py +54 -54
  40. tree_sitter_analyzer/mcp/tools/read_partial_tool.py +310 -308
  41. tree_sitter_analyzer/mcp/tools/table_format_tool.py +386 -379
  42. tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +563 -559
  43. tree_sitter_analyzer/mcp/utils/__init__.py +107 -107
  44. tree_sitter_analyzer/models.py +10 -10
  45. tree_sitter_analyzer/output_manager.py +253 -253
  46. tree_sitter_analyzer/plugins/__init__.py +280 -280
  47. tree_sitter_analyzer/plugins/base.py +529 -529
  48. tree_sitter_analyzer/plugins/manager.py +379 -379
  49. tree_sitter_analyzer/queries/__init__.py +26 -26
  50. tree_sitter_analyzer/queries/java.py +391 -391
  51. tree_sitter_analyzer/queries/javascript.py +148 -148
  52. tree_sitter_analyzer/queries/python.py +285 -285
  53. tree_sitter_analyzer/queries/typescript.py +229 -229
  54. tree_sitter_analyzer/query_loader.py +257 -257
  55. tree_sitter_analyzer/security/validator.py +246 -241
  56. tree_sitter_analyzer/utils.py +294 -277
  57. {tree_sitter_analyzer-0.9.1.dist-info → tree_sitter_analyzer-0.9.2.dist-info}/METADATA +1 -1
  58. tree_sitter_analyzer-0.9.2.dist-info/RECORD +77 -0
  59. {tree_sitter_analyzer-0.9.1.dist-info → tree_sitter_analyzer-0.9.2.dist-info}/entry_points.txt +1 -0
  60. tree_sitter_analyzer-0.9.1.dist-info/RECORD +0 -77
  61. {tree_sitter_analyzer-0.9.1.dist-info → tree_sitter_analyzer-0.9.2.dist-info}/WHEEL +0 -0
@@ -1,308 +1,310 @@
1
- #!/usr/bin/env python3
2
- """
3
- Read Code Partial MCP Tool
4
-
5
- This tool provides partial file reading functionality through the MCP protocol,
6
- allowing selective content extraction with line and column range support.
7
- """
8
-
9
- import json
10
- from pathlib import Path
11
- from typing import Any
12
-
13
- from ...file_handler import read_file_partial
14
- from ...security import SecurityValidator
15
- from ...utils import setup_logger
16
-
17
- # Set up logging
18
- logger = setup_logger(__name__)
19
-
20
-
21
- class ReadPartialTool:
22
- """
23
- MCP Tool for reading partial content from code files.
24
-
25
- This tool integrates with existing file_handler functionality to provide
26
- selective file content reading through the MCP protocol.
27
- """
28
-
29
- def __init__(self, project_root: str = None) -> None:
30
- """Initialize the read partial tool."""
31
- self.security_validator = SecurityValidator(project_root)
32
- logger.info("ReadPartialTool initialized with security validation")
33
-
34
- def get_tool_schema(self) -> dict[str, Any]:
35
- """
36
- Get the MCP tool schema for read_code_partial.
37
-
38
- Returns:
39
- Dictionary containing the tool schema
40
- """
41
- return {
42
- "type": "object",
43
- "properties": {
44
- "file_path": {
45
- "type": "string",
46
- "description": "Path to the code file to read",
47
- },
48
- "start_line": {
49
- "type": "integer",
50
- "description": "Starting line number (1-based)",
51
- "minimum": 1,
52
- },
53
- "end_line": {
54
- "type": "integer",
55
- "description": "Ending line number (1-based, optional - reads to end if not specified)",
56
- "minimum": 1,
57
- },
58
- "start_column": {
59
- "type": "integer",
60
- "description": "Starting column number (0-based, optional)",
61
- "minimum": 0,
62
- },
63
- "end_column": {
64
- "type": "integer",
65
- "description": "Ending column number (0-based, optional)",
66
- "minimum": 0,
67
- },
68
- "format": {
69
- "type": "string",
70
- "description": "Output format for the content",
71
- "enum": ["text", "json"],
72
- "default": "text",
73
- },
74
- },
75
- "required": ["file_path", "start_line"],
76
- "additionalProperties": False,
77
- }
78
-
79
- async def execute(self, arguments: dict[str, Any]) -> dict[str, Any]:
80
- """
81
- Execute the read_code_partial tool.
82
-
83
- Args:
84
- arguments: Tool arguments containing file_path, line/column ranges, and format
85
-
86
- Returns:
87
- Dictionary containing the partial file content and metadata (CLI --partial-read compatible format)
88
-
89
- Raises:
90
- ValueError: If required arguments are missing or invalid
91
- FileNotFoundError: If the specified file doesn't exist
92
- """
93
- # Validate required arguments
94
- if "file_path" not in arguments:
95
- raise ValueError("file_path is required")
96
-
97
- if "start_line" not in arguments:
98
- raise ValueError("start_line is required")
99
-
100
- file_path = arguments["file_path"]
101
- start_line = arguments["start_line"]
102
- end_line = arguments.get("end_line")
103
- start_column = arguments.get("start_column")
104
- end_column = arguments.get("end_column")
105
- # output_format = arguments.get("format", "text") # Not used currently
106
-
107
- # Security validation
108
- is_valid, error_msg = self.security_validator.validate_file_path(file_path)
109
- if not is_valid:
110
- logger.warning(f"Security validation failed for file path: {file_path} - {error_msg}")
111
- raise ValueError(f"Invalid file path: {error_msg}")
112
-
113
- # Validate file exists
114
- if not Path(file_path).exists():
115
- raise FileNotFoundError(f"File not found: {file_path}")
116
-
117
- # Validate line numbers
118
- if start_line < 1:
119
- raise ValueError("start_line must be >= 1")
120
-
121
- if end_line is not None and end_line < start_line:
122
- raise ValueError("end_line must be >= start_line")
123
-
124
- # Validate column numbers
125
- if start_column is not None and start_column < 0:
126
- raise ValueError("start_column must be >= 0")
127
-
128
- if end_column is not None and end_column < 0:
129
- raise ValueError("end_column must be >= 0")
130
-
131
- logger.info(
132
- f"Reading partial content from {file_path}: lines {start_line}-{end_line or 'end'}"
133
- )
134
-
135
- try:
136
- # Use existing file_handler functionality
137
- # Use performance monitoring with proper context manager
138
- from ...mcp.utils import get_performance_monitor
139
-
140
- with get_performance_monitor().measure_operation("read_code_partial"):
141
- content = self._read_file_partial(
142
- file_path, start_line, end_line, start_column, end_column
143
- )
144
-
145
- if content is None:
146
- raise RuntimeError(
147
- f"Failed to read partial content from file: {file_path}"
148
- )
149
-
150
- # Build result structure compatible with CLI --partial-read format
151
- result_data = {
152
- "file_path": file_path,
153
- "range": {
154
- "start_line": start_line,
155
- "end_line": end_line,
156
- "start_column": start_column,
157
- "end_column": end_column,
158
- },
159
- "content": content,
160
- "content_length": len(content),
161
- }
162
-
163
- # Format as JSON string like CLI does
164
- json_output = json.dumps(result_data, indent=2, ensure_ascii=False)
165
-
166
- # Build range info for header
167
- range_info = f"Line {start_line}"
168
- if end_line:
169
- range_info += f"-{end_line}"
170
-
171
- # Build CLI-compatible output with header and JSON (without log message)
172
- cli_output = (
173
- f"--- Partial Read Result ---\n"
174
- f"File: {file_path}\n"
175
- f"Range: {range_info}\n"
176
- f"Characters read: {len(content)}\n"
177
- f"{json_output}"
178
- )
179
-
180
- logger.info(
181
- f"Successfully read {len(content)} characters from {file_path}"
182
- )
183
-
184
- return {"partial_content_result": cli_output}
185
-
186
- except Exception as e:
187
- logger.error(f"Error reading partial content from {file_path}: {e}")
188
- raise
189
-
190
- def _read_file_partial(
191
- self,
192
- file_path: str,
193
- start_line: int,
194
- end_line: int | None = None,
195
- start_column: int | None = None,
196
- end_column: int | None = None,
197
- ) -> str | None:
198
- """
199
- Internal method to read partial file content.
200
-
201
- This method wraps the existing read_file_partial function from file_handler.
202
-
203
- Args:
204
- file_path: Path to the file to read
205
- start_line: Starting line number (1-based)
206
- end_line: Ending line number (1-based, optional)
207
- start_column: Starting column number (0-based, optional)
208
- end_column: Ending column number (0-based, optional)
209
-
210
- Returns:
211
- Partial file content as string, or None if error
212
- """
213
- return read_file_partial(
214
- file_path, start_line, end_line, start_column, end_column
215
- )
216
-
217
- def validate_arguments(self, arguments: dict[str, Any]) -> bool:
218
- """
219
- Validate tool arguments against the schema.
220
-
221
- Args:
222
- arguments: Arguments to validate
223
-
224
- Returns:
225
- True if arguments are valid
226
-
227
- Raises:
228
- ValueError: If arguments are invalid
229
- """
230
- schema = self.get_tool_schema()
231
- required_fields = schema.get("required", [])
232
-
233
- # Check required fields
234
- for field in required_fields:
235
- if field not in arguments:
236
- raise ValueError(f"Required field '{field}' is missing")
237
-
238
- # Validate file_path
239
- if "file_path" in arguments:
240
- file_path = arguments["file_path"]
241
- if not isinstance(file_path, str):
242
- raise ValueError("file_path must be a string")
243
- if not file_path.strip():
244
- raise ValueError("file_path cannot be empty")
245
-
246
- # Validate start_line
247
- if "start_line" in arguments:
248
- start_line = arguments["start_line"]
249
- if not isinstance(start_line, int):
250
- raise ValueError("start_line must be an integer")
251
- if start_line < 1:
252
- raise ValueError("start_line must be >= 1")
253
-
254
- # Validate end_line
255
- if "end_line" in arguments:
256
- end_line = arguments["end_line"]
257
- if not isinstance(end_line, int):
258
- raise ValueError("end_line must be an integer")
259
- if end_line < 1:
260
- raise ValueError("end_line must be >= 1")
261
- if "start_line" in arguments and end_line < arguments["start_line"]:
262
- raise ValueError("end_line must be >= start_line")
263
-
264
- # Validate column numbers
265
- for col_field in ["start_column", "end_column"]:
266
- if col_field in arguments:
267
- col_value = arguments[col_field]
268
- if not isinstance(col_value, int):
269
- raise ValueError(f"{col_field} must be an integer")
270
- if col_value < 0:
271
- raise ValueError(f"{col_field} must be >= 0")
272
-
273
- # Validate format
274
- if "format" in arguments:
275
- format_value = arguments["format"]
276
- if not isinstance(format_value, str):
277
- raise ValueError("format must be a string")
278
- if format_value not in ["text", "json"]:
279
- raise ValueError("format must be 'text' or 'json'")
280
-
281
- return True
282
-
283
- def get_tool_definition(self) -> Any:
284
- """
285
- Get the MCP tool definition for read_code_partial.
286
-
287
- Returns:
288
- Tool definition object compatible with MCP server
289
- """
290
- try:
291
- from mcp.types import Tool
292
-
293
- return Tool(
294
- name="extract_code_section",
295
- description="Extract specific code sections by line range (equivalent to CLI --partial-read option)",
296
- inputSchema=self.get_tool_schema(),
297
- )
298
- except ImportError:
299
- # Fallback for when MCP is not available
300
- return {
301
- "name": "extract_code_section",
302
- "description": "Extract specific code sections by line range (equivalent to CLI --partial-read option)",
303
- "inputSchema": self.get_tool_schema(),
304
- }
305
-
306
-
307
- # Tool instance for easy access
308
- read_partial_tool = ReadPartialTool()
1
+ #!/usr/bin/env python3
2
+ """
3
+ Read Code Partial MCP Tool
4
+
5
+ This tool provides partial file reading functionality through the MCP protocol,
6
+ allowing selective content extraction with line and column range support.
7
+ """
8
+
9
+ import json
10
+ from pathlib import Path
11
+ from typing import Any
12
+
13
+ from ...file_handler import read_file_partial
14
+ from ...security import SecurityValidator
15
+ from ...utils import setup_logger
16
+
17
+ # Set up logging
18
+ logger = setup_logger(__name__)
19
+
20
+
21
+ class ReadPartialTool:
22
+ """
23
+ MCP Tool for reading partial content from code files.
24
+
25
+ This tool integrates with existing file_handler functionality to provide
26
+ selective file content reading through the MCP protocol.
27
+ """
28
+
29
+ def __init__(self, project_root: str = None) -> None:
30
+ """Initialize the read partial tool."""
31
+ self.security_validator = SecurityValidator(project_root)
32
+ logger.info("ReadPartialTool initialized with security validation")
33
+
34
+ def get_tool_schema(self) -> dict[str, Any]:
35
+ """
36
+ Get the MCP tool schema for read_code_partial.
37
+
38
+ Returns:
39
+ Dictionary containing the tool schema
40
+ """
41
+ return {
42
+ "type": "object",
43
+ "properties": {
44
+ "file_path": {
45
+ "type": "string",
46
+ "description": "Path to the code file to read",
47
+ },
48
+ "start_line": {
49
+ "type": "integer",
50
+ "description": "Starting line number (1-based)",
51
+ "minimum": 1,
52
+ },
53
+ "end_line": {
54
+ "type": "integer",
55
+ "description": "Ending line number (1-based, optional - reads to end if not specified)",
56
+ "minimum": 1,
57
+ },
58
+ "start_column": {
59
+ "type": "integer",
60
+ "description": "Starting column number (0-based, optional)",
61
+ "minimum": 0,
62
+ },
63
+ "end_column": {
64
+ "type": "integer",
65
+ "description": "Ending column number (0-based, optional)",
66
+ "minimum": 0,
67
+ },
68
+ "format": {
69
+ "type": "string",
70
+ "description": "Output format for the content",
71
+ "enum": ["text", "json"],
72
+ "default": "text",
73
+ },
74
+ },
75
+ "required": ["file_path", "start_line"],
76
+ "additionalProperties": False,
77
+ }
78
+
79
+ async def execute(self, arguments: dict[str, Any]) -> dict[str, Any]:
80
+ """
81
+ Execute the read_code_partial tool.
82
+
83
+ Args:
84
+ arguments: Tool arguments containing file_path, line/column ranges, and format
85
+
86
+ Returns:
87
+ Dictionary containing the partial file content and metadata (CLI --partial-read compatible format)
88
+
89
+ Raises:
90
+ ValueError: If required arguments are missing or invalid
91
+ FileNotFoundError: If the specified file doesn't exist
92
+ """
93
+ # Validate required arguments
94
+ if "file_path" not in arguments:
95
+ raise ValueError("file_path is required")
96
+
97
+ if "start_line" not in arguments:
98
+ raise ValueError("start_line is required")
99
+
100
+ file_path = arguments["file_path"]
101
+ start_line = arguments["start_line"]
102
+ end_line = arguments.get("end_line")
103
+ start_column = arguments.get("start_column")
104
+ end_column = arguments.get("end_column")
105
+ # output_format = arguments.get("format", "text") # Not used currently
106
+
107
+ # Security validation
108
+ is_valid, error_msg = self.security_validator.validate_file_path(file_path)
109
+ if not is_valid:
110
+ logger.warning(
111
+ f"Security validation failed for file path: {file_path} - {error_msg}"
112
+ )
113
+ raise ValueError(f"Invalid file path: {error_msg}")
114
+
115
+ # Validate file exists
116
+ if not Path(file_path).exists():
117
+ raise ValueError("Invalid file path: file does not exist")
118
+
119
+ # Validate line numbers
120
+ if start_line < 1:
121
+ raise ValueError("start_line must be >= 1")
122
+
123
+ if end_line is not None and end_line < start_line:
124
+ raise ValueError("end_line must be >= start_line")
125
+
126
+ # Validate column numbers
127
+ if start_column is not None and start_column < 0:
128
+ raise ValueError("start_column must be >= 0")
129
+
130
+ if end_column is not None and end_column < 0:
131
+ raise ValueError("end_column must be >= 0")
132
+
133
+ logger.info(
134
+ f"Reading partial content from {file_path}: lines {start_line}-{end_line or 'end'}"
135
+ )
136
+
137
+ try:
138
+ # Use existing file_handler functionality
139
+ # Use performance monitoring with proper context manager
140
+ from ...mcp.utils import get_performance_monitor
141
+
142
+ with get_performance_monitor().measure_operation("read_code_partial"):
143
+ content = self._read_file_partial(
144
+ file_path, start_line, end_line, start_column, end_column
145
+ )
146
+
147
+ if content is None:
148
+ raise RuntimeError(
149
+ f"Failed to read partial content from file: {file_path}"
150
+ )
151
+
152
+ # Build result structure compatible with CLI --partial-read format
153
+ result_data = {
154
+ "file_path": file_path,
155
+ "range": {
156
+ "start_line": start_line,
157
+ "end_line": end_line,
158
+ "start_column": start_column,
159
+ "end_column": end_column,
160
+ },
161
+ "content": content,
162
+ "content_length": len(content),
163
+ }
164
+
165
+ # Format as JSON string like CLI does
166
+ json_output = json.dumps(result_data, indent=2, ensure_ascii=False)
167
+
168
+ # Build range info for header
169
+ range_info = f"Line {start_line}"
170
+ if end_line:
171
+ range_info += f"-{end_line}"
172
+
173
+ # Build CLI-compatible output with header and JSON (without log message)
174
+ cli_output = (
175
+ f"--- Partial Read Result ---\n"
176
+ f"File: {file_path}\n"
177
+ f"Range: {range_info}\n"
178
+ f"Characters read: {len(content)}\n"
179
+ f"{json_output}"
180
+ )
181
+
182
+ logger.info(
183
+ f"Successfully read {len(content)} characters from {file_path}"
184
+ )
185
+
186
+ return {"partial_content_result": cli_output}
187
+
188
+ except Exception as e:
189
+ logger.error(f"Error reading partial content from {file_path}: {e}")
190
+ raise
191
+
192
+ def _read_file_partial(
193
+ self,
194
+ file_path: str,
195
+ start_line: int,
196
+ end_line: int | None = None,
197
+ start_column: int | None = None,
198
+ end_column: int | None = None,
199
+ ) -> str | None:
200
+ """
201
+ Internal method to read partial file content.
202
+
203
+ This method wraps the existing read_file_partial function from file_handler.
204
+
205
+ Args:
206
+ file_path: Path to the file to read
207
+ start_line: Starting line number (1-based)
208
+ end_line: Ending line number (1-based, optional)
209
+ start_column: Starting column number (0-based, optional)
210
+ end_column: Ending column number (0-based, optional)
211
+
212
+ Returns:
213
+ Partial file content as string, or None if error
214
+ """
215
+ return read_file_partial(
216
+ file_path, start_line, end_line, start_column, end_column
217
+ )
218
+
219
+ def validate_arguments(self, arguments: dict[str, Any]) -> bool:
220
+ """
221
+ Validate tool arguments against the schema.
222
+
223
+ Args:
224
+ arguments: Arguments to validate
225
+
226
+ Returns:
227
+ True if arguments are valid
228
+
229
+ Raises:
230
+ ValueError: If arguments are invalid
231
+ """
232
+ schema = self.get_tool_schema()
233
+ required_fields = schema.get("required", [])
234
+
235
+ # Check required fields
236
+ for field in required_fields:
237
+ if field not in arguments:
238
+ raise ValueError(f"Required field '{field}' is missing")
239
+
240
+ # Validate file_path
241
+ if "file_path" in arguments:
242
+ file_path = arguments["file_path"]
243
+ if not isinstance(file_path, str):
244
+ raise ValueError("file_path must be a string")
245
+ if not file_path.strip():
246
+ raise ValueError("file_path cannot be empty")
247
+
248
+ # Validate start_line
249
+ if "start_line" in arguments:
250
+ start_line = arguments["start_line"]
251
+ if not isinstance(start_line, int):
252
+ raise ValueError("start_line must be an integer")
253
+ if start_line < 1:
254
+ raise ValueError("start_line must be >= 1")
255
+
256
+ # Validate end_line
257
+ if "end_line" in arguments:
258
+ end_line = arguments["end_line"]
259
+ if not isinstance(end_line, int):
260
+ raise ValueError("end_line must be an integer")
261
+ if end_line < 1:
262
+ raise ValueError("end_line must be >= 1")
263
+ if "start_line" in arguments and end_line < arguments["start_line"]:
264
+ raise ValueError("end_line must be >= start_line")
265
+
266
+ # Validate column numbers
267
+ for col_field in ["start_column", "end_column"]:
268
+ if col_field in arguments:
269
+ col_value = arguments[col_field]
270
+ if not isinstance(col_value, int):
271
+ raise ValueError(f"{col_field} must be an integer")
272
+ if col_value < 0:
273
+ raise ValueError(f"{col_field} must be >= 0")
274
+
275
+ # Validate format
276
+ if "format" in arguments:
277
+ format_value = arguments["format"]
278
+ if not isinstance(format_value, str):
279
+ raise ValueError("format must be a string")
280
+ if format_value not in ["text", "json"]:
281
+ raise ValueError("format must be 'text' or 'json'")
282
+
283
+ return True
284
+
285
+ def get_tool_definition(self) -> Any:
286
+ """
287
+ Get the MCP tool definition for read_code_partial.
288
+
289
+ Returns:
290
+ Tool definition object compatible with MCP server
291
+ """
292
+ try:
293
+ from mcp.types import Tool
294
+
295
+ return Tool(
296
+ name="extract_code_section",
297
+ description="Extract specific code sections by line range (equivalent to CLI --partial-read option)",
298
+ inputSchema=self.get_tool_schema(),
299
+ )
300
+ except ImportError:
301
+ # Fallback for when MCP is not available
302
+ return {
303
+ "name": "extract_code_section",
304
+ "description": "Extract specific code sections by line range (equivalent to CLI --partial-read option)",
305
+ "inputSchema": self.get_tool_schema(),
306
+ }
307
+
308
+
309
+ # Tool instance for easy access
310
+ read_partial_tool = ReadPartialTool()