workspaces-euc-mcp-server 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. workspaces_euc_mcp_server-0.1.1/.github/workflows/ci.yml +34 -0
  2. workspaces_euc_mcp_server-0.1.1/.github/workflows/publish.yml +35 -0
  3. workspaces_euc_mcp_server-0.1.1/.gitignore +33 -0
  4. workspaces_euc_mcp_server-0.1.1/.pre-commit-config.yaml +21 -0
  5. workspaces_euc_mcp_server-0.1.1/CHANGELOG.md +141 -0
  6. workspaces_euc_mcp_server-0.1.1/DESIGN.md +203 -0
  7. workspaces_euc_mcp_server-0.1.1/LICENSE +201 -0
  8. workspaces_euc_mcp_server-0.1.1/PKG-INFO +270 -0
  9. workspaces_euc_mcp_server-0.1.1/README.md +240 -0
  10. workspaces_euc_mcp_server-0.1.1/iam/README.md +29 -0
  11. workspaces_euc_mcp_server-0.1.1/iam/tier0-diagnostics.json +68 -0
  12. workspaces_euc_mcp_server-0.1.1/iam/tier1-cost.json +78 -0
  13. workspaces_euc_mcp_server-0.1.1/iam/tier2-lifecycle.json +109 -0
  14. workspaces_euc_mcp_server-0.1.1/iam/tier3-destructive.json +119 -0
  15. workspaces_euc_mcp_server-0.1.1/pyproject.toml +78 -0
  16. workspaces_euc_mcp_server-0.1.1/scripts/smoke_readonly.py +77 -0
  17. workspaces_euc_mcp_server-0.1.1/tests/__init__.py +0 -0
  18. workspaces_euc_mcp_server-0.1.1/tests/test_clients.py +74 -0
  19. workspaces_euc_mcp_server-0.1.1/tests/test_cost.py +147 -0
  20. workspaces_euc_mcp_server-0.1.1/tests/test_destructive.py +189 -0
  21. workspaces_euc_mcp_server-0.1.1/tests/test_diagnostics.py +342 -0
  22. workspaces_euc_mcp_server-0.1.1/tests/test_inventory.py +160 -0
  23. workspaces_euc_mcp_server-0.1.1/tests/test_lifecycle.py +231 -0
  24. workspaces_euc_mcp_server-0.1.1/tests/test_naming.py +69 -0
  25. workspaces_euc_mcp_server-0.1.1/tests/test_no_embedded_secrets.py +44 -0
  26. workspaces_euc_mcp_server-0.1.1/tests/test_performance.py +256 -0
  27. workspaces_euc_mcp_server-0.1.1/tests/test_pricing.py +97 -0
  28. workspaces_euc_mcp_server-0.1.1/tests/test_reporting.py +306 -0
  29. workspaces_euc_mcp_server-0.1.1/tests/test_secure_browser.py +85 -0
  30. workspaces_euc_mcp_server-0.1.1/workspaces_euc_mcp_server/__init__.py +6 -0
  31. workspaces_euc_mcp_server-0.1.1/workspaces_euc_mcp_server/clients.py +101 -0
  32. workspaces_euc_mcp_server-0.1.1/workspaces_euc_mcp_server/consts.py +154 -0
  33. workspaces_euc_mcp_server-0.1.1/workspaces_euc_mcp_server/models.py +333 -0
  34. workspaces_euc_mcp_server-0.1.1/workspaces_euc_mcp_server/server.py +129 -0
  35. workspaces_euc_mcp_server-0.1.1/workspaces_euc_mcp_server/tools/__init__.py +4 -0
  36. workspaces_euc_mcp_server-0.1.1/workspaces_euc_mcp_server/tools/_common.py +87 -0
  37. workspaces_euc_mcp_server-0.1.1/workspaces_euc_mcp_server/tools/cost.py +314 -0
  38. workspaces_euc_mcp_server-0.1.1/workspaces_euc_mcp_server/tools/destructive.py +307 -0
  39. workspaces_euc_mcp_server-0.1.1/workspaces_euc_mcp_server/tools/diagnostics.py +799 -0
  40. workspaces_euc_mcp_server-0.1.1/workspaces_euc_mcp_server/tools/inventory.py +158 -0
  41. workspaces_euc_mcp_server-0.1.1/workspaces_euc_mcp_server/tools/lifecycle.py +564 -0
  42. workspaces_euc_mcp_server-0.1.1/workspaces_euc_mcp_server/tools/performance.py +620 -0
  43. workspaces_euc_mcp_server-0.1.1/workspaces_euc_mcp_server/tools/pricing.py +152 -0
  44. workspaces_euc_mcp_server-0.1.1/workspaces_euc_mcp_server/tools/reporting.py +529 -0
  45. workspaces_euc_mcp_server-0.1.1/workspaces_euc_mcp_server/tools/secure_browser.py +190 -0
@@ -0,0 +1,34 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.11", "3.12", "3.13"]
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: ${{ matrix.python-version }}
19
+ - name: Install (into .venv to match the pyright config)
20
+ run: |
21
+ python -m venv .venv
22
+ . .venv/bin/activate
23
+ python -m pip install --upgrade pip
24
+ pip install -e ".[dev]"
25
+ - name: Lint
26
+ run: . .venv/bin/activate && ruff check .
27
+ - name: Format check
28
+ run: . .venv/bin/activate && ruff format --check .
29
+ - name: Type check
30
+ run: . .venv/bin/activate && pyright
31
+ - name: Security scan
32
+ run: . .venv/bin/activate && bandit -c pyproject.toml -r workspaces_euc_mcp_server
33
+ - name: Test (includes no-embedded-secrets guardrail)
34
+ run: . .venv/bin/activate && pytest -q
@@ -0,0 +1,35 @@
1
+ name: Publish to PyPI
2
+
3
+ # Publishes the package to PyPI using OIDC Trusted Publishing (no API token stored).
4
+ # Fires when a GitHub Release is published, or can be run manually from the Actions tab.
5
+ #
6
+ # One-time PyPI setup (project owner): add a "Trusted Publisher" (pending publisher is fine before
7
+ # the first release) at https://pypi.org/manage/account/publishing/ with:
8
+ # PyPI project name: workspaces-euc-mcp-server
9
+ # Owner: bengroeneveldsg
10
+ # Repository: aws-workspaces-euc-mcp
11
+ # Workflow name: publish.yml
12
+ # Environment: pypi
13
+
14
+ on:
15
+ release:
16
+ types: [published]
17
+ workflow_dispatch:
18
+
19
+ jobs:
20
+ publish:
21
+ runs-on: ubuntu-latest
22
+ environment: pypi
23
+ permissions:
24
+ id-token: write # required for OIDC trusted publishing
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+ - uses: actions/setup-python@v5
28
+ with:
29
+ python-version: "3.12"
30
+ - name: Build sdist + wheel
31
+ run: |
32
+ python -m pip install --upgrade build
33
+ python -m build
34
+ - name: Publish to PyPI
35
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,33 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ .venv/
9
+ venv/
10
+ env/
11
+
12
+ # Tooling caches
13
+ .pytest_cache/
14
+ .ruff_cache/
15
+ .pyright/
16
+ .mypy_cache/
17
+
18
+ # OS / editor / tooling
19
+ .DS_Store
20
+ .idea/
21
+ .vscode/
22
+ .claude/
23
+
24
+ # AWS / secrets — never commit credentials
25
+ .aws/
26
+ *.pem
27
+ .env
28
+
29
+ # Generated, account-specific report artifacts — these contain tenant data
30
+ # (real WorkSpace IDs, metrics, costs) and must never be committed.
31
+ *-perf.html
32
+ ws-*.html
33
+ /reports/
@@ -0,0 +1,21 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.6.9
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
8
+ - repo: https://github.com/PyCQA/bandit
9
+ rev: 1.7.10
10
+ hooks:
11
+ - id: bandit
12
+ args: ["-c", "pyproject.toml"]
13
+ additional_dependencies: ["bandit[toml]"]
14
+ - repo: https://github.com/pre-commit/pre-commit-hooks
15
+ rev: v5.0.0
16
+ hooks:
17
+ - id: end-of-file-fixer
18
+ - id: trailing-whitespace
19
+ - id: check-yaml
20
+ - id: check-added-large-files
21
+ - id: detect-private-key
@@ -0,0 +1,141 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [0.1.1] - 2026-06-01
9
+
10
+ Best-practice alignment pass (audited against the awslabs MCP design guidelines and the MCP
11
+ tool-annotations spec).
12
+
13
+ ### Added
14
+ - MCP **tool annotations** on every tool (`readOnlyHint` / `destructiveHint` / `idempotentHint` /
15
+ `openWorldHint` / `title`), so clients can show appropriate consent UX — read-only tools are
16
+ marked read-only, lifecycle writes non-destructive (start/stop/modify idempotent), and
17
+ terminate/rebuild/restore destructive. Aligns with the awslabs MCP design guidelines and the
18
+ MCP tool-annotations spec.
19
+ - `FASTMCP_LOG_LEVEL` env var to control the server log level (default `INFO`).
20
+ - `Literal` types on fixed-value parameters (`running_mode`, cost `granularity`) for clearer
21
+ client-side validation.
22
+
23
+ ## [0.1.0] - 2026-06-01
24
+
25
+ First tagged release. Admin-focused MCP server for the Amazon WorkSpaces EUC portfolio —
26
+ 18 read-only tools (inventory, diagnostics, performance/usage history, cost & right-sizing with
27
+ $ estimates, audit, reporting) and 10 guarded write/destructive tools, across WorkSpaces Personal,
28
+ Pools, Applications, Secure Browser, and Core Managed Instances. Four additive IAM tiers,
29
+ multi-account/MSP via assume-role, no embedded tenant data, CI (ruff/format/pyright/bandit/pytest
30
+ on Py 3.11–3.13).
31
+
32
+ ### Added
33
+ - CI now also runs `pyright` (basic type-checking); the codebase type-checks clean.
34
+ - Multi-account / MSP support: `--assume-role-arn` (+ optional `--external-id`) transparently
35
+ `sts:AssumeRole`s into another account, with auto-refreshing credentials and no tool-code
36
+ changes. The launching identity needs `sts:AssumeRole` on the target role; the role needs the
37
+ matching tier policy.
38
+ - Estimated monthly $ savings on recommendations, via the AWS Price List API (new
39
+ `tools/pricing.py`, needs `pricing:GetProducts` / Tier 1): `recommend_running_mode` now fills
40
+ `estimated_monthly_savings_usd` for AlwaysOn→AutoStop candidates (AlwaysOn monthly − AutoStop
41
+ base − hourly×estimated-usage), and `recommend_bundle_rightsizing` fills the AlwaysOn
42
+ compute-tier monthly difference. Best-effort and conservative: matches the canonical
43
+ Included-license SKU on region/OS/compute/volume sizes and returns **null** (never a wrong
44
+ number) when it can't match. Validated live (Standard 80/50 → $35/mo, Power 175/100 → $98/mo).
45
+ - `diagnose_pool` (Tier 0): a WorkSpaces Pool health diagnostic correlating pool state, pool
46
+ errors, user-session capacity, backing directory health, and CloudWatch session utilization —
47
+ bringing Pools to parity with the WorkSpace and fleet diagnostics.
48
+ - WorkSpaces Core Managed Instances coverage (the `workspaces-instances` API, previously not
49
+ covered at all): `get_euc_inventory_summary` and `generate_inventory_report` now include managed
50
+ instances, enriched with the backing EC2 instance's type / state / launch time / private IP /
51
+ platform (via `ec2:DescribeInstances`). Adds the
52
+ `workspaces-instances:ListWorkspaceInstances`/`GetWorkspaceInstance`/`ListInstanceTypes`/`ListRegions`
53
+ and `ec2:DescribeInstances` IAM actions to all tiers.
54
+ - WorkSpaces Secure Browser parity: `get_secure_browser_portal_details` (resolves user/network
55
+ settings — clipboard/print/download controls) and `get_secure_browser_portal_usage`
56
+ (`AWS/WorkSpacesWeb` session metrics; note Secure Browser only emits these during sessions, so
57
+ idle portals return nothing). Adds `workspaces-web:GetUserSettings`/`GetNetworkSettings` to the
58
+ IAM tiers.
59
+ - `audit_security_posture` is now **cross-service**: in addition to WorkSpace volume encryption and
60
+ directory IP access control groups, it flags **Secure Browser portals** and **Applications
61
+ stacks** that permit data egress (clipboard-to-local / download / print).
62
+
63
+ ### Fixed
64
+ - `generate_inventory_report` Pools capacity was always `null` — it read the wrong key (`Capacity`
65
+ instead of `CapacityStatus`). Now populated with the real session capacity.
66
+
67
+ ### Added
68
+ - WorkSpaces Personal **user mapping** + many previously-dropped fields in `generate_inventory_report`
69
+ (found by auditing the raw API responses): each desktop now exposes assigned `UserName` (as the
70
+ record label), `ComputerName`, `IpAddress`, plus `OperatingSystemName`, `Protocols`, root/user
71
+ volume sizes, AutoStop timeout, root/user encryption flags, and subnet. `diagnose_workspace_connectivity`
72
+ signals now include `user_name`/`computer_name`. Pools also expose bundle/directory/running-mode/
73
+ description; Applications fleets expose image name and session/idle/disconnect timeouts; stacks
74
+ expose `UserSettings` (clipboard/print/file-transfer controls) and storage connectors; Secure
75
+ Browser portals expose authentication type, max concurrent sessions, instance and renderer type.
76
+ - `get_workspace_connection_history` and `get_pool_session_history` (Tier 0): time-series usage
77
+ history for WorkSpaces Personal desktops (UserConnected + connection attempts/failures) and
78
+ WorkSpaces Pools (Active/Actual/Available/Desired/Pending user-session capacity +
79
+ utilization), each with a plain-language summary that flags unused desktops / idle pool
80
+ capacity. Generalized the CloudWatch series fetch and added a generic `UsageHistory` model.
81
+ Note: the Pools CloudWatch dimension is literally `"WorkSpaces pool ID"` (with spaces).
82
+ - `get_application_fleet_usage` (Tier 0): time-series **usage history** for a WorkSpaces
83
+ Applications fleet from the `AWS/AppStream` namespace (InUseCapacity, CapacityUtilization,
84
+ Running/Available/Actual/Desired/Pending capacity) — per-bucket points plus latest/average/peak
85
+ and a plain-language summary that flags idle running capacity.
86
+ - WorkSpaces Applications **stacks**: `get_euc_inventory_summary` now counts stacks (alongside
87
+ fleets) and `generate_inventory_report` lists each stack with its associated fleets
88
+ (`ListAssociatedFleets`). IAM policies updated to use `appstream:ListAssociatedFleets` /
89
+ `ListAssociatedStacks` (replacing a non-existent `DescribeFleetAssociations`).
90
+ - Legacy service-name acceptance: the server instructions and application-fleet tool descriptions
91
+ now teach the model that "AppStream" / "AppStream 2.0" means Amazon WorkSpaces Applications (and
92
+ "WorkSpaces Web" means Secure Browser), so queries using former names route correctly while
93
+ output keeps the current name. Added a `LEGACY_NAME_ALIASES` map and guardrail tests.
94
+ - `get_workspace_performance` (Tier 0): native per-desktop CPU/memory/GPU/FPS/disk/latency/uptime
95
+ metrics from the `AWS/WorkSpaces` namespace (latest/average/peak), no CloudWatch agent required.
96
+ - `recommend_bundle_rightsizing` (Tier 0): now implemented on the native CPU/memory metrics —
97
+ suggests smaller/larger compute types from window-peak headroom (general families; graphics
98
+ excluded). This corrects an earlier wrong assumption that these metrics required the CloudWatch
99
+ agent; verified against a live account.
100
+
101
+ ### Changed
102
+ - Internal: consolidated the per-module `try_call` / `paginate` / `count_by` helpers onto the
103
+ shared `tools/_common.py` (no behaviour change). Refreshed `DESIGN.md` to reflect shipped state
104
+ and added an "Example admin questions" section to the README.
105
+
106
+ ### Added
107
+ - Phase 3 destructive tools (Tier 3), registered only with both `--enable-writes` and
108
+ `--enable-destructive`: `terminate_workspaces`, `rebuild_workspaces`, and `restore_workspace`.
109
+ On top of dry-run + blast-radius cap, each execution requires an exact typed acknowledgement
110
+ phrase (`"TERMINATE"` / `"REBUILD"` / `"RESTORE"`). Added the Tier 3 IAM policy
111
+ (`iam/tier3-destructive.json`) and an optional `acknowledgement_required` field on `WriteOutcome`.
112
+ - Phase 2 guarded lifecycle tools for WorkSpaces Pools and Applications (writes, Tier 2):
113
+ `start_workspaces_pool`, `stop_workspaces_pool`, `update_workspaces_pool_capacity`,
114
+ `start_application_fleet`, `stop_application_fleet`, and `update_application_fleet_capacity`.
115
+ Same safety model (dry-run default, opt-in registration); Tier 2 policy extended with the Pools
116
+ and AppStream start/stop/update actions.
117
+ - Phase 2 guarded lifecycle tools (writes, Tier 2), registered only with `--enable-writes`:
118
+ `start_workspaces`, `stop_workspaces`, `reboot_workspaces`, and `modify_workspace_running_mode`.
119
+ Mutations are dry-run unless `confirm=true`, and confirmed bulk actions are refused above
120
+ `--max-bulk-targets`. Added the Tier 2 IAM policy (`iam/tier2-lifecycle.json`) and
121
+ `WriteOutcome`/`TargetResult` models.
122
+ - Phase 1 reporting & audit tools (read-only, Tier 0): `generate_inventory_report`,
123
+ `audit_security_posture` (volume encryption + directory IP access control groups), and
124
+ `list_unused_resources`. Added a shared `tools/_common.py` (best-effort call + pagination
125
+ helpers) and inventory/audit/unused-resource models; `Finding` gained an optional `resource_id`.
126
+ - Phase 1 cost & utilization tools (read-only, Tier 1): `analyze_workspace_utilization`,
127
+ `recommend_running_mode`, and `get_euc_cost_summary`, plus the Tier 1 IAM policy
128
+ (`iam/tier1-cost.json`) adding Cost Explorer and Pricing access.
129
+ - Utilization/recommendation/cost models (`WorkspaceUtilization`, `UtilizationReport`,
130
+ `Recommendation`, `RecommendationReport`, `CostSummary`).
131
+ - Phase 1 diagnostics tools (read-only, Tier 0): `diagnose_workspace_connectivity`,
132
+ `diagnose_application_fleet`, and `check_directory_health` — each correlates resource state,
133
+ directory health, CloudWatch telemetry, and auto-scaling activity into a severity-ranked
134
+ diagnosis with recommendations.
135
+ - Generic `ServiceError`, `Finding`, `Diagnosis`, and `DirectoryHealthReport` models.
136
+ - Phase 0 scaffold: FastMCP server, region/profile-aware boto3 client factory, read-only safety
137
+ defaults, and the `get_euc_inventory_summary` tool spanning WorkSpaces Personal, Pools,
138
+ Applications, and Secure Browser.
139
+ - Tier 0 (read-only) IAM policy and per-tier IAM documentation.
140
+ - Test suite (fake-client based) and tooling config (ruff, pyright, bandit, pre-commit).
141
+ - `DESIGN.md` with the full tool inventory and phased roadmap.
@@ -0,0 +1,203 @@
1
+ # Amazon WorkSpaces EUC Admin MCP Server — Design & Build Plan
2
+
3
+ > Status: **Phases 0–3 shipped** (2026-05-31). An MCP server giving administrators AI-assisted
4
+ > inventory, troubleshooting, cost/utilization optimization, and guarded lifecycle management
5
+ > across the Amazon WorkSpaces family of End User Computing services.
6
+ >
7
+ > **Shipped:** 10 read-only tools (Tier 0/1) + 10 guarded write tools (Tier 2) + 3 destructive
8
+ > tools (Tier 3), all behind opt-in flags with dry-run/confirm/blast-radius/typed-acknowledgement
9
+ > guards. All four IAM policy tiers ship in `iam/`. CI (ruff/format/bandit/pytest on Py 3.11–3.13)
10
+ > is green. See `README.md` for the live tool catalog and `CHANGELOG.md` for per-phase detail.
11
+ > **Still deferred:** `recommend_bundle_rightsizing` (needs the WorkSpaces CloudWatch agent for
12
+ > CPU/memory) — see §10.
13
+
14
+ ## 1. Principles
15
+
16
+ 1. **Admin persona only.** Operators managing fleets — not end users.
17
+ 2. **Domain intelligence over API mirroring.** Generic servers (AWS MCP Server, Cloud Control,
18
+ AWS API) already call EUC APIs raw. Our value is cross-service diagnosis, fleet-level
19
+ optimization, and EUC-aware guardrails — not 1:1 API wrappers.
20
+ 3. **Security-first, least privilege.** Read-only by default. Writes are opt-in, separately
21
+ permissioned, dry-run-able, confirmation-gated, and blast-radius-limited.
22
+ 4. **No embedded tenant data — ever.** This is redistributable software run by many parties.
23
+ Credentials, account IDs, ARNs, profile names, regions, and any other consumer-specific data
24
+ are supplied **only at runtime** (AWS credential chain, CLI flags, env vars) and are **never**
25
+ hardcoded, persisted to disk, or committed. The codebase ships with zero account-specific data.
26
+ 5. **Official AWS naming everywhere a human reads.** Legacy identifiers only where the SDK/API
27
+ literally requires them (and labelled as such).
28
+ 6. **Build on awslabs conventions** so we match patterns customers already trust.
29
+
30
+ ## 2. Services in scope (official naming → API identifier)
31
+
32
+ | Product name | Underlying API (boto3 client) | Notes |
33
+ |---|---|---|
34
+ | Amazon WorkSpaces Personal | `workspaces` | Persistent desktops |
35
+ | Amazon WorkSpaces Pools | `workspaces` (Pools operations) | Non-persistent pooled |
36
+ | Amazon WorkSpaces Applications | `appstream` | App streaming (formerly AppStream 2.0) |
37
+ | Amazon WorkSpaces Secure Browser | `workspaces-web` | Managed browser (formerly WorkSpaces Web) |
38
+ | Amazon WorkSpaces Core | `workspaces` | Partner/BYO-VDI integration |
39
+
40
+ **Excluded:** Amazon WorkSpaces Thin Client.
41
+
42
+ ## 3. Architecture & stack (per awslabs DESIGN_GUIDELINES)
43
+
44
+ - **Language/framework:** Python 3.11+, FastMCP, Pydantic models, boto3, async/await.
45
+ - **Auth:** standard boto3 credential chain via `AWS_PROFILE` / `AWS_REGION`; no secrets stored
46
+ in the server. Assumed-role / Identity Center friendly. **Single-account v1**, with a client
47
+ factory designed to add cross-account `sts:AssumeRole` later without touching tool code.
48
+ - **Transport:** local `uvx`/stdio first; tool logic kept transport-agnostic so a remote
49
+ (AgentCore Runtime) deployment can be added later.
50
+ - **Distribution:** `uvx awslabs.workspaces-euc-mcp-server@latest` and a Docker image.
51
+ - **Observability:** Loguru with env-controlled log level; structured tool errors via `ctx.error`.
52
+ - **Repo layout:**
53
+ ```
54
+ awslabs/workspaces_euc_mcp_server/
55
+ __init__.py # version
56
+ server.py # FastMCP app + tool registration
57
+ consts.py # service/API constants, region maps
58
+ models.py # Pydantic request/response models
59
+ clients.py # boto3 client factory (region/profile aware)
60
+ tools/
61
+ inventory.py
62
+ diagnostics.py
63
+ cost.py
64
+ reporting.py
65
+ lifecycle.py # Phase 2 (guarded writes)
66
+ iam/ # shippable least-privilege policy docs per tier
67
+ tests/ # pytest + pytest-asyncio + moto
68
+ pyproject.toml, .pre-commit-config.yaml, README.md, CHANGELOG.md, LICENSE
69
+ ```
70
+ - **Quality gates:** ruff (format/lint), pyright (types), bandit (security), moto (AWS mocks),
71
+ pre-commit, Apache-2.0 headers.
72
+
73
+ ## 4. Configuration / safety flags
74
+
75
+ - `--readonly` (default **on**): only Describe/Get/List tools are registered.
76
+ - `--enable-writes`: registers Phase-2 lifecycle tools (still dry-run/confirm gated).
77
+ - `--enable-destructive`: separately gates terminate/rebuild/restore.
78
+ - `--max-bulk-targets N`: blast-radius cap for any bulk mutation.
79
+ - `AWS_REGION` / `AWS_PROFILE`: standard.
80
+
81
+ ## 5. Tool inventory
82
+
83
+ Each tool lists the IAM actions it needs. Tools are *workflows* that compose several API calls
84
+ and return a synthesized result, not raw API passthroughs.
85
+
86
+ ### Phase 1 — Read / Diagnose / Optimize (read-only, Tiers 0–1)
87
+
88
+ **Inventory & discovery**
89
+ | Tool | Purpose | IAM actions |
90
+ |---|---|---|
91
+ | `list_workspaces_personal` | Personal desktops + live connection status | `workspaces:DescribeWorkspaces`, `workspaces:DescribeWorkspacesConnectionStatus`, `workspaces:DescribeWorkspaceDirectories` |
92
+ | `list_workspaces_pools` | Pools + active sessions | `workspaces:DescribeWorkspacesPools`, `workspaces:DescribeWorkspacesPoolSessions` |
93
+ | `list_application_fleets` | WorkSpaces Applications fleets/stacks/associations | `appstream:DescribeFleets`, `appstream:DescribeStacks`, `appstream:DescribeFleetAssociations` |
94
+ | `list_secure_browser_portals` | Secure Browser portals + settings | `workspaces-web:ListPortals`, `workspaces-web:GetPortal`, `workspaces-web:List*Settings` |
95
+ | `get_euc_inventory_summary` | Cross-service rollup (counts, states, regions) | union of the above describes |
96
+
97
+ **Troubleshooting & triage** (the flagship value)
98
+ | Tool | Purpose | IAM actions |
99
+ |---|---|---|
100
+ | `diagnose_workspace_connectivity` | Correlate a Personal WorkSpace's state + connection status + directory health + CloudWatch into a root-cause narrative | `workspaces:Describe*`, `ds:DescribeDirectories`, `cloudwatch:GetMetricData` |
101
+ | `diagnose_pool_session` | Why a Pools session failed/queued — capacity, errors, scaling | `workspaces:DescribeWorkspacesPool*`, `cloudwatch:GetMetricData` |
102
+ | `diagnose_application_fleet` | Fleet state, capacity, scaling activity, fleet errors | `appstream:DescribeFleets`, `appstream:DescribeFleetAssociations`, `cloudwatch:GetMetricData`, `application-autoscaling:DescribeScalingActivities` |
103
+ | `check_directory_health` | Shared dependency: directory reachability/registration | `ds:DescribeDirectories`, `workspaces:DescribeWorkspaceDirectories` |
104
+
105
+ **Cost & utilization optimization**
106
+ | Tool | Purpose | IAM actions |
107
+ |---|---|---|
108
+ | `analyze_workspace_utilization` | Find idle/unused Personal WorkSpaces from connection metrics | `workspaces:DescribeWorkspaces*`, `cloudwatch:GetMetricData` |
109
+ | `recommend_running_mode` | AlwaysOn → AutoStop candidates with $ estimate | `workspaces:DescribeWorkspaces`, `cloudwatch:GetMetricData`, `pricing:GetProducts` |
110
+ | `recommend_bundle_rightsizing` | Over/under-sized bundles from CPU/mem metrics | `workspaces:DescribeWorkspaces`, `workspaces:DescribeWorkspaceBundles`, `cloudwatch:GetMetricData` |
111
+ | `analyze_pool_capacity` | Pools over/under-provisioning | `workspaces:DescribeWorkspacesPool*`, `cloudwatch:GetMetricData` |
112
+ | `analyze_fleet_capacity` | Applications fleet capacity vs demand | `appstream:DescribeFleets`, `cloudwatch:GetMetricData` |
113
+ | `get_euc_cost_summary` | Spend rollup filtered to EUC services | `ce:GetCostAndUsage`, `ce:GetDimensionValues` |
114
+
115
+ **Reporting & audit**
116
+ | Tool | Purpose | IAM actions |
117
+ |---|---|---|
118
+ | `generate_inventory_report` | Structured inventory across all in-scope services | Phase-1 describes |
119
+ | `audit_security_posture` | Encryption at rest, IP access control groups, directory config, portal policies | `workspaces:Describe*`, `workspaces-web:Get*/List*`, `appstream:Describe*` |
120
+ | `list_unused_resources` | Idle desktops / empty fleets / orphaned associations | describes + `cloudwatch:GetMetricData` |
121
+
122
+ ### Phase 2 — Guarded lifecycle (writes; Tier 2, `--enable-writes`)
123
+ All support `dry_run`, return a plan + blast-radius before acting, and honor `--max-bulk-targets`.
124
+
125
+ | Tool | Purpose | IAM actions |
126
+ |---|---|---|
127
+ | `start_workspaces` / `stop_workspaces` / `reboot_workspaces` | Power ops | `workspaces:Start/Stop/RebootWorkspaces` |
128
+ | `modify_workspace_running_mode` | Apply AutoStop/AlwaysOn recommendation | `workspaces:ModifyWorkspaceProperties` |
129
+ | `modify_workspace_compute_type` | Apply right-sizing recommendation | `workspaces:ModifyWorkspaceProperties` |
130
+ | `update_pool_capacity` | Resize a Pool | `workspaces:UpdateWorkspacesPool` |
131
+ | `start_application_fleet` / `stop_application_fleet` / `update_fleet_capacity` | Applications fleet ops | `appstream:Start/Stop/UpdateFleet` |
132
+
133
+ ### Phase 3 — Destructive (Tier 3, `--enable-destructive`, hardest gating)
134
+ | Tool | Purpose | IAM actions |
135
+ |---|---|---|
136
+ | `rebuild_workspaces` / `restore_workspace` | Recover a desktop (data impact) | `workspaces:Rebuild/RestoreWorkspace` |
137
+ | `terminate_workspaces` | Decommission (irreversible) | `workspaces:TerminateWorkspaces` |
138
+
139
+ ## 6. IAM policy tiers (shipped with the server)
140
+
141
+ We ship a managed policy document per tier so customers grant exactly what they enable.
142
+
143
+ - **Tier 0 — Diagnostics (read-only):** `workspaces:Describe*`, `appstream:Describe*`,
144
+ `workspaces-web:Get*`/`List*`, `ds:DescribeDirectories`, `cloudwatch:GetMetricData`,
145
+ `application-autoscaling:DescribeScalingActivities`.
146
+ - **Tier 1 — Cost/optimization (read-only):** Tier 0 + `ce:GetCostAndUsage`,
147
+ `ce:GetDimensionValues`, `pricing:GetProducts`.
148
+ - **Tier 2 — Lifecycle (writes):** Tier 1 + `workspaces:Start/Stop/Reboot/ModifyWorkspace*`,
149
+ `workspaces:UpdateWorkspacesPool`, `appstream:Start/Stop/UpdateFleet`.
150
+ - **Tier 3 — Destructive:** Tier 2 + `workspaces:Rebuild/Restore/TerminateWorkspaces`.
151
+
152
+ Each tier is additive; default install = Tier 0. Recommend scoping by resource tag / directory
153
+ where the API supports it, and using **IAM context keys to separate the agent identity from the
154
+ human operator** (the pattern the AWS MCP Server uses).
155
+
156
+ ## 7. Security model
157
+
158
+ - Read-only default; writes require an explicit launch flag *and* the matching IAM tier.
159
+ - Every mutation: `dry_run` plan → explicit confirmation → blast-radius cap.
160
+ - **No credentials or tenant data in the server.** Credentials are resolved solely from the
161
+ standard AWS chain (`AWS_PROFILE` / `AWS_REGION` / SSO / assumed role) at runtime. The server
162
+ stores nothing to disk — boto3 clients are cached in memory only; there is no config/state file,
163
+ no credential cache, no account ID, ARN, or profile name baked into source.
164
+ - **Redistributable-safe repo:** nothing account-specific is ever committed. `.gitignore` blocks
165
+ `.aws/`, `.env`, `*.pem`; pre-commit runs `detect-private-key`; CI greps for hardcoded
166
+ account IDs/ARNs/secrets. Examples in docs use placeholders only.
167
+ - Full auditability via CloudTrail (every underlying API call is attributable).
168
+ - Optional `audit_security_posture` self-check against EUC best practices.
169
+ - Input validation with Pydantic; bandit + AST checks in CI.
170
+
171
+ ## 8. Phased roadmap
172
+
173
+ - **Phase 0 — Scaffold:** repo per awslabs layout, client factory, auth, `--readonly` flag,
174
+ one end-to-end tool (`get_euc_inventory_summary`), tests with moto, CI/pre-commit. Ship to
175
+ internal users.
176
+ - **Phase 1 — Read/Diagnose/Optimize:** full inventory + diagnostics + cost tools (Tiers 0–1).
177
+ This is the demonstrable-value milestone.
178
+ - **Phase 2 — Guarded lifecycle:** writes behind `--enable-writes`, dry-run + confirm + caps.
179
+ - **Phase 3 — Destructive ops:** terminate/rebuild/restore behind `--enable-destructive`.
180
+ - **Phase 4 — Polish:** packaging (uvx/Docker), docs, optional remote/AgentCore deployment.
181
+
182
+ ## 9. Decisions
183
+
184
+ 1. **Distribution:** standalone **public repo on the author's personal GitHub**, consumable and
185
+ self-deployable by others, with full documentation (README, install, IAM setup, examples).
186
+ Follows awslabs conventions so it feels familiar, but lives independently (not in `awslabs/mcp`).
187
+ 2. **Account model:** **single-account first** (standard boto3 credential chain). Architect the
188
+ client factory so cross-account role assumption (MSP/multi-account) can be added later without
189
+ refactoring tools.
190
+ 3. **Deployment:** **local `uvx` first**, but design transport/config so the same server can be
191
+ deployed remotely (e.g. Bedrock AgentCore Runtime) later — keep tool logic transport-agnostic.
192
+
193
+ ## 10. Still open (defer)
194
+
195
+ - **CORRECTED & SHIPPED:** `recommend_bundle_rightsizing` was previously deferred on the
196
+ (incorrect) assumption that `AWS/WorkSpaces` doesn't publish CPU/memory. It does — the namespace
197
+ natively emits `CPUUsage`, `MemoryUsage`, `GPUUsage`, `FramesPerSecond`, disk usage, latency,
198
+ uptime, etc., keyed by `WorkspaceId`, with **no CloudWatch agent required** (verified against a
199
+ live account). `get_workspace_performance` and `recommend_bundle_rightsizing` now ship on these
200
+ native metrics (Tier 0).
201
+ - Cost tools: Cost Explorer (`ce`) only for v1, or add CUR for finer granularity later?
202
+ - Resource-tag / directory-scoped IAM conditions — which services support them well enough to
203
+ recommend by default.