tree-sitter-analyzer 0.7.0__py3-none-any.whl → 0.8.0__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 (69) 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 +160 -160
  9. tree_sitter_analyzer/cli/commands/default_command.py +18 -18
  10. tree_sitter_analyzer/cli/commands/partial_read_command.py +141 -141
  11. tree_sitter_analyzer/cli/commands/query_command.py +81 -81
  12. tree_sitter_analyzer/cli/commands/structure_command.py +138 -138
  13. tree_sitter_analyzer/cli/commands/summary_command.py +101 -101
  14. tree_sitter_analyzer/cli/commands/table_command.py +235 -235
  15. tree_sitter_analyzer/cli/info_commands.py +121 -121
  16. tree_sitter_analyzer/cli_main.py +297 -297
  17. tree_sitter_analyzer/core/__init__.py +15 -15
  18. tree_sitter_analyzer/core/analysis_engine.py +555 -555
  19. tree_sitter_analyzer/core/cache_service.py +320 -320
  20. tree_sitter_analyzer/core/engine.py +566 -566
  21. tree_sitter_analyzer/core/parser.py +293 -293
  22. tree_sitter_analyzer/encoding_utils.py +459 -459
  23. tree_sitter_analyzer/exceptions.py +406 -337
  24. tree_sitter_analyzer/file_handler.py +210 -210
  25. tree_sitter_analyzer/formatters/__init__.py +1 -1
  26. tree_sitter_analyzer/formatters/base_formatter.py +167 -167
  27. tree_sitter_analyzer/formatters/formatter_factory.py +78 -78
  28. tree_sitter_analyzer/interfaces/__init__.py +9 -9
  29. tree_sitter_analyzer/interfaces/cli.py +528 -528
  30. tree_sitter_analyzer/interfaces/cli_adapter.py +343 -343
  31. tree_sitter_analyzer/interfaces/mcp_adapter.py +206 -206
  32. tree_sitter_analyzer/interfaces/mcp_server.py +425 -405
  33. tree_sitter_analyzer/languages/__init__.py +10 -10
  34. tree_sitter_analyzer/languages/javascript_plugin.py +446 -446
  35. tree_sitter_analyzer/languages/python_plugin.py +755 -755
  36. tree_sitter_analyzer/mcp/__init__.py +31 -31
  37. tree_sitter_analyzer/mcp/resources/__init__.py +44 -44
  38. tree_sitter_analyzer/mcp/resources/code_file_resource.py +209 -209
  39. tree_sitter_analyzer/mcp/server.py +346 -333
  40. tree_sitter_analyzer/mcp/tools/__init__.py +30 -30
  41. tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +654 -654
  42. tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +247 -247
  43. tree_sitter_analyzer/mcp/tools/base_tool.py +54 -54
  44. tree_sitter_analyzer/mcp/tools/read_partial_tool.py +300 -300
  45. tree_sitter_analyzer/mcp/tools/table_format_tool.py +362 -362
  46. tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +543 -543
  47. tree_sitter_analyzer/mcp/utils/__init__.py +107 -107
  48. tree_sitter_analyzer/mcp/utils/error_handler.py +549 -549
  49. tree_sitter_analyzer/output_manager.py +253 -253
  50. tree_sitter_analyzer/plugins/__init__.py +280 -280
  51. tree_sitter_analyzer/plugins/base.py +529 -529
  52. tree_sitter_analyzer/plugins/manager.py +379 -379
  53. tree_sitter_analyzer/queries/__init__.py +26 -26
  54. tree_sitter_analyzer/queries/java.py +391 -391
  55. tree_sitter_analyzer/queries/javascript.py +148 -148
  56. tree_sitter_analyzer/queries/python.py +285 -285
  57. tree_sitter_analyzer/queries/typescript.py +229 -229
  58. tree_sitter_analyzer/query_loader.py +257 -257
  59. tree_sitter_analyzer/security/__init__.py +22 -0
  60. tree_sitter_analyzer/security/boundary_manager.py +237 -0
  61. tree_sitter_analyzer/security/regex_checker.py +292 -0
  62. tree_sitter_analyzer/security/validator.py +224 -0
  63. tree_sitter_analyzer/table_formatter.py +652 -589
  64. tree_sitter_analyzer/utils.py +277 -277
  65. {tree_sitter_analyzer-0.7.0.dist-info → tree_sitter_analyzer-0.8.0.dist-info}/METADATA +4 -1
  66. tree_sitter_analyzer-0.8.0.dist-info/RECORD +76 -0
  67. tree_sitter_analyzer-0.7.0.dist-info/RECORD +0 -72
  68. {tree_sitter_analyzer-0.7.0.dist-info → tree_sitter_analyzer-0.8.0.dist-info}/WHEEL +0 -0
  69. {tree_sitter_analyzer-0.7.0.dist-info → tree_sitter_analyzer-0.8.0.dist-info}/entry_points.txt +0 -0
@@ -1,405 +1,425 @@
1
- #!/usr/bin/env python3
2
- """
3
- MCP Server Interface
4
-
5
- New MCP server implementation that uses the API facade for all operations.
6
- Provides a clean separation between MCP protocol concerns and core analysis logic.
7
- """
8
-
9
- import asyncio
10
- import json
11
- import logging
12
- import sys
13
- from typing import Any
14
-
15
- try:
16
- from mcp.server import Server
17
- from mcp.server.models import InitializationOptions
18
- from mcp.server.stdio import stdio_server
19
- from mcp.types import Resource, TextContent, Tool
20
-
21
- MCP_AVAILABLE = True
22
- except ImportError:
23
- MCP_AVAILABLE = False
24
-
25
- from .. import api
26
- from ..utils import log_error, log_info
27
-
28
- # Configure logging for MCP
29
- logging.basicConfig(
30
- level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
31
- )
32
- logger = logging.getLogger(__name__)
33
-
34
-
35
- class TreeSitterAnalyzerMCPServer:
36
- """
37
- MCP Server for Tree-sitter Analyzer using the new API facade.
38
-
39
- This server provides code analysis capabilities through the Model Context Protocol,
40
- using the unified API facade for all operations.
41
- """
42
-
43
- def __init__(self) -> None:
44
- """Initialize the MCP server."""
45
- if not MCP_AVAILABLE:
46
- raise ImportError("MCP library not available. Please install mcp package.")
47
-
48
- self.server: Server | None = None
49
- self.name = "tree-sitter-analyzer"
50
- self.version = "2.0.0"
51
-
52
- log_info(f"Initializing {self.name} v{self.version}")
53
-
54
- def create_server(self) -> Server:
55
- """Create and configure the MCP server."""
56
- server: Any = Server(self.name)
57
-
58
- @server.list_tools() # type: ignore
59
- async def handle_list_tools() -> list[Tool]:
60
- """List available tools."""
61
- return [
62
- Tool(
63
- name="analyze_file",
64
- description="Analyze a source code file comprehensively",
65
- inputSchema={
66
- "type": "object",
67
- "properties": {
68
- "file_path": {
69
- "type": "string",
70
- "description": "Path to the source file to analyze",
71
- },
72
- "language": {
73
- "type": "string",
74
- "description": "Programming language (optional, auto-detected if not specified)",
75
- },
76
- "queries": {
77
- "type": "array",
78
- "items": {"type": "string"},
79
- "description": "List of query names to execute (optional)",
80
- },
81
- "include_elements": {
82
- "type": "boolean",
83
- "description": "Whether to extract code elements",
84
- "default": True,
85
- },
86
- "include_queries": {
87
- "type": "boolean",
88
- "description": "Whether to execute queries",
89
- "default": True,
90
- },
91
- },
92
- "required": ["file_path"],
93
- "additionalProperties": False,
94
- },
95
- ),
96
- Tool(
97
- name="analyze_code",
98
- description="Analyze source code directly (without file)",
99
- inputSchema={
100
- "type": "object",
101
- "properties": {
102
- "source_code": {
103
- "type": "string",
104
- "description": "Source code string to analyze",
105
- },
106
- "language": {
107
- "type": "string",
108
- "description": "Programming language",
109
- },
110
- "queries": {
111
- "type": "array",
112
- "items": {"type": "string"},
113
- "description": "List of query names to execute (optional)",
114
- },
115
- "include_elements": {
116
- "type": "boolean",
117
- "description": "Whether to extract code elements",
118
- "default": True,
119
- },
120
- "include_queries": {
121
- "type": "boolean",
122
- "description": "Whether to execute queries",
123
- "default": True,
124
- },
125
- },
126
- "required": ["source_code", "language"],
127
- "additionalProperties": False,
128
- },
129
- ),
130
- Tool(
131
- name="extract_elements",
132
- description="Extract code elements from a file",
133
- inputSchema={
134
- "type": "object",
135
- "properties": {
136
- "file_path": {
137
- "type": "string",
138
- "description": "Path to the source file",
139
- },
140
- "language": {
141
- "type": "string",
142
- "description": "Programming language (optional, auto-detected if not specified)",
143
- },
144
- "element_types": {
145
- "type": "array",
146
- "items": {"type": "string"},
147
- "description": "Types of elements to extract (optional)",
148
- },
149
- },
150
- "required": ["file_path"],
151
- "additionalProperties": False,
152
- },
153
- ),
154
- Tool(
155
- name="execute_query",
156
- description="Execute a specific query on a file",
157
- inputSchema={
158
- "type": "object",
159
- "properties": {
160
- "file_path": {
161
- "type": "string",
162
- "description": "Path to the source file",
163
- },
164
- "query_name": {
165
- "type": "string",
166
- "description": "Name of the query to execute",
167
- },
168
- "language": {
169
- "type": "string",
170
- "description": "Programming language (optional, auto-detected if not specified)",
171
- },
172
- },
173
- "required": ["file_path", "query_name"],
174
- "additionalProperties": False,
175
- },
176
- ),
177
- Tool(
178
- name="validate_file",
179
- description="Validate a source code file",
180
- inputSchema={
181
- "type": "object",
182
- "properties": {
183
- "file_path": {
184
- "type": "string",
185
- "description": "Path to the source file to validate",
186
- }
187
- },
188
- "required": ["file_path"],
189
- "additionalProperties": False,
190
- },
191
- ),
192
- Tool(
193
- name="get_supported_languages",
194
- description="Get list of supported programming languages",
195
- inputSchema={
196
- "type": "object",
197
- "properties": {},
198
- "additionalProperties": False,
199
- },
200
- ),
201
- Tool(
202
- name="get_available_queries",
203
- description="Get available queries for a specific language",
204
- inputSchema={
205
- "type": "object",
206
- "properties": {
207
- "language": {
208
- "type": "string",
209
- "description": "Programming language name",
210
- }
211
- },
212
- "required": ["language"],
213
- "additionalProperties": False,
214
- },
215
- ),
216
- Tool(
217
- name="get_framework_info",
218
- description="Get information about the analyzer framework",
219
- inputSchema={
220
- "type": "object",
221
- "properties": {},
222
- "additionalProperties": False,
223
- },
224
- ),
225
- ]
226
-
227
- @server.call_tool() # type: ignore
228
- async def handle_call_tool(
229
- name: str, arguments: dict[str, Any]
230
- ) -> list[TextContent]:
231
- """Handle tool calls."""
232
- try:
233
- result = None
234
-
235
- if name == "analyze_file":
236
- result = api.analyze_file(
237
- file_path=arguments["file_path"],
238
- language=arguments.get("language"),
239
- queries=arguments.get("queries"),
240
- include_elements=arguments.get("include_elements", True),
241
- include_queries=arguments.get("include_queries", True),
242
- )
243
-
244
- elif name == "analyze_code":
245
- result = api.analyze_code(
246
- source_code=arguments["source_code"],
247
- language=arguments["language"],
248
- queries=arguments.get("queries"),
249
- include_elements=arguments.get("include_elements", True),
250
- include_queries=arguments.get("include_queries", True),
251
- )
252
-
253
- elif name == "extract_elements":
254
- result = api.extract_elements(
255
- file_path=arguments["file_path"],
256
- language=arguments.get("language"),
257
- element_types=arguments.get("element_types"),
258
- )
259
-
260
- elif name == "execute_query":
261
- result = api.execute_query(
262
- file_path=arguments["file_path"],
263
- query_name=arguments["query_name"],
264
- language=arguments.get("language"),
265
- )
266
-
267
- elif name == "validate_file":
268
- result = api.validate_file(arguments["file_path"])
269
-
270
- elif name == "get_supported_languages":
271
- result = {
272
- "languages": api.get_supported_languages(),
273
- "total": len(api.get_supported_languages()),
274
- }
275
-
276
- elif name == "get_available_queries":
277
- queries = api.get_available_queries(arguments["language"])
278
- result = {
279
- "language": arguments["language"],
280
- "queries": queries,
281
- "total": len(queries),
282
- }
283
-
284
- elif name == "get_framework_info":
285
- result = api.get_framework_info()
286
-
287
- else:
288
- raise ValueError(f"Unknown tool: {name}")
289
-
290
- return [
291
- TextContent(
292
- type="text",
293
- text=json.dumps(result, indent=2, ensure_ascii=False),
294
- )
295
- ]
296
-
297
- except Exception as e:
298
- log_error(f"Tool call error for {name}: {e}")
299
- error_result = {
300
- "error": str(e),
301
- "tool": name,
302
- "arguments": arguments,
303
- "success": False,
304
- }
305
- return [
306
- TextContent(
307
- type="text",
308
- text=json.dumps(error_result, indent=2, ensure_ascii=False),
309
- )
310
- ]
311
-
312
- @server.list_resources() # type: ignore
313
- async def handle_list_resources() -> list[Resource]:
314
- """List available resources."""
315
- return [
316
- Resource(
317
- uri="code://file/{file_path}", # type: ignore
318
- name="Code File Analysis",
319
- description="Access to code file content and analysis",
320
- mimeType="application/json",
321
- ),
322
- Resource(
323
- uri="code://stats/{stats_type}", # type: ignore
324
- name="Project Statistics",
325
- description="Access to project statistics and analysis data",
326
- mimeType="application/json",
327
- ),
328
- ]
329
-
330
- @server.read_resource() # type: ignore
331
- async def handle_read_resource(uri: str) -> str:
332
- """Read resource content."""
333
- try:
334
- if uri.startswith("code://file/"):
335
- # Extract file path from URI
336
- file_path = uri[len("code://file/") :]
337
-
338
- # Analyze the file
339
- result = api.analyze_file(file_path)
340
- return json.dumps(result, indent=2, ensure_ascii=False)
341
-
342
- elif uri.startswith("code://stats/"):
343
- # Extract stats type from URI
344
- stats_type = uri[len("code://stats/") :]
345
-
346
- # Get framework info as basic stats
347
- if stats_type == "framework":
348
- result = api.get_framework_info()
349
- elif stats_type == "languages":
350
- result = {
351
- "supported_languages": api.get_supported_languages(),
352
- "total_languages": len(api.get_supported_languages()),
353
- }
354
- else:
355
- raise ValueError(f"Unknown stats type: {stats_type}")
356
-
357
- return json.dumps(result, indent=2, ensure_ascii=False)
358
-
359
- else:
360
- raise ValueError(f"Resource not found: {uri}")
361
-
362
- except Exception as e:
363
- log_error(f"Resource read error for {uri}: {e}")
364
- error_result = {"error": str(e), "uri": uri, "success": False}
365
- return json.dumps(error_result, indent=2, ensure_ascii=False)
366
-
367
- self.server = server
368
- log_info("MCP server created successfully")
369
- return server # type: ignore
370
-
371
- async def run(self) -> None:
372
- """Run the MCP server."""
373
- server = self.create_server()
374
-
375
- # Initialize server options
376
- options = InitializationOptions(
377
- server_name=self.name,
378
- server_version=self.version,
379
- capabilities={"tools": {}, "resources": {}}, # type: ignore
380
- )
381
-
382
- log_info(f"Starting MCP server: {self.name} v{self.version}")
383
-
384
- try:
385
- async with stdio_server() as (read_stream, write_stream):
386
- await server.run(read_stream, write_stream, options)
387
- except Exception as e:
388
- log_error(f"Server error: {e}")
389
- raise
390
-
391
-
392
- async def main() -> None:
393
- """Main entry point for the MCP server."""
394
- try:
395
- server = TreeSitterAnalyzerMCPServer()
396
- await server.run()
397
- except KeyboardInterrupt:
398
- log_info("Server stopped by user")
399
- except Exception as e:
400
- log_error(f"Server failed: {e}")
401
- sys.exit(1)
402
-
403
-
404
- if __name__ == "__main__":
405
- asyncio.run(main())
1
+ #!/usr/bin/env python3
2
+ """
3
+ MCP Server Interface
4
+
5
+ New MCP server implementation that uses the API facade for all operations.
6
+ Provides a clean separation between MCP protocol concerns and core analysis logic.
7
+ """
8
+
9
+ import asyncio
10
+ import json
11
+ import logging
12
+ import sys
13
+ from typing import Any
14
+
15
+ try:
16
+ from mcp.server import Server
17
+ from mcp.server.models import InitializationOptions
18
+ from mcp.server.stdio import stdio_server
19
+ from mcp.types import Resource, TextContent, Tool
20
+
21
+ MCP_AVAILABLE = True
22
+ except ImportError:
23
+ MCP_AVAILABLE = False
24
+
25
+ # Fallback types for development without MCP
26
+ class Server:
27
+ pass
28
+
29
+ class InitializationOptions:
30
+ def __init__(self, **kwargs):
31
+ pass
32
+
33
+ class Tool:
34
+ pass
35
+
36
+ class Resource:
37
+ pass
38
+
39
+ class TextContent:
40
+ pass
41
+
42
+ def stdio_server():
43
+ pass
44
+
45
+ from .. import api
46
+ from ..utils import log_error, log_info
47
+
48
+ # Configure logging for MCP
49
+ logging.basicConfig(
50
+ level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
51
+ )
52
+ logger = logging.getLogger(__name__)
53
+
54
+
55
+ class TreeSitterAnalyzerMCPServer:
56
+ """
57
+ MCP Server for Tree-sitter Analyzer using the new API facade.
58
+
59
+ This server provides code analysis capabilities through the Model Context Protocol,
60
+ using the unified API facade for all operations.
61
+ """
62
+
63
+ def __init__(self) -> None:
64
+ """Initialize the MCP server."""
65
+ if not MCP_AVAILABLE:
66
+ raise ImportError("MCP library not available. Please install mcp package.")
67
+
68
+ self.server: Server | None = None
69
+ self.name = "tree-sitter-analyzer"
70
+ self.version = "2.0.0"
71
+
72
+ log_info(f"Initializing {self.name} v{self.version}")
73
+
74
+ def create_server(self) -> Server:
75
+ """Create and configure the MCP server."""
76
+ server: Any = Server(self.name)
77
+
78
+ @server.list_tools() # type: ignore
79
+ async def handle_list_tools() -> list[Tool]:
80
+ """List available tools."""
81
+ return [
82
+ Tool(
83
+ name="analyze_file",
84
+ description="Analyze a source code file comprehensively",
85
+ inputSchema={
86
+ "type": "object",
87
+ "properties": {
88
+ "file_path": {
89
+ "type": "string",
90
+ "description": "Path to the source file to analyze",
91
+ },
92
+ "language": {
93
+ "type": "string",
94
+ "description": "Programming language (optional, auto-detected if not specified)",
95
+ },
96
+ "queries": {
97
+ "type": "array",
98
+ "items": {"type": "string"},
99
+ "description": "List of query names to execute (optional)",
100
+ },
101
+ "include_elements": {
102
+ "type": "boolean",
103
+ "description": "Whether to extract code elements",
104
+ "default": True,
105
+ },
106
+ "include_queries": {
107
+ "type": "boolean",
108
+ "description": "Whether to execute queries",
109
+ "default": True,
110
+ },
111
+ },
112
+ "required": ["file_path"],
113
+ "additionalProperties": False,
114
+ },
115
+ ),
116
+ Tool(
117
+ name="analyze_code",
118
+ description="Analyze source code directly (without file)",
119
+ inputSchema={
120
+ "type": "object",
121
+ "properties": {
122
+ "source_code": {
123
+ "type": "string",
124
+ "description": "Source code string to analyze",
125
+ },
126
+ "language": {
127
+ "type": "string",
128
+ "description": "Programming language",
129
+ },
130
+ "queries": {
131
+ "type": "array",
132
+ "items": {"type": "string"},
133
+ "description": "List of query names to execute (optional)",
134
+ },
135
+ "include_elements": {
136
+ "type": "boolean",
137
+ "description": "Whether to extract code elements",
138
+ "default": True,
139
+ },
140
+ "include_queries": {
141
+ "type": "boolean",
142
+ "description": "Whether to execute queries",
143
+ "default": True,
144
+ },
145
+ },
146
+ "required": ["source_code", "language"],
147
+ "additionalProperties": False,
148
+ },
149
+ ),
150
+ Tool(
151
+ name="extract_elements",
152
+ description="Extract code elements from a file",
153
+ inputSchema={
154
+ "type": "object",
155
+ "properties": {
156
+ "file_path": {
157
+ "type": "string",
158
+ "description": "Path to the source file",
159
+ },
160
+ "language": {
161
+ "type": "string",
162
+ "description": "Programming language (optional, auto-detected if not specified)",
163
+ },
164
+ "element_types": {
165
+ "type": "array",
166
+ "items": {"type": "string"},
167
+ "description": "Types of elements to extract (optional)",
168
+ },
169
+ },
170
+ "required": ["file_path"],
171
+ "additionalProperties": False,
172
+ },
173
+ ),
174
+ Tool(
175
+ name="execute_query",
176
+ description="Execute a specific query on a file",
177
+ inputSchema={
178
+ "type": "object",
179
+ "properties": {
180
+ "file_path": {
181
+ "type": "string",
182
+ "description": "Path to the source file",
183
+ },
184
+ "query_name": {
185
+ "type": "string",
186
+ "description": "Name of the query to execute",
187
+ },
188
+ "language": {
189
+ "type": "string",
190
+ "description": "Programming language (optional, auto-detected if not specified)",
191
+ },
192
+ },
193
+ "required": ["file_path", "query_name"],
194
+ "additionalProperties": False,
195
+ },
196
+ ),
197
+ Tool(
198
+ name="validate_file",
199
+ description="Validate a source code file",
200
+ inputSchema={
201
+ "type": "object",
202
+ "properties": {
203
+ "file_path": {
204
+ "type": "string",
205
+ "description": "Path to the source file to validate",
206
+ }
207
+ },
208
+ "required": ["file_path"],
209
+ "additionalProperties": False,
210
+ },
211
+ ),
212
+ Tool(
213
+ name="get_supported_languages",
214
+ description="Get list of supported programming languages",
215
+ inputSchema={
216
+ "type": "object",
217
+ "properties": {},
218
+ "additionalProperties": False,
219
+ },
220
+ ),
221
+ Tool(
222
+ name="get_available_queries",
223
+ description="Get available queries for a specific language",
224
+ inputSchema={
225
+ "type": "object",
226
+ "properties": {
227
+ "language": {
228
+ "type": "string",
229
+ "description": "Programming language name",
230
+ }
231
+ },
232
+ "required": ["language"],
233
+ "additionalProperties": False,
234
+ },
235
+ ),
236
+ Tool(
237
+ name="get_framework_info",
238
+ description="Get information about the analyzer framework",
239
+ inputSchema={
240
+ "type": "object",
241
+ "properties": {},
242
+ "additionalProperties": False,
243
+ },
244
+ ),
245
+ ]
246
+
247
+ @server.call_tool() # type: ignore
248
+ async def handle_call_tool(
249
+ name: str, arguments: dict[str, Any]
250
+ ) -> list[TextContent]:
251
+ """Handle tool calls."""
252
+ try:
253
+ result = None
254
+
255
+ if name == "analyze_file":
256
+ result = api.analyze_file(
257
+ file_path=arguments["file_path"],
258
+ language=arguments.get("language"),
259
+ queries=arguments.get("queries"),
260
+ include_elements=arguments.get("include_elements", True),
261
+ include_queries=arguments.get("include_queries", True),
262
+ )
263
+
264
+ elif name == "analyze_code":
265
+ result = api.analyze_code(
266
+ source_code=arguments["source_code"],
267
+ language=arguments["language"],
268
+ queries=arguments.get("queries"),
269
+ include_elements=arguments.get("include_elements", True),
270
+ include_queries=arguments.get("include_queries", True),
271
+ )
272
+
273
+ elif name == "extract_elements":
274
+ result = api.extract_elements(
275
+ file_path=arguments["file_path"],
276
+ language=arguments.get("language"),
277
+ element_types=arguments.get("element_types"),
278
+ )
279
+
280
+ elif name == "execute_query":
281
+ result = api.execute_query(
282
+ file_path=arguments["file_path"],
283
+ query_name=arguments["query_name"],
284
+ language=arguments.get("language"),
285
+ )
286
+
287
+ elif name == "validate_file":
288
+ result = api.validate_file(arguments["file_path"])
289
+
290
+ elif name == "get_supported_languages":
291
+ result = {
292
+ "languages": api.get_supported_languages(),
293
+ "total": len(api.get_supported_languages()),
294
+ }
295
+
296
+ elif name == "get_available_queries":
297
+ queries = api.get_available_queries(arguments["language"])
298
+ result = {
299
+ "language": arguments["language"],
300
+ "queries": queries,
301
+ "total": len(queries),
302
+ }
303
+
304
+ elif name == "get_framework_info":
305
+ result = api.get_framework_info()
306
+
307
+ else:
308
+ raise ValueError(f"Unknown tool: {name}")
309
+
310
+ return [
311
+ TextContent(
312
+ type="text",
313
+ text=json.dumps(result, indent=2, ensure_ascii=False),
314
+ )
315
+ ]
316
+
317
+ except Exception as e:
318
+ log_error(f"Tool call error for {name}: {e}")
319
+ error_result = {
320
+ "error": str(e),
321
+ "tool": name,
322
+ "arguments": arguments,
323
+ "success": False,
324
+ }
325
+ return [
326
+ TextContent(
327
+ type="text",
328
+ text=json.dumps(error_result, indent=2, ensure_ascii=False),
329
+ )
330
+ ]
331
+
332
+ @server.list_resources() # type: ignore
333
+ async def handle_list_resources() -> list[Resource]:
334
+ """List available resources."""
335
+ return [
336
+ Resource(
337
+ uri="code://file/{file_path}", # type: ignore
338
+ name="Code File Analysis",
339
+ description="Access to code file content and analysis",
340
+ mimeType="application/json",
341
+ ),
342
+ Resource(
343
+ uri="code://stats/{stats_type}", # type: ignore
344
+ name="Project Statistics",
345
+ description="Access to project statistics and analysis data",
346
+ mimeType="application/json",
347
+ ),
348
+ ]
349
+
350
+ @server.read_resource() # type: ignore
351
+ async def handle_read_resource(uri: str) -> str:
352
+ """Read resource content."""
353
+ try:
354
+ if uri.startswith("code://file/"):
355
+ # Extract file path from URI
356
+ file_path = uri[len("code://file/") :]
357
+
358
+ # Analyze the file
359
+ result = api.analyze_file(file_path)
360
+ return json.dumps(result, indent=2, ensure_ascii=False)
361
+
362
+ elif uri.startswith("code://stats/"):
363
+ # Extract stats type from URI
364
+ stats_type = uri[len("code://stats/") :]
365
+
366
+ # Get framework info as basic stats
367
+ if stats_type == "framework":
368
+ result = api.get_framework_info()
369
+ elif stats_type == "languages":
370
+ result = {
371
+ "supported_languages": api.get_supported_languages(),
372
+ "total_languages": len(api.get_supported_languages()),
373
+ }
374
+ else:
375
+ raise ValueError(f"Unknown stats type: {stats_type}")
376
+
377
+ return json.dumps(result, indent=2, ensure_ascii=False)
378
+
379
+ else:
380
+ raise ValueError(f"Resource not found: {uri}")
381
+
382
+ except Exception as e:
383
+ log_error(f"Resource read error for {uri}: {e}")
384
+ error_result = {"error": str(e), "uri": uri, "success": False}
385
+ return json.dumps(error_result, indent=2, ensure_ascii=False)
386
+
387
+ self.server = server
388
+ log_info("MCP server created successfully")
389
+ return server # type: ignore
390
+
391
+ async def run(self) -> None:
392
+ """Run the MCP server."""
393
+ server = self.create_server()
394
+
395
+ # Initialize server options
396
+ options = InitializationOptions(
397
+ server_name=self.name,
398
+ server_version=self.version,
399
+ capabilities={"tools": {}, "resources": {}}, # type: ignore
400
+ )
401
+
402
+ log_info(f"Starting MCP server: {self.name} v{self.version}")
403
+
404
+ try:
405
+ async with stdio_server() as (read_stream, write_stream):
406
+ await server.run(read_stream, write_stream, options)
407
+ except Exception as e:
408
+ log_error(f"Server error: {e}")
409
+ raise
410
+
411
+
412
+ async def main() -> None:
413
+ """Main entry point for the MCP server."""
414
+ try:
415
+ server = TreeSitterAnalyzerMCPServer()
416
+ await server.run()
417
+ except KeyboardInterrupt:
418
+ log_info("Server stopped by user")
419
+ except Exception as e:
420
+ log_error(f"Server failed: {e}")
421
+ sys.exit(1)
422
+
423
+
424
+ if __name__ == "__main__":
425
+ asyncio.run(main())