If Claude, Cursor, or an internal agent needs files, a database, or your company APIs, keeping MCP only on a laptop over stdio is rarely enough. Teams usually want a shared HTTPS URL on a static-IP VPS. This guide explains how EuroVDC customers can host their own MCP servers (any language or repo) on a Sofia Cloud Server.
For EuroVDC’s open-source server that talks to our commerce APIs, use the dedicated walkthrough: Run MCP on a EuroVDC Sofia VPS (eurovdc-mcp). Here the scope is broader: publish a custom or third-party MCP safely.
stdio versus remote HTTPS
stdio means the client starts the server as a child process. That fits a single developer on one machine. Shared access, off-site work, or Claude remote connectors need Streamable HTTP. The client posts JSON-RPC to a URL such as https://mcp.your-domain.com/mcp. TLS and authentication are on you.
Why Sofia (EU)
- Process and data stay inside the EU, which simplifies location questions in customer contracts.
- Low latency across Central and Eastern Europe, with acceptable RTT into Western Europe.
- You can measure delay after order with Sofia Looking Glass.
- No tunnel vendor lock-in: your domain, certificate, and firewall.
Three production mistakes we keep seeing
- Open port with no auth. MCP often reaches files, shell, or databases. Do not bind to
0.0.0.0without a bearer token or OAuth. - Nginx buffering left on. Streamable HTTP stalls behind a full buffer. Set
proxy_buffering offand a longproxy_read_timeout. - App listening on 443 directly. Terminate TLS at Nginx or Caddy so renewals, logs, and limits stay manageable.
1. Prepare the VPS
A small Sofia plan (1 vCPU / 2 GB RAM) is enough for one MCP process. Install your runtime, Nginx, Certbot, and open only 22, 80, and 443. Keep the app port off the public internet.
sudo apt update && sudo apt upgrade -y
sudo apt install -y nginx certbot python3-certbot-nginx ufw
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable2. Bind the MCP process to localhost
Language does not matter. Listen on 127.0.0.1 and a private port (for example 3100). Keep the process alive with systemd or PM2.
cd /opt/my-mcp
npm install && npm run build
# .env: HOST=127.0.0.1 PORT=3100 MCP_TOKEN=...sudo tee /etc/systemd/system/my-mcp.service > /dev/null <<'EOF'
[Unit]
Description=Customer MCP server
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/my-mcp
EnvironmentFile=/opt/my-mcp/.env
ExecStart=/usr/bin/node dist/index.js
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now my-mcp3. HTTPS reverse proxy that keeps streams alive
server {
listen 80;
server_name mcp.your-domain.com;
location /mcp {
proxy_pass http://127.0.0.1:3100;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Authorization $http_authorization;
proxy_set_header Connection "";
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
}
}sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d mcp.your-domain.comValidate tokens in the app when you can. A proxy header check is only a stopgap; prefer the protocol’s own auth or OAuth for the long term.
4. Connect Claude or Cursor
claude mcp add --transport http my-mcp https://mcp.your-domain.com/mcp \
--header "Authorization: Bearer YOUR_TOKEN"In Cursor, add the same HTTPS URL and Authorization header. Prefer Streamable HTTP for new deploys; use an SSE bridge only when the server still requires it.
5. Verify in production
- Check TLS with
curl -sI https://mcp.your-domain.com/mcp. - Confirm the tool list in the client.
- Optional: run AI Readiness Checker if you publish
/.well-known/mcp.json. - Measure RTT with Looking Glass.
EuroVDC MCP versus your MCP
Need agents to buy domains or hosting through EuroVDC APIs? Follow the eurovdc-mcp guide. Building tools for your CRM or internal APIs? Use this Sofia + TLS + auth pattern. Both can share one VPS on different ports and subdomains.
Frequently asked questions
Can I host any MCP?
Yes. Node, Python, or Go is fine as long as it listens on localhost and can sit behind an HTTPS proxy.
Do I need a tunnel?
No. Your domain plus Let’s Encrypt is enough. For local work, stdio or an SSH tunnel is enough.
How much capacity do I need?
A small Sofia cloud plan covers one light MCP. Scale vCPU and RAM when tools are heavy or many clients connect.
Is IP allowlisting enough without a token?
No. Allowlists help, but do not expose MCP to the public internet without a bearer token or OAuth.
Connected but no tools appear?
Usually Nginx buffering or a short timeout. Check proxy_buffering off and proxy_read_timeout.
Does this replace the eurovdc-mcp guide?
No. This is the general hosting model. For EuroVDC API tools follow eurovdc-mcp.