Secure an MCP Server: Stdio Is Not a Sandbox

|Author: QUASA Editorial Team|6 min read| 1
Secure an MCP Server: Stdio Is Not a Sandbox

Secure an MCP server by limiting who can invoke it and what its tools can reach. For remote HTTP deployments, authenticate protected requests, validate that each token targets this server, and enforce permissions when a tool executes. For local deployments, restrict the process’s files, network access, and secrets: OWASP’s MCP security guidance explains that stdio removes a listening endpoint but does not confine the subprocess.

Start with a list of tools, the data each can read or change, and the credentials used for those actions. HTTP needs a defended request boundary; stdio needs an operating-system boundary; both need authorization inside the tool handler. Apply the controls in that order, then test whether the deployed configuration actually denies unwanted actions.

Authenticate and validate remote HTTP requests

Place authentication ahead of protected operations and publish protected-resource metadata so clients can discover the authorization server. The MCP authorization specification requires clients to identify the intended MCP server with the resource parameter in authorization and token requests and to send bearer authorization in the header of every HTTP request.

At the MCP server, validate the token, its expiry, its intended audience, and the scope required for the operation. Reject a valid token issued for another API or MCP server: a correct signature alone does not establish permission to use this resource. An expired or invalid token should receive HTTP 401, while insufficient scope calls for HTTP 403. If a tool calls an upstream API, use a separate credential intended for that API rather than passing through the token received from the MCP client.

Carry the caller’s user or tenant identity through routing and into the tool handler. A gateway that verifies a token but executes every request under one broad service identity can still expose another user’s records. For remote Streamable HTTP, use TLS, validate allowed Origin and Host values, and do not treat a connection or session identifier as proof of identity.

Limit each tool’s authority

Define the permitted action, resource, and calling identity for every tool. A search tool, file writer, and URL fetcher have different effects even if they share one MCP connection. Grant each server only the upstream scopes and filesystem access its approved tools require; separate sensitive tools when a shared credential would give every handler excessive authority.

For a hypothetical project-search tool, allow reads only under the approved project directory for the caller. Resolve paths, including symbolic links, before enforcing that boundary. For a hypothetical URL-fetch tool, allow only intended destinations and check each redirect so an acceptable first URL cannot lead to an internal service. A restrictive input schema can reject malformed arguments, but trusted application code must decide whether a valid project ID belongs to the caller.

Check the tool name, arguments, resource, and caller permissions immediately before performing the action. A scope that permits listing records does not automatically permit export, and a user permitted to read one project cannot gain another by changing an argument. Treat tool descriptions and responses as untrusted content: they must not change a server-side permission decision. Bind any required confirmation for a destructive or data-sharing action to its actual arguments, so a changed request needs a new decision.

Confine the stdio server process

Launch a local stdio server under a dedicated low-privilege identity or an enforced sandbox. Allow only required directories, block unrelated credential stores, and deny network access unless a named tool needs it. Where egress is necessary, limit destinations. A container provides containment only when its mounts, capabilities, credentials, and network access are constrained in the deployed configuration.

Inspect the command and environment the MCP client uses to start the child process. The server may inherit API keys or cloud credentials from its parent even when none appears in its tool schema. Pass only job-specific secrets, keep tokens out of plaintext configuration, and remove sensitive values from logs. Review the package and complete tool definitions before deployment and when they change.

Match OAuth callbacks and discovery targets exactly

Register the precise OAuth callback URI and make the authorization server reject near matches. The MCP authorization security requirements call for exact matching of registered redirect URIs, PKCE, token audience checks, and defenses against mix-up, open-redirection, SSRF, and confused-deputy attacks. A broad hostname or path match can send an authorization code to an unintended callback.

On the client, retain the selected authorization server’s issuer with the pending request and compare a returned issuer before sending the code to a token endpoint. Require that issuer in the response when the server advertises it; verify state when used, and complete the PKCE exchange with the stored code verifier. If an authorization server fetches client ID metadata, restrict destinations and redirects so discovery cannot reach internal addresses. A proxy with upstream privileges must preserve which client and user authorized each action.

Run denial checks in the deployed environment

Exercise these controls with the gateway, process identity, mounts, network policy, and authorization server intended for release. Each rejected call should stop before its side effect, while logs record the decision without exposing credentials:

  1. Send no token, an expired token, a token for another audience, and a token lacking the required scope to a protected HTTP tool. Confirm that an allowed token reaches only its own user or tenant data.
  2. Give a read tool write-shaped arguments, another user’s resource ID, an unexpected field, and a path outside its approved directory. Confirm that the handler rejects each unauthorized action.
  3. Launch the stdio process with harmless canary secrets outside its allowed area. Verify that it cannot read them, write outside its approved directory, or connect to an unapproved destination.
  4. Attempt an unregistered callback, a near-match redirect URI, a mismatched issuer or state, and a metadata URL that redirects to an internal address. Check that no code, token, or internal response escapes.

Repeat the checks when a tool gains a capability, a server package changes, or deployment permissions change. Any of those changes can expand a tool’s effective authority while the MCP transport stays the same.

Also read:

Share:

Subscribe to our newsletter

Get the latest Web3, AI, and crypto news delivered straight to your inbox.

0