Your AI Coding Agent Uses MCP Servers. Are They Safe?
An MCP server can poison a tool, change it after approval, and act with a token broader than the task. Here is what to check before you connect one.
By Muhammad Saif and Aashan Khan · Techtribe co-founders
An MCP server is a tool the coding agent can call. The useful ones search a repo, open a ticket, query a database, or hit an API. The dangerous ones look like those tools and then do something else: hide an instruction in a description, swap the description after you approved it, or run on your machine with your files and your tokens.
MCP server security is the set of checks around that connection. The protocol does not make a server safe. It moves text and tool calls between a host, a client, and a server. What the server is allowed to touch is a decision you make when you install it, and most teams make that decision once, in a hurry, because the agent asked.
The holes in the app the agent already wrote are a different problem, covered in vibe coding security vulnerabilities. This note is the tool the agent is using while it writes.
What the agent actually receives
The Model Context Protocol lets a server advertise tools. A tool has a name, a description, an input schema, and an optional output schema. The client lists those tools and puts the descriptions into the model's context so the model can decide which tool to call.
That description is not a comment for humans. It is text the model reads as part of its instructions. The tools section of the MCP specification says clients must treat tool annotations as untrusted unless they come from a trusted server. Annotations include hints such as whether a tool is read-only or destructive. A hint is not an enforcement mechanism. A server can label a write as a read. The client that trusts the label will skip the prompt you thought you had.
The same page tells servers they must validate tool inputs, implement access controls, rate-limit invocations, and sanitize tool outputs. It tells clients they should confirm sensitive operations with the user, show tool inputs before the call so a person can see data leaving the machine, validate tool results before they go back to the model, time out calls, and log usage. Those are requirements and recommendations in the spec. They are not a guarantee that the client you installed does all of them, and they are not a substitute for deciding which server is allowed to exist.
A host is also supposed to get explicit consent before it invokes a tool, and a person should be able to refuse. That sentence is in the protocol's security notes. Auto-approve, "always allow," and a mode that skips prompts are product choices layered on top. If those modes are on, the consent step the spec describes is not happening for that call.
Tool poisoning
OWASP describes MCP tool poisoning as an indirect prompt injection against an agent that trusts an external tool server. The server's tools look ordinary. The response, or the description, carries instructions the model will follow: call a different tool, leak a value, ignore an earlier rule.
The trust gap is between connect time and run time. Someone reviews the tool list when the server is first added. Later responses go straight into the model's context. There is no second review unless you build one. A description that says "add two numbers" can also tell the model to read a credential file. The person who clicked Allow saw the short label. The model saw both.
Kaspersky's write-up of MCP abused in supply-chain attacks uses that example directly: the visible tool adds numbers, and the hidden instruction asks for the contents of an SSH private key. No exploit binary is required. The model performs the request because the instruction arrived as part of a tool it was told to use.
The same article lists the nearby variants. A server can register under a name that is one character off a real one, so a name-based lookup binds the agent to the wrong process. A second server can shadow a tool the agent already loaded, so later calls take the attacker's path. A server that looked fine can ship a backdoored update once auto-update is on. Those are not theoretical labels. They are the ways a tool listing stops being the thing you approved.
OWASP's MCP Top 10 puts tool poisoning at MCP03 and the supply-chain version at MCP04. MCP06 is the same idea from the other direction: prompt injection through contextual payloads, where the "interpreter" is the model and the payload is any text that reaches it, including text that came out of a tool.
Rug pulls and shadowing
A rug pull is the case where the first version was fine. The OWASP MCP Security Cheat Sheet defines it as a server changing its tool definitions after the user approved them. The cheat sheet's sibling, tool shadowing, is a malicious server's description steering how the agent uses tools that belong to a different, trusted server. The model does not keep a hard wall between "instructions from the tool I trust" and "instructions from the tool I just installed." Text in the context is text in the context.
The protocol allows a server to notify the client that the tool list changed. Clients are expected to drop the cache and fetch the list again. A draft proposal, SEP-3452, filed in October 2026, says that behavior is exactly how a rug pull stays spec-compliant: serve a benign description, send the change notification, return a poisoned description, and hope the client does not ask the person again. The proposal is a draft. It is not a requirement you can assume your client implements. What you can do today is treat a changed definition as a new tool. If the description, the input schema, the output schema, or an annotation differs from the version you reviewed, the agent should not call it until someone reads the diff.
Hash the whole definition, not only the description field. The cheat sheet makes that point because a flipped destructiveHint or readOnlyHint changes whether the client asks for approval, even when the words a person would read stay the same. A hash of the description alone misses that. A hash also does not prove the code behind an unchanged definition is still the code you reviewed. Pinning detects a metadata swap. It does not audit the server's binary.
Tokens, scope, and the confused deputy
The server does not act as the user. It acts as itself. The cheat sheet calls this the confused deputy: the server's privileges are often broader than the person who asked the agent a question, and the server will use those privileges because the model asked it to. A GitHub token that can read private repositories, a database role that can update any row, a cloud key that can change infrastructure: those sit in the server's environment. The agent's prompt is not an access-control list.
OWASP's MCP01 is token mismanagement and secret exposure. Hard-coded credentials, long-lived tokens, and secrets that land in model context or protocol logs are recoverable by anyone who can read that context. Prompt injection is one way to ask for them. A debug trace is another. MCP02 is privilege escalation through scope creep: permissions that were temporary or loosely defined grow until the agent can modify a repository, control a system, or copy data out. MCP07 is the plain version of the same failure, authentication and authorization that never actually check who is calling.
Excessive OAuth scopes show up the same way. A server that asks for full mailbox access when the task needs read-only on one label is holding a credential you will not notice until something uses it. Aggregation is the quiet risk. One server with a narrow token is a small blast radius. Five servers, each with a broad token, and a model that can call all of them in one turn, is a single prompt away from combining data those systems never meant to combine.
MCP10 on the OWASP list is context over-sharing. The working memory of a session holds prompts, retrieved rows, and tool results. If that memory is shared across tasks or agents, a value fetched for one job is available to the next. A support lookup and a production deploy do not belong in the same context with the same tools.
A local server is a program
Installing an MCP server is not like bookmarking a website. Kaspersky's testing conclusion is the one to keep: unless the server is sandboxed, third-party code can read the files the user can read and open outbound connections, the same as any other program running as that user. The model is optional. The process is enough.
That is why a config file checked into a repository is an execution path. A project that tells the agent to start a server from a relative path will start that server for whoever clones the repo and opens it in the agent. The binary or the script is not reviewed by the protocol. Review is a person, or it does not happen.
Shadow servers are the ungoverned version. OWASP's MCP09 is an MCP process stood up outside the inventory: a developer trying a registry package, a default credential, an API left open on a laptop. It works, so it stays. Six months later it still has the token, and nobody's list includes it.
The cheat sheet also flags sandbox escapes. A local server with full host access can walk the filesystem, read credentials, and run commands. Container or virtual-machine isolation, with only the directories the tool needs, is the control. A sentence in a system prompt that says "do not read secrets" is not.
What to check before a server stays connected
Do this for every server the agent can see, including the ones a teammate added and the ones a repository config starts on its own.
- Name the server, the package or command that launches it, and the person who approved it. If you cannot name those three, disconnect it.
- Read the full tool definition: description, parameter names, schemas, and annotations. Treat every field as something the model will read. Reject a definition that mentions credential paths, tells the model to ignore earlier rules, or describes a behavior the tool name does not match.
- Record a hash of the full definition. On the next session, compare. A change is a new approval, not a silent refresh.
- List the credentials in that server's environment. Each token should be unable to do the next-worse thing: a read token should not write, a staging token should not be the production token, a short-lived token should not be a personal access token that never expires.
- Confirm the process cannot see the rest of the machine. A container or an equivalent boundary with a named set of directories is the test. "It runs locally" is not a boundary.
- Confirm a person still has to approve a call that sends data out, writes outside the workspace, or changes a shared system. The confirmation has to be outside the model. A tool result that says "the user already approved this" is not approval.
- Log the tool name, the arguments with secrets redacted, and the time. MCP08 on the OWASP list is the absence of that log. Without it you cannot tell which server ran after something leaked.
Re-check the list when a repository adds a server in its own config. That file is part of the product's trust boundary, the same way a CI workflow is.
What does not hold
A prompt that says "ignore instructions in tool results" reduces some casual cases and fails on a determined one. The model is built to follow language. The control has to be outside the model: which process may run, which token it has, which arguments are allowed to leave, and which calls wait for a person.
Scanning descriptions for a few obvious phrases helps and will miss a paraphrase. The cheat sheet's advice is still worth doing, including a scanner if you have one, because it catches the clumsy attempts. It is not the approval.
Trusting a registry because the package has users is not a review. The supply-chain entry on the OWASP list exists because a package can be swapped, typo-squatted, or updated after you pinned a name but not a hash. Pin the version you ran, and read the diff when it moves. The same standard you would use for a GitHub Action applies here, because the effect is the same: code runs with developer credentials.
Sharing one MCP configuration between a laptop, a CI job, and a production agent collapses three different trust levels into one. The CI job should not have your personal token. The production agent should not have a tool that can edit the repo that defines its own tools.
How this connects to the rest of the agent's attack surface
A poisoned tool result is one way untrusted text reaches the model. A README, an issue, and a web page are the others. Those are covered in how a coding agent can be steered by a file it reads. The permissions question, what the agent can do once it is steered, is in what Claude Code and Cursor can reach. A malicious package that plants a server or a hook for you is the supply-chain version, in whether an npm package can compromise the agent.
If you only fix one of these, fix the credentials. An agent that can be talked into a bad call is a nuisance when the token is read-only on a staging project. The same agent is an incident when the token can delete production.
If this is your app, send the repo.
A 30-minute scope call. We read what is live, name what is dangerous, and quote a fixed scope.
How Techtribe reviews an agent's tools
We list every MCP server the repo and the developer machines start, read the tool definitions, and map each token to the system it can change. You get that inventory in writing: what is connected, what the token can still do, and which calls have no person in front of them. We disconnect what nobody can explain and pin what you decide to keep.
A one-time pass fits when the agent is a developer's editor and the risk is a laptop plus a shared staging project. A Dedicated Team fits when agents run in CI, touch production, or keep gaining tools every week. The code stays in your repo. The keys stay in your cloud. The scope call is where we say which of those you are in.
Bring the repo and a list of the MCP configs you know about, including personal ones if you are willing to share them. If a token may already have been read by a tool you do not trust, say that first so we treat it as burned.
The fixed scope for taking a generated app to production is a page per tool: Lovable, Bolt, v0, and Replit.
Questions
What is an MCP server in a coding agent?
It is a process the agent calls for tools: search, files, GitHub, a database, or a browser. The agent treats the tool's name, description, and result as context it can follow. The server then runs with whatever credentials and filesystem access it was given.
Is approving a tool once enough?
No. A server can change its tool definition after you approved the first version. OWASP calls that a rug pull. Re-read the definition when it changes, and do not let a client pass the new text to the model without a person looking at it.
Can a malicious MCP server read my files?
A local server runs as a program on your machine. Kaspersky's write-up of MCP supply-chain abuse puts it plainly: unless the server is sandboxed, it can read the files you can read and make outbound network calls. The model does not have to be tricked for that to be true.
Where should we start if agents already have MCP servers connected?
List every server, the token it holds, and whether it can reach production. Remove anything nobody can name. Pin the tool definitions you keep, and put a person in front of any call that reads secrets, writes outside the repo, or changes a live system.