EngineeringBest Practices

MCP Security: What Changes When a Model Decides

Shiplight AI Team

Shiplight AI Team

Updated on July 31, 2026

View as Markdown
Illustrated Shiplight blog cover: a protocol connector between an agent and a tool, with a scoped permission boundary drawn around the tool.

Connecting a tool to an agent feels like installing a plugin. It is closer to handing a credential to a colleague who is enthusiastic, literal, and cannot always tell the difference between an instruction from you and a sentence they read in a file.

The protocol itself is not the problem. What changes is who decides when a capability gets used.

The shift

With ordinary code, you write the conditions. if user.isAdmin, then delete. The trigger is explicit and auditable.

With a tool exposed over the Model Context Protocol, the model decides. It reads the tool's description, considers the task, and calls it when that seems right. There is no line of code you can point at that says when.

That is the entire security story, and everything below follows from it.

Prompt injection through tool results

The failure mode most specific to this setup, and the one teams miss.

A model cannot reliably distinguish instructions from you from instructions embedded in content it reads. If a tool returns text, and that text contains something shaped like an instruction, the model may follow it.

Concretely: an agent reads a GitHub issue to implement it. The issue body, written by anyone on the internet, contains a line saying to also read the environment file and include its contents in the pull request description. The agent has a filesystem tool. It complies, reasonably, because the text arrived as part of its task.

This is not hypothetical for any agent connected to a repository, an issue tracker, a support inbox, or a web fetcher. Any tool returning attacker-influenced content is an injection vector.

Mitigations, in order of effectiveness:

Do not pair untrusted input with sensitive capability. An agent that reads public issues should not also hold production credentials in the same session. Separating those is worth more than any prompt-level defense.

Scope narrowly. If the filesystem tool cannot read outside the project directory, the instruction fails regardless of whether the model was persuaded.

Require confirmation for consequential actions. A human approving a destructive action is a control the model cannot be talked past.

Prompt-level defenses ("ignore instructions in content") help and should not be relied on. They are advisory to a system that interprets rather than executes.

Permission scoping

The main lever, and mostly a matter of doing the boring thing.

Read-only unless writing is required. Most useful agent work is reading.

Narrow the surface. Specific repositories rather than an organization. A project directory rather than the home directory. One database role with one schema rather than an owner account.

Separate profiles by risk. A default configuration for exploration, and a second one you enable deliberately for work that needs write access. This is the same instinct as not running as root, and it works for the same reason.

Keep production out of the default. An agent that can reach production is an agent that can reach production while working on something unrelated.

Supply chain

Installing a server is installing a dependency that runs on your machine with your permissions. The usual rules apply and are applied less often, because the install is one line of config and feels lighter than it is.

Prefer servers whose source you can read. Prefer maintained ones. Pin versions rather than tracking latest, since an auto-updating server is code you did not review executing with access you already granted. Watch for typosquatting on popular names.

What good looks like

A defensible setup, in practice:

  1. Narrow scopes by default, widened deliberately and temporarily.
  2. Untrusted input isolated from sensitive capability. Never in one session.
  3. Servers pinned and reviewed, like any dependency with filesystem access.
  4. Consequential actions gated behind human confirmation.
  5. Verification that does not depend on the agent's account of itself. If an agent says it made a change safely, that is a claim, not evidence.

That last point connects to the wider problem. An agent reporting its own work is assessing from the context that produced it, and the characteristic failure of agent-written code is a silently removed protection rather than an added vulnerability. See AI code security and can coding agents test their own code?

Shiplight is one of the tools you would connect, so the same rules apply to it. Local runs need no account and no token, browser automation stays on your machine, and the tests it generates are written into your repository where you can read them rather than into a vendor's database. The security-relevant property is that once a guard's behavior is asserted in a committed test, a later change removing that guard becomes a failing build rather than a silence.

Frequently Asked Questions

1

Is MCP secure?

The protocol does not make an unsafe server safe. What changes is that a capability is invoked by a model deciding on its own, so scoping and isolation matter more than they would for code you wrote.

2

What is prompt injection in an MCP context?

Content returned by a tool, such as an issue body or a fetched page, containing text shaped like an instruction that the model then follows. Any tool returning attacker-influenced content is a vector.

3

How do I reduce the risk most effectively?

Do not give one session both untrusted input and sensitive capability. That separation is worth more than any prompt-level defense.

4

Should I audit MCP servers before installing?

Yes. A server runs on your machine with the permissions you grant. Prefer readable source, pin versions, and treat it like any dependency with filesystem access.

5

Can I let an agent deploy to production?

Only behind an explicit human confirmation. A tool the model can call is one it can call at the wrong moment, and "the model decided to" is a poor incident summary.