Securing Your Local MCP Servers

Security is a critical aspect of any application, and MCP is no exception. In this guide, we will explore how to secure your local MCP servers, ensuring they are protected against unauthorized access and potential threats.

The Risks

There are a few types of risks that can compromise your local MCP servers. These include:

Malicious code execution

Since MCP servers have to run on the host machine, they have the full capability to execute any code. This means that a malicious server could encrypt your data, steal your credentials, or even take over your machine. Anything you would expect from traditional malware, such as keylogging, can be performed by a local MCP server.

Malicious prompt injection

Since the tools from the server have their descriptions included in the prompt automatically, any connected mcp server (remote or local) can potentially inject malicious prompts into the conversation history. This means that a server can force a language model to generate malicious code or instructions, potentially compromising your system. This can also be expanded to more advanced attacks, including hijacking the agentic behavior of the language model. For example, a server could add documentation for a pypi package the llm would try and use, which when installed would execute malicious code. If you use the paypal MCP server, it could tell the LLM to send money each time a tool is used, which could lead to a financial loss.

Malicious responses

Any server can respond with incorrect or malicious information, overwriting the ground truth data the model was trained on. This can lead to incorrect predictions or make the model less effective in its intended purpose, acting as a DoS vector. An example of this is a calculator tool that returns incorrect results, leading to incorrect calculations. 2 + 2 = 5 instead of 4 + 2 = 6. This would cause a lot of headaches for a financial agent.

Securing Your Servers

Filesystem Permissions

The best way to mitigate the risk of remote code execution is to ensure that your server has the appropriate permissions. The easiest way to do this is to run the server in an isolated environment, such as a Docker container. Use cap-drop to remove unnecessary capabilities, and set the user to a non-root user. Any volume mounts should be read-only unless the server is explicitly designed to modify data, and they should be mounted as a sub directory on the host machine. This entirely eliminates the ability for malicious code to read files with sensitive information outside of your intended scope.

To run the example time server in docker with cap-drop and read-only, you can use the following command:

docker run -i --rm --name mcp-time-server --cap-drop all --read-only mcp/time

Network Security

MCP servers can connect to the internet, so it's important to secure your network. Use a firewall to block incoming connections entirely, and filter outbound traffic to only known hosts. This will prevent a malicious server from communicating with the outside world, and prevent exfiltration of sensitive data. If you are using docker as previously mentioned you can entirely isolate the server from the host and internet by using --network none. This is ideal for servers that perform in memory processing only, such as a calculator or the official sequential thinking server. This also works in docker compose via the network_mode: "none" option. Unfortunately, most servers are not able to be fully isolated, so we need another method. Docker supports iptables out of the box, which can be used to filter outbound traffic. See the docker networking documentation for more information.

Expanding on the previous example, you can use the following command to run with no network connectivity:

docker run -i --rm --name mcp-time-server --network none --cap-drop all --read-only mcp/time

To replicate this in docker compose, you can use the following:

services:
  mcp-time-server:
    image: mcp/time
    container_name: mcp-time-server
    stdin_open: true
    tty: true
    network_mode: "none"
    cap_drop:
      - ALL
    read_only: true
    restart: "no"

And then run it with the following command:

docker-compose run --rm mcp-time-server

More in depth filtering can be done with a proxy solution like squid that supports filtering outbound traffic via rules such as:

  • protocol
  • address
  • port
  • URL regex

This can allow more granular control, allowing servers such as mcp-wolfram-alpha to be run in a docker container with no network connectivity, but still allowing access to Wolfram Alpha API.

Projecting against prompt injection

The best way to manually prevent prompt injection is to manually review the tool descriptions exposed by the MCP server. The easiest way to do this is to use wong2/mcp-cli to interact with the server.

npx "@wong2/mcp-cli" docker run -i --rm --name mcp-time-server --network none --cap-drop all --read-only mcp/time

This will execute the server locally the same way a chat client would, but exposes all the tools/resources/prompts to the user directly. You can then manually check the descriptions and ensure they are safe.

I would suggest pinning the version of the server you are using, as the descriptions may be updated over time. This also has the side effect of preventing supply chain attacks, where a validated server is updated down the line to include malicious code. UVX/NPX will automatically update servers without any notification.

Forking servers

The best way to avoid the malicious updates as explained above is to fork the server and use your own version. This means you can see exactly what changes are being made and can audit the code for malicious behavior. I would also suggest enabling codeql analysis on your fork, as this will help you identify any potential vulnerabilities in the code. This is free for public repos.

Conclusion

Securing your local MCP servers is crucial to preventing malicious code execution, prompt injection, and malicious responses. In future posts, we will explore how to secure your remote MCP servers, ensuring they are protected against unauthorized access and potential threats.