mcp-home-server
Self-hostable MCP server that gives Claude tools to run shell scripts and read files on a home server. Runs on a Multipass VM, exposed via Cloudflare Tunnel.
Tools
| Tool | What it does |
|---|---|
run_script(name, args[]) |
Runs /opt/mcp-server/scripts/{name} on the VM |
read_file(path) |
Returns file contents (unrestricted path — VM is the sandbox) |
update_self() |
git pull + systemctl restart — picks up new scripts automatically |
VM Deployment
git clone [email protected]:Axolotlpi/mcp-home-server.git /opt/mcp-server
cp /opt/mcp-server/.env.example /opt/mcp-server/.env
nano /opt/mcp-server/.env # set MCP_TOKEN to a long random secret
sudo bash /opt/mcp-server/setup.sh
Allow the service to restart itself without a password prompt:
echo 'ubuntu ALL=(ALL) NOPASSWD: /bin/systemctl restart mcp-server' \
| sudo tee /etc/sudoers.d/mcp-server
Cloudflare Tunnel Setup
This exposes 127.0.0.1:8000 on the VM to a public HTTPS URL without opening firewall ports.
1. Install cloudflared
curl -L https://pkg.cloudflare.com/cloudflare-main.gpg \
| sudo tee /usr/share/keyrings/cloudflare-main.gpg > /dev/null
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared jammy main' \
| sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt update && sudo apt install cloudflared -y
2. Authenticate and create a tunnel
cloudflared tunnel login # opens browser — pick your domain
cloudflared tunnel create mcp-server
Note the tunnel ID printed after creation.
3. Find your credentials file path
The credentials file location depends on which user ran tunnel login:
# if you ran as root
ls /root/.cloudflared/
# if you ran as your normal user
ls ~/.cloudflared/
You're looking for a file named <YOUR_TUNNEL_ID>.json. Use whichever path exists — you'll need it in the next step.
4. Create the config file
sudo mkdir -p /etc/cloudflared
sudo tee /etc/cloudflared/config.yml <<EOF
tunnel: <YOUR_TUNNEL_ID>
credentials-file: /root/.cloudflared/<YOUR_TUNNEL_ID>.json
ingress:
- hostname: mcp.yourdomain.com
service: http://127.0.0.1:8000
- service: http_status:404
EOF
Replace <YOUR_TUNNEL_ID> and mcp.yourdomain.com with your values.
5. Route DNS
cloudflared tunnel route dns mcp-server mcp.yourdomain.com
This creates a CNAME record in your Cloudflare dashboard pointing to the tunnel.
6. Run as a service
sudo cloudflared service install
sudo systemctl enable --now cloudflared
The tunnel will now start on boot. Your server is reachable at https://mcp.yourdomain.com.
Adding to Claude
The MCP server speaks SSE. The endpoint is https://mcp.yourdomain.com/sse.
Claude Desktop
Edit claude_desktop_config.json:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"home-server": {
"url": "https://mcp.yourdomain.com/sse",
"headers": {
"Authorization": "Bearer YOUR_MCP_TOKEN"
}
}
}
}
Restart Claude Desktop after saving.
Claude Code (CLI)
claude mcp add --transport sse home-server https://mcp.yourdomain.com/sse \
--header "Authorization: Bearer YOUR_MCP_TOKEN"
Or add it to .claude/settings.json manually:
{
"mcpServers": {
"home-server": {
"type": "sse",
"url": "https://mcp.yourdomain.com/sse",
"headers": {
"Authorization": "Bearer YOUR_MCP_TOKEN"
}
}
}
}
Adding New Scripts
- Add your script to
scripts/and push to GitHub - Tell Claude: "run update_self" — it pulls the latest code and restarts
- Tell Claude: "run my-script.sh" — it executes on the VM
The connection will drop briefly during the restart on step 2. That's expected.
To block a script from being callable via the API, add its filename to blacklist.txt.