MCP Server Security: The Trust Boundary Most Teams Haven't Thought Through
By Renn Calloway · July 29, 2026
Category: attack-surface-threat-modeling
MCP server security is the trust boundary most teams have not thought through - here is how to model it before an attacker does.
Key takeaways
The problem MCP servers run as separate processes with their own credentials, but teams treat them as transparent client extensions.
Core insight Limiting tool scope, rotating credentials, and logging every call are the controls that actually close the exposure.
Practical outcome Classify each MCP server by blast radius and apply isolation proportional to what a compromise would enable.
We deployed an MCP server in a staging environment last year that had read access to our production customer database. It was supposed to be temporary. It ran for four months before anyone noticed it was still active, still connected, still callable by any Claude instance that had been configured to reach it. The credentials it held were valid. The data it could return included PII. Nobody had attacked it - but if someone had, we would not have known until the damage was visible in the data.
MCP server security is the trust boundary most teams have not thought through, and the gap is not technical so much as conceptual. Teams model their AI pipelines as client-side concerns: how does the agent behave, what can it prompt, what tools can it call. The server sitting on the other end of those tool calls gets far less scrutiny.
Understanding MCP Server Trust Boundaries
An MCP server is a process that exposes tools and resources to a client - Claude, an agent, or another application - over a defined protocol. It is not a library embedded in your application. It is a separate running process with its own execution context, its own credentials, and its own access to whatever systems it was configured to reach. When Claude calls a tool, it is making a request to that process. What that process does with the request, what it can access, and what it can return are determined by how it was built and deployed - not by the client's trust model.
The core problem is that teams treat MCP servers as transparent extensions of the client application. They are not. They are separate processes with separate privilege contexts. A Claude instance might be sandboxed, carefully prompted, and tightly scoped - but if it can call an MCP server that holds admin credentials to a production database, the sandbox matters much less than the credential the server is holding.
Most teams have modeled API authentication, database access controls, and agent prompt injection. Almost none have modeled what happens when an MCP server itself becomes the attack surface - when an attacker reaches it directly, or when a compromised client drives it toward actions the designer did not intend. That gap is where the real exposure lives.
Why MCP Servers Become Trust Liabilities
MCP servers are designed for convenience and capability expansion. They run with the permissions of the user or service account that started them. They accept connections from clients they were configured to trust. They execute whatever tool calls arrive, because that is their job. None of this is wrong - it is exactly what makes them useful. But it is also what makes them liabilities when the threat model is incomplete.
The incentive misalignment is structural. Developers build MCP servers to be useful: broad access, persistent connections, minimal friction. They deploy them in environments where the threat model was never formally stated. The security review, if there is one, focuses on the client application. The MCP server is infrastructure.
Here is a failure mode we have seen more than once. A team deploys an MCP server that connects to their production database using a service account with broad SELECT permissions - good enough for the intended use case, which is answering internal queries. The server is called by a Claude instance that is also accessible to external users through a chat interface. An attacker crafts a prompt that causes Claude to call the MCP server's query tool with a carefully constructed parameter. The server executes the query. The attacker receives customer records.
This is not a flaw in MCP itself. MCP servers have no inherent reason to distrust their clients. The problem is that the team modeled the trust boundary at the Claude prompt level and did not model it at the server level. The server trusted everything that reached it, because it was designed to.
Strategy 1: Inventory and Classify Your MCP Servers
Most teams do not have a complete list of MCP servers running in their environment. They exist in development environments, in agent deployments, in side projects that got productionized without a formal review. The first step is knowing what you have.
For each MCP server in your environment, record: what it does, what credentials or secrets it holds, who or what can call it, what data it can access or modify, and what the impact would be if it were compromised. That last item is the one most teams skip. It is also the most important.
Classify servers by risk. A read-only MCP server that queries a public API is lower risk than one that can execute arbitrary SQL or modify production infrastructure. A server that holds a short-lived token scoped to a single resource is lower risk than one holding a long-lived credential with broad permissions.
Concrete example: you have an MCP server that calls your internal Slack API to post messages. It holds a bot token with channel:write permissions. It is called by a Claude instance that handles internal support requests. That server can send messages as your bot to any channel it has access to. If it is compromised, an attacker can send messages to your entire organization. That is not catastrophic, but it is not trivial either - and it belongs in your inventory with a clear risk classification.
Strategy 2: Implement Credential Isolation and Rotation
An MCP server should hold the minimum credentials necessary to do its job, and those credentials should be rotated frequently and independently of the client application. This sounds obvious. In practice, most MCP servers we have reviewed hold long-lived credentials - API keys, database passwords, service account tokens - that were set up once and never touched again.
The mechanism: instead of embedding a long-lived API key or database password in the MCP server's configuration, use a credential provider (AWS Secrets Manager, HashiCorp Vault, or similar) to inject short-lived credentials at runtime. The MCP server requests a credential when it needs one, uses it, and the credential expires. An attacker who extracts the credential from memory has a narrow window to use it.
Walk through the scenario: an attacker compromises an MCP server that holds a database credential. If the credential is long-lived and valid for months, the attacker can exfiltrate data over weeks without detection. If the credential is rotated every hour, the attacker has at most an hour's window - and if your monitoring is working, you will see the anomalous access before that window closes.
The operational cost is real. Credential rotation requires infrastructure - a secrets manager, monitoring, alerting when rotation fails. It is not free. But the cost of a long-lived credential being compromised is not free either, and it is typically much higher.
Strategy 3: Enforce Least-Privilege Access at the MCP Server Level
An MCP server should expose only the tools and resources that a specific client actually needs. If a Claude instance only needs to read from a database, the MCP server it calls should not expose a tool that can write. This is not a novel security principle, but it is one that gets consistently skipped in MCP deployments.
The implementation matters. Instead of a single execute_query tool that accepts arbitrary SQL, define separate tools: get_customer_by_id, list_orders_for_account, search_products. Each tool does exactly one thing and accepts only the parameters it needs. The attack surface is the set of things the server can do. Narrow tools mean a narrower attack surface.
Here is the failure mode: a team builds an MCP server that exposes a query_database tool accepting a SQL string. An attacker injects a prompt that causes Claude to call this tool with SELECT * FROM users followed by a UNION statement. The server executes it. Granular tools would have prevented this - not because the tool validates the input (though it should), but because there is no tool that accepts raw SQL.
The design cost is real: granular tools require more upfront work and more code. But they are also more maintainable and more auditable. The cost is paid once, at design time. The security benefit is continuous.
Strategy 4: Add Observability and Alerting to MCP Server Calls
If an MCP server is compromised, you need to know it happened. Most teams have no visibility into MCP server calls. They do not log which tools were called, with what parameters, by which client, or what was returned. The server runs. Things happen. No record exists.
For each MCP server call, log: the timestamp, the tool name, the input parameters (sanitized if they contain sensitive data), the output or a hash of it, the client identifier, and the duration. This is the minimum. From this log, you can reconstruct what happened, when, and whether the pattern matches normal operation.
Detection scenario: an attacker compromises an MCP server and uses it to exfiltrate customer data. They call a tool repeatedly with different customer IDs. A normal call pattern for that tool might be three to five calls per session. Fifty calls in four minutes is anomalous. If you have a log and an alert threshold, you catch it. If you have neither, you find out when a customer reports that their data was exposed.
Address the false positive concern directly: yes, legitimate clients might trigger alerts in high-volume environments. That is fine. Set thresholds based on observed baselines, not guesses. The goal is not zero false positives - it is a signal-to-noise ratio that makes genuine anomalies visible. We have run through this calibration on several deployments and found that even rough baseline thresholds catch the most obvious attack patterns.
Strategy 5: Validate and Sanitize MCP Server Inputs
An MCP server receives input from a client. That client might be Claude, an agent, or an external application. The input might contain injected content - a prompt that caused the client to send parameters the designer never intended. The server has no way to know whether the input was generated by a legitimate user request or an attacker's injection. It needs to validate regardless.
For each tool, define a schema that specifies what inputs are valid. Use a schema validation library - JSON Schema, Pydantic, or similar - to enforce that schema before the tool executes. A get_customer_by_id tool should accept exactly one parameter: a customer ID that matches a specific format. Anything else should be rejected before it reaches the database.
Concrete scenario: an MCP server exposes a tool called execute_command that takes a command parameter. Without validation, an attacker injects a prompt that causes Claude to call this tool with rm -rf / as the command value. With schema validation, the tool rejects any command that is not in an explicit allowlist. The attack fails at the validation layer, not at the execution layer.
Validation is not a complete defense. A sophisticated attacker who understands the schema can craft inputs that pass validation and still cause harm. But it is a necessary baseline that eliminates the most obvious injection paths and forces attackers to work harder. We treat it as a floor, not a ceiling.
Strategy 6: Isolate MCP Servers by Risk Level and Client
Not all MCP servers should be accessible to all clients. A high-risk server - one that can modify production data or call external APIs with write permissions - should only be accessible to specific, authenticated clients with a documented reason to reach it. A low-risk server can have broader access. This is network segmentation applied to the MCP layer.
Deploy MCP servers in separate processes or containers. Use network controls - firewalls, VPCs, security groups - to restrict which clients can reach which servers. Require authentication at the MCP layer: the server should verify that the client calling it is authorized to do so, not just assume that anything reaching the port is legitimate.
Scenario: a team has two MCP servers - one that reads from a public API (low risk) and one that can modify production infrastructure (high risk). They deploy both accessible to the same Claude instance. An attacker compromises the Claude instance and can now reach the high-risk server. If the servers were isolated - the high-risk server accessible only to a separate, tightly controlled agent with its own authentication - the compromise of the general-purpose Claude instance does not give the attacker access to production infrastructure.
Isolation requires infrastructure: separate processes, network configuration, authentication systems. It is more complex than running everything on one host. The trade-off is worth it for high-risk servers. For low-risk servers, the overhead may exceed the benefit - and that is a legitimate design decision, as long as it is a conscious one.
Strategy 7: Design MCP Servers for Auditability and Rollback
If an MCP server is compromised and used to modify data, you need to be able to audit what changed and reverse it. This requires that the server logs not just that a tool was called, but what state existed before the call and what state exists after. Without this, you know something went wrong but not what to fix.
For any tool that modifies state - writes to a database, updates a file, calls an external API with side effects - log the before-and-after state. Use transaction IDs that correlate the tool call log with the modification log. If you need to roll back a set of changes made during a compromise window, the transaction IDs tell you exactly which changes to revert.
Scenario: an attacker compromises an MCP server and uses it to modify customer records. The server logs each modification: transaction_id: abc123, tool: update_customer_record, before: {email: user@example.com}, after: {email: attacker@example.com}, timestamp: .... When the incident is detected, the team queries the log for all transactions in the compromise window and reverses them. Without this log, the team has to identify affected records by comparing backups - a much slower and less reliable process.
Logging before-and-after state adds overhead. For high-volume operations, this can be significant. Sampling strategies - logging every Nth operation, or logging only operations that modify sensitive fields - can reduce the cost while preserving most of the auditability benefit. The key decision is making this trade-off explicitly rather than defaulting to no logging at all.
When to Seek Support
Escalate to security specialists if an MCP server holds credentials with broad permissions - admin access to a database, write access to production infrastructure, or tokens that can act on behalf of users. Broad credentials in an unaudited server is the combination that produces the worst incidents. If you cannot answer the question "what would an attacker be able to do if this server were compromised" with confidence, that is a signal to get help before deployment rather than after.
Security specialists can help with threat modeling specific to your MCP architecture, designing credential isolation and rotation systems, setting up observability infrastructure, and reviewing tool definitions for least-privilege compliance. These are not exotic skills, but they require time and focus that development teams rarely have during the build phase.
If you are unsure whether to escalate, use this decision framework: if this MCP server were fully compromised, what is the worst realistic outcome? If the answer involves data exfiltration at scale, modification of production systems, or lateral movement to other internal services, escalate. If the answer is "an attacker could read public API responses," you probably have sufficient internal controls. The threshold is proportional to the blast radius, not to the probability of compromise.
We are still working through some of this ourselves. Trust boundary modeling across multi-tenant agent deployments - where the same MCP server is called by agents running in different customer contexts - is an open problem for us. The strategies above apply, but the multi-tenant case introduces complexity around credential isolation and call attribution that we have not fully resolved. We will write about that when we have something more concrete to say.
Frequently Asked Questions
Do I need to worry about MCP server security if I am only using Claude in a development environment?
It depends on what the MCP server can access. If it only reads from a local file or queries a public API with no authentication, the risk is low. If it holds credentials to a shared database, a production API, or any system that other people depend on, the risk is real - even in a development environment. Development environments are frequently less monitored and less restricted than production, which makes them attractive targets for lateral movement. The right question is not whether you are in development or production, but what an attacker could reach if the server were compromised.
Can I just use a VPN or firewall to protect my MCP servers?
Network segmentation is necessary but not sufficient. It prevents external attackers from reaching your MCP servers directly, but it does not protect against a compromised client driving the server toward unintended actions - which is the most common attack path in practice. It also does not protect against an insider threat or a compromised developer machine that is already inside the network perimeter. Use network controls as one layer, but do not treat them as a complete defense. You still need credential isolation, input validation, and observability.
What is the difference between MCP server security and API security?
They are similar in many ways - both require authentication, authorization, input validation, logging, and credential management. The key difference is the client context. An API is typically called by code you wrote and control. An MCP server is called by an LLM that may be generating tool call parameters based on user input, injected content, or its own reasoning. This means the input space is much harder to bound. A human-written API client sends predictable, validated requests. An LLM-driven client might send anything the model decides to send. This shifts the validation burden and makes anomaly detection more important.
How do I know if an MCP server has been compromised?
Look for unusual patterns in the logs: more calls than normal, calls with unusual parameters, calls at unusual times, or calls to tools that are rarely used. If you do not have logs, you will not know until damage is visible - a customer complaint, a data mismatch, or an external notification. The single most important step you can take toward detecting compromise is implementing call logging before an incident occurs. After the fact, you can sometimes reconstruct what happened from database logs or external API audit trails, but that process is slow and incomplete compared to having your own log.
How often should I rotate credentials held by an MCP server?
It depends on the sensitivity of the credential and the infrastructure you have in place. For credentials with broad permissions - database admin accounts, cloud provider tokens - rotate as frequently as your secrets management infrastructure allows, ideally every few hours to a day. For lower-privilege credentials, longer rotation windows may be acceptable. The key principle is that the rotation window sets the upper bound on how long a compromised credential is useful to an attacker. Shorter windows are better. The practical constraint is your ability to rotate without breaking the server's availability, which is why investing in a secrets manager early matters.