35 Commits

Author SHA1 Message Date
13e4734ef1 docs: document multi-host config and per-call host selection
Add a 'Managing Multiple ESXi Hosts' section to the environment reference
and CLAUDE.md: numbered ESXI_HOST[_N] families, credential inheritance for
suffixed hosts, lazy connections, and the per-call host argument. Update
the source layout with servers.py, connection_manager.py, and mixins/_base.py.
2026-06-08 05:53:21 -06:00
9c02d7238c Make all tools host-aware: per-call host selection across every mixin
Rolls the host: str | None = None selector and conn = self._conn(host)
routing across all remaining tools in the 12 mixins (the inventory tools
landed earlier). 97 of 98 tools now accept an optional host to target a
specific managed ESXi server; list_servers is the only exception (it is
the registry itself).

Private helpers that touched self.conn (e.g. ovf NFC/datastore helpers,
nic _get_network_backing, vcenter_ops folder/pool/cluster finders,
host_management _get_host, resources datastore browse/stream) now take a
conn parameter threaded from their tool call sites. Several tools had a
local 'host' variable renamed to avoid shadowing the new selector.

Verified: full server builds (98 tools), and get_host_info/list_hosts
route correctly to two distinct live hosts (205 vs 222).
2026-06-08 05:47:04 -06:00
2930318125 Multi-host support: manage a list of ESXi servers
Adds a pluggable server inventory and per-host connection routing:

- servers.py: load_servers() returns the managed host list. Today it reads
  ESXI_HOST[_N] env vars (a suffixed host inherits the unsuffixed
  USER/PASS/INSECURE/NETWORK); this one function is the seam an API-backed
  source replaces later. Servers are identified by host.
- connection_manager.py: ConnectionManager holds the inventory and lazily
  connects per host (one dead host doesn't block startup or the others),
  keyed by host, with a default.
- mixins/_base.py: VSphereMixin base gives every mixin self.conn (default
  host) and self._conn(host) for per-call routing. All 13 mixins now take
  the manager instead of a single connection.
- server.py builds the manager from load_servers() (falling back to the
  single VCENTER_* server) and eager-connects the default.
- New list_servers tool; list_vms/get_vm_info take an optional host arg as
  the per-call routing pattern.

Verified across two live hosts: default + host='10.22.22.222' route to the
right box; unknown host gives a clear error.
2026-06-08 05:33:22 -06:00
b743da7666 Add CD/DVD + ISO-boot support for appliance installs
Adds add_cdrom (attach a CD/DVD drive to an existing VM, optionally with
an ISO and CD-first boot) and extends deploy_ova with iso_path/
iso_datastore/boot_from_iso so a diskless appliance OVA can be deployed
and pointed at a bootable installer ISO in one call.

deploy_ova reuses the OVA's existing primary CD/DVD drive rather than
adding a new one — Cisco templates (CUCM) already define empty drives and
the BIOS boots the first, so the ISO must land there. Verified end to end:
CUCM 15 Small OVA + bootable ISO boots to the UCOS installer.
2026-06-08 04:49:25 -06:00
539aa913e9 deploy_ova: support OVF deployment options + add inspect_ova
Cisco-style OVAs (CUCM/CUC/UCCX) ship multiple deployment configurations
(e.g. Small/Medium/Large) in a DeploymentOptionSection and default to one.
deploy_ova now takes deployment_option to select a config; without it the
OVF default is used.

inspect_ova reads an OVA (local path or URL) and reports product, guest
OS, hardware version, selectable deployment options, networks, and disks
so clients can choose deployment_option/network before deploying.

Verified against CUCM 15 OVA: Small config yields 2 vCPU / 10 GB / 110 GB
/ VMXNET3 exactly per Cisco's spec.
2026-06-08 04:28:49 -06:00
4fa2286e57 Add deploy_ova tool: stream a local/URL OVA to the host via NFC
Implements OVA deployment over an HttpNfcLease, the existing deploy_ovf
explicitly rejected OVA and its disk upload was a no-op stub. deploy_ova
reads an OVA from a local path or http(s) URL, builds an import spec
(mapping every OVF network to the target port group), opens an NFC lease,
and streams each disk to the lease URL with a keepalive thread.

Key details: the NFC PUT needs an 'Overwrite: t' header because
ImportVApp pre-creates the disk file; lease device URLs use '*' for the
host on direct ESXi connections, so the configured host is substituted.
2026-06-08 04:25:06 -06:00
7888494efb create_vm: add CD/DVD drive with optional ISO boot
Previously created VMs had no CD/DVD drive, so attach_iso failed with
'No CD/DVD drive found' and there was no way to install a guest from an
ISO. create_vm now always adds a CD/DVD drive on the default IDE
controller. New optional args iso_path/iso_datastore back the drive with
an ISO and boot_from_iso puts the CD/DVD first in the boot order, giving
MCP clients a complete create-and-install-from-ISO path.
2026-06-08 04:08:15 -06:00
c93c97a0de Add on-demand ESXi SSH toggle script
Toggles the TSM-SSH service via the vSphere API (govc + .env creds) with
on/off/status/shell subcommands. The shell subcommand restores the prior
service state on exit so it leaves the host as it found it.
2026-06-07 20:39:57 -06:00
0e7942f510 docs: add Starlight documentation site
- Set up Astro + Starlight for documentation
- Create comprehensive docs covering:
  - Getting started (introduction, installation, quickstart)
  - Configuration (environment variables, vCenter connection)
  - Deployment (Docker, OAuth multi-user)
  - Reference (94 tools, RBAC permissions, architecture)
- VMware-inspired blue color scheme
- Custom logo and styling
- Search enabled via Pagefind
2026-01-16 12:39:00 -07:00
a0f405412e release: v0.2.3 - Docker OAuth deployment support v0.2.3 2026-01-16 12:26:16 -07:00
ebbf2c297c docs: add Docker Compose setup for OAuth multi-user mode
- Update Dockerfile to default to streamable-http transport
- Add docker-compose.oauth-standalone.yml for existing OIDC providers
- Add .env.oauth.example template with all required settings
- Update README_DOCKER.md with OAuth deployment instructions

OAuth mode requires streamable-http transport (not stdio) since
authentication happens via browser redirect flow.
2026-01-12 14:40:50 -07:00
1d9fcf73af release: v0.2.2 - OAuth claims extraction fix
- Fix OAuth user/group extraction using FastMCP's get_access_token()
- Update README with correct RBAC group names (vsphere-readers, not viewers)
- Add missing vsphere-host-admins group to documentation
v0.2.2
2025-12-28 12:50:57 -07:00
79d2caef45 fix: use FastMCP get_access_token() for OAuth claims extraction
The previous implementation tried to access OAuth token claims via
context.request_context.access_token.claims, which doesn't exist in
FastMCP's context structure.

FastMCP stores access tokens in Python's ContextVars, accessible via
the get_access_token() dependency function. This fix updates both
extract_user_from_context() and RBACMiddleware._extract_user_from_context()
to use this correct approach.

Before: Users appeared as "anonymous" with no groups (RBAC denied all)
After: User identity and groups correctly extracted from OAuth claims
2025-12-28 11:15:28 -07:00
ab83c70c31 docs: update OAuth/RBAC architecture documentation
Rewrites the architecture doc from design proposal to implementation
reference. Documents the complete RBAC system including:

- 5 permission levels (READ_ONLY → FULL_ADMIN)
- 5 OAuth groups with permission mappings
- RBACMiddleware implementation details
- Audit log format with user identity
- Configuration environment variables
- OIDC provider setup (Authentik example)
- Troubleshooting guide for common issues

Updates implementation checklist to reflect completed status.
2025-12-27 08:22:02 -07:00
00857b1840 fix: enforce strict RBAC - deny access for users without groups
Security fix: Previously users with no OAuth groups or unrecognized
groups would default to READ_ONLY access. Now:
- Empty groups = no permissions (denied access to all tools)
- Unrecognized groups = no permissions (denied access)

Also adds missing restart_service mapping to FULL_ADMIN permission.
2025-12-27 08:10:01 -07:00
6159098963 feat: implement RBAC middleware for OAuth group-based permissions
Add RBACMiddleware that integrates with FastMCP's middleware system to
enforce role-based access control on all tool calls:

- Intercepts every tool call via on_call_tool() hook
- Extracts user groups from OAuth token claims
- Checks permissions using existing permissions.py mappings
- Logs all tool invocations with user identity via audit.py
- Denies access with clear PermissionDeniedError when unauthorized

Permission levels (from permissions.py):
- READ_ONLY: view operations (vsphere-readers)
- POWER_OPS: power/snapshot ops (vsphere-operators)
- VM_LIFECYCLE: create/delete VMs (vsphere-admins)
- HOST_ADMIN: ESXi host management (vsphere-host-admins)
- FULL_ADMIN: guest ops, services (vsphere-super-admins)

Middleware only enabled when OAuth is active (OAUTH_ENABLED=true).
STDIO mode continues to work without permission checking.
2025-12-27 07:37:26 -07:00
0e29fea857 docs: add OAuth multi-user mode to README
- Add Multi-User / OAuth Mode section with quick setup
- Document permission groups for RBAC
- Update transport option to streamable-http
- Link to OAUTH-ARCHITECTURE.md for details
2025-12-27 06:03:59 -07:00
4890950e19 Merge branch 'feature/oauth-authentication'
OAuth 2.1 + PKCE authentication for mcvsphere MCP server.

Features:
- OIDC integration via FastMCP's OIDCProxy
- Authentik identity provider support
- Dynamic Client Registration for MCP clients
- PKCE flow for secure authorization
- Permission groups mapped from Authentik groups
- Audit logging with user identity

Tested end-to-end with Claude Code CLI.
2025-12-27 05:54:57 -07:00
64ba7a69de fix OAuth token validation for Authentik opaque tokens
- Remove required_scopes validation (Authentik doesn't embed scopes in JWT)
- Add oauth_base_url config for proper HTTPS callback URLs
- Add docker-compose.dev.yml for host proxy via Caddy
- Update docker-compose.oauth.yml with unique domain label

Authentik uses opaque access tokens that don't include scope claims.
Authentication is enforced at the IdP level, so scope validation in
the token is unnecessary and was causing 401 errors.
2025-12-27 05:27:21 -07:00
cda49f2912 implement OAuth authentication with Authentik support
Core OAuth infrastructure:
- permissions.py: 5-level permission model (read_only → full_admin)
  Maps all 94 tools to permission levels
  Maps OAuth groups to permission sets
- audit.py: Centralized logging with OAuth user identity
- auth.py: OIDCProxy configuration for Authentik/OIDC providers
- middleware.py: Permission checking decorator and tool wrapper

Server integration:
- config.py: Add OAuth settings (oauth_enabled, oauth_issuer_url, etc.)
  Validate OAuth config completeness, require HTTP transport
- server.py: Integrate auth provider, add HTTP transport support
  Show OAuth status in startup banner

Deployment:
- docker-compose.oauth.yml: Authentik stack (server, worker, postgres, redis)
- .env.example: Document all OAuth and Authentik environment variables

Permission model:
- vsphere-readers: READ_ONLY (32 tools)
- vsphere-operators: + POWER_OPS (14 tools)
- vsphere-admins: + VM_LIFECYCLE (33 tools)
- vsphere-host-admins: + HOST_ADMIN (6 tools)
- vsphere-super-admins: + FULL_ADMIN (9 tools)
2025-12-27 01:12:58 -07:00
f843a8a161 add OAuth architecture design document
- Service Account + OAuth Audit model for vCenter integration
- Authentik as OIDC provider with JWT validation
- Permission escalation based on OAuth groups
- Credential broker pattern for user mapping
- Implementation checklist and environment variables
2025-12-27 00:53:24 -07:00
d0aa37e9c3 bump version to 0.2.1 for PyPI README update 2025-12-26 21:04:28 -07:00
7843adede1 rewrite README for PyPI with confident, direct style
- Bold opening: 94 tools, full VMware control
- Clear install instructions upfront
- Organized tool documentation with tables
- Real-world usage examples
- Streamlined configuration reference
2025-12-26 21:03:51 -07:00
eb59cd5e9a rename project: esxi-mcp-server → mcvsphere
mcvsphere = Model Control for vSphere

Updates:
- Package renamed from esxi_mcp_server to mcvsphere
- CLI entry point: mcvsphere (was esxi-mcp-server)
- All imports and references updated
- Docker configs updated
- Test suites updated
2025-12-26 20:58:48 -07:00
c65f91c571 add extended test suite for 22 additional tools
New test_extended.py covers:
- Console tools: vm_screenshot, wait_for_vm_tools, get_vm_tools_status
- Serial port: setup, get, connect, clear, remove
- Guest operations: run_command, list/create/delete directory, read/write/delete file
- Power control: reboot_guest, reset_vm, shutdown_guest
- Snapshots: revert_to_current, delete_all
- VM hardware: change_nic_network, set_nic_mac, clone_vm

Test coverage improved from 61% to 79% (75/94 tools)
2025-12-26 19:13:19 -07:00
8e28b84e59 add console and serial port mixins, expand to 94 tools
New features:
- ConsoleMixin: vm_screenshot, wait_for_vm_tools, get_vm_tools_status
- SerialPortMixin: setup_serial_port, get_serial_port, connect_serial_port,
  clear_serial_port, remove_serial_port

Enables:
- VM console screenshots via vSphere HTTP API
- VMware Tools status monitoring and wait utilities
- Network serial ports for headless VMs and network appliances

README rewritten with comprehensive documentation of all 94 tools.
2025-12-26 18:44:09 -07:00
d771db2e1d fix list_guest_directory for varying guest OS attributes
FileInfo attributes (owner, modificationTime, size, type) vary across
guest OS types. Use getattr with defaults to prevent AttributeError
when these optional fields are missing.
2025-12-26 18:26:55 -07:00
7918a78bfa add comprehensive test suites and fix VM creation
- Fix create_vm: add required files property to ConfigSpec
- Fix disk backing: use fileName instead of datastore reference
- test_client.py: comprehensive read-only test suite (86 tools, 6 resources)
- test_destructive.py: destructive test suite covering 29 operations:
  - VM lifecycle (create, info, rename, reconfigure)
  - Power operations (on, suspend, off)
  - Disk management (add, list, extend, remove)
  - NIC management (add, list, connect, remove)
  - Snapshots (create, list, rename, revert, delete)
  - Folder operations (create, move VM)
  - Datastore operations (create folder, delete)
  - vCenter advanced (storage_vmotion, convert_to_template,
    deploy_from_template, convert_to_vm)
2025-12-26 08:52:33 -07:00
b9c411fdf9 add idempotentHint to safe-to-retry vCenter tools
Mark tools that handle already-in-target-state gracefully:
- storage_vmotion: returns "no_migration_needed" if already on target
- convert_to_template: returns "already_template" if already converted
- convert_to_vm: returns "already_vm" if already a VM

This signals to LLM clients that these operations are safe to retry.
2025-12-26 06:23:35 -07:00
359167ec6a add vCenter-specific operations mixin
VCenterOpsMixin provides tools that require vCenter Server:

Storage vMotion:
- storage_vmotion: Move VM disks to different datastore
- move_vm_disk: Move specific disk to different datastore

Template Management:
- convert_to_template: Convert VM to template
- convert_to_vm: Convert template back to VM
- deploy_from_template: Deploy new VM from template

Folder Organization:
- list_folders: List VM folders in datacenter
- create_folder: Create new VM folder
- move_vm_to_folder: Move VM to different folder

Tasks & Events:
- list_recent_tasks: List recent vCenter tasks
- list_recent_events: List recent vCenter events

Cluster Operations:
- list_clusters: List clusters with DRS/HA status
- get_drs_recommendations: Get DRS recommendations for cluster

Also fixes empty-list serialization issue in FastMCP by returning
informative messages when results are empty.

Total: 86 tools, 6 resources
2025-12-26 06:03:19 -07:00
9e39c1c678 Refactor to modular mixin architecture with 74 tools
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
2025-12-26 05:53:51 -07:00
bright8192
a2f4c709c5 add docker support 2025-07-01 17:22:45 +08:00
bright8192
7b12024005 typo fix 2025-03-13 17:22:21 +08:00
bright8192
694d221a30 v0.0.1 2025-03-13 17:13:21 +08:00
Bright8192
ba0e03495b
Initial commit 2025-03-13 17:10:34 +08:00