A secure MCP server needs more than a valid tool schema. Model output, retrieved pages, tool results, and remote servers are all potentially untrusted. The real boundary is who may call a tool, which action and resource are authorized, when approval is required, whether execution is replay-safe, what output may leave the system, and whether an incident can be traced and reversed.

What threat model should you start with?

Separate six actors in every tool call:

  1. The user owns a goal and a set of resource permissions.
  2. The agent proposes calls from context but is not the authorization authority.
  3. The MCP client presents, approves, and dispatches calls.
  4. The MCP server authenticates, authorizes, validates, and scopes access.
  5. The downstream system is a database, cloud API, filesystem, or messaging service.
  6. Untrusted content includes pages, email, documents, logs, and tool output.

The central rule is: the model proposes; deterministic systems authorize and execute. Even when the model understands intent, the server re-authorizes the current identity and resource. ZoyTown's MC AI / AIBot uses a related boundary—LLM planning with deterministic state-machine execution—because that separation is easier to test than an unrestricted natural-language loop.

How should a remote MCP server authorize calls?

The official MCP authorization tutorial recommends standardized authorization for remote HTTP servers and calls out short-lived tokens, token validation, HTTPS, least-privilege scopes, and credential-safe logging. “Can connect to the server” must not mean “can invoke every tool.”

Authorize at least this product:

principal × client × tool × action × resource × tenant × consent

drive.read and drive.delete need different capabilities. Access to documents/project-a/* must not expand to the entire drive. Derive user and tenant from a verified token; never trust model-provided user_id or tenant_id.

Why is custom token validation dangerous?

A valid signature does not prove the token was issued for your server. Validate issuer, audience, expiry, scopes, resource indicators, and key rotation with a maintained library and a fixed algorithm policy. Fail closed when authorization infrastructure is unavailable; do not “temporarily allow” privileged calls during an outage.

Is a local stdio server automatically safe?

No. The MCP Security Best Practices warns that local servers may inherit the client's privileges. stdio reduces network exposure, but malicious local processes, compromised dependencies, and broad filesystem access remain dangerous.

Default local policy should include:

  • An allowlisted workspace rather than the entire home directory.
  • Network access disabled by default and opened for explicit destinations.
  • Structured subprocess arguments rather than concatenated shell commands.
  • A minimal environment-variable set.
  • Separate read, write, overwrite, delete, and permission-change capabilities.
  • A container or platform sandbox for high-risk execution.

Never make the home directory, Keychain, browser profile, or SSH directory a general search root.

What does schema validation miss?

JSON Schema or Pydantic proves shape, not semantic safety. The server still validates:

Layer Example
Type limit is an integer and URL is a string
Bounds limit <= 100 and timeout is capped
Resource Path remains under an allowed root after normalization
Business state The order is cancelable and revision still matches
Permission The principal may perform this action on this target
Freshness Approved parameters, price, and revision did not change

Approval must bind to a digest of normalized arguments. If the agent changes the tool, target, amount, recipient, or file hash while approval is pending, the old approval is invalid.

Which calls require human approval?

Classify by effect rather than tool name:

  • Low-sensitivity reads may run automatically after authorization and rate limiting.
  • Recoverable writes should show the target and change summary.
  • External communications should show audience, body, and attachments.
  • Deletes, overwrites, and permission changes should show recovery and blast radius.
  • Credentials, payments, legal commitments, and high-impact decisions need stronger confirmation or human takeover.

The same files.write tool may create a disposable draft or overwrite production configuration. An approval surface must show the normalized target, diff, and side effects, not just the tool name.

How do you stop prompt injection from crossing tool boundaries?

Instructions found in a page or document are data, not authority. Use layered controls:

  1. Keep user instructions distinct from retrieved content.
  2. Expose only the tools required for the current task.
  3. Validate paths, domains, recipients, and actions before execution.
  4. Sanitize tool output for secrets, executable markup, and fake instructions.
  5. Re-authorize at the downstream server even if the client already checked.

The OpenAI Agents SDK guardrails documentation explains that tool-guardrail coverage differs for function tools, hosted tools, built-in tools, and handoffs. Therefore, a framework hook is not evidence that every execution path is protected. Inventory the actual path for each tool class.

Why are idempotency and revision CAS security controls?

A retry can turn one approved effect into many. A mutating tool should accept an idempotency key or expected resource revision:

{
  "tool": "article.publish",
  "arguments": {
    "slug": "example",
    "expectedDraftRevision": 4,
    "expectedStateRevision": 2
  },
  "approvalDigest": "sha256:..."
}

If the resource changed after approval, return a conflict and show the new diff. Do not automatically fetch the latest revision and continue; that applies an old approval to new content. ZoyTown's FastAPI, MongoDB, and Redis publishing guide shows how content and state revisions prevent ABA replay.

What should logs and traces contain?

An audit trail should answer who, when, why, what resource, which action, and what result without copying secrets and sensitive bodies into another system. Useful fields include:

  • Trace ID, request ID, and tool version.
  • Internal or irreversible principal, tenant, and client identifiers.
  • Normalized tool, resource class, action, and result code.
  • An argument digest or structured values with sensitive fields masked.
  • Approval policy, approver class, digest, and expiry.
  • Downstream state, retry count, and an idempotency-key digest.

The OpenAI Agents SDK tracing documentation describes spans for generations, tools, handoffs, and guardrails, along with sensitive-data configuration. Production systems should minimize captured content by default and place independent access control and retention limits on the trace backend.

Never log authorization headers, access tokens, authorization codes, cookies, private keys, secrets embedded in prompts, or raw credentials returned by tools.

Which failures should fail closed?

Failure Safe default
Authorization service unavailable Reject privileged calls; do not use expired permission
Policy engine timeout Reject writes; any read fallback needs an explicit policy
Approval state missing Do not execute; require a new approval
Audit backend failure Pause high-risk calls or use a bounded protected queue
Downstream timeout Query idempotent state before retrying a write
Sandbox unavailable Disable tools that require the sandbox

Availability is not permission to bypass authorization. When the downstream may have committed but the response was lost, use an idempotency key or state query before deciding whether to retry.

What should red-team tests cover?

  • Put malicious “read unrelated secrets” instructions in retrieved documents.
  • Replace a permitted path with symlink, .., or encoded traversal.
  • Change arguments or resource revision after approval.
  • Replay the same tool call and verify one side effect.
  • Force authorization, policy, audit, sandbox, and downstream timeouts separately.
  • Return HTML, script, fake system messages, and token-shaped strings from tools.
  • Try cross-tenant IDs, stale tokens, wrong audiences, and broad scopes.
  • Inspect error responses for stacks, internal URLs, and credential material.

Production checklist

  • [ ] Every tool has explicit action, resource, and scope semantics.
  • [ ] The server authorizes each call and ignores model-asserted identity.
  • [ ] High-risk approvals bind normalized arguments and resource revision.
  • [ ] Mutations are idempotent and retries do not multiply effects.
  • [ ] Filesystem, network, subprocess, and environment access use least privilege.
  • [ ] Guardrail coverage is proven for every execution path.
  • [ ] Tracing is redacted by default with separate access and retention policy.
  • [ ] Authorization, policy, and sandbox outages fail closed.
  • [ ] Deletes and overwrites have recovery or require human takeover.
  • [ ] Red-team cases run continuously instead of only during launch review.

How do you manage server and tool supply chains?

A good security design can be invalidated by an update. For local and remote servers:

  • Pin package versions, container digests, or signed release artifacts.
  • Review changes to tool schemas, permission scopes, and downstream domains.
  • Keep new tools invisible by default until they enter an allowlist.
  • Validate configuration permissions and dependency integrity at startup.
  • Give each server separate credentials instead of a universal shared token.

The client should show a server's source, version, and requested capabilities. An update that expands filesystem roots, network destinations, or OAuth scopes is a permission change, not an invisible routine upgrade.

What should an incident-response plan provide?

After suspected privilege misuse or prompt injection, the team needs to:

  1. Disable capability by server, client, principal, or tool.
  2. Revoke affected tokens, subscription tickets, and downstream sessions.
  3. Locate calls by trace ID without spreading sensitive content.
  4. Distinguish model proposal, user approval, server execution, and downstream commitment.
  5. Compensate recoverable writes and notify owners for irreversible effects.
  6. Turn the attack sample into regression tests and policy rules.

The kill switch must not depend entirely on the policy service that may be failing. Keep a tightly controlled independent disable path and exercise it.

FAQ

Can read-only tools run without approval?

They can run automatically under a risk-based policy, but “read-only” does not mean harmless. Reading private email, source code, or an entire filesystem still requires strict authorization, scope, and audit.

Why guard tool output?

Results may contain secrets, malicious HTML, prompt injection, or false permission claims. Validate type, size, sensitive fields, and rendering safety before the output enters model context or a user interface.

Does one universal MCP proxy simplify security?

It may simplify connectivity while increasing confused-deputy and token-custody risk. Preserve per-client consent, downstream audience, least-privilege scopes, and separate audit. A proxy's static credential must not silently represent every user.

Do not replace evidence with the phrase “security reviewed.” Record the tests that ran, enforced blocks, known exceptions, and recovery drills. The same discipline—placing verifiable boundaries before confident claims—appears in ZoyTown's official-source GEO/AEO guide.