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