Custom permissions
ToolHive includes a permission system that lets you control an MCP server's access to your host's file system and to network resources. This is crucial for maintaining security and ensuring that MCP servers operate within defined boundaries.
This guide shows you how to create and apply custom permission profiles for MCP servers, including built-in profiles and examples of common use cases.
Understanding permission profiles
Permissions are defined using permission profiles. These profiles specify:
- Host file system access (read and/or write access to specific paths)
 - Network access rules (outbound connections from the MCP server)
 
Since the MCP server runs in a container, it can't access the host file system by default. File system access is relative to the container's file system.
When you run a server with the --volume flag to mount a local path, ToolHive
adds the path to the MCP server's permission profile automatically.
Profiles include the following sections:
read: List of file system paths that the MCP server can read, relative to the container's file system.write: List of file system paths that the MCP server can write to (this also implies read access).network: Network access rules for outbound connections.outbound: Outbound network access rules, which include:insecure_allow_all: If set totrue, allows unrestricted outbound network access. This isn't recommended for production use.allow_transport: List of allowed transport protocols (e.g.,tcp,udp).allow_host: List of allowed hostnames or IP addresses for outbound connections. To allow all subdomains of a domain, prefix the domain with a period (e.g.,.github.comallows any subdomain ofgithub.com). Wildcards are not supported.allow_port: List of allowed ports for outbound connections.
Default permissions in the ToolHive registry
ToolHive includes default least-privilege permissions for MCP servers in the built-in registry. These defaults are designed to balance functionality and security, but you should review them to make sure they meet your specific requirements.
View these permissions using the following command:
thv registry info <server-name>
In the output, look for the "Permissions" section:
Permissions:
  Read:
    - /data
  Write:
    - /tmp
  Network:
    Allow Transport: tcp
    Allow Host: .google.com
    Allow Port: 443
This example shows that the MCP server has read access to /data, read/write
access to /tmp, and can make outbound TCP connections to *.google.com (note
the leading . which enables subdomain matching) on port 443.
Always verify the default permissions and override them with a custom profile if needed to meet your security policies.
Add --format json to the
thv registry info command to get the
output in JSON format for easier customization. Use the contents of the
permissions section as a starting point for creating a custom profile.
Built-in profiles
ToolHive includes two built-in profiles that you can use without creating a custom file:
- 
The
networkprofile permits outbound network access. It's the default profile applied to MCP servers when you run a server without the--permission-profileflag.importantThis profile is useful for development and testing but isn't recommended for production use since it doesn't restrict network destinations. If possible, create a custom profile that specifies the allowed hosts and ports.
 - 
The
noneprofile provides no network access. It's useful for MCP servers that don't require any external connectivity. File system access is limited to paths you explicitly mount using the--volumeflag. 
Create a custom permissions profile
Create a JSON file with your desired permissions, like ~/custom-profile.json.
For example:
{
  "read": ["/example/path1", "/example/path2"],
  "write": ["/example/path3"],
  "network": {
    "outbound": {
      "insecure_allow_all": false,
      "allow_transport": ["tcp", "udp"],
      "allow_host": ["localhost", ".google.com"],
      "allow_port": [80, 443]
    }
  }
}
This profile:
- Allows read-only access to 
/example/path1and/example/path2 - Allows read and write access to 
/example/path3(note that thewritesetting also implies read access) - Allows outbound TCP or UDP connections to 
localhostandgoogle.com(including subdomains) on ports 80 and 443 
Apply a permissions profile
Using a built-in profile
To run an MCP server with a built-in profile:
# This is equivalent to running a server without the --permission-profile flag
thv run --permission-profile network <server-name>
or
thv run --permission-profile none <server-name>
Add the --isolate-network flag to enforce network restrictions:
thv run --isolate-network --permission-profile none <server-name>
Using a custom profile file
To run an MCP server with your custom profile:
thv run --isolate-network --permission-profile </path/to/custom-profile.json> <server-name>
Network isolation
To enforce the network access rules defined in your permission profile, you must
use the --isolate-network flag when running the MCP server:
thv run --isolate-network --permission-profile </path/to/custom-profile.json> <server-name>
When network isolation is enabled, ToolHive creates a secure network architecture around your MCP server. Along with the main MCP server container, ToolHive launches:
- An egress Squid proxy container that filters outgoing network traffic
 - A dnsmasq container that provides controlled DNS resolution
 - An ingress Squid proxy container that proxies incoming SSE requests from the ToolHive proxy process (only for MCP servers using SSE transport; stdio MCP servers don't need this since they don't expose ports)
 
This multi-container setup ensures that all network traffic flows through controlled proxy points, allowing ToolHive to enforce the network access rules specified in your permission profile.
Network isolation currently supports only HTTP and HTTPS protocols. Other protocols like TCP sockets for database connections will not work with network isolation enabled.
Example: Restrict network access
The GitHub MCP server in the registry has a default profile that allows access
to github.com, but you might need to customize it for a self-hosted GitHub
Enterprise instance:
- 
Create a file named
github-profile.json:{
"network": {
"outbound": {
"insecure_allow_all": false,
"allow_transport": ["tcp"],
"allow_host": ["github.example.com"],
"allow_port": [443]
}
}
} - 
Run the GitHub MCP server with this profile:
thv run --isolate-network --permission-profile ./github-profile.json --secret github,target=GITHUB_PERSONAL_ACCESS_TOKEN github 
This restricts the GitHub MCP server to make HTTPS connections only to
github.example.com.
Security best practices
When creating and using permission profiles:
- Use the 
noneprofile when possible (for MCP servers that don't require network or file access) - Only grant necessary permissions
 - Avoid enabling 
network.outbound.insecure_allow_all, as this allows unrestricted outbound network access - Review and test custom profiles thoroughly
 - Keep permission profiles in version control to track changes and share them with your team
 
Related information
Troubleshooting
File system access issues
If your MCP server can't access the file system as expected:
- 
Verify that the path(s) in your profile are correct
 - 
Check that the permissions are set correctly (read/write)
 - 
Make sure the paths are accessible from within the container. You can execute a shell in the container to check (this assumes the container includes an interactive shell):
docker exec -it <server-name> /bin/sh - 
Restart the server with the updated profile or a corrected volume mount
 
Network connectivity issues
If your MCP server can't connect to external services:
- 
Verify that your profile allows the necessary hosts and ports
 - 
Check that the transport protocol (TCP/UDP) is allowed
 - 
Check the logs of the egress proxy container for any blocked requests:
docker logs <mcp-server-name>-egressLook for messages indicating denied connections.
 - 
Try temporarily using the default
networkprofile to confirm it's a permissions issue