You probably know who you think they should be talking to, but how do you know for sure? And how do you keep it that way?
Modern AI workflows rely on agentic systems that leverage Model Context Protocol (MCP) servers. These servers provide rich context to LLMs, enabling smarter, safer, and more customized behavior. But if you’re not controlling their network access, you’re trusting that these tools won’t spill secrets, phone home, or tunnel into places they shouldn’t.
With the new network isolation features in ToolHive, you don’t have to trust. You can verify – and enforce.
Let’s prove the point with a quick test.
I gave the Fetch MCP server a very strict permission profile: it could only connect to stacklok.com and nothing else. Then I used Copilot to fetch content from both stacklok.com and anthropic.com.
Here’s what happened:
And the audit trail from the egress proxy that ToolHive spun up for me:
$ docker logs fetch-egress
1750875295.189 449 172.20.0.4 TCP_TUNNEL/200 10451 CONNECT stacklok.com:443 - HIER_DIRECT/5.161.48.178 -
1750875314.012 0 172.20.0.4 TCP_DENIED/403 3786 CONNECT www.anthropic.com:443 - HIER_NONE/- text/html
✅ Allowed: stacklok.com
⛔ Blocked: anthropic.com
That’s real-time enforcement of network policy, with a full audit trail. No special infrastructure required.
Let’s look at why this matters, and how you can do it yourself.
Why network isolation matters
Containerization is a great start for security, but it’s not a silver bullet. A malicious MCP server could still:
- Exfiltrate proprietary data or credentials
- Leak sensitive API access to an unknown endpoint
- Become a pivot point for lateral movement within your network
The attack surface expands when containers are able to download unverified tools, or when a once-trusted MCP gets silently updated with malicious code. These aren’t theoretical risks, they’ve already shown up in detailed proof of concept research. Even legitimate MCP servers can be manipulated to devious ends through prompt injection and other techniques, like this exploitation of the WhatsApp MCP.
That’s why ToolHive lets you explicitly define where each MCP can connect, and just as importantly, where it can’t.
How to lock it down
ToolHive’s permission profiles let you precisely define network rules for each MCP server. Here’s a quick walkthrough of some common use cases.
Example 1: Allow only internal domains
Suppose you want to restrict the Fetch MCP server to only talk to your local system, internal corporate services, and your tenant in Atlassian Cloud:
fetch-permissions.json
{
"network": {
"outbound": {
"allow_host": [
"localhost",
".acmecorp.com",
"acmecorp.atlassian.net"
],
"allow_port": [80, 443],
"allow_transport": ["tcp"],
"insecure_allow_all": false
}
}
}
Note the syntax of the .acmecorp.com
entry. The leading .
permits all subdomains below the main domain.
Then, simply launch the Fetch server with the --isolate-network
flag and your custom permission profile:
thv run --isolate-network --permission-profile ./fetch-permissions.json fetch
Example 2: Use default registry permissions
Some MCPs ship with default profiles in the built-in ToolHive registry. Want to run the GitHub MCP as-is?
thv run --isolate-network github
You can inspect its default permissions first:
thv registry info github
The Permissions section reveals the default policy:
Permissions:
Network:
Allow Transport: tcp
Allow Host: .github.com, .githubusercontent.com
Allow Port: 443
Example 3: Customize for GitHub Enterprise
If you self-host GitHub, tweak the permission profile to replace the allow_host
list with your internal name:
{
"network": {
"outbound": {
"allow_host": ["github.example.com"],
"allow_port": [443],
"allow_transport": ["tcp"],
"insecure_allow_all": false
}
}
}
And run with your custom profile:
thv run --isolate-network --permission-profile ./github-enterprise.json github
Example 4: Block all network access
Need to sandbox an MCP completely? Use the built-in "none" profile:
thv run --isolate-network --permission-profile none <MCP_SERVER>
How it works
Behind the scenes, ToolHive runs each MCP server inside a locked-down container within that routes egress traffic through a layer 7 HTTP proxy. That proxy enforces the rules you define in your permission profile.
You can:
- Block access entirely
- Allow specific domains, ports, and protocols
- Monitor attempted connections using logs
It’s simple to apply and doesn’t require you to manage iptables, Squid rules, write sidecar policies, or wrangle your own container network routing.
Pro tips
-
Don’t know what to allow? Start with
--permission-profile none
and check the logs for denied requests.
docker logs <mcp-name>-egress
-
Need auditability more than isolation? Set
"insecure_allow_all": true
in your profile and run with--isolate-network
to log everything without blocking. Currently, the proxy logs are ephemeral inside the egress container, but if you’d like to see a persistence option please let us know via a GitHub issue!
Safer defaults, smarter agents
As AI tooling becomes more agentic — running background tasks, accessing services, and making autonomous decisions — you’ll need guardrails that match the autonomy. Network isolation is one of the simplest, most powerful controls you can put in place.
Ready to take control of your MCP network surface?
- 🚀 Follow the quickstart guide to get up and running fast
- 📄 Learn more about network isolation in the custom permissions guide
- ⭐ Check out ToolHive on GitHub to explore the code and contribute
- 💬 Join the Stacklok Discord to get support, ask questions, or share your feedback
Build smarter, safer AI workflows, one locked-down container at a time.
Top comments (0)