MCP Security Checklist for Small Teams: OAuth, Least Privilege & Testing

Why MCP security is different from ordinary API security
Model Context Protocol, or MCP, gives an AI client a standard way to discover and call tools exposed by a server. That makes integrations easier, but it also concentrates a trust boundary: one tool invocation may read a document, call an external API, write a record, or trigger a business action.
The risk is not that every model is malicious. The risk is that a model can be influenced by untrusted user input, retrieved documents, web pages, tool descriptions, or previous conversation context. If the server exposes more access than the task requires, a prompt-injection mistake can become a data leak or an unintended write.
Official MCP security guidance discusses confused-deputy attacks, token passthrough, SSRF, state-handle hijacking, OAuth URL validation, mix-up attacks, local-server compromise, and scope minimization [1]. For a small team, the practical lesson is simple: reduce trust assumptions, make every permission explicit, and test failure paths—not only happy paths.
A small-team threat model
Before choosing a framework, write down what the server can see, what it can change, and who can invoke it. A useful first version can fit on one page.
Do not begin by asking whether the model is “safe.” Begin by asking what the system is allowed to do if the model is wrong. That question produces controls that remain useful across different models and clients.
The pre-production MCP security checklist
| Control area | Minimum practical control | Evidence to keep |
|---|---|---|
| Transport | Use HTTPS for remote HTTP-based MCP and restrict network exposure. | Deployment configuration and a test showing insecure HTTP is rejected or redirected. |
| Authentication | Require authentication for user-specific data and administrative actions. | Successful and failed authentication tests. |
| Authorization | Assign only the tools and scopes needed for each role or workflow. | Permission matrix and denied-call examples. |
| Token handling | Validate issuer, expiry, signature, scope, and intended audience; never pass tokens through blindly. | Token-validation tests and redacted logs. |
| Input handling | Treat prompts, documents, tool metadata, and API responses as untrusted data. | Injection and malformed-input test cases. |
| High-impact actions | Use a separate approval step for irreversible or externally visible operations. | Approval records and rejection tests. |
| Observability | Record actor, tool, target, outcome, latency, and correlation ID without secrets. | Sample audit event and retention rule. |
| Recovery | Keep a tested disable switch, versioned configuration, and rollback procedure. | Rollback rehearsal notes and owner. |
Least privilege: the control that pays off first
Least privilege means the agent receives only the smallest set of capabilities needed for a defined task. A read-only research assistant should not receive a database-write tool. A documentation assistant may read a prepared folder but should not browse the entire filesystem. A support workflow may draft a reply but should not send it without approval.

Use a written matrix instead of relying on descriptions alone. For every tool, record its operation type, allowed resources, required identity, approval requirement, rate limit, and logging fields.
| Tool | Allowed | Not allowed | Approval |
|---|---|---|---|
file_reader | Read selected documentation files | Secrets, keys, home directories | No, if read-only |
ticket_drafter | Create an unsent draft | Send, delete, or change priority | Before publishing |
database_lookup | Specific views and filtered fields | Arbitrary SQL or bulk export | For sensitive records |
deployment_trigger | Approved environment and version | Production without release gate | Always |
{
"agent": "support-drafter",
"tools": {
"file_reader": {"mode": "read", "paths": ["/app/approved-docs/*"]},
"ticket_drafter": {"mode": "draft", "send": false}
},
"blocked": ["*.env", "*.key", "*.pem", "/etc/*"],
"require_approval_for": ["send_message", "delete", "publish", "deploy"]
}
This is a policy sketch, not a drop-in configuration. Adapt it to your server, identity provider, network model, and data boundaries.
Remote authentication without OAuth shortcuts
For HTTP-based remote MCP servers, use an authorization design appropriate to the resource’s sensitivity. MCP authorization guidance covers protected-resource metadata, authorization-server discovery, dynamic client registration, authorization-code flows with PKCE, resource indicators, and bearer-token requests [2].
Do not accept a token merely because it is structurally valid. Verify its signature and issuer according to the identity system, check expiry and scopes, and confirm that it was intended for the protected resource. RFC 8707 describes resource indicators that help an authorization server issue a token for a specific resource and audience [3].
Redirect handling also matters. Exact redirect-URI matching, PKCE, CSRF protection, one-time state values, and mix-up defenses help prevent authorization codes or tokens from being redirected to a destination the user did not approve. Do not trust arbitrary authorization endpoints or set consent state before the authorization result is validated.
Prompt injection, tool poisoning, and untrusted data
Keep instructions and data separate. A web page, uploaded document, email, tool description, or tool result may contain text that looks like an instruction. Your application should label it as untrusted content and prevent it from silently changing the policy that governs tool use.
- Validate arguments. Enforce strict schemas for length, type, destination, resource, and allowed operation.
- Protect policy boundaries. Do not let retrieved text redefine permissions, approvals, system prompts, or security settings.
- Preview consequences. Show the target and effect of a high-impact action before approval.
- Validate outputs. Check tool output before passing it to another tool or using it to make a decision.
- Protect secrets. Keep tokens, passwords, private document bodies, and keys out of prompts, tool descriptions, errors, and normal logs.
OWASP’s AI Agent Security Cheat Sheet groups these controls with least privilege, memory isolation, human approval, output validation, monitoring, privacy, and adversarial testing. Treat them as defense in depth—not as a promise that one filter stops every attack.
Testing before launch
Run tests in a non-production environment with fake credentials and synthetic records. Record the expected result before running each case. “The model probably refuses” is not a control; a stronger result is that the server rejects the request, returns a safe error, writes a redacted audit event, and leaves the protected system unchanged.
| Test family | Example | Expected result |
|---|---|---|
| Authorization | Expired token, wrong audience, missing scope, unknown client, altered redirect URI, replayed state | Reject request; no tool execution; redacted audit event. |
| Tool boundary | Unlisted tool, write through read-only tool, path traversal, oversized input, external destination | Fail closed and preserve the protected system. |
| Injection | Fake instructions in a document, web result, tool description, or prior message | Untrusted text cannot grant permission. |
| Operations | Slow API, repeated failure, log outage, leaked test key, disable or rollback | Limits, circuit breaker, containment, and recovery work as designed. |

Logging, rate limits, and rollback
Logs should answer five questions: who requested the action, which tool was called, what resource was targeted, whether the request was approved, and what happened afterward. Add a correlation ID so one user request can connect to the model decision, tool call, downstream response, and approval event.
Never log access tokens, passwords, private document bodies, or complete customer records merely because they are available. Prefer identifiers, hashes where appropriate, outcome codes, and carefully redacted samples. Protect the logs themselves because they may reveal sensitive workflows.
Set separate limits for reads, writes, exports, retries, and expensive downstream calls. Combine rate limits with a circuit breaker and kill switch. If a tool behaves unexpectedly, the team should be able to disable that tool without deleting the entire application.
For a deeper runbook, see the companion guide to AI-agent rollback before production, and connect the audit records to tool-call auditing and agent observability.
Frequently asked questions
Is authentication mandatory for every MCP server?
No. Authorization is optional in the MCP specification, and local STDIO servers commonly obtain credentials from the environment or an embedded library. For a remote server handling user data or meaningful actions, authentication and authorization are the safer default.
Should a small team start with OAuth?
For a remote, multi-user server, an established identity provider and standards-based flow are usually safer than inventing a token system. For a local single-user prototype, keep the scope narrow and do not expose it to the network.
Can least privilege stop prompt injection?
No. It limits the damage if instructions are manipulated, but it does not replace input validation, output validation, approvals, monitoring, or adversarial testing.
Does this checklist guarantee compliance or security?
No. It is an educational starting point. Obligations depend on the data, industry, identity system, deployment model, and applicable law. Have a qualified security professional review high-risk deployments.
Conclusion
The most reliable way for a small team to secure MCP is to make the system boring: fewer tools, narrower scopes, explicit approvals, validated tokens, isolated data, useful logs, and a tested way to stop. Build the first deployment around one low-risk workflow, collect evidence from the tests, and expand only when the team can explain every new permission.
For background, see the guide to how MCP connects AI to approved tools and data and the guide to preventing AI-agent memory poisoning.
Join the conversation