Major refactoring from monolithic server.py to modular MCPMixin pattern: Architecture: - src/esxi_mcp_server/ package with proper src-layout - FastMCP MCPMixin pattern for tool organization - Separate mixins for each functional area - Shared VMwareConnection class with lazy datastore/network lookup New Mixins Added: - DiskManagementMixin: add_disk, remove_disk, extend_disk, list_disks, attach_iso, detach_iso - NICManagementMixin: add_nic, remove_nic, change_nic_network, connect_nic, set_nic_mac, list_nics - HostManagementMixin: get_host_info, enter/exit_maintenance_mode, list_services, start/stop_service, set_service_policy, get/configure_ntp, reboot_host, shutdown_host, get_host_hardware, get_host_networking - OVFManagementMixin: deploy_ovf, export_vm_ovf, list_ovf_networks - ResourcesMixin: Added move_datastore_file, copy_datastore_file Streaming Support: - Generator-based streaming for datastore downloads - Memory-efficient large file handling with save_to parameter - Chunked uploads from disk Testing: - test_client.py: MCP SDK-based test client - Validates all 74 tools against real ESXi host Build System: - pyproject.toml with uv, ruff configuration - Docker dev/prod modes with hot-reload - Updated Makefile for uv-based workflow
133 lines
5.4 KiB
Makefile
133 lines
5.4 KiB
Makefile
# ESXi MCP Server Makefile
|
|
# Modern Python with uv, Docker Compose for containerization
|
|
|
|
.PHONY: help install dev test lint format build run run-dev stop logs clean
|
|
|
|
# Default target
|
|
help: ## Show this help
|
|
@echo "ESXi MCP Server"
|
|
@echo "==============="
|
|
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Development Commands
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
install: ## Install dependencies with uv
|
|
uv sync
|
|
|
|
dev: ## Install with dev dependencies
|
|
uv sync --all-extras
|
|
|
|
test: ## Run tests
|
|
uv run pytest
|
|
|
|
lint: ## Run ruff linter
|
|
uv run ruff check src/
|
|
|
|
format: ## Format code with ruff
|
|
uv run ruff format src/
|
|
uv run ruff check --fix src/
|
|
|
|
typecheck: ## Run type checking
|
|
uv run mypy src/
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Local Run Commands
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
run-local: ## Run MCP server locally (stdio mode for Claude Desktop)
|
|
uv run esxi-mcp-server
|
|
|
|
run-local-sse: ## Run MCP server locally with SSE transport
|
|
uv run esxi-mcp-server --transport sse
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Docker Commands
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
setup: ## Initial setup - create .env from example
|
|
@if [ ! -f .env ]; then \
|
|
cp .env.example .env; \
|
|
echo "Created .env from .env.example"; \
|
|
echo "Please edit .env with your vCenter credentials"; \
|
|
else \
|
|
echo ".env already exists"; \
|
|
fi
|
|
@mkdir -p logs
|
|
|
|
build: ## Build Docker image
|
|
docker compose build esxi-mcp-server
|
|
|
|
build-dev: ## Build development Docker image
|
|
docker compose build esxi-mcp-server-dev
|
|
|
|
run: setup ## Run production container
|
|
docker compose --profile prod up -d
|
|
@echo "Waiting for container to start..."
|
|
@sleep 3
|
|
docker compose --profile prod logs --tail=20
|
|
|
|
run-dev: setup ## Run development container with hot-reload
|
|
docker compose --profile dev up -d
|
|
@echo "Waiting for container to start..."
|
|
@sleep 3
|
|
docker compose --profile dev logs --tail=20
|
|
|
|
stop: ## Stop all containers
|
|
docker compose --profile prod --profile dev down
|
|
|
|
restart: stop run ## Restart production container
|
|
|
|
logs: ## Show container logs
|
|
docker compose --profile prod --profile dev logs -f
|
|
|
|
logs-prod: ## Show production logs only
|
|
docker compose --profile prod logs -f
|
|
|
|
logs-dev: ## Show development logs only
|
|
docker compose --profile dev logs -f
|
|
|
|
shell: ## Open shell in running container
|
|
docker compose --profile prod exec esxi-mcp-server bash || \
|
|
docker compose --profile dev exec esxi-mcp-server-dev bash
|
|
|
|
status: ## Show container status
|
|
docker compose --profile prod --profile dev ps
|
|
|
|
health: ## Check container health
|
|
@docker compose --profile prod exec esxi-mcp-server \
|
|
python -c "import urllib.request; urllib.request.urlopen('http://localhost:8080')" \
|
|
&& echo "✅ Health check passed" || echo "❌ Health check failed"
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Maintenance Commands
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
clean: ## Remove containers and images
|
|
docker compose --profile prod --profile dev down -v --rmi local
|
|
rm -rf .venv __pycache__ .pytest_cache .ruff_cache
|
|
|
|
clean-all: clean ## Remove everything including uv cache
|
|
rm -rf .uv
|
|
|
|
lock: ## Update uv.lock file
|
|
uv lock
|
|
|
|
update: ## Update dependencies
|
|
uv lock --upgrade
|
|
uv sync
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Release Commands
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
build-release: ## Build release package
|
|
uv build
|
|
|
|
publish-test: ## Publish to TestPyPI
|
|
uv publish --repository testpypi
|
|
|
|
publish: ## Publish to PyPI
|
|
uv publish
|