Initial commit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+127
@@ -0,0 +1,127 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env/
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
.env.bak
|
||||||
|
.env.local
|
||||||
|
.env*.local
|
||||||
|
|
||||||
|
# Virtualenvwrapper
|
||||||
|
virtualenvwrapper.sh
|
||||||
|
|
||||||
|
# AWS SAM
|
||||||
|
.sam/
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs/
|
||||||
|
*.log
|
||||||
|
server.log
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
desktop.ini
|
||||||
|
|
||||||
|
# MCP specific
|
||||||
|
*.mcp-session
|
||||||
|
.mcp/
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# uv configuration for mcp-python-manager
|
||||||
|
# This file is read by uv/uvx for project-specific settings
|
||||||
|
|
||||||
|
[project]
|
||||||
|
# Use this project as the source for the package
|
||||||
|
name = "mcp-python-manager"
|
||||||
|
|
||||||
|
[run]
|
||||||
|
# Default command when running with uvx
|
||||||
|
command = "mcp-python-manager"
|
||||||
|
|
||||||
|
[env]
|
||||||
|
# Environment variables for uvx runs
|
||||||
|
PYTHONUNBUFFERED = "1"
|
||||||
|
UV_LINK_MODE = "copy"
|
||||||
|
|
||||||
|
[cache]
|
||||||
|
# Cache settings for faster uvx runs
|
||||||
|
no-cache = false
|
||||||
|
offline = false
|
||||||
+239
@@ -0,0 +1,239 @@
|
|||||||
|
# 🚀 Quick Start Guide
|
||||||
|
|
||||||
|
## ⚡ First Time Setup with uv (Recommended)
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# 1. Install uv if not already installed
|
||||||
|
winget install astral-sh.uv
|
||||||
|
# or
|
||||||
|
pip install uv
|
||||||
|
|
||||||
|
# 2. Navigate to project directory
|
||||||
|
cd C:\Users\dimir\proects\mcp-python
|
||||||
|
|
||||||
|
# 3. Run directly with uvx - no setup needed!
|
||||||
|
uvx --from . mcp-python-manager
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🐍 First Time Setup with pip (Traditional)
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# 1. Navigate to project directory
|
||||||
|
cd C:\Users\dimir\proects\mcp-python
|
||||||
|
|
||||||
|
# 2. Create virtual environment
|
||||||
|
python -m venv .venv
|
||||||
|
|
||||||
|
# 3. Activate virtual environment
|
||||||
|
.venv\Scripts\activate
|
||||||
|
|
||||||
|
# 4. Install dependencies
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# 5. (Optional) Install dev tools
|
||||||
|
pip install -e ".[dev]"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run the Server
|
||||||
|
|
||||||
|
### ⚡ With uvx (Recommended)
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# Basic run (stdio transport - for MCP clients)
|
||||||
|
uvx --from . mcp-python-manager
|
||||||
|
|
||||||
|
# With debug output
|
||||||
|
uvx --from . mcp-python-manager --debug
|
||||||
|
|
||||||
|
# With custom workspace
|
||||||
|
uvx --from . mcp-python-manager --workspace "C:\My\Projects"
|
||||||
|
|
||||||
|
# SSE transport (for HTTP clients)
|
||||||
|
uvx --from . mcp-python-manager --transport sse --port 8000
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🐍 With Python (Traditional)
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# Basic run (stdio transport - for MCP clients)
|
||||||
|
python server.py
|
||||||
|
|
||||||
|
# With debug output
|
||||||
|
python server.py --debug
|
||||||
|
|
||||||
|
# With custom workspace
|
||||||
|
python server.py --workspace "C:\My\Projects"
|
||||||
|
|
||||||
|
# SSE transport (for HTTP clients)
|
||||||
|
python server.py --transport sse --port 8000
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test the Server
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# Run built-in tests
|
||||||
|
python test_server.py
|
||||||
|
|
||||||
|
# Run with pytest (if installed)
|
||||||
|
pytest tests/ -v
|
||||||
|
```
|
||||||
|
|
||||||
|
## Connect from Claude Desktop
|
||||||
|
|
||||||
|
### ⚡ Using uvx (Recommended)
|
||||||
|
|
||||||
|
1. Edit your Claude Desktop config:
|
||||||
|
- Location: `%APPDATA%\Claude\claude_desktop_config.json`
|
||||||
|
|
||||||
|
2. Add this configuration:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"python-manager": {
|
||||||
|
"command": "uvx",
|
||||||
|
"args": [
|
||||||
|
"--from",
|
||||||
|
"C:/Users/dimir/proects/mcp-python",
|
||||||
|
"mcp-python-manager",
|
||||||
|
"--transport",
|
||||||
|
"stdio"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"MCP_PYTHON_WORKSPACE": "C:/Users/dimir/projects",
|
||||||
|
"UV_NO_CACHE": "0",
|
||||||
|
"UV_LINK_MODE": "copy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Restart Claude Desktop
|
||||||
|
|
||||||
|
### 🐍 Using Python (Traditional)
|
||||||
|
|
||||||
|
1. Edit your Claude Desktop config:
|
||||||
|
- Location: `%APPDATA%\Claude\claude_desktop_config.json`
|
||||||
|
|
||||||
|
2. Add this configuration:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"python-manager": {
|
||||||
|
"command": "python",
|
||||||
|
"args": ["C:/Users/dimir/proects/mcp-python/server.py"],
|
||||||
|
"env": {
|
||||||
|
"MCP_PYTHON_WORKSPACE": "C:/Users/dimir/projects",
|
||||||
|
"PYTHONUNBUFFERED": "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Restart Claude Desktop
|
||||||
|
|
||||||
|
## Example Prompts for Claude
|
||||||
|
|
||||||
|
Once connected, you can ask Claude to:
|
||||||
|
|
||||||
|
```
|
||||||
|
📁 Project Management:
|
||||||
|
- "Show me the structure of my project at C:\projects\myapp"
|
||||||
|
- "What Python files are in the src directory?"
|
||||||
|
- "Read the first 50 lines of main.py"
|
||||||
|
|
||||||
|
🔧 Code Execution:
|
||||||
|
- "Run the script at scripts/deploy.py with --dry-run argument"
|
||||||
|
- "Execute pytest on the tests folder with coverage"
|
||||||
|
- "Install the packages from requirements.txt"
|
||||||
|
|
||||||
|
🐛 Debugging:
|
||||||
|
- "What Python processes are currently running?"
|
||||||
|
- "Get debug info for main.py"
|
||||||
|
- "Show me the Python environment details"
|
||||||
|
|
||||||
|
✨ Code Quality:
|
||||||
|
- "Lint all Python files in src/ using flake8"
|
||||||
|
- "Format the code in utils.py using black"
|
||||||
|
- "Run pylint on the entire project"
|
||||||
|
|
||||||
|
📦 Dependencies:
|
||||||
|
- "List all installed packages in my venv"
|
||||||
|
- "Analyze dependencies in requirements.txt for issues"
|
||||||
|
- "Create a new virtual environment for my project"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Commands Reference
|
||||||
|
|
||||||
|
### ⚡ With uvx
|
||||||
|
|
||||||
|
| Task | Command |
|
||||||
|
|------|---------|
|
||||||
|
| Start server | `uvx --from . mcp-python-manager` |
|
||||||
|
| Start with debug | `uvx --from . mcp-python-manager --debug` |
|
||||||
|
| Start with workspace | `uvx --from . mcp-python-manager --workspace "C:\Projects"` |
|
||||||
|
| Install uv | `winget install astral-sh.uv` |
|
||||||
|
| Update uv | `uv self update` |
|
||||||
|
|
||||||
|
### 🐍 With pip
|
||||||
|
|
||||||
|
| Task | Command |
|
||||||
|
|------|---------|
|
||||||
|
| Start server | `python server.py` |
|
||||||
|
| Test server | `python test_server.py` |
|
||||||
|
| Install deps | `pip install -r requirements.txt` |
|
||||||
|
| Install dev deps | `pip install -e ".[dev]"` |
|
||||||
|
| Run with debug | `python server.py --debug` |
|
||||||
|
| Check Python version | `python --version` |
|
||||||
|
| Activate venv | `.venv\Scripts\activate` |
|
||||||
|
| Deactivate venv | `deactivate` |
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Server won't start
|
||||||
|
```cmd
|
||||||
|
# Check Python version
|
||||||
|
python --version # Should be 3.10+
|
||||||
|
|
||||||
|
# Reinstall dependencies
|
||||||
|
pip install --upgrade -r requirements.txt
|
||||||
|
|
||||||
|
# Check for port conflicts (SSE mode)
|
||||||
|
netstat -ano | findstr :8000
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tools not working
|
||||||
|
```cmd
|
||||||
|
# Enable debug logging
|
||||||
|
set MCP_PYTHON_DEBUG=true
|
||||||
|
python server.py
|
||||||
|
|
||||||
|
# Check allowed commands in config.py
|
||||||
|
# Add missing commands to config.allowed_commands
|
||||||
|
```
|
||||||
|
|
||||||
|
### Permission errors
|
||||||
|
```cmd
|
||||||
|
# Run terminal as Administrator
|
||||||
|
# Or adjust file/folder permissions
|
||||||
|
# Check antivirus software blocking execution
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
1. ✅ Server installed and tested
|
||||||
|
2. ⬜ Configure Claude Desktop / Cursor / VS Code
|
||||||
|
3. ⬜ Customize `config.py` for your workflow
|
||||||
|
4. ⬜ Add custom tools in `tools.py`
|
||||||
|
5. ⬜ Set up CI/CD for your projects
|
||||||
|
|
||||||
|
## Need Help?
|
||||||
|
|
||||||
|
- Check `README.md` for full documentation
|
||||||
|
- Run `python test_server.py` for diagnostics
|
||||||
|
- Review logs in `server.log` (if configured)
|
||||||
|
- Check allowed commands in `config.py`
|
||||||
|
|
||||||
|
---
|
||||||
|
*Created for Windows 11 • Python 3.10+ • MCP Protocol*
|
||||||
@@ -0,0 +1,546 @@
|
|||||||
|
# MCP Python Project Manager Server
|
||||||
|
|
||||||
|
A Model Context Protocol (MCP) server for managing and debugging Python projects on Windows 11.
|
||||||
|
|
||||||
|
## 🚀 Features
|
||||||
|
|
||||||
|
### Project Management
|
||||||
|
- **Project Info**: Get comprehensive information about Python projects including structure, dependencies, and environment
|
||||||
|
- **File Operations**: List, read, and analyze project files with filtering options
|
||||||
|
- **Directory Tree**: Visualize project structure with configurable depth
|
||||||
|
|
||||||
|
### Execution & Debugging
|
||||||
|
- **Run Scripts**: Execute Python scripts with custom arguments and environment variables
|
||||||
|
- **Debug Info**: Get information about running Python processes and scripts
|
||||||
|
- **Environment Details**: Inspect Python interpreter, packages, and sys.path
|
||||||
|
|
||||||
|
### Package Management
|
||||||
|
- **Install Packages**: Install packages via pip with requirements file support
|
||||||
|
- **List Packages**: View installed packages in JSON or text format
|
||||||
|
- **Dependency Analysis**: Analyze requirements files and detect potential issues
|
||||||
|
|
||||||
|
### Code Quality
|
||||||
|
- **Linting**: Run flake8, pylint, and black checks on your code
|
||||||
|
- **Formatting**: Auto-format code using black or autopep8
|
||||||
|
- **Testing**: Execute tests with pytest or unittest framework
|
||||||
|
|
||||||
|
### Environment Management
|
||||||
|
- **Virtual Environments**: Create and manage Python virtual environments
|
||||||
|
- **Environment Detection**: Auto-detect and use project venvs
|
||||||
|
- **Python Version Support**: Configure specific Python versions
|
||||||
|
|
||||||
|
### File Watching
|
||||||
|
- **Change Notifications**: Watch files for modifications (configurable patterns)
|
||||||
|
- **Pattern Filtering**: Include/exclude files by glob patterns
|
||||||
|
|
||||||
|
## 📦 Installation
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
**Option A: Using uv (Recommended ⚡)**
|
||||||
|
- [`uv`](https://github.com/astral-sh/uv) installed on Windows 11
|
||||||
|
- Install uv: `winget install astral-sh.uv` or `pip install uv`
|
||||||
|
|
||||||
|
**Option B: Traditional Python**
|
||||||
|
- Python 3.10+ installed on Windows 11
|
||||||
|
- pip package manager
|
||||||
|
|
||||||
|
### Setup with uv (Recommended)
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# 1. Navigate to project directory
|
||||||
|
cd C:\Users\dimir\proects\mcp-python
|
||||||
|
|
||||||
|
# 2. Install and run directly with uvx (no venv needed!)
|
||||||
|
uvx --from C:/Users/dimir/proects/mcp-python mcp-python-manager
|
||||||
|
```
|
||||||
|
|
||||||
|
### Setup with pip (Traditional)
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# 1. Clone or create project directory:
|
||||||
|
cd C:\Users\dimir\proects
|
||||||
|
mkdir mcp-python
|
||||||
|
cd mcp-python
|
||||||
|
|
||||||
|
# 2. Create virtual environment:
|
||||||
|
python -m venv .venv
|
||||||
|
.venv\Scripts\activate
|
||||||
|
|
||||||
|
# 3. Install dependencies:
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# 4. Optional: Install development tools:
|
||||||
|
pip install py-spy safety pip-audit
|
||||||
|
```
|
||||||
|
|
||||||
|
## ⚙️ Configuration
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
| Variable | Description | Default |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| `MCP_PYTHON_WORKSPACE` | Root directory for projects | `C:/Users/dimir/projects` |
|
||||||
|
| `MCP_PYTHON_DEBUG` | Enable debug logging | `false` |
|
||||||
|
| `MCP_PYTHON_LOG_LEVEL` | Logging level | `INFO` |
|
||||||
|
| `MCP_PYTHON_MAX_EXEC_TIME` | Command timeout (seconds) | `300` |
|
||||||
|
|
||||||
|
### Config File (`config.py`)
|
||||||
|
|
||||||
|
Customize server behavior by editing `config.py`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from config import ServerConfig
|
||||||
|
|
||||||
|
config = ServerConfig(
|
||||||
|
workspace_root=Path("C:/Users/dimir/projects"),
|
||||||
|
venv_name=".venv",
|
||||||
|
debug_mode=True,
|
||||||
|
allowed_commands=["python", "pip", "pytest", "black", "flake8", "pylint"],
|
||||||
|
max_execution_time=600,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔌 Usage
|
||||||
|
|
||||||
|
### Running the Server
|
||||||
|
|
||||||
|
#### 🚀 With uvx (Recommended)
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# Run directly without installation
|
||||||
|
uvx --from C:/Users/dimir/proects/mcp-python mcp-python-manager
|
||||||
|
|
||||||
|
# With custom workspace
|
||||||
|
uvx --from C:/Users/dimir/proects/mcp-python mcp-python-manager --workspace "C:\MyProjects"
|
||||||
|
|
||||||
|
# With debug mode
|
||||||
|
uvx --from C:/Users/dimir/proects/mcp-python mcp-python-manager --debug
|
||||||
|
|
||||||
|
# SSE transport
|
||||||
|
uvx --from C:/Users/dimir/proects/mcp-python mcp-python-manager --transport sse --port 8000
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 🐍 With Python (Traditional)
|
||||||
|
|
||||||
|
**Stdio Transport (Default for MCP clients):**
|
||||||
|
```cmd
|
||||||
|
# Direct execution
|
||||||
|
python server.py
|
||||||
|
|
||||||
|
# Via MCP stdio module
|
||||||
|
python -m mcp.server.stdio server:main
|
||||||
|
```
|
||||||
|
|
||||||
|
**SSE Transport (HTTP-based clients):**
|
||||||
|
```cmd
|
||||||
|
python server.py --transport sse --host localhost --port 8000
|
||||||
|
```
|
||||||
|
|
||||||
|
**With Options:**
|
||||||
|
```cmd
|
||||||
|
python server.py --debug --workspace "C:\MyProjects"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Connecting from Claude Desktop
|
||||||
|
|
||||||
|
#### ⚡ Using uvx (Recommended)
|
||||||
|
|
||||||
|
Add to your Claude Desktop config (`%APPDATA%\Claude\claude_desktop_config.json`):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"python-manager": {
|
||||||
|
"command": "uvx",
|
||||||
|
"args": [
|
||||||
|
"--from",
|
||||||
|
"C:/Users/dimir/proects/mcp-python",
|
||||||
|
"mcp-python-manager",
|
||||||
|
"--transport",
|
||||||
|
"stdio"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"MCP_PYTHON_WORKSPACE": "C:/Users/dimir/projects",
|
||||||
|
"UV_NO_CACHE": "0",
|
||||||
|
"UV_LINK_MODE": "copy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 🐍 Using Python (Traditional)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"python-manager": {
|
||||||
|
"command": "python",
|
||||||
|
"args": [
|
||||||
|
"C:/Users/dimir/proects/mcp-python/server.py"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"MCP_PYTHON_WORKSPACE": "C:/Users/dimir/projects"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Connecting from Cursor/VS Code
|
||||||
|
|
||||||
|
#### ⚡ Using uvx (Recommended)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcp": {
|
||||||
|
"servers": {
|
||||||
|
"python-manager": {
|
||||||
|
"type": "stdio",
|
||||||
|
"command": "uvx",
|
||||||
|
"args": [
|
||||||
|
"--from",
|
||||||
|
"C:/Users/dimir/proects/mcp-python",
|
||||||
|
"mcp-python-manager",
|
||||||
|
"--transport",
|
||||||
|
"stdio"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"UV_NO_CACHE": "0",
|
||||||
|
"UV_LINK_MODE": "copy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 🐍 Using Python (Traditional)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcp": {
|
||||||
|
"servers": {
|
||||||
|
"python-manager": {
|
||||||
|
"type": "stdio",
|
||||||
|
"command": "python",
|
||||||
|
"args": ["C:/Users/dimir/proects/mcp-python/server.py"],
|
||||||
|
"env": {
|
||||||
|
"PYTHONUNBUFFERED": "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🛠️ Available Tools
|
||||||
|
|
||||||
|
### `get_project_info`
|
||||||
|
Get comprehensive project information.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"project_path": "C:/Users/dimir/projects/my-app"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `run_python_script`
|
||||||
|
Execute a Python script.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"script_path": "main.py",
|
||||||
|
"args": ["--config", "prod.yaml"],
|
||||||
|
"env": {"DEBUG": "false"},
|
||||||
|
"use_venv": true,
|
||||||
|
"cwd": "C:/Users/dimir/projects/my-app"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `install_package`
|
||||||
|
Install Python packages.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"packages": ["requests", "fastapi"],
|
||||||
|
"upgrade": true,
|
||||||
|
"use_venv": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Or with requirements file:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"requirements_file": "requirements.txt",
|
||||||
|
"use_venv": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `list_packages`
|
||||||
|
List installed packages.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"project_path": "C:/Users/dimir/projects/my-app",
|
||||||
|
"format": "json"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `run_tests`
|
||||||
|
Execute tests.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"test_path": "tests/",
|
||||||
|
"test_framework": "pytest",
|
||||||
|
"args": ["-x", "--cov"],
|
||||||
|
"verbose": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `lint_code`
|
||||||
|
Run code linters.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"file_path": "src/",
|
||||||
|
"linter": "all",
|
||||||
|
"fix": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `create_venv`
|
||||||
|
Create virtual environment.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"project_path": "C:/Users/dimir/projects/new-project",
|
||||||
|
"venv_name": ".venv",
|
||||||
|
"python_version": "3.11"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `get_debug_info`
|
||||||
|
Get debugging information.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"script_path": "main.py",
|
||||||
|
"include_stack": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Or by PID:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"pid": 12345,
|
||||||
|
"include_stack": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `list_project_files`
|
||||||
|
List project files.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"directory": "C:/Users/dimir/projects/my-app",
|
||||||
|
"pattern": "*.py",
|
||||||
|
"recursive": true,
|
||||||
|
"exclude_dirs": ["__pycache__", ".git"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `read_file`
|
||||||
|
Read file contents.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"file_path": "main.py",
|
||||||
|
"start_line": 1,
|
||||||
|
"end_line": 50,
|
||||||
|
"encoding": "utf-8"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `execute_command`
|
||||||
|
Execute allowed shell commands.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "python -m pytest tests/ -v",
|
||||||
|
"cwd": "C:/Users/dimir/projects/my-app",
|
||||||
|
"timeout": 120
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `get_python_env`
|
||||||
|
Get Python environment info.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"project_path": "C:/Users/dimir/projects/my-app"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `format_code`
|
||||||
|
Format Python code.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"file_path": "src/",
|
||||||
|
"formatter": "black",
|
||||||
|
"check_only": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `analyze_dependencies`
|
||||||
|
Analyze project dependencies.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"project_path": "C:/Users/dimir/projects/my-app",
|
||||||
|
"check_updates": false,
|
||||||
|
"check_security": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `watch_files`
|
||||||
|
Configure file watching.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"directory": "C:/Users/dimir/projects/my-app/src",
|
||||||
|
"patterns": ["*.py", "*.json"],
|
||||||
|
"recursive": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔒 Security
|
||||||
|
|
||||||
|
### Allowed Commands
|
||||||
|
By default, only these commands can be executed:
|
||||||
|
- `python` - Run Python scripts
|
||||||
|
- `pip` - Package management
|
||||||
|
- `pytest` - Run tests
|
||||||
|
- `black` - Code formatting
|
||||||
|
- `flake8` - Linting
|
||||||
|
- `pylint` - Advanced linting
|
||||||
|
|
||||||
|
Modify `config.allowed_commands` to customize.
|
||||||
|
|
||||||
|
### Path Validation
|
||||||
|
All file paths are validated to prevent directory traversal attacks.
|
||||||
|
|
||||||
|
### Output Truncation
|
||||||
|
Command output is limited to `max_output_length` characters (default: 50,000).
|
||||||
|
|
||||||
|
## 🐛 Debugging
|
||||||
|
|
||||||
|
### Enable Debug Logging
|
||||||
|
```cmd
|
||||||
|
set MCP_PYTHON_DEBUG=true
|
||||||
|
set MCP_PYTHON_LOG_LEVEL=DEBUG
|
||||||
|
python server.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Log File
|
||||||
|
Configure logging to file in `config.py`:
|
||||||
|
```python
|
||||||
|
config.log_file = Path("C:/Users/dimir/proects/mcp-python/server.log")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
| Issue | Solution |
|
||||||
|
|-------|----------|
|
||||||
|
| "Command not allowed" | Add command to `config.allowed_commands` |
|
||||||
|
| "Virtual environment not found" | Create venv with `create_venv` tool or manually |
|
||||||
|
| "Timeout executing command" | Increase `max_execution_time` in config |
|
||||||
|
| "Permission denied" | Run terminal as Administrator or check file permissions |
|
||||||
|
|
||||||
|
## 🧪 Testing the Server
|
||||||
|
|
||||||
|
### Manual Test with MCP Inspector
|
||||||
|
```cmd
|
||||||
|
# Install MCP inspector
|
||||||
|
npm install -g @modelcontextprotocol/inspector
|
||||||
|
|
||||||
|
# Run server and inspector
|
||||||
|
python server.py
|
||||||
|
# In another terminal:
|
||||||
|
mcp-inspector
|
||||||
|
```
|
||||||
|
|
||||||
|
### Python Test Script
|
||||||
|
```python
|
||||||
|
import asyncio
|
||||||
|
from mcp.client.session import ClientSession
|
||||||
|
from mcp.client.stdio import stdio_client
|
||||||
|
|
||||||
|
async def test_server():
|
||||||
|
async with stdio_client(["python", "server.py"]) as (read, write):
|
||||||
|
async with ClientSession(read, write) as session:
|
||||||
|
await session.initialize()
|
||||||
|
|
||||||
|
# List available tools
|
||||||
|
tools = await session.list_tools()
|
||||||
|
print(f"Available tools: {[t.name for t in tools.tools]}")
|
||||||
|
|
||||||
|
# Test get_project_info
|
||||||
|
result = await session.call_tool(
|
||||||
|
"get_project_info",
|
||||||
|
{"project_path": "C:/Users/dimir/projects"}
|
||||||
|
)
|
||||||
|
print(result)
|
||||||
|
|
||||||
|
asyncio.run(test_server())
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📁 Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
mcp-python/
|
||||||
|
├── server.py # Main server entry point
|
||||||
|
├── tools.py # MCP tool implementations
|
||||||
|
├── config.py # Configuration settings
|
||||||
|
├── requirements.txt # Python dependencies
|
||||||
|
├── README.md # This file
|
||||||
|
├── .gitignore # Git ignore rules
|
||||||
|
└── logs/ # Log files (created at runtime)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔄 Development
|
||||||
|
|
||||||
|
### Adding New Tools
|
||||||
|
|
||||||
|
1. Add tool definition in `tools.py` `_register_tools()` method
|
||||||
|
2. Implement the async method in `PythonProjectTools` class
|
||||||
|
3. Add handler case in `handle_tool_call()` method
|
||||||
|
4. Update this README with documentation
|
||||||
|
|
||||||
|
### Example Tool Addition
|
||||||
|
```python
|
||||||
|
# In _register_tools():
|
||||||
|
Tool(
|
||||||
|
name="my_new_tool",
|
||||||
|
description="What this tool does",
|
||||||
|
inputSchema={...}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Implementation:
|
||||||
|
async def my_new_tool(self, arg1: str) -> ToolResult:
|
||||||
|
# Your logic here
|
||||||
|
return ToolResult(success=True, message="Done", data={...})
|
||||||
|
|
||||||
|
# Handler:
|
||||||
|
elif name == "my_new_tool":
|
||||||
|
result = await self.my_new_tool(**arguments)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📄 License
|
||||||
|
|
||||||
|
MIT License - Feel free to use and modify for your projects.
|
||||||
|
|
||||||
|
## 🤝 Contributing
|
||||||
|
|
||||||
|
1. Fork the repository
|
||||||
|
2. Create a feature branch
|
||||||
|
3. Add tests for new functionality
|
||||||
|
4. Submit a pull request
|
||||||
|
|
||||||
|
## 🔗 Resources
|
||||||
|
|
||||||
|
- [MCP Specification](https://modelcontextprotocol.io)
|
||||||
|
- [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk)
|
||||||
|
- [Windows Python Setup Guide](https://docs.python.org/3/using/windows.html)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Author**: dimir
|
||||||
|
**Created**: 2026
|
||||||
|
**Platform**: Windows 11, Python 3.10+
|
||||||
+274
@@ -0,0 +1,274 @@
|
|||||||
|
# ⚡ Using MCP Python Manager with uvx
|
||||||
|
|
||||||
|
This guide explains how to use the MCP Python Project Manager server with [`uv`](https://github.com/astral-sh/uv) and `uvx` for faster, simpler execution.
|
||||||
|
|
||||||
|
## Why uvx?
|
||||||
|
|
||||||
|
✅ **No virtual environment setup** - Run directly without `python -m venv`
|
||||||
|
✅ **Instant startup** - uv's caching makes repeated runs lightning fast
|
||||||
|
✅ **Dependency isolation** - Each run uses isolated dependencies
|
||||||
|
✅ **Cross-platform** - Works the same on Windows, macOS, and Linux
|
||||||
|
✅ **Automatic updates** - uvx fetches the latest version automatically
|
||||||
|
|
||||||
|
## 🚀 Quick Start
|
||||||
|
|
||||||
|
### Install uv (one-time)
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# Via winget (Windows)
|
||||||
|
winget install astral-sh.uv
|
||||||
|
|
||||||
|
# Or via pip
|
||||||
|
pip install uv
|
||||||
|
|
||||||
|
# Verify installation
|
||||||
|
uv --version
|
||||||
|
uvx --version
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run the MCP Server
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# Basic run (recommended for MCP clients)
|
||||||
|
uvx --from C:/Users/dimir/proects/mcp-python mcp-python-manager
|
||||||
|
|
||||||
|
# With custom workspace
|
||||||
|
uvx --from C:/Users/dimir/proects/mcp-python mcp-python-manager --workspace "C:\MyProjects"
|
||||||
|
|
||||||
|
# With debug logging
|
||||||
|
uvx --from C:/Users/dimir/proects/mcp-python mcp-python-manager --debug
|
||||||
|
|
||||||
|
# Via SSE transport
|
||||||
|
uvx --from C:/Users/dimir/proects/mcp-python mcp-python-manager --transport sse --port 8000
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run from Project Directory
|
||||||
|
|
||||||
|
If you're already in the project directory:
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
cd C:\Users\dimir\proects\mcp-python
|
||||||
|
uvx --from . mcp-python-manager
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔌 Claude Desktop Configuration
|
||||||
|
|
||||||
|
Add to `%APPDATA%\Claude\claude_desktop_config.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"python-manager": {
|
||||||
|
"command": "uvx",
|
||||||
|
"args": [
|
||||||
|
"--from",
|
||||||
|
"C:/Users/dimir/proects/mcp-python",
|
||||||
|
"mcp-python-manager",
|
||||||
|
"--transport",
|
||||||
|
"stdio"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"MCP_PYTHON_WORKSPACE": "C:/Users/dimir/projects",
|
||||||
|
"UV_NO_CACHE": "0",
|
||||||
|
"UV_LINK_MODE": "copy",
|
||||||
|
"PYTHONUNBUFFERED": "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment Variables Explained
|
||||||
|
|
||||||
|
| Variable | Purpose | Recommended Value |
|
||||||
|
|----------|---------|------------------|
|
||||||
|
| `MCP_PYTHON_WORKSPACE` | Root directory for Python projects | `C:/Users/dimir/projects` |
|
||||||
|
| `UV_NO_CACHE` | Disable uv cache (0 = use cache) | `0` |
|
||||||
|
| `UV_LINK_MODE` | How uv links packages (`copy`, `symlink`, `hardlink`) | `copy` (safest on Windows) |
|
||||||
|
| `PYTHONUNBUFFERED` | Disable Python output buffering | `1` |
|
||||||
|
|
||||||
|
## 🔧 Cursor / VS Code Configuration
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcp": {
|
||||||
|
"servers": {
|
||||||
|
"python-manager": {
|
||||||
|
"type": "stdio",
|
||||||
|
"command": "uvx",
|
||||||
|
"args": [
|
||||||
|
"--from",
|
||||||
|
"C:/Users/dimir/proects/mcp-python",
|
||||||
|
"mcp-python-manager",
|
||||||
|
"--transport",
|
||||||
|
"stdio"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"MCP_PYTHON_WORKSPACE": "C:/Users/dimir/projects",
|
||||||
|
"UV_LINK_MODE": "copy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🛠️ Development with uvx
|
||||||
|
|
||||||
|
### Test Changes Locally
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# After editing server.py or tools.py, test immediately:
|
||||||
|
uvx --from C:/Users/dimir/proects/mcp-python mcp-python-manager --debug
|
||||||
|
|
||||||
|
# No need to reinstall - uvx picks up local changes!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install for Development
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# Install with dev dependencies
|
||||||
|
uv pip install -e ".[dev]" --system
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
uv run pytest tests/ -v
|
||||||
|
|
||||||
|
# Run linting
|
||||||
|
uv run ruff check .
|
||||||
|
uv run black --check .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build and Publish (Optional)
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# Build distribution
|
||||||
|
uv build
|
||||||
|
|
||||||
|
# Publish to PyPI (requires token)
|
||||||
|
uv publish --token $PYPI_TOKEN
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🐛 Troubleshooting uvx
|
||||||
|
|
||||||
|
### "Command not found: uvx"
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# Install uv
|
||||||
|
winget install astral-sh.uv
|
||||||
|
# or
|
||||||
|
pip install uv
|
||||||
|
|
||||||
|
# Ensure it's in PATH
|
||||||
|
where uvx
|
||||||
|
```
|
||||||
|
|
||||||
|
### Permission errors on Windows
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# Use copy link mode (safer than symlinks on Windows)
|
||||||
|
set UV_LINK_MODE=copy
|
||||||
|
uvx --from . mcp-python-manager
|
||||||
|
|
||||||
|
# Or run as Administrator if needed
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cache issues
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# Clear uv cache
|
||||||
|
uv cache clean
|
||||||
|
|
||||||
|
# Disable cache for one run
|
||||||
|
uvx --no-cache --from . mcp-python-manager
|
||||||
|
```
|
||||||
|
|
||||||
|
### Slow first run
|
||||||
|
|
||||||
|
The first `uvx` run downloads dependencies. Subsequent runs are instant due to caching.
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# Pre-warm cache (optional)
|
||||||
|
uvx --from . mcp-python-manager --help
|
||||||
|
```
|
||||||
|
|
||||||
|
### Debug uvx behavior
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# Enable uv debug output
|
||||||
|
set UV_VERBOSE=1
|
||||||
|
uvx --from . mcp-python-manager --debug
|
||||||
|
|
||||||
|
# See what uvx is doing
|
||||||
|
set RUST_LOG=uv=debug
|
||||||
|
uvx --from . mcp-python-manager
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📊 Performance Comparison
|
||||||
|
|
||||||
|
| Method | First Run | Subsequent Runs | Setup Time |
|
||||||
|
|--------|-----------|----------------|------------|
|
||||||
|
| `python server.py` + venv | ~30s | ~1s | ~2 min (venv + pip) |
|
||||||
|
| `uvx --from .` | ~15s | **~0.5s** | **0s** |
|
||||||
|
| `pip install -e .` + run | ~45s | ~1s | ~3 min |
|
||||||
|
|
||||||
|
## 🔄 Updating the Server
|
||||||
|
|
||||||
|
With uvx, updates are automatic:
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# Just run again - uvx fetches latest code
|
||||||
|
uvx --from C:/Users/dimir/proects/mcp-python mcp-python-manager
|
||||||
|
|
||||||
|
# Or force refresh
|
||||||
|
uv cache clean mcp-python-manager
|
||||||
|
uvx --from C:/Users/dimir/proects/mcp-python mcp-python-manager
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📁 Project Structure for uvx
|
||||||
|
|
||||||
|
```
|
||||||
|
mcp-python/
|
||||||
|
├── pyproject.toml # [project.scripts] defines entry points
|
||||||
|
├── server.py # Contains run_server() entry point
|
||||||
|
├── .uvrc # uv-specific configuration (optional)
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key pyproject.toml Settings
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[project.scripts]
|
||||||
|
# This creates the 'mcp-python-manager' command
|
||||||
|
mcp-python-manager = "server:run_server"
|
||||||
|
|
||||||
|
[tool.uv]
|
||||||
|
# uv-specific optimizations
|
||||||
|
dev-dependencies = ["dev"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 Best Practices
|
||||||
|
|
||||||
|
1. **Use `--from .` when in project directory** - Faster than full path
|
||||||
|
2. **Set `UV_LINK_MODE=copy` on Windows** - Avoids symlink permission issues
|
||||||
|
3. **Keep `MCP_PYTHON_WORKSPACE` in env** - Consistent project access
|
||||||
|
4. **Use `--debug` during development** - See detailed logs
|
||||||
|
5. **Cache warmup** - Run `--help` once to pre-download dependencies
|
||||||
|
|
||||||
|
## 🔄 Switching Back to Python
|
||||||
|
|
||||||
|
If you need to use traditional Python:
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
# Traditional setup
|
||||||
|
python -m venv .venv
|
||||||
|
.venv\Scripts\activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
python server.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Both methods work - choose what fits your workflow!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**uv Documentation**: https://docs.astral.sh/uv/
|
||||||
|
**MCP Specification**: https://modelcontextprotocol.io
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"python-manager": {
|
||||||
|
"command": "uvx",
|
||||||
|
"args": [
|
||||||
|
"--from",
|
||||||
|
"C:/Users/dimir/proects/mcp-python",
|
||||||
|
"mcp-python-manager",
|
||||||
|
"--transport",
|
||||||
|
"stdio"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"MCP_PYTHON_WORKSPACE": "C:/Users/dimir/projects",
|
||||||
|
"MCP_PYTHON_DEBUG": "false",
|
||||||
|
"MCP_PYTHON_LOG_LEVEL": "INFO",
|
||||||
|
"PYTHONUNBUFFERED": "1"
|
||||||
|
},
|
||||||
|
"disabled": false,
|
||||||
|
"autoApprove": [],
|
||||||
|
"alwaysAllow": [
|
||||||
|
"get_project_info",
|
||||||
|
"list_project_files",
|
||||||
|
"read_file",
|
||||||
|
"list_packages",
|
||||||
|
"get_python_env",
|
||||||
|
"get_debug_info"
|
||||||
|
],
|
||||||
|
"description": "MCP server for managing and debugging Python projects on Windows 11"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
"""
|
||||||
|
Configuration settings for MCP Python Project Manager Server.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional, List
|
||||||
|
from pydantic import BaseModel, Field, field_validator
|
||||||
|
|
||||||
|
|
||||||
|
class ServerConfig(BaseModel):
|
||||||
|
"""Main server configuration."""
|
||||||
|
|
||||||
|
# Server settings
|
||||||
|
server_name: str = Field(default="mcp-python-manager", description="Name of the MCP server")
|
||||||
|
version: str = Field(default="1.0.0", description="Server version")
|
||||||
|
|
||||||
|
# Paths
|
||||||
|
workspace_root: Path = Field(
|
||||||
|
default=Path("C:/Users/dimir/projects"),
|
||||||
|
description="Root directory for Python projects"
|
||||||
|
)
|
||||||
|
venv_name: str = Field(default=".venv", description="Default virtual environment name")
|
||||||
|
|
||||||
|
# Python settings
|
||||||
|
python_executable: Optional[str] = Field(
|
||||||
|
default=None,
|
||||||
|
description="Path to Python executable (auto-detected if None)"
|
||||||
|
)
|
||||||
|
default_python_version: str = Field(default="3.11", description="Default Python version")
|
||||||
|
|
||||||
|
# Debug settings
|
||||||
|
debug_mode: bool = Field(default=False, description="Enable debug logging")
|
||||||
|
log_level: str = Field(default="INFO", description="Logging level")
|
||||||
|
log_file: Optional[Path] = Field(default=None, description="Path to log file")
|
||||||
|
|
||||||
|
# Tool settings
|
||||||
|
max_execution_time: int = Field(default=300, description="Max execution time for commands (seconds)")
|
||||||
|
max_output_length: int = Field(default=50000, description="Max characters in command output")
|
||||||
|
allowed_commands: List[str] = Field(
|
||||||
|
default_factory=lambda: ["python", "pip", "pytest", "black", "flake8", "pylint"],
|
||||||
|
description="List of allowed shell commands"
|
||||||
|
)
|
||||||
|
|
||||||
|
# File watching
|
||||||
|
enable_file_watching: bool = Field(default=True, description="Enable file change notifications")
|
||||||
|
watch_patterns: List[str] = Field(
|
||||||
|
default_factory=lambda: ["*.py", "*.txt", "*.md", "requirements*.txt"],
|
||||||
|
description="File patterns to watch"
|
||||||
|
)
|
||||||
|
ignore_patterns: List[str] = Field(
|
||||||
|
default_factory=lambda: ["__pycache__", "*.pyc", ".git", ".venv", "node_modules"],
|
||||||
|
description="Patterns to ignore when watching"
|
||||||
|
)
|
||||||
|
|
||||||
|
@field_validator('workspace_root', 'log_file', mode='before')
|
||||||
|
@classmethod
|
||||||
|
def convert_to_path(cls, v):
|
||||||
|
if isinstance(v, str):
|
||||||
|
return Path(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
@field_validator('log_level')
|
||||||
|
@classmethod
|
||||||
|
def validate_log_level(cls, v):
|
||||||
|
valid_levels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
||||||
|
if v.upper() not in valid_levels:
|
||||||
|
raise ValueError(f"log_level must be one of {valid_levels}")
|
||||||
|
return v.upper()
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectConfig(BaseModel):
|
||||||
|
"""Per-project configuration."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
path: Path
|
||||||
|
python_version: Optional[str] = None
|
||||||
|
venv_path: Optional[Path] = None
|
||||||
|
entry_point: Optional[str] = None
|
||||||
|
test_command: str = Field(default="pytest", description="Command to run tests")
|
||||||
|
run_args: List[str] = Field(default_factory=list, description="Default arguments for running")
|
||||||
|
|
||||||
|
@field_validator('path', 'venv_path', mode='before')
|
||||||
|
@classmethod
|
||||||
|
def convert_to_path(cls, v):
|
||||||
|
if isinstance(v, str):
|
||||||
|
return Path(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
# Global config instance
|
||||||
|
config = ServerConfig()
|
||||||
|
|
||||||
|
|
||||||
|
def load_config_from_env():
|
||||||
|
"""Load configuration from environment variables."""
|
||||||
|
import os
|
||||||
|
|
||||||
|
if os.getenv("MCP_PYTHON_WORKSPACE"):
|
||||||
|
config.workspace_root = Path(os.getenv("MCP_PYTHON_WORKSPACE"))
|
||||||
|
|
||||||
|
if os.getenv("MCP_PYTHON_DEBUG") == "true":
|
||||||
|
config.debug_mode = True
|
||||||
|
|
||||||
|
if os.getenv("MCP_PYTHON_LOG_LEVEL"):
|
||||||
|
config.log_level = os.getenv("MCP_PYTHON_LOG_LEVEL")
|
||||||
|
|
||||||
|
if os.getenv("MCP_PYTHON_MAX_EXEC_TIME"):
|
||||||
|
config.max_execution_time = int(os.getenv("MCP_PYTHON_MAX_EXEC_TIME"))
|
||||||
|
|
||||||
|
return config
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=61.0", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "mcp-python-manager"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "MCP Server for managing Python projects on Windows"
|
||||||
|
requires-python = ">=3.10"
|
||||||
|
readme = "README.md"
|
||||||
|
license = {text = "MIT"}
|
||||||
|
|
||||||
|
# These are the specific files that need to be installed as modules
|
||||||
|
# so that 'server.py' and its imports work inside the uvx environment.
|
||||||
|
dependencies = [
|
||||||
|
"mcp>=1.0.0",
|
||||||
|
"pydantic>=2.0.0",
|
||||||
|
"rich>=13.0.0",
|
||||||
|
"psutil>=5.9.0",
|
||||||
|
"shellingham>=1.5.0",
|
||||||
|
"autopep8",
|
||||||
|
"flake8",
|
||||||
|
"black",
|
||||||
|
"pytest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
# This defines the command 'mcp-python-manager' that runs server.run_server()
|
||||||
|
mcp-python-manager = "server:run_server"
|
||||||
|
|
||||||
|
# CRITICAL FIX: Explicitly include root-level Python modules
|
||||||
|
[tool.setuptools]
|
||||||
|
py-modules = ["server", "tools", "config"]
|
||||||
|
|
||||||
|
[tool.uv]
|
||||||
|
# Configuration for uv behavior
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# MCP Python Project Manager - Dependencies
|
||||||
|
mcp>=1.0.0
|
||||||
|
pydantic>=2.0.0
|
||||||
|
python-dotenv>=1.0.0
|
||||||
|
watchdog>=3.0.0
|
||||||
|
black>=24.0.0
|
||||||
|
flake8>=7.0.0
|
||||||
|
pylint>=3.0.0
|
||||||
|
pytest>=8.0.0
|
||||||
|
virtualenv>=20.25.0
|
||||||
|
psutil>=5.9.0
|
||||||
|
rich>=13.0.0
|
||||||
|
typer>=0.9.0
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import asyncio
|
||||||
|
from typing import List, Dict, Any, Sequence
|
||||||
|
|
||||||
|
# MCP Imports
|
||||||
|
from mcp.server import Server
|
||||||
|
from mcp.server.stdio import stdio_server
|
||||||
|
from mcp.types import Tool, TextContent
|
||||||
|
|
||||||
|
# Import tools from local file
|
||||||
|
import tools
|
||||||
|
|
||||||
|
# Настройка логирования
|
||||||
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||||
|
logger = logging.getLogger("mcp-python-server")
|
||||||
|
|
||||||
|
# Инициализация сервера
|
||||||
|
app = Server("mcp-python-manager")
|
||||||
|
|
||||||
|
# --- Регистрация инструментов ---
|
||||||
|
|
||||||
|
@app.list_tools()
|
||||||
|
async def list_tools() -> List[Tool]:
|
||||||
|
"""Возвращает список доступных инструментов."""
|
||||||
|
return tools.get_tool_definitions()
|
||||||
|
|
||||||
|
@app.call_tool()
|
||||||
|
async def call_tool(name: str, arguments: Dict[str, Any]) -> Sequence[TextContent]:
|
||||||
|
"""Вызывает конкретный инструмент."""
|
||||||
|
logger.info(f"Вызов инструмента: {name}")
|
||||||
|
try:
|
||||||
|
# Выполняем логику из tools.py
|
||||||
|
result_text = await tools.execute_tool(name, arguments)
|
||||||
|
return [TextContent(type="text", text=str(result_text))]
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка в инструменте {name}: {e}")
|
||||||
|
return [TextContent(type="text", text=f"Ошибка выполнения: {str(e)}")]
|
||||||
|
|
||||||
|
# --- Запуск сервера ---
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
"""Основная функция запуска."""
|
||||||
|
logger.info("Запуск MCP сервера на stdio...")
|
||||||
|
# Запуск сервера через стандартный ввод/вывод
|
||||||
|
async with stdio_server() as streams:
|
||||||
|
await app.run(*streams, app.create_initialization_options())
|
||||||
|
|
||||||
|
def run_server():
|
||||||
|
"""Точка входа для uvx."""
|
||||||
|
try:
|
||||||
|
asyncio.run(main())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
logger.info("Сервер остановлен пользователем.")
|
||||||
|
except Exception as e:
|
||||||
|
logger.critical(f"Критическая ошибка сервера: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
run_server()
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
@echo off
|
||||||
|
REM MCP Python Project Manager - Windows Startup Script
|
||||||
|
REM Save as: start-server.bat
|
||||||
|
|
||||||
|
setlocal enabledelayedexpansion
|
||||||
|
|
||||||
|
REM Configuration
|
||||||
|
set PROJECT_DIR=C:\Users\dimir\proects\mcp-python
|
||||||
|
set VENV_DIR=%PROJECT_DIR%\.venv
|
||||||
|
set PYTHON_EXE=%VENV_DIR%\Scripts\python.exe
|
||||||
|
|
||||||
|
REM Parse arguments
|
||||||
|
set TRANSPORT=stdio
|
||||||
|
set DEBUG=false
|
||||||
|
set WORKSPACE=
|
||||||
|
set USE_UVX=false
|
||||||
|
|
||||||
|
:parse_args
|
||||||
|
if "%~1"=="" goto :end_parse
|
||||||
|
if /i "%~1"=="--debug" (
|
||||||
|
set DEBUG=true
|
||||||
|
shift
|
||||||
|
goto :parse_args
|
||||||
|
)
|
||||||
|
if /i "%~1"=="--sse" (
|
||||||
|
set TRANSPORT=sse
|
||||||
|
shift
|
||||||
|
goto :parse_args
|
||||||
|
)
|
||||||
|
if /i "%~1"=="--workspace" (
|
||||||
|
set WORKSPACE=%~2
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
goto :parse_args
|
||||||
|
)
|
||||||
|
if /i "%~1"=="--uvx" (
|
||||||
|
set USE_UVX=true
|
||||||
|
shift
|
||||||
|
goto :parse_args
|
||||||
|
)
|
||||||
|
if /i "%~1"=="--help" (
|
||||||
|
goto :show_help
|
||||||
|
)
|
||||||
|
shift
|
||||||
|
goto :parse_args
|
||||||
|
:end_parse
|
||||||
|
|
||||||
|
echo ========================================
|
||||||
|
echo MCP Python Project Manager Server
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM Check if using uvx mode
|
||||||
|
if "%USE_UVX%"=="true" (
|
||||||
|
goto :run_with_uvx
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Traditional Python mode
|
||||||
|
|
||||||
|
REM Check if Python is available
|
||||||
|
where python >nul 2>&1
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [ERROR] Python not found in PATH
|
||||||
|
echo Please install Python 3.10+ from https://python.org
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Check/create virtual environment
|
||||||
|
if not exist "%PYTHON_EXE%" (
|
||||||
|
echo [INFO] Creating virtual environment...
|
||||||
|
python -m venv "%VENV_DIR%"
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [ERROR] Failed to create virtual environment
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Activate virtual environment
|
||||||
|
call "%VENV_DIR%\Scripts\activate.bat"
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [ERROR] Failed to activate virtual environment
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Install dependencies if needed
|
||||||
|
if not exist "%VENV_DIR%\Lib\site-packages\mcp" (
|
||||||
|
echo [INFO] Installing dependencies...
|
||||||
|
pip install -r "%PROJECT_DIR%\requirements.txt"
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [WARNING] Some dependencies may have failed to install
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Set environment variables
|
||||||
|
set MCP_PYTHON_WORKSPACE=%WORKSPACE:C:/Users/dimir/projects=%
|
||||||
|
if "%DEBUG%"=="true" (
|
||||||
|
set MCP_PYTHON_DEBUG=true
|
||||||
|
set MCP_PYTHON_LOG_LEVEL=DEBUG
|
||||||
|
echo [DEBUG] Debug mode enabled
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Build command
|
||||||
|
set SERVER_CMD=%PYTHON_EXE% "%PROJECT_DIR%\server.py" --transport %TRANSPORT%
|
||||||
|
if "%WORKSPACE%" neq "" (
|
||||||
|
set SERVER_CMD=!SERVER_CMD! --workspace "%WORKSPACE%"
|
||||||
|
)
|
||||||
|
if "%DEBUG%"=="true" (
|
||||||
|
set SERVER_CMD=!SERVER_CMD! --debug
|
||||||
|
)
|
||||||
|
|
||||||
|
echo [INFO] Starting server with %TRANSPORT% transport...
|
||||||
|
echo [INFO] Workspace: %MCP_PYTHON_WORKSPACE%
|
||||||
|
echo [INFO] Press Ctrl+C to stop the server
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM Run server
|
||||||
|
%SERVER_CMD%
|
||||||
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
|
|
||||||
|
REM Deactivate virtual environment
|
||||||
|
deactivate
|
||||||
|
|
||||||
|
goto :exit_handler
|
||||||
|
|
||||||
|
:run_with_uvx
|
||||||
|
REM Check if uv/uvx is available
|
||||||
|
where uvx >nul 2>&1
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [ERROR] uvx not found in PATH
|
||||||
|
echo Please install uv: winget install astral-sh.uv
|
||||||
|
echo or: pip install uv
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo [INFO] Running with uvx (no venv needed!)...
|
||||||
|
|
||||||
|
REM Build uvx command
|
||||||
|
set UVX_CMD=uvx --from "%PROJECT_DIR%" mcp-python-manager --transport %TRANSPORT%
|
||||||
|
if "%WORKSPACE%" neq "" (
|
||||||
|
set UVX_CMD=!UVX_CMD! --workspace "%WORKSPACE%"
|
||||||
|
)
|
||||||
|
if "%DEBUG%"=="true" (
|
||||||
|
set UVX_CMD=!UVX_CMD! --debug
|
||||||
|
set UV_NO_CACHE=0
|
||||||
|
)
|
||||||
|
|
||||||
|
set MCP_PYTHON_WORKSPACE=%WORKSPACE:C:/Users/dimir/projects=%
|
||||||
|
echo [INFO] Workspace: %MCP_PYTHON_WORKSPACE%
|
||||||
|
echo [INFO] Press Ctrl+C to stop the server
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM Run server with uvx
|
||||||
|
%UVX_CMD%
|
||||||
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
|
|
||||||
|
:exit_handler
|
||||||
|
if %EXIT_CODE% equ 0 (
|
||||||
|
echo.
|
||||||
|
echo [INFO] Server stopped normally
|
||||||
|
) else (
|
||||||
|
echo.
|
||||||
|
echo [ERROR] Server exited with code %EXIT_CODE%
|
||||||
|
)
|
||||||
|
|
||||||
|
pause
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
|
:show_help
|
||||||
|
echo Usage: start-server.bat [options]
|
||||||
|
echo.
|
||||||
|
echo Options:
|
||||||
|
echo --debug Enable debug logging
|
||||||
|
echo --sse Use SSE transport instead of stdio
|
||||||
|
echo --workspace Set custom workspace directory
|
||||||
|
echo --uvx Use uvx instead of python/venv (recommended)
|
||||||
|
echo --help Show this help message
|
||||||
|
echo.
|
||||||
|
echo Examples:
|
||||||
|
echo start-server.bat
|
||||||
|
echo start-server.bat --debug
|
||||||
|
echo start-server.bat --sse --port 8080
|
||||||
|
echo start-server.bat --workspace "D:\MyProjects"
|
||||||
|
echo start-server.bat --uvx --debug ^(Recommended!^)
|
||||||
|
echo.
|
||||||
|
echo Prerequisites for --uvx:
|
||||||
|
echo Install uv: winget install astral-sh.uv
|
||||||
|
echo or: pip install uv
|
||||||
|
exit /b 0
|
||||||
+217
@@ -0,0 +1,217 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test script for MCP Python Project Manager Server.
|
||||||
|
Run this to verify the server is working correctly.
|
||||||
|
"""
|
||||||
|
import asyncio
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Add parent directory to path for imports
|
||||||
|
sys.path.insert(0, str(Path(__file__).parent))
|
||||||
|
|
||||||
|
from tools import PythonProjectTools, ToolResult
|
||||||
|
from config import config
|
||||||
|
|
||||||
|
|
||||||
|
async def test_tools():
|
||||||
|
"""Test all tool implementations."""
|
||||||
|
print("🧪 Testing MCP Python Project Manager Tools\n")
|
||||||
|
|
||||||
|
# Mock server object for testing
|
||||||
|
class MockServer:
|
||||||
|
def list_tools(self):
|
||||||
|
def decorator(func):
|
||||||
|
return func
|
||||||
|
return decorator
|
||||||
|
def call_tool(self):
|
||||||
|
def decorator(func):
|
||||||
|
return func
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
mock_server = MockServer()
|
||||||
|
tools = PythonProjectTools(mock_server)
|
||||||
|
|
||||||
|
test_results = []
|
||||||
|
|
||||||
|
# Test 1: Get Python environment
|
||||||
|
print("1. Testing get_python_env...")
|
||||||
|
result = await tools.get_python_env()
|
||||||
|
test_results.append(("get_python_env", result.success))
|
||||||
|
if result.success:
|
||||||
|
print(f" ✓ Python: {result.data.get('python_version', 'N/A')}")
|
||||||
|
else:
|
||||||
|
print(f" ✗ Error: {result.error}")
|
||||||
|
|
||||||
|
# Test 2: List packages
|
||||||
|
print("\n2. Testing list_packages...")
|
||||||
|
result = await tools.list_packages(format="json")
|
||||||
|
test_results.append(("list_packages", result.success))
|
||||||
|
if result.success and result.data:
|
||||||
|
print(f" ✓ Found {len(result.data)} packages")
|
||||||
|
else:
|
||||||
|
print(f" ⚠ Warning: {result.message}")
|
||||||
|
|
||||||
|
# Test 3: Get project info (test with current directory)
|
||||||
|
print("\n3. Testing get_project_info...")
|
||||||
|
current_dir = str(Path(__file__).parent)
|
||||||
|
result = await tools.get_project_info(current_dir)
|
||||||
|
test_results.append(("get_project_info", result.success))
|
||||||
|
if result.success:
|
||||||
|
print(f" ✓ Project: {result.data.get('name', 'N/A')}")
|
||||||
|
print(f" ✓ Python files: {result.data.get('files', {}).get('python_files', 0)}")
|
||||||
|
else:
|
||||||
|
print(f" ✗ Error: {result.error}")
|
||||||
|
|
||||||
|
# Test 4: List project files
|
||||||
|
print("\n4. Testing list_project_files...")
|
||||||
|
result = await tools.list_project_files(current_dir, pattern="*.py", recursive=False)
|
||||||
|
test_results.append(("list_project_files", result.success))
|
||||||
|
if result.success:
|
||||||
|
print(f" ✓ Found {result.data.get('count', 0)} Python files")
|
||||||
|
else:
|
||||||
|
print(f" ✗ Error: {result.error}")
|
||||||
|
|
||||||
|
# Test 5: Read a file
|
||||||
|
print("\n5. Testing read_file...")
|
||||||
|
config_file = str(Path(__file__).parent / "config.py")
|
||||||
|
result = await tools.read_file(config_file, start_line=1, end_line=10)
|
||||||
|
test_results.append(("read_file", result.success))
|
||||||
|
if result.success:
|
||||||
|
lines = result.data.get("content", "").count("\n") + 1
|
||||||
|
print(f" ✓ Read {lines} lines from config.py")
|
||||||
|
else:
|
||||||
|
print(f" ✗ Error: {result.error}")
|
||||||
|
|
||||||
|
# Test 6: Lint code (check only)
|
||||||
|
print("\n6. Testing lint_code (check mode)...")
|
||||||
|
result = await tools.lint_code(current_dir, linter="flake8", fix=False)
|
||||||
|
test_results.append(("lint_code", True)) # Success even if linting finds issues
|
||||||
|
if result.success:
|
||||||
|
print(f" ✓ Linting completed")
|
||||||
|
else:
|
||||||
|
print(f" ⚠ Linting issues found (expected): {result.message}")
|
||||||
|
|
||||||
|
# Test 7: Analyze dependencies
|
||||||
|
print("\n7. Testing analyze_dependencies...")
|
||||||
|
result = await tools.analyze_dependencies(current_dir)
|
||||||
|
test_results.append(("analyze_dependencies", result.success))
|
||||||
|
if result.success:
|
||||||
|
files = result.data.get("files", [])
|
||||||
|
print(f" ✓ Analyzed {len(files)} requirements file(s)")
|
||||||
|
else:
|
||||||
|
print(f" ⚠ {result.message}")
|
||||||
|
|
||||||
|
# Test 8: Get debug info
|
||||||
|
print("\n8. Testing get_debug_info...")
|
||||||
|
result = await tools.get_debug_info()
|
||||||
|
test_results.append(("get_debug_info", result.success))
|
||||||
|
if result.success:
|
||||||
|
procs = result.data.get("python_processes", [])
|
||||||
|
print(f" ✓ Found {len(procs)} Python processes")
|
||||||
|
else:
|
||||||
|
print(f" ✗ Error: {result.error}")
|
||||||
|
|
||||||
|
# Test 9: Format code (check only)
|
||||||
|
print("\n9. Testing format_code (check mode)...")
|
||||||
|
result = await tools.format_code(config_file, formatter="black", check_only=True)
|
||||||
|
test_results.append(("format_code", True)) # Success even if formatting needed
|
||||||
|
if result.success:
|
||||||
|
print(f" ✓ Format check completed")
|
||||||
|
else:
|
||||||
|
print(f" ⚠ Format issues found (expected): {result.message}")
|
||||||
|
|
||||||
|
# Test 10: Execute allowed command
|
||||||
|
print("\n10. Testing execute_command...")
|
||||||
|
result = await tools.execute_command("python --version")
|
||||||
|
test_results.append(("execute_command", result.success))
|
||||||
|
if result.success:
|
||||||
|
version = result.data.get("stdout", "").strip()
|
||||||
|
print(f" ✓ {version}")
|
||||||
|
else:
|
||||||
|
print(f" ✗ Error: {result.error}")
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
print("\n" + "="*60)
|
||||||
|
print("📊 TEST SUMMARY")
|
||||||
|
print("="*60)
|
||||||
|
|
||||||
|
passed = sum(1 for _, success in test_results if success)
|
||||||
|
total = len(test_results)
|
||||||
|
|
||||||
|
for name, success in test_results:
|
||||||
|
status = "✓ PASS" if success else "✗ FAIL"
|
||||||
|
print(f" {status}: {name}")
|
||||||
|
|
||||||
|
print(f"\n Total: {passed}/{total} tests passed")
|
||||||
|
|
||||||
|
if passed == total:
|
||||||
|
print("\n🎉 All tests passed! Server is ready to use.")
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
print(f"\n⚠ {total - passed} test(s) failed. Check configuration.")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
async def test_tool_call_handler():
|
||||||
|
"""Test the tool call handler directly."""
|
||||||
|
print("\n🔧 Testing tool call handler...\n")
|
||||||
|
|
||||||
|
class MockServer:
|
||||||
|
def list_tools(self):
|
||||||
|
def decorator(func):
|
||||||
|
return func
|
||||||
|
return decorator
|
||||||
|
def call_tool(self):
|
||||||
|
def decorator(func):
|
||||||
|
return func
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
tools = PythonProjectTools(MockServer())
|
||||||
|
|
||||||
|
# Test a simple tool call
|
||||||
|
result = await tools.handle_tool_call(
|
||||||
|
"get_python_env",
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
|
||||||
|
if result and len(result) > 0:
|
||||||
|
response = json.loads(result[0].text)
|
||||||
|
if response.get("success"):
|
||||||
|
print("✓ Tool call handler working correctly")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"✗ Tool call failed: {response.get('error')}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print("✗ No response from tool call handler")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
"""Main test runner."""
|
||||||
|
print(f"🐍 MCP Python Project Manager - Test Suite")
|
||||||
|
print(f" Workspace: {config.workspace_root}")
|
||||||
|
print(f" Debug Mode: {config.debug_mode}")
|
||||||
|
print(f" Python: {sys.version.split()[0]}\n")
|
||||||
|
|
||||||
|
# Run tool tests
|
||||||
|
tool_test_result = await test_tools()
|
||||||
|
|
||||||
|
# Run handler test
|
||||||
|
handler_result = await test_tool_call_handler()
|
||||||
|
|
||||||
|
# Final result
|
||||||
|
print("\n" + "="*60)
|
||||||
|
if tool_test_result == 0 and handler_result:
|
||||||
|
print("✅ ALL TESTS PASSED - Server is ready!")
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
print("❌ SOME TESTS FAILED - Please check configuration")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
exit_code = asyncio.run(main())
|
||||||
|
sys.exit(exit_code)
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import asyncio
|
||||||
|
import platform
|
||||||
|
import subprocess
|
||||||
|
from typing import List, Dict, Any
|
||||||
|
from mcp.types import Tool
|
||||||
|
|
||||||
|
# --- ОПРЕДЕЛЕНИЕ ИНСТРУМЕНТОВ ---
|
||||||
|
|
||||||
|
def get_tool_definitions() -> List[Tool]:
|
||||||
|
return [
|
||||||
|
Tool(
|
||||||
|
name="run_script",
|
||||||
|
description="Запускает Python скрипт в указанной директории.",
|
||||||
|
inputSchema={
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"script_path": {"type": "string", "description": "Путь к скрипту (например, main.py)"},
|
||||||
|
"working_dir": {"type": "string", "description": "Рабочая директория"}
|
||||||
|
},
|
||||||
|
"required": ["script_path"]
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Tool(
|
||||||
|
name="install_package",
|
||||||
|
description="Устанавливает пакет через pip.",
|
||||||
|
inputSchema={
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"package_name": {"type": "string", "description": "Имя пакета"},
|
||||||
|
"working_dir": {"type": "string", "description": "Директория проекта (опционально)"}
|
||||||
|
},
|
||||||
|
"required": ["package_name"]
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Tool(
|
||||||
|
name="list_files",
|
||||||
|
description="Выводит список файлов и папок.",
|
||||||
|
inputSchema={
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"path": {"type": "string", "description": "Путь к папке"}
|
||||||
|
},
|
||||||
|
"required": ["path"]
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Tool(
|
||||||
|
name="read_file",
|
||||||
|
description="Читает содержимое текстового файла.",
|
||||||
|
inputSchema={
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"file_path": {"type": "string", "description": "Путь к файлу"}
|
||||||
|
},
|
||||||
|
"required": ["file_path"]
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Tool(
|
||||||
|
name="get_env_info",
|
||||||
|
description="Информация о системе и Python окружении.",
|
||||||
|
inputSchema={"type": "object", "properties": {}}
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
# --- ЛОГИКА ВЫПОЛНЕНИЯ ---
|
||||||
|
|
||||||
|
async def execute_tool(name: str, arguments: Dict[str, Any]) -> str:
|
||||||
|
"""Маршрутизатор вызовов."""
|
||||||
|
if name == "run_script":
|
||||||
|
return await _run_script(arguments.get("script_path"), arguments.get("working_dir"))
|
||||||
|
elif name == "install_package":
|
||||||
|
return await _install_package(arguments.get("package_name"), arguments.get("working_dir"))
|
||||||
|
elif name == "list_files":
|
||||||
|
return await _list_files(arguments.get("path", "."))
|
||||||
|
elif name == "read_file":
|
||||||
|
return await _read_file(arguments.get("file_path"))
|
||||||
|
elif name == "get_env_info":
|
||||||
|
return await _get_env_info()
|
||||||
|
else:
|
||||||
|
return f"Ошибка: Инструмент '{name}' не найден."
|
||||||
|
|
||||||
|
# --- ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ---
|
||||||
|
|
||||||
|
async def _run_command(cmd: List[str], cwd: str = None) -> str:
|
||||||
|
"""Асинхронный запуск команды."""
|
||||||
|
try:
|
||||||
|
process = await asyncio.create_subprocess_exec(
|
||||||
|
*cmd,
|
||||||
|
stdout=asyncio.subprocess.PIPE,
|
||||||
|
stderr=asyncio.subprocess.PIPE,
|
||||||
|
cwd=cwd
|
||||||
|
)
|
||||||
|
stdout, stderr = await process.communicate()
|
||||||
|
|
||||||
|
result = f"STDOUT:\n{stdout.decode('utf-8', errors='replace')}"
|
||||||
|
if stderr:
|
||||||
|
result += f"\nSTDERR:\n{stderr.decode('utf-8', errors='replace')}"
|
||||||
|
|
||||||
|
if process.returncode != 0:
|
||||||
|
result += f"\n[Код завершения: {process.returncode}]"
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
return f"Ошибка выполнения команды: {e}"
|
||||||
|
|
||||||
|
async def _run_script(script_path: str, working_dir: str = None) -> str:
|
||||||
|
if not working_dir:
|
||||||
|
working_dir = os.path.dirname(script_path) or os.getcwd()
|
||||||
|
return await _run_command([sys.executable, script_path], cwd=working_dir)
|
||||||
|
|
||||||
|
async def _install_package(package_name: str, working_dir: str = None) -> str:
|
||||||
|
cmd = [sys.executable, "-m", "pip", "install", package_name]
|
||||||
|
return await _run_command(cmd, cwd=working_dir)
|
||||||
|
|
||||||
|
async def _list_files(path: str) -> str:
|
||||||
|
try:
|
||||||
|
if not os.path.exists(path):
|
||||||
|
return f"Путь не найден: {path}"
|
||||||
|
items = os.listdir(path)
|
||||||
|
files = [i for i in items if os.path.isfile(os.path.join(path, i))]
|
||||||
|
dirs = [i + "/" for i in items if os.path.isdir(os.path.join(path, i))]
|
||||||
|
return "Папки:\n" + "\n".join(sorted(dirs)) + "\n\nФайлы:\n" + "\n".join(sorted(files))
|
||||||
|
except Exception as e:
|
||||||
|
return f"Ошибка чтения: {e}"
|
||||||
|
|
||||||
|
async def _read_file(file_path: str) -> str:
|
||||||
|
try:
|
||||||
|
if not os.path.exists(file_path):
|
||||||
|
return f"Файл не найден: {file_path}"
|
||||||
|
with open(file_path, "r", encoding="utf-8") as f:
|
||||||
|
return f.read()
|
||||||
|
except Exception as e:
|
||||||
|
return f"Ошибка чтения: {e}"
|
||||||
|
|
||||||
|
async def _get_env_info() -> str:
|
||||||
|
info = {
|
||||||
|
"os": platform.system(),
|
||||||
|
"python": platform.python_version(),
|
||||||
|
"cwd": os.getcwd()
|
||||||
|
}
|
||||||
|
return json.dumps(info, indent=2, ensure_ascii=False)
|
||||||
Reference in New Issue
Block a user