A local MCP server is ordinary code downloaded from the internet and run as a child process of the user, with access to everything that user can read, every secret in their environment and an open path to the internet. The protocol does not sandbox it: the MCP project's own Local Server Security guidance says the client and a stdio server share one trust domain, and that any isolation is the job of the host application and whoever operates the machine. This guide covers how access actually works for local servers, where privilege creeps in, how to handle the credentials they need, what to log, and a hardening baseline for individual developers and for fleets. It reflects MCP specification revision 2026-07-28 and the accompanying security pages, checked on 27 October 2026, and is written for endpoint, platform and application security teams. For finding servers nobody approved, see the Unsanctioned AI Agents and MCP Servers Guide.
Key takeaways
- stdio is not a sandbox. A local server inherits the user's privileges, environment variables and network access the moment it is launched; the security decisions happen before launch.
- Consent is required but not sufficient. Clients offering one-click installation MUST show the exact command and get explicit approval (SEP-1024), but a dialog cannot reveal what a later version will do.
- Containment decides what a bad install costs. Running third-party servers in a container or sandbox with no home-directory mounts and no network unless needed is the highest-leverage control.
- Credentials should be per server, narrow and out of plaintext. Pass each server only its own scoped token through per-server configuration or the OS secret store, never a shell-wide export.
- Treat local servers as managed software. Inventory client configuration files, keep an allowlist of approved servers with pinned versions, and be able to block egress and rotate credentials fleet-wide.
How identity and access work in local MCP servers
With the stdio transport, the client launches the server as a subprocess and exchanges newline-delimited JSON-RPC messages over stdin and stdout. The server MUST NOT write anything to stdout that is not a valid MCP message and may log to stderr. There is no authentication between the two processes: the MCP authorisation specification says stdio implementations should not use the OAuth flow and should instead retrieve credentials from the environment. The identity a local server acts with is therefore the operating system account that launched it, plus whatever tokens it is handed.
| What the server process gets | Why | Consequence if the server is malicious or compromised |
|---|---|---|
| User's file permissions | Ordinary child process | Reads ~/.ssh, ~/.aws, browser profiles, source trees |
| Inherited environment | Launcher passes its environment | Shell-exported cloud keys and API tokens are exposed |
| Unrestricted outbound network | No default egress control | Silent exfiltration |
| Full dependency tree | Resolved at install or launch time | A compromised transitive package runs with the same rights |
| Influence over the model | Tool names and descriptions are read as instructions | Tool poisoning can steer how the agent uses other servers' tools |
The Local Server Security page names five threats: a malicious server (typosquatted package or hijacked project), an overcollecting server, a compromised dependency, a poisoned tool catalogue (including definitions changed after approval, a "rug pull"), and a vulnerable server or local bridge. It also states plainly that no check proves what a server will do; provenance tells you whom you are trusting, not that the trust is warranted.
Should it run locally at all?
The cheapest control is not installing locally. Reading the working tree, driving a local tool or reaching hardware are reasons to run a server locally; wrapping a SaaS API is not. A remote server over Streamable HTTP runs no code on the workstation, uses the protocol's OAuth flow instead of a token in a config file, and is patched in one place. A small team should default to remote versions where they exist. A large organisation should go further and host shared SaaS-wrapping servers centrally, so there is one instance to patch and audit instead of hundreds. Hosted servers then need the controls in the Remote MCP Server Hardening Guide.
Admin roles and privileged access
Local servers acquire privilege in three ways, and each is avoidable.
- Elevated launch: a client run as administrator or root launches every server with the same rights. Developers should run MCP clients as standard users; local administrator rights on developer machines should be just-in-time, not standing.
- Commands that escalate: the specification's best practices tell clients to highlight dangerous patterns such as
sudoandrm -rf, network operations and access outside expected directories, and to warn on commands touching the home directory, SSH keys or system directories. A server install that needssudoshould be rejected by policy. - Privileged plumbing: mounting the container runtime socket into a "sandboxed" server, or granting it the user's whole home directory, recreates full host access. Grant a single project directory, read-only where the job is reading.
The client itself is a privileged component because it decides what runs. Under SEP-1024 (Final), clients that support one-click configuration MUST display the exact command without truncation, including all arguments, warn that the operation may be dangerous, require an affirmative action and allow cancellation. The specification adds SHOULD-level guardrails: warn that servers run with client privileges, run them sandboxed with minimal default privileges, and provide explicit grants for extra directory or network access. Choose clients that do this, and prefer clients that record tool definitions at approval and ask again when they change; the protocol does not require that behaviour.
Repository-supplied configuration deserves special handling. In the Amazon Q MCP config vulnerability, MCP server definitions in a repository's .amazonq/mcp.json could be launched when a developer opened the project, and the spawned processes inherited AWS keys and session tokens. Treat workspace-level MCP configuration like any other code from the repository: untrusted until reviewed. See the AI IDE and Coding Agent Security Guide.
Integrations, API tokens and service accounts
Most useful local servers call something: GitHub, a cloud API, an email service. The tokens they hold are non-human identity credentials and should be managed like any other.
| Option | How it works | Risk | Use when |
|---|---|---|---|
| Shell-wide export | Token in .bashrc or .zshrc, inherited by every process | Every server sees every token | Never for MCP |
Per-server env block in client config | Token passed only to the named server | Plaintext in a predictable file location | Short-lived or low-value tokens |
| OS secret store reference | macOS Keychain, Windows Credential Manager or freedesktop Secret Service, where the client supports it | Depends on client support | Default for long-lived secrets |
| Broker or secrets manager issuing at launch | Short-lived credential minted per session | Operational complexity | Fleets and high-value systems |
- Scope narrowly: one token per server with the smallest scope that works, for example a fine-grained token limited to one repository rather than an account-wide token. See the GitHub Personal Access Tokens Security Guide.
- Do not reuse: a personal broad-scope token shared across servers turns one compromise into all of them.
- Remember files are credentials:
~/.sshand~/.awsare only protected from a server by isolation, not by configuration. - Rotate on removal: when a server is removed or found malicious, rotate everything its configuration passed to it.
The postmark-mcp malicious MCP server illustrates the token angle: a lookalike npm package worked normally until one release added a hidden BCC, sending every email through the victim's own Postmark credentials. A narrowly scoped, separately issued token limits the damage and makes revocation clean. See the Secrets Management Guide.
Local servers that listen on a port
Some local servers and bridges use HTTP instead of stdio. The Streamable HTTP transport says servers MUST validate the Origin header on all incoming connections to prevent DNS rebinding and MUST return 403 when it is present and invalid; when running locally they SHOULD bind only to 127.0.0.1 rather than 0.0.0.0; and they SHOULD authenticate all connections. The Local Server Security page adds that binding to loopback is not an authentication boundary, because other local processes and, through the browser, websites can reach it. The best practices recommend stdio, or an authorisation token, Unix domain sockets or other restricted IPC when HTTP is unavoidable.
Logging and detection
The protocol cannot inventory or watch processes on machines it does not manage, so detection relies on endpoint and network telemetry.
- Configuration inventory: collect MCP client configuration files from managed endpoints (for example
claude_desktop_config.jsonfor Claude Desktop,.vscode/mcp.jsonin workspaces, and the files other clients use) and parse server names, commands, arguments, package versions and declared environment variable names, never values. - Process lineage: in EDR, alert when an MCP client or IDE spawns
npx,uvx,dockeror interpreters with packages not on the allowlist, and when a server's child process reads~/.ssh,~/.awsor browser profile paths. - Egress: log destinations per server through an egress proxy; a server wrapping one API should have a short, predictable list.
- MCP activity: where the client supports it, log which server, which tool and when, so an incident review can reconstruct what a server actually did.
- Tool definition changes: record tool descriptions at approval and alert on changes.
| Metric | What good looks like |
|---|---|
| Servers on managed endpoints not on the allowlist | Trending to zero |
| Allowlisted servers with pinned versions (or image digests) | 100% |
| Third-party servers running isolated rather than as bare processes | Rising each quarter; 100% for servers handling sensitive data |
| Servers configured with shell-inherited or shared broad tokens | Zero |
| Time to find every instance of a named server across the fleet | Minutes, not days |
| Egress attempts outside a server's allowlist | Each one investigated |
Hardening baseline
For each workstation
- Prune: remove servers you no longer use; know where each remaining one comes from.
- Verify provenance: tie the package to a source repository and identifiable publisher, check the exact package name, and prefer signed artifacts with build attestations and an SBOM.
- Pin: install a specific version, not
latest. Pinning withnpxoruvxfixes only the top-level package, since transitive dependencies are typically resolved fresh; pinning a container image by digest (image@sha256:...) freezes the whole tree. - Isolate: run third-party servers in a container (Docker or Podman) or a dedicated VM, with no mounts beyond the directory they need. stdio works unchanged with a container's stdin and stdout.
- Restrict files: one project directory, read-only where possible. Configuration-level allowlists are cooperative boundaries that only honest servers respect; the container is the enforcement.
- Restrict network: use
--network=nonefor servers that work only on local files; give the rest an egress allowlist. - Harden further: apply your distribution's seccomp, AppArmor or SELinux defaults to containers, run as a non-root user and drop capabilities.
- Review tools: read each server's tool descriptions once, for example with the MCP Inspector, and remove any server whose descriptions contain instructions unrelated to its job.
For a fleet: phased rollout
- Discover (weeks 1 to 2): inventory configuration files across endpoints and publish the results to the server owners.
- Define (weeks 2 to 4): publish an allowlist with pinned versions and acceptance criteria (identifiable publisher, readable source, provenance metadata, SBOM) and a default runtime posture such as "third-party servers run in containers with no home-directory mounts".
- Pilot (weeks 4 to 8): enforce the posture for one engineering group through endpoint management, in audit mode first so breakage is visible before blocking.
- Enforce: block non-allowlisted server launches and move SaaS-wrapping servers to central remote deployment.
- Roll back safely: exceptions are per server and time-limited, approved by the server owner, not a global switch-off.
- Prepare the fleet incident: when a widely used server or its SDK is vulnerable, find every instance from the inventory, block its egress at the proxy, rotate every credential its configurations held and push the fixed pinned version. SBOMs are what make "which machines run the affected SDK version" answerable quickly.
Framework mapping
| Control | NIST SP 800-53 Rev. 5 | NIST CSF 2.0 | ATT&CK / ATLAS addressed |
|---|---|---|---|
| Allowlist and install consent | CM-11 User-installed Software, CM-7 Least Functionality | PR.PS-05 | T1204.002 Malicious File |
| Provenance, pinning, signatures | SR-4 Provenance, SR-11 Component Authenticity, CM-14 Signed Components | GV.SC-05, PR.PS-02 | T1195.002 Compromise Software Supply Chain, AML.T0010 AI Supply Chain Compromise |
| Container or sandbox isolation | SC-39 Process Isolation, AC-6 Least Privilege | PR.PS-01 | T1552.001 Credentials In Files |
| Egress control | SC-7 Boundary Protection | PR.IR-01 | T1567 Exfiltration Over Web Service |
| Inventory and activity logging | AU-2, SI-4 System Monitoring | ID.AM-02, DE.CM-09 | Supports detection across the above |
In ISO/IEC 27001:2022 Annex A, the closest controls are 8.19 Installation of software on operational systems, 8.7 Protection against malware and 8.9 Configuration management. In CIS Controls v8.1, Control 2 (Inventory and Control of Software Assets) is the starting point. The OWASP MCP Top 10 (2025 beta) entries MCP03 Tool Poisoning, MCP04 Software Supply Chain Attacks and Dependency Tampering, and MCP09 Shadow MCP Servers apply directly.
Common misconfigurations
- Unpinned launchers:
npx some-server@latestin configuration, so a compromised future release installs itself silently. - Global secrets: cloud credentials exported in the shell profile, readable by every server the user ever adds.
- Home directory as the filesystem root: a file server configured with
~to do a job that needs one project folder. - Trusting workspace configuration: MCP definitions committed to a repository are launched without review when the project is opened.
- Loopback as authentication: a local HTTP bridge bound to
127.0.0.1with no token and noOrigincheck, reachable from a web page through DNS rebinding. - One-time review only: tool descriptions checked at install, with no alert when the server changes them later.
Practitioner checklist
- Run MCP clients as standard users and reject server installs that require
sudoor administrator rights. - Prefer remote versions for servers that only wrap SaaS APIs.
- Use only clients that show the exact install command and require consent, and that re-prompt when tool definitions change.
- Install from identifiable publishers, pin versions, and prefer container images pinned by digest.
- Run third-party servers in containers or sandboxes with a single project mount and no network unless needed.
- Give each server its own narrowly scoped token via per-server config or the OS secret store; never export secrets globally.
- For local HTTP servers, validate
Origin, bind to127.0.0.1and require a token, or use stdio or Unix sockets. - Inventory client configuration files across the fleet and alert on non-allowlisted servers.
- Log egress per server and investigate destinations outside its allowlist.
- Keep a fleet playbook to find, block, rotate and update a vulnerable server everywhere.
Standards and references
- Model Context Protocol: Local Server Security
- Model Context Protocol: Security Best Practices (Local MCP Server Compromise)
- Model Context Protocol: SEP-1024 MCP Client Security Requirements for Local Server Installation
- Model Context Protocol: stdio Transport (revision 2026-07-28)
- Model Context Protocol: Streamable HTTP Transport (revision 2026-07-28)
- OWASP GenAI Security Project: A Practical Guide for Secure MCP Server Development
- OWASP: MCP Top 10
Related NHI Mgmt Group resources: Unsanctioned AI Agents and MCP Servers Guide · MCP Security Guide · AI Agent Sandboxing and Code Execution Guide · MCP Registry and Server Publishing Security Guide · Container Runtime Security Guide