The risk in an agentic system does not live in the model. We worry about prompt injection, hallucinated commands, jailbreaks, the whole language layer. That is where the demos go wrong, so that is where the attention goes, and it is a misread of where the actual blast radius is.
When an agent reaches into AWS through the Model Context Protocol (opens in new tab), the model decides what to ask for. The MCP server decides what is possible. And what is possible is a function of one boring, decades-old control: the IAM permissions sitting behind that server. MCP didn't invent a new class of vulnerability. It did something more dangerous — it gave a non-deterministic caller a credential and a catalog of tools, and we mostly handed it the same broad role we hand a CI runner because that was faster.
A server is an identity, not a feature
People treat an MCP server like a plugin, a convenience layer that lets the assistant "do AWS things." It is not a plugin. It is a new principal in your environment — a credential, a network path, and a set of capabilities, taking instructions from a probabilistic process an outsider may be able to influence through your own data.
Once you see it that way, the problem snaps into a discipline we already know. The question is never "is the agent safe?" It is the same question we ask of every other identity: what can this thing do, on what resources, under what conditions, and can I prove it after the fact? If you can't answer that for an MCP server, you have deployed an unscoped service account with a chat interface. We spent fifteen years killing those. Don't reintroduce them because the wrapper is exciting.
The trap is the convenience role. Someone stands up an MCP server for "read-only AWS access," attaches a managed policy that is read-only in name, and ships it. But ReadOnlyAccess in AWS includes the ability to read Lambda source, Systems Manager parameters, S3 object contents, and a hundred other things that are absolutely not benign to exfiltrate. Read-only is a confidentiality control, not a safety guarantee. An agent that can read everything is an agent that can be talked into describing everything to whoever is steering it.
Scope at the call, not at the server
Here is how I would wire it. Not theory. The pattern I would defend in a control review.
One IAM role per server, never a shared one. Each MCP server gets its own principal with its own policy, so its permissions are legible in isolation and its actions are attributable in CloudTrail without forensic guesswork. The moment two servers share a role, you have lost both least privilege and your audit trail.
Use real credentials, not long-lived keys. On AWS that means IAM Roles Anywhere or an OIDC trust to your identity provider, vending short-lived session credentials. A static access key pasted into an MCP config file is the 2026 version of a password in source control. If the server runs in your own compute, give it an instance or task role and let the metadata service do the rotation.
Scope the policy to the tools the server actually exposes. This is the part people skip. If your server offers three tools — list buckets, read a specific config object, describe an RDS instance — the policy should grant exactly those actions on exactly those resource ARNs and nothing else. The IAM policy and the tool manifest should be readable side by side and tell the same story. When they diverge, the policy is the lie.
Push the conditions you actually have. Least privilege is about circumstances as much as actions. Use IAM condition keys: source VPC, source IP, the presence of a session tag, time windows where it makes sense. Layer a permissions boundary or an SCP so that even a misconfigured server policy can't grant beyond a hard ceiling. That ceiling is what saves you when a human inevitably over-grants in a hurry.
Separate read from write, and make write loud. Read tools can run unattended. Tools that mutate state, that terminate or delete or modify or put, should live behind a different role with a higher bar: tighter resource scope, narrower conditions, and ideally a human approval step or a change record the action references. The agent can prepare the change. It shouldn't be the sole signatory on the destructive one.
Scoped permissions are how you say yes fast
The objection I always get is that this is friction, and friction kills the thing that made agents worth adopting. I would argue the opposite, the same way I would about any guardrail. A tightly bounded server is one you can approve in an afternoon, because the worst case is knowable. The unscoped one sits in security review for three weeks while everyone tries to imagine what it could touch.
So make the safe path the easy path. Ship a baseline IAM module — a policy template, a roles-anywhere trust, a permissions boundary — that every new MCP server inherits, the way you template any landing-zone account. Generate the policy from the tool manifest where you can, so least privilege is the default output rather than a chore someone deprioritizes. And turn CloudTrail into a feedback loop: IAM Access Analyzer will tell you which granted permissions a server never used, and that unused set is your next pull request. Velocity comes from the paved road, not from skipping the guardrails.
Running security and platform together at a company serving more than 1,500 financial institutions, I have learned the boring lesson over and over. New technology rarely brings a new control. It brings an old control to a place we forgot to apply it. MCP is exactly that. The model gets the headlines. The IAM policy decides the outcome.
So pick one MCP server you have already deployed against AWS and pull its role. If you can't read the attached policy and recite, line by line, why each permission is there and what tool needs it, you don't have an agent problem. You have an identity you don't understand reaching into your cloud. Fix that one first, then make it the template for the next ten.