A minimal, containerized Model Context Protocol (MCP) server built with FastMCP and Docker. This serves as a clean starting point for building your own MCP servers with secure, isolated execution environments.
- π³ Fully Dockerized - No need to install dependencies locally
- π Flexible Access Control - Grant precise file system permissions from read-only to full write access as needed
- π FastMCP Framework - Simple, decorator-based tool creation
- π§ Just Integration - Modern build automation with tab completion
- π§ͺ MCP Inspector Ready - Easy testing with browser-based tools
- β‘ Minimal Setup - Get started in seconds
# macOS
brew install just
# Other platforms: see https://github.com/casey/just?tab=readme-ov-file#installation
# Build the Docker image
just build
# Test with MCP Inspector (provides URL to open in browser)
just test
# Interactive development shell
just dev
# Run MCP server in background
just serve
# Build
docker build -t mcp-template .
# Test with Inspector
npx @modelcontextprotocol/inspector docker run -i --rm mcp-template
# Run in background
docker run -i -d --rm mcp-template
The MCP Inspector provides a web-based interface for testing your tools:
- Run
just test
(or the manual npx command) - Copy the pre-filled URL from terminal output (includes auth token)
- Open the URL in your browser
- Click "Connect" to connect to your server
- Test tools in the "Tools" tab
mcp-template/
βββ Dockerfile # Container definition
βββ server.py # MCP server implementation
βββ justfile # Build automation
βββ README.md # This file
The server currently includes one example tool:
add(a, b)
- Adds two numbers together
Add new tools by creating functions with the @mcp.tool
decorator:
@mcp.tool
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
@mcp.tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers"""
return a * b
This template emphasizes secure, controlled access to your file system.
By default, the container has no access to your host files. You explicitly grant access using volume mounts:
# Read-only access to specific directories
docker run -i --rm -v $HOME/my-docs:/workdir/docs:ro mcp-template
docker run -i --rm -v $HOME/code:/workdir/code:ro mcp-template
# Read-write access
docker run -i --rm -v $HOME/sandbox:/workdir/sandbox:rw mcp-template
For the most secure setup, combine multiple flags:
docker run -i --rm \
--network none \
--user $(id -u):$(id -g) \
--read-only \
--tmpfs /tmp \
--cap-drop ALL \
--security-opt no-new-privileges \
-v $HOME/safe-folder:/workdir/data:ro \
mcp-template
Note: You may need to replace the
$(id -u):$(id -g)
and$HOME
with the explicit values on the agent configuration.
For enhanced security, consider adding these Docker flags:
β’ --network none
- Completely disables network access
- Prevents the container from making any network connections
- Ideal for file processing tools that don't need internet access
- Example:
docker run -i --rm --network none mcp-template
β’ --user $(id -u):$(id -g)
- Runs container as current user
- Prevents root privilege escalation
- Files created by container will have your user ownership
- Example:
docker run -i --rm --user $(id -u):$(id -g) mcp-template
β’ --read-only
- Makes container filesystem read-only
- Prevents container from modifying its own files
- Enhances security by limiting container's ability to persist changes
- Example:
docker run -i --rm --read-only mcp-template
β’ --tmpfs /tmp
- Provides temporary filesystem in memory
- Allows container to write to /tmp without affecting host
- Useful when combined with
--read-only
- Example:
docker run -i --rm --read-only --tmpfs /tmp mcp-template
β’ --cap-drop ALL
- Removes all Linux capabilities
- Minimizes container privileges
- Prevents container from performing privileged operations
- Example:
docker run -i --rm --cap-drop ALL mcp-template
β’ --security-opt no-new-privileges
- Prevents privilege escalation
- Blocks processes from gaining additional privileges
- Added security layer against potential exploits
- Example:
docker run -i --rm --security-opt no-new-privileges mcp-template
- Prevent accidents - MCP server can't modify files unless explicitly permitted
- Limit scope - Only mount directories the server actually needs
- Audit access - Clear visibility into what directories are accessible
- Safe experimentation - Test tools on copies/sandboxes before using on real data
- Defense in depth - Multiple security layers protect against various attack vectors
This approach lets you build powerful MCP tools while maintaining fine-grained control over what they can access.
To use this MCP server with Claude Desktop, add it to your claude_desktop_config.json
configuration file:
{
"mcpServers": {
"mcp-template": {
"command": "docker",
"args": [
"run", "-i", "--rm", "mcp-template"
]
}
}
}
{
"mcpServers": {
"mcp-template": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-v", "<REPLACE_WITH_HOME_PATH>/Documents:/workdir/docs:ro",
"mcp-template"
]
}
}
}
{
"mcpServers": {
"mcp-template-max-secure": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"--network", "none",
"--user", "<REPLACE_WITH_USER>:<REPLACE_WITH_GROUP>",
"--read-only",
"--tmpfs", "/tmp",
"--cap-drop", "ALL",
"--security-opt", "no-new-privileges",
"-v", "<REPLACE_WITH_HOME_PATH>/Documents:/workdir/docs:ro",
"mcp-template"
]
}
}
}
After adding this configuration, restart Claude Desktop. The MCP server will appear as available tools that Claude can use during conversations.
This template includes a GitHub Action (.github/workflows/docker-publish.yml
) that automatically publishes Docker images to Docker Hub when you push code.
- Create a Docker Hub account and repository
- Add these to your GitHub repository settings:
- Variable:
DOCKERHUB_USERNAME
(your Docker Hub username) - Secret:
DOCKERHUB_TOKEN
(your Docker Hub access token)
- Variable:
- Push to
main
branch or create any tag β automatic Docker image build and publish
If you don't want automatic Docker Hub publishing, simply delete:
rm .github/workflows/docker-publish.yml
- Edit
server.py
with your tools - Build with
just build
- Test with
just test
- Iterate and repeat
- Ensure you're using the auth token URL provided in terminal output
- Check that the container started successfully (docker ps)
docker ps
docker logs <name>
- Verify the
@mcp.tool
decorator is present - Check that the function has a docstring
- Rebuild the container after changes
MIT License - Feel free to use this as a starting point for your own MCP servers.