Initial commit

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
dinlo
2026-05-31 18:45:22 +08:00
commit 017135fe0e
13 changed files with 2008 additions and 0 deletions
+127
View File
@@ -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/
+20
View File
@@ -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
View File
@@ -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*
+546
View File
@@ -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
View File
@@ -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
+31
View File
@@ -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"
}
}
}
+110
View File
@@ -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
+36
View File
@@ -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
+13
View File
@@ -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
+61
View File
@@ -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()
+192
View File
@@ -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
View File
@@ -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)
+142
View File
@@ -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)