Why host your own MCP server
Third-party hosted MCP services introduce an external dependency: your data, prompts and contexts pass through infrastructure you do not control. On a VPS, the MCP server runs in your network, with your access rules and your chain of trust. This is the same logic as self-hosting a Git repository or a Docker registry: autonomy takes precedence over convenience.
What you gain by self-hosting
- Data confidentiality: no context leaves your infrastructure.
- No third-party round-trip: the MCP server and your application run on the same network or on neighbouring VPS instances.
- Full customisation: in-house tools, proprietary connectors, tailor-made runtime environment.
- Predictable cost: a fixed VPS subscription, with no per-call billing.
- Version control: you decide when to update the server and its dependencies.
Prerequisites before you start
You need a VPS with root access, a recent Linux distribution (Ubuntu 22.04 LTS or Debian 12 are recommended), Node.js 18+ or Python 3.11+ depending on the implementation chosen, and a domain name pointing to your server's IP. A plan with at least 1 vCPU and 2 GB of RAM is suitable for a moderately used MCP server. For heavy loads or multiple MCP servers in parallel, plan for 2 vCPU and 4 GB.
Deploy an MCP server in 10 steps
Update the system and install Node.js
Connect via SSH with your key and run
apt update && apt upgrade -y. Install Node.js from the official NodeSource repository:curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && apt install -y nodejs. Verify withnode -vandnpm -v.Create a dedicated user
Never run the MCP server as root. Create an application user:
useradd -m -s /bin/bash mcp && su - mcp. All subsequent commands run under this user.Clone and install the MCP server
Choose your implementation (see the 'Recommended open source MCP servers' section below). For
@modelcontextprotocol/server-filesystem:npm install -g @modelcontextprotocol/server-filesystem. Test locally:npx @modelcontextprotocol/server-filesystem /tmp/test.Create a systemd service file
Create
/etc/systemd/system/mcp-server.servicewith the directivesUser=mcp,ExecStart=/usr/bin/npx @modelcontextprotocol/server-filesystem /home/mcp/data,Restart=alwaysandEnvironment=NODE_ENV=production. Enable and start:systemctl enable --now mcp-server.Install nginx
Nginx acts as a reverse proxy in front of your MCP server.
apt install -y nginx. Create a vhost in/etc/nginx/sites-available/mcpwith alocation /that doesproxy_pass http://127.0.0.1:3000;and the headersproxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr;. Enable:ln -s /etc/nginx/sites-available/mcp /etc/nginx/sites-enabled/ && nginx -t && systemctl reload nginx.Obtain a TLS certificate with Certbot
apt install -y certbot python3-certbot-nginx && certbot --nginx -d your-domain.com. Certbot automatically modifies your nginx vhost to redirect HTTP to HTTPS and sets up automatic renewal. Verify renewal:certbot renew --dry-run.Enable Bearer authentication
Edit your nginx vhost to require a token in the HTTP header:
if ($http_authorization != 'Bearer YOUR_SECRET_TOKEN') { return 401; }. Generate a strong token withopenssl rand -hex 32. Keep this token: it will be entered in your AI client configuration.Configure the firewall
Close all ports except 22, 80 and 443:
ufw allow 22/tcp && ufw allow 80/tcp && ufw allow 443/tcp && ufw enable. The internal port of the MCP server (3000 by default) must never be exposed directly.Test the endpoint with curl
curl -H 'Authorization: Bearer YOUR_SECRET_TOKEN' https://your-domain.com/health. You should get a status JSON. A 401 response indicates an incorrect token; a 502 response indicates the systemd service is not running (systemctl status mcp-server).Enable nginx access logs
Add to your vhost:
access_log /var/log/nginx/mcp_access.log; error_log /var/log/nginx/mcp_error.log warn;. These logs are essential for detecting unauthorised calls or request loops. Rotate them with logrotate to avoid filling the disk.
Always enable nginx access logs for your server
An MCP server receives machine-to-machine calls: without logs, you cannot detect unauthorised access attempts or integration bugs. Also configure log_format to record the truncated Authorization header (the first 8 characters are enough to identify the source without exposing the full token).
Recommended open source MCP servers
@modelcontextprotocol/server-filesystem— controlled access to the file system, reading and writing local files. Ideal for giving an agent access to a working directory.@modelcontextprotocol/server-git— clone, log, diff, commit via a local repository. Allows an agent to read history or create branches.@modelcontextprotocol/server-fetch— delegates outbound HTTP requests to the MCP server, bypassing client network restrictions.@modelcontextprotocol/server-postgres— connection to a PostgreSQL database: SELECT queries, schema, describe table. Do not expose for writing without auditing permissions.@modelcontextprotocol/server-playwright— control of a headless Chromium browser from the agent: screenshot, click, form filling.mcp-server-sqlite(community) — lightweight alternative for local SQLite databases, without PostgreSQL dependency.mcp-obsidian(community) — access to an Obsidian vault, useful for Markdown knowledge bases.
Securing your MCP server in production
An MCP server exposed on the Internet is an attack surface. Four measures are non-negotiable before connecting an AI client to this server in production.
Bearer token authentication. Enter a unique token per client in the Authorization header. Immediately revoke a compromised token and generate a new one with openssl rand -hex 32. Do not reuse the same token for multiple clients: you will lose traceability.
nginx rate-limiting. Add to your vhost: limit_req_zone $binary_remote_addr zone=mcp:10m rate=30r/m; limit_req zone=mcp burst=10 nodelay;. This limits to 30 requests per minute per IP, with a burst of 10. Adjust according to your actual usage.
Mandatory HTTPS and HSTS. After installing Certbot, add in the HTTPS server block: add_header Strict-Transport-Security "max-age=31536000" always;. This prevents clients from connecting over plain HTTP even if they try.
Token rotation. Schedule a rotation every 90 days via cron or your secrets management tool. Document each active token and its associated client in a private registry (not in the code repository).
Integrating Claude Desktop and Cursor with your MCP server
Once the server is online and secured, connecting from an AI client takes less than two minutes.
Claude Desktop. Open ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows). Add an entry in the mcpServers key:
{
"mcpServers": {
"my-vps": {
"url": "https://your-domain.com",
"headers": {
"Authorization": "Bearer YOUR_SECRET_TOKEN"
}
}
}
}Restart Claude Desktop. The server appears in the list of available tools.
Cursor. In settings (Cursor > Settings > MCP), click 'Add server', choose the HTTP type, enter the URL and add the Authorization header. Cursor automatically injects MCP tools into the context of each conversation.
Verification. Ask the agent to list available tools. If the filesystem server is active, the response should include read_file, write_file and list_directory. The absence of these tools indicates a configuration error — check the nginx logs first.
MCP vs REST API vs WebSocket for AI agents
Scroll the table
| Criterion | MCP | REST API | WebSocket |
|---|---|---|---|
| Communication model | Typed tool calls, dynamic schema discovery | Stateless HTTP request/response, OpenAPI contract | Persistent bidirectional channel, real-time events |
| Native integration with LLMs | Native: Claude, Cursor, Cline, Continue read the MCP schema directly | Requires a function-calling wrapper or plugin | Requires an adapter on the agent side |
| Deployment complexity | Low: one Node/Python process, one nginx vhost | Low to medium: standard REST framework | Medium to high: connection management, reconnection, state |
| Suited for | Local tools, file access, databases, agent automation | Third-party integrations, webhooks, existing microservices | Push notifications, real-time collaboration, streaming |
| Versioning and evolution | Schema declared in the server, auto-discovered by the client | Explicit versioning in the URL or header | Application protocol to be managed manually |
Troubleshooting: 4 common errors
1. MCP transport error: Failed to fetch
This message appears in Claude Desktop or Cursor when the client cannot reach the configured URL. Common causes: the systemd service is not running (systemctl status mcp-server), nginx has not been reloaded after modifying the vhost (nginx -t && systemctl reload nginx), or a firewall is blocking port 443 (ufw status).
2. Connection refused on 127.0.0.1:3000
The MCP server did not start or crashed at startup. Check the systemd logs: journalctl -u mcp-server -n 50. Common causes are an invalid JSON configuration file, a missing npm dependency (npm install to re-run in the project directory) or a port already in use (ss -tlnp | grep 3000).
3. Request timed out after 30000ms
The server responds but too slowly. On a filesystem tool, this happens if the directory being scanned is too large or the disk is full (df -h). For a postgres tool, check that the query is not doing a full scan on a table without an index. Increase the nginx timeout as a last resort: proxy_read_timeout 120s;.
4. 401 Unauthorized systematically
The token sent by the client does not match the one expected by nginx. Check the token accuracy in the client configuration (trailing space, quotes accidentally included). If you have just renewed the token server-side, restart nginx and reload the AI client configuration.
Towards a complete AI environment on your VPS
An MCP server is one component among many in a self-hosted AI environment. On the same VPS, you can run a local model via Ollama, a vector database like Qdrant or Chroma, and an orchestrator like n8n or Flowise — each connected to the MCP server via dedicated tools. ServOrbit offers ready-to-use VPS templates for these environments, installable in a few clicks from the Marketplace, on infrastructure hosted in European data centres with dedicated IPv4 and root access.