feat: install the Agent Toolkit for AWS by default - #30
Merged
Conversation
Claude now boots with live AWS tools and AWS domain guidance, no setup. Two halves, both driven by the new init-aws-toolkit.sh (entrypoint step 4, after `claude update`, before cron): * AWS MCP Server — registers the `aws-mcp` stdio server against the new build-pinned `mcp-proxy-for-aws` (ARG MCP_PROXY_FOR_AWS_VER=1.6.4, via `uv tool install` beside ruff), which SigV4-signs calls to AWS's hosted endpoint. Pinned at build rather than the upstream-suggested floating `uvx mcp-proxy-for-aws@X`, which would resolve from PyPI on every server start — a supply-chain hole and a startup-latency hit. * Skills — the 23-skill `aws-core` set, version-pinned in the new seed/aws-skills.txt, installed via `aws agent-toolkit`. Already present in the pinned CLI 2.36.11 (toolkit needs >= 2.35.0), so no CLI bump. Read-only by default (--read-only); AWS_MCP_READ_ONLY=0 opts into writes, AWS_MCP_REGION picks the region. The MCP entry is re-registered every boot, not seeded once: ~/.claude is a persistent volume, so copy-if-missing would freeze the first boot's version and flags forever. Skills are gated on the manifest's SHA-256, so steady-state boots do no network I/O and a deliberately removed skill stays removed. No firewall change needed — both toolkit endpoints resolve into CloudFront prefixes tagged AMAZON/GLOBAL, which @aws-ip-ranges always keeps. Verified against the live ip-ranges.json feed and in a strict-mode (OUTPUT DROP) boot: 23/23 skills installed, 0 failures. Credentials gate the whole server, not just its API tools: the proxy signs `initialize` too, so without them Claude Code shows an opaque `-32602: Invalid request parameters` (contra the upstream docs, measured against 1.6.4). The boot step probes with `aws sts get-caller-identity`, logs aws.credentials.ok/.absent, and prints an actionable hint. Also fixes two pre-existing bugs in the validation gates, both exposed by the new assertions and both required for them to be meaningful: * smoke/CI asserted against a still-booting container — they waited for ENVIRONMENT.md, written at step 2 of 6, so every later assertion raced `claude update`, the AWS step and cron. Now waits for `pgrep -x cron`, the last step before `exec`. * `jq -e 'select(...)'` is not a membership test — with -e the exit status reflects only the LAST input line, so the boot-journal probes passed purely because entrypoint.ready happens to be the journal's final event. Replaced with `jq -se 'any(.[]; .event=="…")'`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Boots the container with the Agent Toolkit for AWS already wired up — Claude gets live AWS tools and AWS domain guidance with no manual setup.
What lands
New
init-aws-toolkit.sh(entrypoint step 4, afterclaude update, before cron) does two things:aws-mcpstdio server against the new build-pinnedmcp-proxy-for-aws(ARG MCP_PROXY_FOR_AWS_VER=1.6.4,uv tool installbesideruff), which SigV4-signs calls to AWS's hosted endpoint.aws-coreset, version-pinned in the newseed/aws-skills.txt, installed to~/.claude/skills.Knobs (compose env):
AWS_MCP_REGION(defaultus-east-1),AWS_MCP_READ_ONLY(default1).Design notes
uvx mcp-proxy-for-aws@X, which resolves from PyPI every time the MCP server starts — a supply-chain hole and a startup-latency hit. Pinning at build time keeps the repo's existing integrity gate intact.aws agent-toolkitalready ships in the pinned 2.36.11 (toolkit requires ≥ 2.35.0).~/.claudeis a persistent volume, so copy-if-missing would freeze the first boot's proxy version and flags forever. Skills use the opposite discipline — gated on the manifest's SHA-256 — so steady-state boots do no network I/O and a deliberately removed skill stays removed.--regionis mandatory on everyaws agent-toolkitcall: the catalog is unauthenticated, but botocore still refuses to sign without a region, so a fresh container would otherwise fail every skill install withNoRegion.AMAZON/GLOBAL, which@aws-ip-rangesalways keeps.Credentials caveat (worth knowing)
The proxy signs every request including
initialize, so with no resolvable credentialsaws-mcpdoesn't merely lose its API tools — it fails to connect, and Claude Code reports an opaque-32602: Invalid request parameters. Upstream docs claim credential-free doc/skill discovery still works over MCP; measured against 1.6.4, it does not. The boot step therefore probes withaws sts get-caller-identity, logsaws.credentials.ok/.absent, and prints a "runaws sso login" hint. Skills work regardless.Also fixed (pre-existing, exposed by the new assertions)
ENVIRONMENT.md, written at step 2 of 6, so every later assertion racedclaude update, the AWS step, and cron. Now waits forpgrep -x cron, the last step beforeexec.jq -e 'select(...)'is not a membership test — with-e, jq's exit status reflects only the last input line, so the boot-journal probes passed purely becauseentrypoint.readyhappens to be the journal's final event. Replaced withjq -se 'any(.[]; .event=="…")'.Verification
make lint— shellcheck / hadolint / yamllint /compose configall clean.make smoke→ smoke OK;make boot-check→ boot-check OK (now requiresaws.mcp.registered+aws.toolkit.ready).OUTPUT DROPconfirmed active):aws.skills.installed count=23 failed=0— the@aws-ip-rangescoverage claim measured, not assumed.serverInfo: MCP Proxy for AWS 1.6.4) through the strict firewall.aws.skills.current(stamp hit, no re-download).AWS_MCP_READ_ONLY=0 AWS_MCP_REGION=eu-west-1→ server re-registered at the eu-west-1 endpoint with--read-onlydropped, proving the regenerate-each-boot design.status=degraded), missing binary (status=skipped), and budget exhaustion (incomplete=1).🤖 Generated with Claude Code