pylance-mcp-server 1.0.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 (34) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +213 -0
  3. package/bin/pylance-mcp.js +68 -0
  4. package/mcp_server/__init__.py +13 -0
  5. package/mcp_server/__pycache__/__init__.cpython-312.pyc +0 -0
  6. package/mcp_server/__pycache__/__init__.cpython-313.pyc +0 -0
  7. package/mcp_server/__pycache__/__init__.cpython-314.pyc +0 -0
  8. package/mcp_server/__pycache__/ai_features.cpython-313.pyc +0 -0
  9. package/mcp_server/__pycache__/api_routes.cpython-313.pyc +0 -0
  10. package/mcp_server/__pycache__/auth.cpython-313.pyc +0 -0
  11. package/mcp_server/__pycache__/cloud_sync.cpython-313.pyc +0 -0
  12. package/mcp_server/__pycache__/logging_db.cpython-312.pyc +0 -0
  13. package/mcp_server/__pycache__/logging_db.cpython-313.pyc +0 -0
  14. package/mcp_server/__pycache__/pylance_bridge.cpython-312.pyc +0 -0
  15. package/mcp_server/__pycache__/pylance_bridge.cpython-313.pyc +0 -0
  16. package/mcp_server/__pycache__/pylance_bridge.cpython-314.pyc +0 -0
  17. package/mcp_server/__pycache__/resources.cpython-312.pyc +0 -0
  18. package/mcp_server/__pycache__/resources.cpython-313.pyc +0 -0
  19. package/mcp_server/__pycache__/tools.cpython-312.pyc +0 -0
  20. package/mcp_server/__pycache__/tools.cpython-313.pyc +0 -0
  21. package/mcp_server/__pycache__/tracing.cpython-313.pyc +0 -0
  22. package/mcp_server/ai_features.py +274 -0
  23. package/mcp_server/api_routes.py +429 -0
  24. package/mcp_server/auth.py +275 -0
  25. package/mcp_server/cloud_sync.py +427 -0
  26. package/mcp_server/logging_db.py +403 -0
  27. package/mcp_server/pylance_bridge.py +579 -0
  28. package/mcp_server/resources.py +174 -0
  29. package/mcp_server/tools.py +642 -0
  30. package/mcp_server/tracing.py +84 -0
  31. package/package.json +53 -0
  32. package/requirements.txt +29 -0
  33. package/scripts/check-python.js +57 -0
  34. package/server.py +1228 -0
@@ -0,0 +1,174 @@
1
+ """
2
+ MCP Resources Module
3
+
4
+ Implements all @mcp.resource decorators for file system operations.
5
+ """
6
+
7
+ import logging
8
+ from pathlib import Path
9
+ from typing import List
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ class PylanceResources:
15
+ """Collection of MCP resources for file system operations."""
16
+
17
+ def __init__(self, workspace_root: str):
18
+ """
19
+ Initialize resources with workspace root.
20
+
21
+ Args:
22
+ workspace_root: Absolute path to the workspace root directory
23
+ """
24
+ self.workspace_root = Path(workspace_root).resolve()
25
+
26
+ def list_workspace_files(self) -> List[str]:
27
+ """
28
+ Return every .py file in the current project recursively.
29
+
30
+ Returns:
31
+ List of relative file paths to Python files
32
+ """
33
+ try:
34
+ python_files = []
35
+
36
+ # Recursively find all .py files
37
+ for py_file in self.workspace_root.rglob("*.py"):
38
+ # Skip common directories
39
+ skip_dirs = {
40
+ "__pycache__",
41
+ ".pytest_cache",
42
+ ".mypy_cache",
43
+ ".tox",
44
+ "venv",
45
+ "env",
46
+ ".venv",
47
+ ".env",
48
+ "node_modules",
49
+ ".git",
50
+ "build",
51
+ "dist",
52
+ "*.egg-info",
53
+ }
54
+
55
+ # Check if any parent is in skip_dirs
56
+ if any(part in skip_dirs or part.endswith(".egg-info") for part in py_file.parts):
57
+ continue
58
+
59
+ try:
60
+ # Get relative path
61
+ relative_path = py_file.relative_to(self.workspace_root)
62
+ python_files.append(str(relative_path))
63
+ except ValueError:
64
+ # File is outside workspace root
65
+ continue
66
+
67
+ # Sort for consistent ordering
68
+ python_files.sort()
69
+
70
+ logger.info(f"Found {len(python_files)} Python files in workspace")
71
+ return python_files
72
+
73
+ except Exception as e:
74
+ logger.error(f"list_workspace_files error: {e}")
75
+ return []
76
+
77
+ def read_file(self, path: str) -> str:
78
+ """
79
+ Read file content.
80
+
81
+ Args:
82
+ path: Relative or absolute path to the file
83
+
84
+ Returns:
85
+ File content as string
86
+ """
87
+ try:
88
+ file_path = Path(path)
89
+
90
+ # If relative, resolve against workspace root
91
+ if not file_path.is_absolute():
92
+ file_path = self.workspace_root / file_path
93
+
94
+ file_path = file_path.resolve()
95
+
96
+ # Validate path is within workspace
97
+ try:
98
+ file_path.relative_to(self.workspace_root)
99
+ except ValueError:
100
+ raise ValueError(f"File path {path} is outside workspace root")
101
+
102
+ if not file_path.exists():
103
+ raise FileNotFoundError(f"File not found: {path}")
104
+
105
+ if not file_path.is_file():
106
+ raise ValueError(f"Path is not a file: {path}")
107
+
108
+ content = file_path.read_text(encoding="utf-8")
109
+ logger.info(f"Read file: {path} ({len(content)} bytes)")
110
+ return content
111
+
112
+ except Exception as e:
113
+ logger.error(f"read_file error for {path}: {e}")
114
+ raise
115
+
116
+ def get_workspace_structure(self) -> dict:
117
+ """
118
+ Get the complete workspace structure.
119
+
120
+ Returns:
121
+ Dictionary representing the directory tree
122
+ """
123
+ try:
124
+ def build_tree(directory: Path) -> dict:
125
+ """Recursively build directory tree."""
126
+ tree = {
127
+ "name": directory.name,
128
+ "type": "directory",
129
+ "path": str(directory.relative_to(self.workspace_root)),
130
+ "children": []
131
+ }
132
+
133
+ skip_dirs = {
134
+ "__pycache__",
135
+ ".pytest_cache",
136
+ ".mypy_cache",
137
+ ".tox",
138
+ "venv",
139
+ "env",
140
+ ".venv",
141
+ ".env",
142
+ "node_modules",
143
+ ".git",
144
+ "build",
145
+ "dist",
146
+ }
147
+
148
+ try:
149
+ for item in sorted(directory.iterdir()):
150
+ if item.name.startswith(".") and item.name not in [".gitignore"]:
151
+ continue
152
+
153
+ if item.name in skip_dirs or item.name.endswith(".egg-info"):
154
+ continue
155
+
156
+ if item.is_dir():
157
+ tree["children"].append(build_tree(item))
158
+ else:
159
+ tree["children"].append({
160
+ "name": item.name,
161
+ "type": "file",
162
+ "path": str(item.relative_to(self.workspace_root)),
163
+ })
164
+ except PermissionError:
165
+ pass
166
+
167
+ return tree
168
+
169
+ structure = build_tree(self.workspace_root)
170
+ return structure
171
+
172
+ except Exception as e:
173
+ logger.error(f"get_workspace_structure error: {e}")
174
+ return {"name": "root", "type": "directory", "children": []}