MCP Server Security Checklist
MCP server security comes down to a short list of controls: a pinned, known source, tool descriptions you have read, tokens that are least-privilege and checked for audience, a sandbox for anything local, and a person approving destructive calls. Pick whether you are building, adopting or connecting to a remote server, and stdio or HTTP, and this checklist shows only the checks that apply, each with how to verify it. You get a score, a verdict on whether the server is safe to use, and a fix list. Everything runs in your browser.
Someone else’s server that you install and run. 17 checks apply to this combination. Answer Yes, Partly, No or N/A. A critical item answered No is a blocker, whatever the score. Nothing you enter leaves your browser.
Source and supply chain
Where the server comes from and whether it can change under you.
- HighThe server is on an approved inventory with a named owner and a review date.
Why: Servers that people add to their IDE or assistant on their own run outside review, logging and patching. OWASP calls these shadow MCP servers.
How to check: List every MCP server configured in your clients (IDE, desktop assistant, agent platform) and match each one to an owner, an approval record and the data it can reach.
- HighYou know who publishes the server and where its code or service comes from.
Why: Anyone can publish an MCP server, and it runs with whatever access you give it. A compromised or lookalike package can change what your agent does.
How to check: Check the source repository, the maintainers, recent release activity and open security issues. Confirm the package name you install matches the repository exactly, so a typosquat cannot slip in.
- CriticalThe exact version is pinned, so a new release cannot start without a review.
Why: A config that launches a package without a version can pick up whatever was published most recently. A server can behave well when you review it and change later (a rug pull), and a hijacked maintainer account can ship code that runs on your next start.
How to check: Pin an exact version (package@1.4.2) or a container image digest (image@sha256:…), keep a lockfile, and update on purpose after re-reviewing the release. MCP Guard flags unpinned installs in a config.
- CriticalYou read the full launch command before adding the server.
Why: A stdio server is a program your client starts with your own privileges. The MCP Security Best Practices list a malicious start-up command in a client configuration as an attack, and require clients that offer one-click setup to show the exact command, untruncated, and ask for approval.
How to check: Read the command and its arguments line by line. Red flags: a pipe into a shell (curl … | sh), sudo, extra commands chained with && or ;, and paths outside what the server needs. Paste the config into MCP Guard for a second look.
Tool definitions and outputs
Tool poisoning, rug pulls and injected content.
- CriticalYou have read every tool description and parameter schema for hidden instructions.
Why: The model reads tool descriptions as trusted context, and users rarely see the full text. Tool poisoning hides instructions there, for example to read a key file and pass it in a parameter, or to change how another server’s tool is used.
How to check: List the tools (your client’s tool list, or the official MCP Inspector) and read each description and schema in full. Red flags: text addressed to the model, “before using any other tool”, references to other servers’ tools, requests for files, keys or chat history, very long descriptions, invisible characters, and parameters with no clear purpose.
- HighTool definitions were recorded at approval, and any change triggers a new review.
Why: MCP lets a server change its tool list while running and announce it with a notifications/tools/list_changed message. A remote server can change on the operator’s side with no update on yours. A rug pull uses exactly this: approved first, changed later.
How to check: Save a copy or hash of the tools/list response when you approve the server. Compare it after every version change and on a schedule. Treat a new tool or a changed description as a new approval.
- HighYou do not rely on a tool’s annotations alone to decide it is safe.
Why: Annotations such as readOnlyHint and destructiveHint are hints. The specification says clients must treat them as untrusted unless they come from trusted servers, so a malicious server can label a destructive tool read-only.
How to check: Decide approval settings from what the tool really does (its code or documented behaviour), not from its label.
- HighContent returned by tools is treated as untrusted data, not as instructions.
Why: Tools return web pages, tickets, emails and files that anyone can write. Instructions hidden in that content reach the model as indirect prompt injection. The specification says servers must sanitize tool outputs and clients should validate tool results before passing them to the model.
How to check: Find the tools that return third-party content (fetch, search, issue trackers, email). Do not combine them in one session with tools that can send data out or change things unless each of those calls needs approval.
Network exposure
DNS rebinding, listening address and outbound requests.
- HighOutbound requests are limited: tools cannot reach internal addresses or cloud metadata endpoints.
Why: A tool that fetches URLs chosen by the model can be pointed at internal services or the cloud metadata endpoint and leak credentials (server-side request forgery). The MCP best practices recommend blocking private, loopback and link-local ranges for OAuth-related fetches and using an egress proxy; the same controls protect any URL-fetching tool.
How to check: If the server has a fetch, browse or webhook tool, run it where it cannot reach internal networks. Mark N/A if it makes no outbound requests chosen by the model.
Least privilege, secrets and sandboxing
What the server can reach if something goes wrong.
- CriticalThe server uses dedicated, least-privilege credentials, not your personal admin token.
Why: The server can do anything its credentials allow, and the model decides which tools to call. Permissions that grow over time are OWASP MCP02; an over-scoped token turns one injected instruction into repository changes or data exfiltration.
How to check: Create a token just for this server with the narrowest scope (read-only, one repository, one project), an expiry and a name that makes it easy to find and revoke.
- CriticalSecrets are not hard-coded, not in shared config files and never returned to the model.
Why: Hard-coded credentials, long-lived tokens and secrets left in model context or logs are the first item in the OWASP MCP Top 10. For stdio servers the specification says credentials come from the environment, not the OAuth flow, so the config is where keys leak.
How to check: Keep API keys out of MCP config files that are committed or synced; use environment variables or the client’s secret store, and rotate any key that was ever pasted in plain text. MCP Guard flags plaintext secrets in a config.
- CriticalThe server runs in a sandbox with limited file, network and process access.
Why: A local server runs with the privileges of the client that started it: your files, SSH keys and cloud credentials. The MCP best practices say local server commands should run in a sandbox with minimal default privileges, with more access granted only explicitly.
How to check: Run it in a container or OS sandbox as a non-root user. Mount only the directories it needs (read-only where possible), not your home directory or the Docker socket, and give it no network if its tools do not need one.
- HighFile access is limited to named directories, enforced by the server or the sandbox.
Why: MCP roots tell a server which directories the client considers relevant, but the specification says they are guidance, not access control, and the protocol does not enforce them. Roots are also deprecated as of the 2026-07-28 revision. Only the server or the sandbox can stop a path outside the project.
How to check: Pass only project directories in the server’s arguments or mounts, never your home directory or the file system root. Mark N/A if the server has no file tools.
Input validation and execution
What happens to the arguments the model fills in.
- CriticalNo tool builds shell commands, SQL or code from model input.
Why: Command injection happens when an agent runs commands, scripts or queries assembled from untrusted input: the user’s prompt, retrieved content or a third-party API.
How to check: Search the code for shell execution fed by tool arguments: exec, spawn with shell: true, os.system, subprocess with shell=True, eval, and SQL built by string concatenation. The MCP Security Linter flags dangerous capabilities in a tool manifest.
Human approval, logging and limits
Who approves risky calls and whether you can investigate later.
- CriticalDestructive or sensitive tool calls need a person to approve each one.
Why: The Tools specification says there should always be a human in the loop who can deny tool calls, and that clients should ask for confirmation on sensitive operations and show tool inputs first. Giving an agent more autonomy than the task needs is OWASP LLM06 Excessive Agency.
How to check: Turn off “always allow” for any tool that writes, deletes, sends, pays or runs code. Keep auto-approve only for read-only tools you have reviewed, and read the arguments before you approve.
- HighEvery tool call is logged: who, which tool, the arguments (secrets redacted) and the result.
Why: Without telemetry you cannot investigate what an agent did (OWASP MCP08). The specification says clients should log tool usage for audit purposes.
How to check: Turn on tool-call logging in your client or MCP gateway, send it to central logging, and check you can answer: which tools ran yesterday, for whom, with what arguments.
- StandardTool calls are rate limited and time out.
Why: The specification says servers must rate limit tool invocations and clients should set timeouts on tool calls. An agent stuck in a loop or an abusive client can otherwise burn upstream quotas and money.
How to check: Check your client or gateway sets a timeout per tool call, and that the server or vendor documents its rate limits.
What this tool is
- 28 MCP server security checks in seven areas: supply chain, tool definitions, authentication and authorization, network exposure, least privilege and sandboxing, input validation, and human approval and logging.
- Pick your situation (building a custom or private server, adopting an open-source or third-party one, or connecting to a remote hosted one) and the transport (stdio or Streamable HTTP). Only the checks that apply are shown.
- Each check says why it matters, how to check it, and the MCP specification page or OWASP entry it comes from.
- Get a weighted score out of 100, a verdict on whether the server is safe to use (or ready to ship), a list of blockers and an ordered fix list.
- Copy it as a plain-text report for a security review or a pull request. Everything runs in your browser; nothing is uploaded and the server is never contacted.
The full MCP server security checklist
All 28 checks, grouped by area. Each line shows its severity and which situations it applies to. A critical check answered “no” blocks the verdict whatever the score, because one missing control of that kind is enough to lose data or credentials.
Source and supply chain
- The server is on an approved inventory with a named owner and a review date. (High; all server types) Servers that people add to their IDE or assistant on their own run outside review, logging and patching. OWASP calls these shadow MCP servers.
- You know who publishes the server and where its code or service comes from. (High; open source / third party, remote hosted) Anyone can publish an MCP server, and it runs with whatever access you give it. A compromised or lookalike package can change what your agent does.
- The exact version is pinned, so a new release cannot start without a review. (Critical; open source / third party) A config that launches a package without a version can pick up whatever was published most recently. A server can behave well when you review it and change later (a rug pull), and a hijacked maintainer account can ship code that runs on your next start.
- Dependencies are locked, scanned and updated on purpose. (High; custom / private) A compromised dependency can change what your server does or add a backdoor, and every user of your server inherits it.
- You read the full launch command before adding the server. (Critical; open source / third party, stdio only) A stdio server is a program your client starts with your own privileges. The MCP Security Best Practices list a malicious start-up command in a client configuration as an attack, and require clients that offer one-click setup to show the exact command, untruncated, and ask for approval.
Tool definitions and outputs
- You have read every tool description and parameter schema for hidden instructions. (Critical; all server types) The model reads tool descriptions as trusted context, and users rarely see the full text. Tool poisoning hides instructions there, for example to read a key file and pass it in a parameter, or to change how another server’s tool is used.
- Tool definitions were recorded at approval, and any change triggers a new review. (High; open source / third party, remote hosted) MCP lets a server change its tool list while running and announce it with a notifications/tools/list_changed message. A remote server can change on the operator’s side with no update on yours. A rug pull uses exactly this: approved first, changed later.
- You do not rely on a tool’s annotations alone to decide it is safe. (High; all server types) Annotations such as readOnlyHint and destructiveHint are hints. The specification says clients must treat them as untrusted unless they come from trusted servers, so a malicious server can label a destructive tool read-only.
- Content returned by tools is treated as untrusted data, not as instructions. (High; all server types) Tools return web pages, tickets, emails and files that anyone can write. Instructions hidden in that content reach the model as indirect prompt injection. The specification says servers must sanitize tool outputs and clients should validate tool results before passing them to the model.
Authentication and authorization
- The server refuses requests that carry no valid credentials. (Critical; all server types, HTTP only) An HTTP server can be reached by anything that can reach its URL or port. The Streamable HTTP transport says servers should authenticate all connections. Authorization is optional in the specification, but an HTTP server that supports it should follow it.
- The server only accepts tokens issued for it, and never passes your token through to another API. (Critical; all server types, HTTP only) The specification requires servers to validate that a token was issued for them as the intended audience (RFC 8707) and forbids token passthrough. Without it, a token stolen from one service works on another, controls that depend on the audience are bypassed, and upstream logs show the wrong caller.
- Tokens travel only over HTTPS, in the Authorization header, never in the URL. (High; all server types, HTTP only) The specification requires the access token in an Authorization: Bearer header on every request and forbids it in the URL query string, where it ends up in logs, history and proxies. Authorization server endpoints must use HTTPS, and redirect URIs must be localhost or HTTPS.
- You grant only the OAuth scopes the job needs. (High; all server types, HTTP only) A stolen token with broad scopes opens every tool at once. The MCP Security Best Practices recommend a minimal initial scope set and step-up requests when a privileged operation is first tried, and list wildcard or catch-all scopes as a common mistake.
- If the server fronts a third-party API with one static client ID, it asks for consent per client. (Critical; custom / private, open source / third party, HTTP only) This is the confused deputy problem. A proxy server that uses one static client ID with a third-party authorization server can let a malicious client get an authorization code without the user approving that client, because the third party remembers the earlier consent. The best practices say such servers must keep consent per client and show their own consent page.
- Session IDs and state handles are random, bound to the user and never treated as authentication. (High; custom / private, HTTP only) The best practices describe state handle hijacking: if a server accepts a guessed or leaked handle (a cart or workflow ID) without checking it belongs to the caller, the attacker works on another user’s state. Servers must verify every request and must not treat holding a handle as proof of identity.
Network exposure
- The server validates the Origin header and rejects unknown origins with 403. (Critical; custom / private, open source / third party, HTTP only) The Streamable HTTP transport requires servers to validate the Origin header on all incoming connections. Without it, DNS rebinding lets a website open in your browser talk to a server running on localhost.
- When it runs on a workstation, it listens on 127.0.0.1 only, not on every interface. (Critical; custom / private, open source / third party, HTTP only) The specification says local servers should bind to localhost rather than 0.0.0.0. Otherwise anyone on the same network, such as office or café Wi-Fi, can reach it. The best practices add that a local server should prefer stdio, or require a token or a restricted socket if it uses HTTP.
- Outbound requests are limited: tools cannot reach internal addresses or cloud metadata endpoints. (High; custom / private, open source / third party) A tool that fetches URLs chosen by the model can be pointed at internal services or the cloud metadata endpoint and leak credentials (server-side request forgery). The MCP best practices recommend blocking private, loopback and link-local ranges for OAuth-related fetches and using an egress proxy; the same controls protect any URL-fetching tool.
Least privilege, secrets and sandboxing
- The server uses dedicated, least-privilege credentials, not your personal admin token. (Critical; all server types) The server can do anything its credentials allow, and the model decides which tools to call. Permissions that grow over time are OWASP MCP02; an over-scoped token turns one injected instruction into repository changes or data exfiltration.
- Secrets are not hard-coded, not in shared config files and never returned to the model. (Critical; all server types) Hard-coded credentials, long-lived tokens and secrets left in model context or logs are the first item in the OWASP MCP Top 10. For stdio servers the specification says credentials come from the environment, not the OAuth flow, so the config is where keys leak.
- The server runs in a sandbox with limited file, network and process access. (Critical; custom / private, open source / third party) A local server runs with the privileges of the client that started it: your files, SSH keys and cloud credentials. The MCP best practices say local server commands should run in a sandbox with minimal default privileges, with more access granted only explicitly.
- File access is limited to named directories, enforced by the server or the sandbox. (High; custom / private, open source / third party) MCP roots tell a server which directories the client considers relevant, but the specification says they are guidance, not access control, and the protocol does not enforce them. Roots are also deprecated as of the 2026-07-28 revision. Only the server or the sandbox can stop a path outside the project.
Input validation and execution
- Every tool input is validated on the server against its schema and your business rules. (Critical; custom / private) The specification says servers must validate all tool inputs, implement access controls, rate limit tool calls and sanitize outputs. The model fills in arguments from content an attacker may control.
- No tool builds shell commands, SQL or code from model input. (Critical; custom / private, open source / third party) Command injection happens when an agent runs commands, scripts or queries assembled from untrusted input: the user’s prompt, retrieved content or a third-party API.
Human approval, logging and limits
- Destructive or sensitive tool calls need a person to approve each one. (Critical; all server types) The Tools specification says there should always be a human in the loop who can deny tool calls, and that clients should ask for confirmation on sensitive operations and show tool inputs first. Giving an agent more autonomy than the task needs is OWASP LLM06 Excessive Agency.
- Every tool call is logged: who, which tool, the arguments (secrets redacted) and the result. (High; all server types) Without telemetry you cannot investigate what an agent did (OWASP MCP08). The specification says clients should log tool usage for audit purposes.
- Tool calls are rate limited and time out. (Standard; all server types) The specification says servers must rate limit tool invocations and clients should set timeouts on tool calls. An agent stuck in a loop or an abusive client can otherwise burn upstream quotas and money.
- You know what data the operator receives, where it is processed and how long it is kept. (High; remote hosted, HTTP only) Every argument and every result passes through a server someone else runs. Data you send to a remote tool is data you have shared with that operator.
What the MCP specification itself requires
The specification is explicit on several points, and they are the backbone of this list. Authorization is optional, but an HTTP server that supports it should follow the authorization specification: the server is an OAuth 2.1 resource server, publishes OAuth 2.0 Protected Resource Metadata (RFC 9728), and must validate that each access token was issued for it as the audience (RFC 8707). It must not accept or pass through any other token. Clients send the token in the Authorization header on every request, never in the URL. A stdio server should not use that flow and takes its credentials from the environment instead.
The Streamable HTTP transport requires servers to validate the Origin header to stop DNS rebinding, answering 403 for an invalid origin, and says a server running locally should bind to 127.0.0.1 rather than every interface. The Tools page says servers must validate all tool inputs, implement access controls, rate limit tool invocations and sanitize tool outputs; that clients must treat tool annotations as untrusted unless the server is trusted; and that there should always be a human in the loop who can deny a tool call. Roots, the feature that tells a server which directories matter, are guidance rather than access control, and are deprecated as of the 2026-07-28 revision.
A checklist, not a scanner
This page scores the controls around a server: how you got it, how it is configured, and how it is allowed to act. To look at the server itself, paste its config into MCP Guard or a tool manifest into the MCP Security Linter, screen its tool definitions with the Malicious MCP Server Scanner, or look it up in MCP Scan. For an approval decision with owner, logging, scope and review gates, use the MCP Server Governance & Risk Check. To practise spotting the attacks, try the MCP Rug-Pull Lab.
Sources
- MCP Security Best Practices
- MCP specification: Authorization
- MCP Authorization: Security Considerations
- MCP specification: Streamable HTTP transport (security warning)
- MCP specification: Tools (security considerations)
- MCP specification: Roots
- OWASP MCP Top 10 (2025, beta)
- OWASP Top 10 for LLM Applications 2025
- OWASP SSRF Prevention Cheat Sheet
Checked against the MCP specification revision 2026-07-28 and the OWASP pages above in October 2026.
Frequently asked questions
Are MCP servers safe?
Not by default. An MCP server runs tools with the access you give it, its tool descriptions go straight into the model’s context, and many servers are community code. A server is reasonable to use when you know who publishes it, the version is pinned, you have read its tool descriptions, its credentials are dedicated and least-privilege, it runs sandboxed if it is local, an HTTP server requires valid tokens issued for it, and destructive tools need a person to approve each call.
What are the main MCP security risks?
Tool poisoning (hidden instructions in tool descriptions), rug pulls (a server that changes its tools after you approve it), prompt injection through content that tools return, over-scoped tokens and secrets in config files, token passthrough and missing audience checks on HTTP servers, DNS rebinding against local HTTP servers, command injection in tools that run shell commands, and supply-chain compromise of the package itself. Most of these map to entries in the OWASP MCP Top 10 (2025, beta).
What are the MCP server security best practices?
The MCP specification’s own guidance says: HTTP servers act as OAuth 2.1 resource servers, validate that each token was issued for them and never pass a client’s token through to other APIs; tokens go in the Authorization header, never the URL; Streamable HTTP servers validate the Origin header and bind to localhost when run locally; servers validate all tool inputs, rate limit tool calls and sanitize outputs; clients treat tool annotations as untrusted, keep a human able to deny tool calls and log tool usage; and local servers run sandboxed with minimal privileges.
How do I secure a custom or private MCP server?
Follow the MCP authorization specification for HTTP: publish Protected Resource Metadata, return 401 without a valid token, check the token audience, keep scopes minimal and step up with 403 insufficient_scope. Validate every tool input against a strict schema, never build shell commands or SQL from model input, keep descriptions short and factual, split read and write tools, log every call with the authenticated user, rate limit, and lock and scan your dependencies. Being private does not remove these: anyone on the network who can reach it, or a prompt injection inside an approved session, can still use it.
Is an open source MCP server safe to use?
It can be, after a review. Check the repository and maintainers, pin an exact version or image digest, read the full launch command and every tool description, give it a dedicated least-privilege token, run it in a container with only the directories it needs, and record its tool list so you notice when it changes. Open source lets you read the code; it does not mean someone already has.
What is MCP tool poisoning?
Tool poisoning is hiding instructions in a tool’s description or parameter schema. The model reads that text as trusted context, so it can be told to read a key file and pass it in a parameter, or to misuse another server’s tool, while the user sees only a short tool name. It is MCP03 in the OWASP MCP Top 10. Defend against it by reading every description before you approve a server, recording the tool list and re-reviewing any change, and requiring approval for tools that can send data out.
More free security tools
The tools people use most on PlayCISO.
Catch injected instructions hiding in content your AI agent should only read.
Score your readiness against the first international standard for AI security threats.
Critical CVEs across 21 major vendors, month by month — and what the 2026 surge means.
Build an ordered ruleset, replay labelled packets and catch shadowed and any-to-any rules.
Self-assess all six Functions, from Govern to Recover, and see your weakest one.
Search 172 threat actors across Microsoft, CrowdStrike, Mandiant and community names.