v2.13.0 — AWS provider, S3 object storage, 21 new MCP tools
AWS provider, end-to-end
Servonaut now manages AWS EC2 as a first-class provider alongside Hetzner and OVH — full lifecycle in the TUI and full coverage on the MCP server.
TUI
- AWS sidebar section with
⚙ Manage(per-instance start / stop / reboot / terminate),📊 CloudWatch,🔒 IP Ban Manager, and🔍 CloudTrail— the AWS-specific log + security tools previously lived under their own "Logs & Security" section; they're now grouped where they belong. - EC2 launch wizard — full create-instance flow with region / AMI / instance type / keypair / subnet / security-group selection, AMI search with debounce, and
Nametag pre-fill. - S3 / Object Storage screens for AWS, Hetzner Object Storage, and OVH Object Storage — bucket list, object browser, upload / download / copy / move / delete, presigned-URL generation, breadcrumb navigation. All three providers share the same screen (
ObjectStorageScreen(provider=...)). - Provider setup wizards now own the S3 form — Hetzner setup adds a Step 4 (Object Storage), OVH setup adds a Step 7. Each setup screen also rebuilds the S3 service on save so the sidebar
Object Storagebutton appears immediately without a restart. - Region dropdowns replace free-form text inputs on all three S3 forms. AWS = 21 regions, Hetzner = 3, OVH = 9. Default values selected so the form is never invalid.
- Docked
Save Settingsbutton at the bottom of the Settings screen — no more hunting forCtrl+Safter scrolling through twelve sections.
MCP server (+21 tools)
11 AWS EC2 tools + 10 S3 tools (provider-parameterised across aws / hetzner / ovh):
| Tier | Tools |
|---|---|
| readonly | aws_list_regions, aws_list_amis, aws_list_instance_types, aws_list_key_pairs, aws_list_subnets, aws_list_security_groups, s3_list_buckets, s3_list_objects |
| standard | aws_start_instance, aws_stop_instance, aws_reboot_instance, s3_download_object |
| dangerous | aws_terminate_instance, aws_run_instances, s3_create_bucket, s3_delete_bucket, s3_upload_object, s3_delete_object, s3_copy_object, s3_move_object, s3_generate_presigned_url |
All mutating tools go through the existing audit trail (~/.servonaut/aws_audit.jsonl for AWS lifecycle, ~/.servonaut/mcp_audit.jsonl for the MCP layer). s3_generate_presigned_url is classified dangerous despite being a read — the returned URL is a bearer credential and is masked in the audit row (only the JSON-RPC return value to the agent contains the URL itself).
Sidebar conditional visibility
OVH and Hetzner sections were previously hidden entirely when the compute service wasn't configured — which broke the new "S3-only" use case (configure object-storage credentials without setting up the provider's compute API). Now: section visible when either compute OR S3 is configured, with the compute-only buttons hiding when only S3 is set up. AWS section is always visible per the original design; only its Object Storage button is gated on credential availability.
Fix: config-sync data loss
A separate bug found while testing this PR — Hetzner api_token and OVH application_key / application_secret / consumer_key were being silently wiped on config-sync pull because the preservation loop didn't recurse into nested dataclasses at depth ≥2 and the copy at the top was shallow. Both fixed with deep-copy + materialising depth-aware preservation. Regression tests added.
Under the hood
- New
services/object_storage_service.py— singleObjectStorageServiceclass parameterised by provider; SSRF-guarded endpoint validation (https-only, no@-userinfo, no path/query/fragment, alternate IPv4 encodings rejected viasocket.inet_aton), path-traversal validation against(cwd, ~, ~/Downloads). - New
services/object_storage_factory.py— singlebuild_object_storage_services(config)shared between the TUI app and the headless MCP server so credential-handling logic never drifts between the two surfaces. - New
services/aws_audit.py— JSONL audit trail withO_NOFOLLOW | O_CREAT | O_APPENDmode 0o600 — symlink-resistant + private by default. - New
services/object_storage_regions.py— single source of truth for the dropdown options + defaults. config.jsonis now written atomically with mode 0o600 +O_NOFOLLOW; a leftover symlink at the target is detected and refused rather than silently followed.
Install / upgrade
pipx install servonaut --force
# or for an existing install
pipx upgrade servonaut