If you have built an MCP server and want an assistant on another computer to connect to it, you need a public address and a process that keeps running. A VPS gives you control over that process, the HTTPS proxy and updates, but it also makes you responsible for the machine.
This is different from connecting an assistant to the Hostbrid account MCP server: that service lets you inspect and manage resources in your account; it does not run an MCP server you have written. To deploy an AI-generated website, see Projects. For a persistent MCP service that you manage yourself, this guide uses a VPS.
Choose the transport before deployment
The MCP protocol defines stdio and Streamable HTTP. With stdio, the client starts the process locally on its own computer. To connect to a remote service, you need an accessible HTTP endpoint, usually a route such as https://mcp.example.com/mcp. Streamable HTTP uses HTTP requests and can keep responses open as SSE; a proxy or firewall that does not support this traffic can break the session even if the page responds.
Check which transports your server and client support before you order a VPS. If you only need local tools for yourself, stdio may be enough and does not require a public VPS.
Build a small, protected server
This example uses the official MCP TypeScript SDK v2, Express and a harmless ping tool. It was validated on October 9, 2026, with @modelcontextprotocol/server and @modelcontextprotocol/client 2.3.1, @modelcontextprotocol/express 2.0.2, @modelcontextprotocol/node 2.1.1, Express and Zod. Check current versions before deployment: the SDK and specification evolve.
Install the dependencies and save exact versions in package-lock.json:
npm install --save-exact @modelcontextprotocol/server@2.3.1 @modelcontextprotocol/express@2.0.2 @modelcontextprotocol/node@2.1.1 express zod
Create server.mjs:
import { createMcpExpressApp } from '@modelcontextprotocol/express';
import { toNodeHandler } from '@modelcontextprotocol/node';
import { McpServer, createMcpHandler } from '@modelcontextprotocol/server';
import { timingSafeEqual } from 'node:crypto';
import { z } from 'zod';
const port = Number(process.env.PORT || 3000);
const bearer = process.env.MCP_BEARER_TOKEN;
const allowedHost = process.env.MCP_ALLOWED_HOST || '127.0.0.1';
if (!bearer || bearer.length < 32) throw new Error('Set MCP_BEARER_TOKEN to a random secret of at least 32 characters.');
if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error('PORT is invalid.');
const app = createMcpExpressApp({
host: '0.0.0.0',
allowedHosts: [allowedHost],
allowedOrigins: [allowedHost],
});
const handler = createMcpHandler(() => {
const server = new McpServer({ name: 'my-mcp-server', version: '1.0.0' });
server.registerTool('ping', {
description: 'Returns a fixed status response and makes no changes.',
inputSchema: z.object({}),
}, async () => ({ content: [{ type: 'text', text: 'pong' }] }));
return server;
});
const nodeHandler = toNodeHandler(handler);
app.all('/mcp', (req, res) => {
const header = req.get('authorization') || '';
const actual = Buffer.from(header.startsWith('Bearer ') ? header.slice(7) : '');
const expected = Buffer.from(bearer);
const valid = actual.length === expected.length && timingSafeEqual(actual, expected);
if (!valid) return res.status(401).json({ error: 'unauthorized' });
return void nodeHandler(req, res, req.body);
});
app.listen(port, '127.0.0.1', () => console.log(`MCP listening on 127.0.0.1:${port}/mcp`));
allowedHosts and allowedOrigins should contain the public hostname served by the proxy, such as mcp.example.com. The process listens only on loopback; do not expose Node’s port directly to the Internet. If clients send a different Origin—for example, a browser extension—add only the origin you actually use.
The bearer authentication in this example is suitable for a controlled test and for a client that lets you configure that header. For multiple users, scoped tokens or OAuth access, use an authentication flow that your MCP clients support. Never put secrets in Git, example repositories or logs.
Keep the process running and serve HTTPS
Run the application as a system user without administrator privileges. A systemd service can restart it after a failure or when the machine boots. Store MCP_BEARER_TOKEN in an environment file readable only by that user, not on the command line or in the repository.
Put Nginx in front of the process, terminate TLS for the subdomain and forward the /mcp route to 127.0.0.1:3000/mcp. Preserve the Host and Origin headers so validation uses the public domain, allow the HTTP methods required by Streamable HTTP, and disable buffering for SSE responses. Adjust the read timeout if your server supports long-running responses. Do not expose administration or database ports to the Internet.
After obtaining an HTTPS certificate, check from outside the VPS that DNS points to its IP and that the MCP route reaches the service. The exact Nginx instructions depend on your certificate, domain, SDK version and whether your server uses sessions; test the setup on a subdomain before moving real traffic.
Check the protocol, access and recovery
Connect a real MCP client—such as MCP Inspector—to the HTTPS endpoint. Confirm that it can initialize a session, list ping and receive pong. Repeat the test without a token and with a disallowed Origin: this example should reject both. Also check the GET/SSE method if your server offers it, service restarts and whether logs contain tokens.
The local test for this example used the official MCP client: a request without a token received HTTP 401, the authorized client listed ping and received pong, and a disallowed origin received HTTP 403. This validates the example’s protocol and controls; it does not prove your VPS’s production performance, availability or configuration.
When a VPS makes sense and what it involves
A VPS fits when you need a persistent process, system packages, control over the proxy or custom networking. Hostbrid provides the virtual machine; you manage the operating system, updates, permissions, application, secrets, backups and incident response. Review VPS sizes and prices and check the total cost and resources before ordering.
A Node.js app on Sites hosting might work for a simple HTTP MCP server, but the public documentation does not confirm support for sessions, SSE streaming or each client’s connection limits. Test that behavior with your provider before relying on it. Projects is designed to build and publish web repositories; do not treat it as a persistent MCP process without testing its limits.
If the service stores data, define a backup plan and test how to restore it. If a tool can delete data, change permissions or spend money, add explicit authorization, limits and human confirmation. MCP connects clients to tools; it does not make a tool safe by itself.