Commit 02998ed
feat(aws-transform-mcp-server): add AWS Transform MCP server (#3282)
* feat(aws-transform-mcp-server): add AWS Transform MCP server
Python MCP server for AWS Transform enabling AI coding assistants to
manage the full transformation lifecycle — workspaces, jobs, connectors,
HITL tasks, artifacts, chat, and agent registry — directly from the IDE.
25 tools across 14 handlers. Dual auth: FES (cookie/SSO bearer) and
TCP (SigV4). 413 tests passing. Pyright and Ruff clean.
Port of internal TypeScript codebase (ATXCustomerFacingMcpV2) aligned
with the awslabs/mcp monorepo Python architecture.
Ref: RFC #2811
* refactor(aws-transform-mcp-server): remove poll_message, agent_registry, and connector tools; use send_message for job status
Port of internal commit cac188d: replace poll_message with send_message
for job status queries, remove agent_registry and connector tools,
simplify get_resource and list_resources, improve audit logging.
* feat(aws-transform-mcp-server): add get_job_status tool for IDE agent polling
Add a new get_job_status tool that returns a unified job status snapshot
(job metadata, worklogs, HITL tasks, messages, plan steps) in a single
call. The tool includes _pollingGuidance in the response to instruct
IDE agents to automatically poll every minute until the job reaches a
terminal state.
- Parallel FES calls via asyncio.gather for low latency
- Server-side HITL task filtering for actionable statuses only
- [CRITICAL] directives in tool description and suggestedAction output
to prevent the IDE agent from ending its turn between polls
- 9 tests covering all paths (terminal, in-progress, HITL, failures)
* fix(aws-transform-mcp-server): add .python-version and bump pytest to fix CI
Add missing .python-version file required by actions/setup-python and
bump pytest from >=8.0.0 to >=9.0.3 to resolve GHSA-6w46-j5rx-g56g
(insecure tmpdir handling).
* add fes client and remove get_job_status
* fix the fes json file
* Revert "fix the fes json file"
This reverts commit 90f2890.
* Revert "add fes client and remove get_job_status"
This reverts commit e792c6c.
* refactor(aws-transform-mcp-server): auto-detect AWS credentials, remove configure_sigv4
Replace the frozen credential snapshot pattern with boto3 auto-detection.
AWS credentials are now resolved from the standard credential chain
(AWS_PROFILE, env vars, ~/.aws/credentials, instance profile) on every
TCP call, matching the pattern used by aws-api-mcp-server, eks-mcp-server,
and all other boto3-dependent servers in the monorepo.
- Remove configure_sigv4 tool — credentials no longer need explicit
configuration via a tool call
- Move STS validation into get_status — shows accountId, ARN, stage,
region, and TCP endpoint
- Refactor tcp_client.py to resolve credentials per call via
AwsHelper.create_session() instead of reading from frozen SigV4Config
- Consolidate session/region helpers into AwsHelper class
- Simplify accept_connector — infer awsAccountId from boto3 credentials
via STS, remove it as a required parameter
- Clean up config_store.py — remove SigV4Config state management
- Update README, CHANGELOG, server instructions, and tests
* feat(aws-transform-mcp-server): add gated SigV4 FES auth with startup probe
Add SigV4 authentication support for FES API calls, gated behind
SIGV4_FES_ENABLED = False in consts.py. When enabled, the server probes
FES with SigV4 at startup and falls back to SigV4 for all FES tool calls
when no cookie/SSO config exists.
- Add call_fes_direct_sigv4 using manual SigV4 signing via AwsHelper
- Add _probe_sigv4_fes startup probe with 6s timeout, 0 retries
- Combine load_persisted_config + probe into single asyncio.run(_startup)
- Add is_fes_available() guard — returns True if cookie/SSO OR SigV4 works
- Update all tool handlers from is_configured to is_fes_available
- Only disable SigV4 on 401/403 auth failures, not transient errors
- Validate ATX_STAGE against allowlist to prevent endpoint injection
- Eliminate duplicate session creation by passing region to SigV4 calls
- Use existing session for STS in accept_connector
- Separate ValueError from credential errors in get_status
- Add get_status sigv4Fes section showing probe result
- Add 13 SigV4 FES tests (probe, direct call, fallback, stage validation)
- Add 3 accept_connector tests and AwsHelper cache test
- Fix test mocks to use proper STS return values
* test(aws-transform-mcp-server): increase test coverage from 86% to 94%
Add tests for uncovered code paths across 9 test files:
- test_audit.py (new): _safe_args, audited_tool wrapper logging, _extract_error
- test_file_validation.py (new): blocked dirs, blocked filenames, valid paths
- test_upload_helper.py: upload_file_artifact happy path, file too large, S3 failure
- test_connector.py: _build_verification_link, create_connector (5 paths)
- test_hitl.py: download_agent_artifact (success, non-JSON, HTTP error, exception)
- test_get_resource.py: task with artifact download, dynamic schema, messageIds
- test_oauth.py: _open_browser platform dispatch, CallbackHandler edge cases
- test_http_utils.py: error body JSON fallback, retry loop safety net
- test_configure.py: cookie/SSO exceptions, bearer expiry, bad region, STS failure
* feat(aws-transform-mcp-server): add typed FES boto3 client and rework get_job_status fallback
* feat(aws-transform-mcp-server): add multi-region profile discovery and SSO login fix
- Fan out ListAvailableProfiles across all FES regions (5s timeout each)
to auto-discover profiles without requiring the user to know the service region
- Add MCP elicitation-based profile selection with fallback to profileName param
- Add switch_profile tool for changing profiles without re-authentication
- Extract service region from applicationUrl instead of conflating IdC and FES regions
- Replace single region param with idcRegion (SSO) and auto-extraction (cookie)
- Add defensive AWS_PROFILE handling for empty/whitespace env values
- Add token expiry check before fan-out in switch_profile
- Remove debug print that corrupted stdio transport
* Add adaptive polling tool and update instructions
* Fix listing artifacts
* test(aws-transform-mcp-server): increase test coverage from 93% to 98%
Add tests for uncovered code paths in configure.py (switch_profile,
_discover_profiles, elicitation), fes_client.py (boto3 helpers, token
refresh, SigV4), hitl_schemas.py (preprocessors, schema builders,
validators), and tool_utils.py (format helpers, download edge cases).
* reduce number of tools for hitl and move send message to get job status
* fix(aws-transform-mcp-server): quote OAuth URL in Windows browser open to prevent &-truncation
On Windows, cmd.exe interprets '&' in URLs as a command separator,
causing the OAuth authorize URL to be truncated at the first query
parameter. This drops client_id, code_challenge, and other PKCE
parameters, resulting in "Client ID is required" errors on the IdC
login page.
Switch from list-form subprocess.Popen(['cmd', '/c', 'start', '', url])
to a quoted shell string: cmd /c start "" "{url}" which prevents cmd.exe
from splitting on '&'.
Also adds Windows Installation section to README with the standard
uvx --from pattern used by other awslabs MCP servers.
* fix(aws-transform-mcp-server): suppress Bandit B602 for Windows browser open
The shell=True is required to properly quote the OAuth URL and prevent
cmd.exe from interpreting '&' as a command separator. The URL is built
internally from the OIDC authorization endpoint, not from user input.
* fix vmware connector bugs
* fix(aws-transform-mcp-server): resolve Semgrep subprocess-shell-true and logger-credential-leak findings
Replace subprocess.Popen shell=True with os.startfile (Win32 ShellExecute)
for the Windows browser-open path, eliminating the shell injection surface.
Rephrase log message to avoid triggering credential-disclosure false positive.
* defer downloading huge hitl artifacts and fix bug with connector selection
* Remove Gamma access from mcp
* feat(aws-transform-mcp-server): remove SIGV4_FES_ENABLED client-side … (#15)
* feat(aws-transform-mcp-server): remove SIGV4_FES_ENABLED client-side feature flag
The FES service gates SigV4 access per-account via AppConfig, making
the client-side flag redundant. The startup probe now runs
unconditionally. Also avoids Semgrep credential-disclosure false
positive by removing 'token' keyword from log message.
* fix(aws-transform-mcp-server): set region on session before credential resolution
Botocore's LoginProvider creates an internal signin service client
during credential refresh which requires a region. Create the session
with region_name resolved from the profile config to prevent
NoRegionError during the SigV4 FES probe at startup.
* fix(aws-transform-mcp-server): pass region to call_fes_direct_sigv4 in probe
The probe resolved region but didn't pass it to call_fes_direct_sigv4,
which then created its own regionless session internally — still
triggering NoRegionError from botocore's LoginProvider.
* fix(aws-transform-mcp-server): create SigV4 FES client with user profile and region
_create_sigv4_client was using _service_model.create_session() which
creates a botocore session with no profile or region. This caused
NoRegionError when credential providers (LoginProvider) tried to create
internal service clients during credential resolution.
Fix: create a fresh botocore session with the user's AWS_PROFILE and
region set, register the vendored FES model on it, then use it for the
client. This allows credential resolution to succeed.
Also reverts the workaround of passing region through from the probe
and the create_session_with_region helper, since the root cause is now
fixed at the client creation level.
* fix(aws-transform-mcp-server): don't permanently disable SigV4 on 401/403 and report SigV4 in get_status
- Remove set_sigv4_fes_available(False) on 401/403 in call_fes().
Both status codes indicate transient credential expiry, not permanent
loss of access. SigV4 stays enabled until user explicitly runs
configure (which takes priority via config presence).
- Update get_status to report fes.configured=True with authMode=sigv4
when SigV4 FES is available, preventing the LLM from reflexively
calling configure and downgrading auth.
* test(aws-transform-mcp-server): add test for SSO config superseding SigV4
Verifies that when explicit SSO/cookie config exists, the SigV4 path
is never used even if sigv4_fes_available is True. Ensures explicit
configure takes priority over auto-detected SigV4.
* fix(aws-transform-mcp-server): remove unused variable flagged by ruff F841
* fix(aws-transform-mcp-server): improve auth status messages and instructions
- get_status now presents all 3 auth options (SigV4, SSO, cookie) in
error messages instead of only mentioning configure.
- Server instructions updated to list SigV4 as the first (zero-config)
option and clarify that any ONE method is sufficient.
- Added explicit instruction: if get_status shows a valid connection,
do NOT call configure.
- Error messages for region/credential issues now include actionable
guidance (set AWS_PROFILE, AWS_REGION in env block).
* refactor(aws-transform-mcp-server): remove dead try/except HttpError: raise
* fix(aws-transform-mcp-server): revert SigV4 switch_profile, return honest error
SigV4 profile switching cannot work because:
1. call_fes() derives its endpoint from AWS_REGION — switching to a
profile in a different region has no effect on subsequent calls.
2. VerifySession without an Origin header only confirms IAM creds,
not profile access.
3. No persistence mechanism for selected profile in SigV4 mode.
Instead, return a clear error explaining the user should set AWS_REGION
to match their desired profile's region and restart.
* fix(aws-transform-mcp-server): fail early with clear message when SSO token expired and unrefreshable
When bearer token is expired but refresh fields are missing, raise
immediately with actionable guidance instead of making a doomed FES
call that returns a raw 401.
* fix(aws-transform-mcp-server): suppress CodeQL clear-text-logging false positive
The OAuth authorize URL printed on browser-open failure contains only
public values (PKCE challenge, state, redirect_uri) — not tokens or
secrets. The URL must be shown for the user to complete login manually.
* fix(aws-transform-mcp-server): fix security scan findings
- Upgrade python-multipart 0.0.26 → 0.0.27 (GHSA-pp6c-gr5w-3c5g, DoS
via unbounded multipart part headers).
- Suppress CodeQL clear-text-logging false positives on OAuth authorize
URL prints — these contain only public PKCE values, not credentials,
and must be shown for manual browser login.
* feat(aws-transform-mcp-server): add endpoint and scope env var overri… (#19)
* feat(aws-transform-mcp-server): add endpoint and scope env var overrides for local testing
Add ATX_FES_ENDPOINT, ATX_TCP_ENDPOINT, and ATX_OAUTH_SCOPE environment
variable overrides to allow testing against non-production environments
without exposing internal endpoint patterns in source code.
Endpoint overrides support {region} template interpolation for multi-region
fan-out (e.g. https://api.transform-gamma.{region}.on.aws/), or can be
set as static URLs.
Also re-derives fes_endpoint at call-time from config.region (matching
TCP's existing pattern) so that toggling the env var takes effect
immediately without stale values persisted to config.json.
* fix(aws-transform-mcp-server): add Origin header to SigV4 FES path via profile discovery
The SigV4 FES path never sent an Origin header, causing HTTP 403
"Invalid request origin" on operations that require it. Cookie and
bearer paths always sent Origin from their stored ConnectionConfig.
Replace the startup ListWorkspaces probe with a ListAvailableProfiles
fan-out across all FES regions using SigV4. If exactly one profile is
found, auto-select it and store origin/region in memory. If multiple
profiles exist, store the list and raise ProfileSelectionRequired on
first tool call (switch_profile SigV4 support in follow-up change).
Also: TCP client now uses the discovered profile region as source of
truth, falling back to AWS_REGION.
* fix(aws-transform-mcp-server): use ListWorkspaces region discovery instead of ListAvailableProfiles
ListAvailableProfiles requires instanceArn and bearerToken which SigV4
callers don't have (TransformControlPlaneActivity.java:67-77). Replace
with ListWorkspaces fan-out across all FES regions — any non-error
response means the account has a SigV4-enabled profile in that region.
SigV4 callers don't need an Origin header (RequestExtractionHandler
passes SigV4 through without Origin). The FES service resolves the
profile server-side via SigV4ProfileResolutionHandler. Remove all
Origin injection code from the SigV4 path.
Also fix stale config bug: call clear_config() in _startup() when
load_persisted_config() returns False, preventing an expired bearer
config from blocking the SigV4 path in call_fes().
* feat(aws-transform-mcp-server): add SigV4 region selection to switch_profile
When SigV4 auth is active with multiple discovered regions,
switch_profile now presents the available regions for selection
via MCP elicitation (with fallback to returning the list).
Previously switch_profile rejected SigV4 callers entirely.
* Add region to switch profile tool. Optional
* refactor(aws-transform-mcp-server): address code review feedback on SigV4 implementation
- Use str.replace() instead of str.format() for env var interpolation
- Add list[str] type parameters to bare list annotations
- Set asyncio.wait_for timeout to PROFILE_DISCOVERY_TIMEOUT_SECONDS + 2
as a safety net (inner boto3 timeout fires first)
- Remove redundant inline import os as _os
- Switch to ctx.elicit() from lower-level elicit_with_validation
- Add region parameter to switch_profile for direct LLM invocation
- Improve switch_profile region description for LLM tool-use clarity
* style: apply ruff format to test_sigv4_fes.py
* docs(README): add VPC configuration section and fix tool inventory (#20)
* docs(README): add VPC configuration section and fix tool inventory
Add comprehensive VPC section documenting required endpoints, PrivateLink
service names, security group rules, and troubleshooting guidance for
running the MCP server in a VPC without direct internet access. All
endpoints verified against source code and official AWS documentation.
Fix Available Tools section to match actual codebase:
- Correct tool count from 21 to 19
- Remove phantom poll_message tool (send_message handles both)
- Add missing tools: switch_profile, get_job_status, adaptive_poll
- Add users to list_resources supported types
- Update Features list to reflect actual capabilities
* Update and remove fes from file anme
* Update test mock
* Update test
* Update
* Update name
* update test
* Update wording for connection / code owner / add agent header for client (#22)
---------
Co-authored-by: eswarjal <eswarjgs@gmail.com>1 parent ff98a81 commit 02998ed
84 files changed
Lines changed: 40238 additions & 0 deletions
File tree
- .github
- docusaurus
- docs/servers
- static/assets
- src/aws-transform-mcp-server
- awslabs
- aws_transform_mcp_server
- _service_model
- elasticgumbyfrontendservice/2022-07-26
- tools
- chat
- tests
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
| 45 | + | |
45 | 46 | | |
46 | 47 | | |
47 | 48 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
180 | 180 | | |
181 | 181 | | |
182 | 182 | | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
183 | 189 | | |
184 | 190 | | |
185 | 191 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
46 | 53 | | |
47 | 54 | | |
48 | 55 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
65 | 88 | | |
66 | 89 | | |
67 | 90 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
0 commit comments