FastMCP supports HTTPS for secure connections by providing SSL certificate options. This guide covers setting up HTTPS for development and production.
Quick start
Enable HTTPS by providing SSL certificate options:
import { FastMCP } from "fastmcp";
const server = new FastMCP({
name: "My Server",
version: "1.0.0",
});
server.start({
transportType: "httpStream",
httpStream: {
port: 8443,
sslCert: "./path/to/cert.pem",
sslKey: "./path/to/key.pem",
sslCa: "./path/to/ca.pem", // Optional: for client certificate authentication
},
});
The server will start with HTTPS on https://localhost:8443/mcp.
SSL options
Path to the SSL certificate file (PEM format)
Path to the SSL private key file (PEM format)
Path to the CA certificate for mutual TLS authentication (optional)
Development setup
For local development and testing, you can generate self-signed certificates:
Generate self-signed certificates
Use OpenSSL to create a self-signed certificate:openssl req -x509 -newkey rsa:2048 \
-keyout key.pem \
-out cert.pem \
-days 365 \
-nodes \
-subj "/CN=localhost"
This creates:
key.pem - Private key
cert.pem - Self-signed certificate valid for 365 days
Configure your server
import { FastMCP } from "fastmcp";
import { fileURLToPath } from "url";
import { dirname, join } from "path";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const server = new FastMCP({
name: "HTTPS Dev Server",
version: "1.0.0",
});
server.addTool({
name: "greet",
description: "Say hello",
execute: async () => "Hello from HTTPS!",
});
server.start({
transportType: "httpStream",
httpStream: {
port: 8443,
sslCert: join(__dirname, "cert.pem"),
sslKey: join(__dirname, "key.pem"),
},
});
console.log("Server running at https://localhost:8443/mcp");
Accept self-signed certificate
When connecting from a client, you’ll need to accept the self-signed certificate warning. This is normal for development.Never use self-signed certificates in production. They don’t provide proper authentication and are vulnerable to man-in-the-middle attacks.
Production setup
For production, use certificates from a trusted Certificate Authority (CA).
Using Let’s Encrypt
Let’s Encrypt provides free SSL certificates:
Install Certbot
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install certbot
# macOS
brew install certbot
Obtain certificate
sudo certbot certonly --standalone \
-d your-domain.com \
-d www.your-domain.com
Certificates will be saved to:
/etc/letsencrypt/live/your-domain.com/fullchain.pem (certificate)
/etc/letsencrypt/live/your-domain.com/privkey.pem (private key)
Configure server
server.start({
transportType: "httpStream",
httpStream: {
port: 443,
sslCert: "/etc/letsencrypt/live/your-domain.com/fullchain.pem",
sslKey: "/etc/letsencrypt/live/your-domain.com/privkey.pem",
},
});
Set up auto-renewal
Let’s Encrypt certificates expire after 90 days. Set up automatic renewal:# Add to crontab
sudo crontab -e
# Add this line to renew twice daily
0 0,12 * * * certbot renew --quiet --post-hook "systemctl restart your-service"
Using commercial certificates
If you have certificates from a commercial CA (DigiCert, GlobalSign, etc.):
server.start({
transportType: "httpStream",
httpStream: {
port: 443,
sslCert: "/path/to/certificate.crt",
sslKey: "/path/to/private.key",
sslCa: "/path/to/ca-bundle.crt", // If provided by CA
},
});
Mutual TLS (mTLS)
For enhanced security, require clients to present valid certificates:
Generate client certificates
# Create a CA
openssl req -x509 -new -nodes -key ca-key.pem -sha256 -days 365 -out ca.pem
# Create client certificate
openssl req -new -key client-key.pem -out client.csr
openssl x509 -req -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -days 365
Configure server with CA
server.start({
transportType: "httpStream",
httpStream: {
port: 8443,
sslCert: "./server-cert.pem",
sslKey: "./server-key.pem",
sslCa: "./ca.pem", // CA that signed client certificates
},
});
Connect with client certificate
Clients must present a certificate signed by the specified CA to connect.
Complete example
Here’s a production-ready HTTPS server with proper error handling:
import { FastMCP } from "fastmcp";
import { z } from "zod";
import { readFileSync } from "fs";
const server = new FastMCP({
name: "Secure MCP Server",
version: "1.0.0",
});
server.addTool({
name: "secureData",
description: "Access secure data",
parameters: z.object({
query: z.string(),
}),
execute: async (args) => {
return `Secure response for: ${args.query}`;
},
});
try {
// Verify certificates exist and are readable
readFileSync(process.env.SSL_CERT_PATH!);
readFileSync(process.env.SSL_KEY_PATH!);
server.start({
transportType: "httpStream",
httpStream: {
port: Number(process.env.PORT) || 443,
sslCert: process.env.SSL_CERT_PATH!,
sslKey: process.env.SSL_KEY_PATH!,
sslCa: process.env.SSL_CA_PATH, // Optional
},
});
console.log(`Secure server running on port ${process.env.PORT || 443}`);
} catch (error) {
console.error("Failed to start HTTPS server:", error);
process.exit(1);
}
Security best practices
Use strong cipher suites
Configure Node.js to use strong cipher suites:export NODE_OPTIONS="--tls-cipher-list=ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256"
Keep certificates secure
- Store private keys with restricted permissions (chmod 600)
- Never commit certificates to version control
- Use environment variables for certificate paths
- Consider using a secrets management service (AWS Secrets Manager, HashiCorp Vault)
Enable HSTS
Force HTTPS connections using HTTP Strict Transport Security:server.addRoute("GET", "/*", async (req, res) => {
res.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
});
Monitor certificate expiration
Set up alerts to renew certificates before they expire:# Check certificate expiration
openssl x509 -enddate -noout -in cert.pem
Troubleshooting
Error: ENOENT - Certificate file not found
Verify the file paths are correct and the files exist:ls -la /path/to/cert.pem
ls -la /path/to/key.pem
Error: ERR_SSL_PROTOCOL_ERROR
This usually means:
- The certificate and key don’t match
- The certificate is invalid or expired
- Wrong certificate format (should be PEM)
Verify certificate and key match:openssl x509 -noout -modulus -in cert.pem | openssl md5
openssl rsa -noout -modulus -in key.pem | openssl md5
The MD5 hashes should match.
Self-signed certificate warnings
Browsers and clients will warn about self-signed certificates. For development:
- Accept the warning (temporary)
- Add certificate to system trust store (better)
For production, always use certificates from a trusted CA.
Next steps
Production Deployment
Learn about production deployment best practices
Authentication
Add authentication to your HTTPS server