Skip to content

feat: install the Agent Toolkit for AWS by default - #30

Merged
ChrisSc merged 1 commit into
mainfrom
feat/aws-agent-toolkit
Aug 31, 2026
Merged

feat: install the Agent Toolkit for AWS by default#30
ChrisSc merged 1 commit into
mainfrom
feat/aws-agent-toolkit

Conversation

@ChrisSc

@ChrisSc ChrisSc commented Aug 31, 2026

Copy link
Copy Markdown
Owner

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, after claude update, before cron) does two things:

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, uv tool install beside ruff), which SigV4-signs calls to AWS's hosted endpoint.
Skills The 23-skill aws-core set, version-pinned in the new seed/aws-skills.txt, installed to ~/.claude/skills.

Knobs (compose env): AWS_MCP_REGION (default us-east-1), AWS_MCP_READ_ONLY (default 1).

Design notes

  • Pinned rather than the plugin route. Upstream suggests 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.
  • No AWS CLI bump neededaws agent-toolkit already ships in the pinned 2.36.11 (toolkit requires ≥ 2.35.0).
  • 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 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.
  • --region is mandatory on every aws agent-toolkit call: the catalog is unauthenticated, but botocore still refuses to sign without a region, so a fresh container would otherwise fail every skill install with NoRegion.
  • No firewall change. Both toolkit endpoints resolve into CloudFront prefixes tagged AMAZON/GLOBAL, which @aws-ip-ranges always keeps.

Credentials caveat (worth knowing)

The proxy signs every request including initialize, so with no resolvable credentials aws-mcp doesn'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 with aws sts get-caller-identity, logs aws.credentials.ok/.absent, and prints a "run aws sso login" hint. Skills work regardless.

Also fixed (pre-existing, exposed by the new assertions)

  • smoke/CI asserted against a still-booting container — both 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, jq's 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=="…")'.

Verification

  • make lint — shellcheck / hadolint / yamllint / compose config all clean.
  • make smokesmoke OK; make boot-checkboot-check OK (now requires aws.mcp.registered + aws.toolkit.ready).
  • Strict-mode boot (OUTPUT DROP confirmed active): aws.skills.installed count=23 failed=0 — the @aws-ip-ranges coverage claim measured, not assumed.
  • Handshake proven: with resolvable credentials the proxy negotiates successfully (serverInfo: MCP Proxy for AWS 1.6.4) through the strict firewall.
  • Idempotency: restart → aws.skills.current (stamp hit, no re-download).
  • Config propagation: recreate with AWS_MCP_READ_ONLY=0 AWS_MCP_REGION=eu-west-1 → server re-registered at the eu-west-1 endpoint with --read-only dropped, proving the regenerate-each-boot design.
  • Edge paths exercised against stubs in a Linux container: partial skill failure (no stamp written, status=degraded), missing binary (status=skipped), and budget exhaustion (incomplete=1).

🤖 Generated with Claude Code

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>
@ChrisSc
ChrisSc merged commit 2ac5b74 into main Aug 31, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant