Remote MCP Server Connections

Remote connections allow you to connect to Model Context Protocol (MCP) servers hosted on remote machines, cloud infrastructure, or different networks. This enables distributed architectures where MCP servers can be deployed separately from client applications.

Understanding Remote MCP Architecture

Remote MCP servers enable scalable, distributed AI systems by allowing:

  • Centralized server deployment - Host specialized MCP servers on dedicated infrastructure
  • Cross-network access - Connect to servers across different networks and cloud providers
  • Load distribution - Distribute processing across multiple server instances
  • Shared resources - Multiple clients can access the same MCP server capabilities

For comprehensive information about the MCP specification and architecture, visit the official MCP documentation.

Transport Protocols

Pylee supports two transport protocols for remote MCP server connections:

The Streamable HTTP transport uses modern HTTP streaming capabilities for efficient communication with remote MCP servers. This is the recommended protocol for most use cases.

Transport Type: streamable

URL Format:

https://api.example.com/v1/mcp
http://localhost:3000/mcp

Key Features:

  • Efficient HTTP streaming for real-time communication
  • Built-in error handling and retry mechanisms
  • Support for bidirectional communication
  • Compatible with standard HTTP infrastructure
  • Automatic connection management

Advantages:

  • Modern streaming capabilities
  • Lower latency than traditional request-response
  • Firewall and proxy friendly
  • Built-in HTTPS security support
  • Excellent performance for high-frequency operations

Best for:

  • Production deployments
  • Real-time applications
  • High-performance scenarios
  • Modern cloud infrastructure
  • Client applications with intermittent connectivity needs

WebSocket Protocol

Provides persistent, bidirectional communication channels for real-time interaction.

URL Format:

ws://hostname:port/mcp
wss://hostname:port/mcp

Advantages:

  • Real-time bidirectional communication
  • Lower latency for frequent operations
  • Persistent connection reduces overhead
  • Native browser support

Disadvantages:

  • More complex connection management
  • May require special network configuration
  • Connection state management complexity

Best for:

  • Interactive applications requiring immediate responses
  • High-frequency tool invocation scenarios
  • Real-time collaborative environments
  • Applications needing bidirectional data flow

Server-Sent Events (SSE)

Uses Server-Sent Events for server-to-client streaming communication.

URL Format:

http://hostname:port/mcp/events
https://hostname:port/mcp/events

Advantages:

  • Real-time server-to-client updates
  • Automatic reconnection handling
  • HTTP-based (firewall friendly)
  • Built-in browser support

Disadvantages:

  • Unidirectional (server to client only)
  • Limited browser connection limits
  • May require additional endpoint for client-to-server requests

Best for:

  • Live monitoring and status updates
  • Progress tracking for long-running operations
  • Event-driven architectures
  • Applications requiring server push notifications

Configuring Remote Connections in Pylee

Using the Pylee Configuration Interface

Navigate to your server’s configuration page and select Remote Configuration to set up remote MCP connections:

  1. Go to Configuration

    /{organization}/server/{server}/configuration/remotes
    
  2. Add Remote Connection

    • Click “Add Remote” to create a new remote connection
    • Configure the transport type and endpoint URL
    • Set up authentication headers if required

Remote Configuration Options

Basic Configuration

Transport Type: Choose between streamable (recommended) or sse (deprecated)

URL: The endpoint URL for your remote MCP server

https://api.example.com/v1/mcp

Authentication Headers

Configure HTTP headers for authentication and custom requirements:

Common Authentication Patterns:

{
  "name": "Authorization",
  "value": "Bearer your-api-token",
  "description": "API authentication token",
  "is_required": true,
  "is_secret": true
}
{
  "name": "X-API-Key",
  "value": "your-api-key",
  "description": "Service API key",
  "is_required": true,
  "is_secret": true
}

Header Configuration Fields

  • Name: The HTTP header name (e.g., “Authorization”, “X-API-Key”)
  • Value: The header value (tokens, keys, etc.)
  • Description: Optional description of the header’s purpose
  • Required: Mark if this header is mandatory for the connection
  • Secret: Mark if this header contains sensitive information

Example Configurations

Production API with Authentication

{
  "transport_type": "streamable",
  "url": "https://mcp-api.yourcompany.com/v1/mcp",
  "headers": [
    {
      "name": "Authorization",
      "value": "Bearer prod_token_xyz123",
      "description": "Production API authentication",
      "is_required": true,
      "is_secret": true
    },
    {
      "name": "X-Client-Version",
      "value": "1.0.0",
      "description": "Client version identifier",
      "is_required": false,
      "is_secret": false
    }
  ]
}

Development Environment

{
  "transport_type": "streamable",
  "url": "http://localhost:3000/mcp",
  "headers": [
    {
      "name": "X-Environment",
      "value": "development",
      "description": "Environment identifier",
      "is_required": false,
      "is_secret": false
    }
  ]
}

Legacy Server Configuration

For reference, here’s how to configure an MCP server to accept remote connections:

Node.js Streamable Server
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StreamableTransport } from '@modelcontextprotocol/sdk/server/streamable.js';
import express from 'express';

const app = express();
const server = new Server(
  {
    name: 'remote-mcp-server',
    version: '1.0.0',
  },
  {
    capabilities: {
      resources: {},
      tools: {},
    },
  }
);

// Configure HTTP transport
const transport = new HTTPServerTransport({
  port: 8080,
  host: '0.0.0.0',
  cors: {
    origin: ['https://your-client-domain.com'],
    credentials: true
  }
});

await server.connect(transport);
console.log('MCP server listening on http://0.0.0.0:8080');
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { WebSocketServerTransport } from '@modelcontextprotocol/sdk/server/websocket.js';

const server = new Server(
  {
    name: 'websocket-mcp-server',
    version: '1.0.0',
  },
  {
    capabilities: {
      resources: {},
      tools: {},
    },
  }
);

const transport = new WebSocketServerTransport({
  port: 8080,
  host: '0.0.0.0',
  path: '/mcp',
  // Optional authentication
  authenticate: async (request) => {
    const token = request.headers.authorization;
    return validateToken(token);
  }
});

await server.connect(transport);
console.log('WebSocket MCP server listening on ws://0.0.0.0:8080/mcp');

Client Configuration

Configure your client to connect to remote MCP servers:

import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { HTTPClientTransport } from '@modelcontextprotocol/sdk/client/http.js';

const client = new Client(
  {
    name: 'mcp-client',
    version: '1.0.0',
  },
  {
    capabilities: {},
  }
);

const transport = new HTTPClientTransport({
  baseUrl: 'https://your-mcp-server.com:8080',
  headers: {
    'Authorization': 'Bearer your-api-token',
    'Content-Type': 'application/json'
  },
  timeout: 30000
});

await client.connect(transport);

// Use the client
const resources = await client.listResources();
console.log('Available resources:', resources);

Authentication and Security

Authentication Methods

Implement proper authentication for remote MCP servers:

// Token-based authentication
const authenticateToken = async (token) => {
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    return { valid: true, user: decoded };
  } catch (error) {
    return { valid: false, error: error.message };
  }
};

// API key authentication
const authenticateApiKey = async (apiKey) => {
  const validKeys = await loadValidApiKeys();
  return validKeys.includes(apiKey);
};

// Custom authentication middleware
server.setAuthenticationHandler(async (request) => {
  const authHeader = request.headers.authorization;
  
  if (!authHeader) {
    throw new Error('Authentication required');
  }
  
  if (authHeader.startsWith('Bearer ')) {
    const token = authHeader.substring(7);
    const result = await authenticateToken(token);
    if (!result.valid) {
      throw new Error('Invalid token');
    }
    return result.user;
  }
  
  if (authHeader.startsWith('ApiKey ')) {
    const apiKey = authHeader.substring(7);
    const isValid = await authenticateApiKey(apiKey);
    if (!isValid) {
      throw new Error('Invalid API key');
    }
    return { apiKey };
  }
  
  throw new Error('Unsupported authentication method');
});

Security Best Practices

Always implement these security measures for remote MCP servers:

  • Use HTTPS/WSS - Always encrypt connections in production
  • Implement authentication - Require valid credentials for all requests
  • Validate inputs - Sanitize and validate all tool parameters and resource requests
  • Rate limiting - Implement request rate limiting to prevent abuse
  • CORS configuration - Configure Cross-Origin Resource Sharing appropriately
  • Audit logging - Log all access attempts and operations
  • Regular updates - Keep MCP SDK and dependencies updated
// Security middleware example
import rateLimit from 'express-rate-limit';
import helmet from 'helmet';

// Rate limiting
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // limit each IP to 100 requests per windowMs
  message: 'Too many requests from this IP'
});

// Security headers
app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      connectSrc: ["'self'", "wss:"]
    }
  }
}));

app.use('/mcp', limiter);

// Input validation
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;
  
  // Validate tool name
  if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
    throw new Error('Invalid tool name format');
  }
  
  // Validate arguments
  const validated = await validateToolArguments(name, args);
  if (!validated.valid) {
    throw new Error(`Invalid arguments: ${validated.error}`);
  }
  
  return await executeTool(name, validated.args);
});

Load Balancing and Scaling

Multiple Server Instances

Deploy multiple MCP server instances for high availability:

// Load balancer configuration example
const servers = [
  'https://mcp-server-1.com:8080',
  'https://mcp-server-2.com:8080',
  'https://mcp-server-3.com:8080'
];

class LoadBalancedMCPClient {
  constructor(serverUrls) {
    this.servers = serverUrls;
    this.currentIndex = 0;
    this.clients = new Map();
  }
  
  async getClient() {
    const serverUrl = this.servers[this.currentIndex];
    
    if (!this.clients.has(serverUrl)) {
      const client = new Client({
        name: 'load-balanced-client',
        version: '1.0.0'
      }, { capabilities: {} });
      
      const transport = new HTTPClientTransport({
        baseUrl: serverUrl,
        timeout: 10000
      });
      
      await client.connect(transport);
      this.clients.set(serverUrl, client);
    }
    
    // Round-robin selection
    this.currentIndex = (this.currentIndex + 1) % this.servers.length;
    
    return this.clients.get(serverUrl);
  }
  
  async callTool(name, arguments) {
    const maxRetries = 3;
    let lastError;
    
    for (let i = 0; i < maxRetries; i++) {
      try {
        const client = await this.getClient();
        return await client.callTool({ name, arguments });
      } catch (error) {
        lastError = error;
        console.warn(`Server failed, trying next: ${error.message}`);
      }
    }
    
    throw new Error(`All servers failed: ${lastError.message}`);
  }
}

Docker Deployment

Deploy MCP servers using Docker for scalability:

# Dockerfile for MCP server
FROM node:18-slim

WORKDIR /app

# Install dependencies
COPY package*.json ./
RUN npm ci --only=production

# Copy application code
COPY . .

# Create non-root user
RUN useradd -m -u 1001 mcpuser
RUN chown -R mcpuser:mcpuser /app
USER mcpuser

# Expose port
EXPOSE 8080

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1

# Start server
CMD ["node", "dist/server.js"]
# docker-compose.yml for multiple instances
version: '3.8'
services:
  mcp-server-1:
    build: .
    ports:
      - "8081:8080"
    environment:
      - NODE_ENV=production
      - SERVER_ID=server-1
    restart: unless-stopped
    
  mcp-server-2:
    build: .
    ports:
      - "8082:8080"
    environment:
      - NODE_ENV=production
      - SERVER_ID=server-2
    restart: unless-stopped
    
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/nginx/ssl
    depends_on:
      - mcp-server-1
      - mcp-server-2
    restart: unless-stopped

Monitoring and Observability

Health Checks

Implement health monitoring for remote MCP servers:

// Health check endpoint
server.addHealthCheck('/health', async () => {
  const checks = {
    server: 'healthy',
    database: await checkDatabase(),
    externalServices: await checkExternalServices(),
    memory: process.memoryUsage(),
    uptime: process.uptime()
  };
  
  const allHealthy = Object.values(checks)
    .filter(v => typeof v === 'string')
    .every(status => status === 'healthy');
  
  return {
    status: allHealthy ? 'healthy' : 'unhealthy',
    timestamp: new Date().toISOString(),
    checks
  };
});

// Readiness check for load balancers
server.addHealthCheck('/ready', async () => {
  const isReady = await checkServerReadiness();
  return {
    status: isReady ? 'ready' : 'not-ready',
    timestamp: new Date().toISOString()
  };
});

Metrics Collection

Track server performance and usage:

// Prometheus metrics example
import prometheus from 'prom-client';

const requestCounter = new prometheus.Counter({
  name: 'mcp_requests_total',
  help: 'Total number of MCP requests',
  labelNames: ['method', 'status']
});

const requestDuration = new prometheus.Histogram({
  name: 'mcp_request_duration_seconds',
  help: 'Duration of MCP requests',
  labelNames: ['method']
});

const activeConnections = new prometheus.Gauge({
  name: 'mcp_active_connections',
  help: 'Number of active MCP connections'
});

// Instrument request handling
server.onRequest(async (request, response) => {
  const startTime = Date.now();
  const method = request.method;
  
  try {
    const result = await handleRequest(request);
    requestCounter.inc({ method, status: 'success' });
    return result;
  } catch (error) {
    requestCounter.inc({ method, status: 'error' });
    throw error;
  } finally {
    const duration = (Date.now() - startTime) / 1000;
    requestDuration.observe({ method }, duration);
  }
});

// Expose metrics endpoint
server.addRoute('/metrics', async (req, res) => {
  res.set('Content-Type', prometheus.register.contentType);
  res.end(await prometheus.register.metrics());
});

Security Best Practices

Authentication

  • Always use HTTPS for production deployments
  • Implement proper API key or token-based authentication
  • Mark sensitive headers as “secret” in the configuration
  • Rotate authentication credentials regularly

Network Security

  • Use secure transport protocols (HTTPS)
  • Configure proper CORS policies on your MCP servers
  • Implement rate limiting and request throttling
  • Monitor and log connection attempts

Troubleshooting Remote Connections

Configuration Issues

Remote endpoint not accessible:

  • Verify the URL is correct and reachable
  • Check network connectivity and firewall rules
  • Ensure the remote server is running and accepting connections

Authentication failures:

  • Verify API keys or tokens are correct and not expired
  • Check that required headers are properly configured
  • Ensure sensitive headers are marked as “secret”

Transport protocol issues:

  • Use streamable transport for new implementations
  • Migrate from sse to streamable for better performance
  • Verify the remote server supports the selected transport type

Debugging Steps

  1. Test connectivity:

    curl -I https://your-mcp-endpoint.com/v1/mcp
    
  2. Verify authentication:

    curl -H "Authorization: Bearer your-token" https://your-mcp-endpoint.com/v1/mcp
    
  3. Check server logs for connection attempts and errors

  4. Monitor network traffic to identify connection issues

Common Issues

Connection Timeouts

  • Check network connectivity between client and server
  • Verify firewall rules allow traffic on required ports
  • Increase client timeout settings if operations are slow
  • Monitor server resource usage and performance

Authentication Failures

  • Verify API keys or tokens are valid and not expired
  • Check authentication headers are properly formatted
  • Ensure server authentication configuration matches client
  • Review server logs for specific authentication errors

Protocol Errors

  • Validate MCP message format compliance using MCP Inspector
  • Check JSON-RPC 2.0 format adherence
  • Verify required fields are present in all messages
  • Test with minimal client to isolate issues

Performance Issues

  • Monitor server resource usage (CPU, memory, network)
  • Check for database connection pooling bottlenecks
  • Implement caching for frequently accessed resources
  • Consider using connection pooling on the client side

Debugging Tools

Use these tools to debug remote MCP connections:

# Test server connectivity
curl -v https://your-mcp-server.com:8080/health

# WebSocket connection testing
wscat -c wss://your-mcp-server.com:8080/mcp

# MCP protocol testing
npx @modelcontextprotocol/inspector http https://your-mcp-server.com:8080/mcp

# Load testing
npx autocannon -c 10 -d 30 https://your-mcp-server.com:8080/mcp

Protocol Selection Guide

Choose the right protocol based on your requirements:

Use CaseRecommended ProtocolReason
Web APIsHTTP/HTTPSStandard, cacheable, firewall-friendly
Real-time AppsWebSocketBidirectional, low-latency communication
Live DashboardsSSEServer push, automatic reconnection
Mobile AppsHTTP/HTTPSBetter battery life, intermittent connectivity
High-frequency ToolsWebSocketPersistent connection, lower overhead
Enterprise IntegrationHTTP/HTTPSSecurity policies, monitoring tools
MicroservicesHTTP/HTTPSService mesh compatibility, load balancing

Deployment Patterns

Cloud Deployment

Common patterns for deploying remote MCP servers:

  • Container orchestration - Use Kubernetes or Docker Swarm for scaling
  • Serverless functions - Deploy as AWS Lambda, Azure Functions, or Google Cloud Functions
  • API Gateway integration - Use cloud API gateways for routing and authentication
  • CDN deployment - Cache resources using content delivery networks
  • Multi-region deployment - Deploy servers across regions for global access

Edge Computing

Deploy MCP servers closer to users:

// Edge-optimized MCP server
const edgeServer = new Server({
  name: 'edge-mcp-server',
  version: '1.0.0'
}, {
  capabilities: {
    resources: {},
    tools: {},
    // Enable caching for edge deployment
    caching: {
      enabled: true,
      ttl: 300,
      regions: ['us-east-1', 'eu-west-1', 'ap-southeast-1']
    }
  }
});

// Implement geo-aware resource routing
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
  const clientRegion = request.headers['cf-ipcountry'] || 'US';
  const nearestCache = await findNearestCache(clientRegion);
  
  return await nearestCache.getResource(request.params.uri);
});

Next Steps

Once you have remote MCP server connections working:

Migration from SSE to Streamable

If you’re currently using SSE transport, consider migrating to Streamable HTTP:

Migration Steps

  1. Update transport type from sse to streamable in your remote configuration
  2. Verify endpoint compatibility with Streamable HTTP protocol
  3. Test the connection thoroughly in a development environment
  4. Update monitoring and logging to account for the new transport
  5. Deploy gradually using canary or blue-green deployment strategies

Benefits of Migration

  • Improved performance and reliability
  • Better error handling and recovery
  • Enhanced streaming capabilities
  • Future-proof protocol choice

Resources and Support

For additional help with remote MCP connections:

Remote MCP Server Connections

Remote connections allow you to connect to Model Context Protocol (MCP) servers hosted on remote machines, cloud infrastructure, or different networks. This enables distributed architectures where MCP servers can be deployed separately from client applications.

Understanding Remote MCP Architecture

Remote MCP servers enable scalable, distributed AI systems by allowing:

  • Centralized server deployment - Host specialized MCP servers on dedicated infrastructure
  • Cross-network access - Connect to servers across different networks and cloud providers
  • Load distribution - Distribute processing across multiple server instances
  • Shared resources - Multiple clients can access the same MCP server capabilities

For comprehensive information about the MCP specification and architecture, visit the official MCP documentation.

Transport Protocols

Pylee supports two transport protocols for remote MCP server connections:

The Streamable HTTP transport uses modern HTTP streaming capabilities for efficient communication with remote MCP servers. This is the recommended protocol for most use cases.

Transport Type: streamable

URL Format:

https://api.example.com/v1/mcp
http://localhost:3000/mcp

Key Features:

  • Efficient HTTP streaming for real-time communication
  • Built-in error handling and retry mechanisms
  • Support for bidirectional communication
  • Compatible with standard HTTP infrastructure
  • Automatic connection management

Advantages:

  • Modern streaming capabilities
  • Lower latency than traditional request-response
  • Firewall and proxy friendly
  • Built-in HTTPS security support
  • Excellent performance for high-frequency operations

Best for:

  • Production deployments
  • Real-time applications
  • High-performance scenarios
  • Modern cloud infrastructure
  • Client applications with intermittent connectivity needs

WebSocket Protocol

Provides persistent, bidirectional communication channels for real-time interaction.

URL Format:

ws://hostname:port/mcp
wss://hostname:port/mcp

Advantages:

  • Real-time bidirectional communication
  • Lower latency for frequent operations
  • Persistent connection reduces overhead
  • Native browser support

Disadvantages:

  • More complex connection management
  • May require special network configuration
  • Connection state management complexity

Best for:

  • Interactive applications requiring immediate responses
  • High-frequency tool invocation scenarios
  • Real-time collaborative environments
  • Applications needing bidirectional data flow

Server-Sent Events (SSE)

Uses Server-Sent Events for server-to-client streaming communication.

URL Format:

http://hostname:port/mcp/events
https://hostname:port/mcp/events

Advantages:

  • Real-time server-to-client updates
  • Automatic reconnection handling
  • HTTP-based (firewall friendly)
  • Built-in browser support

Disadvantages:

  • Unidirectional (server to client only)
  • Limited browser connection limits
  • May require additional endpoint for client-to-server requests

Best for:

  • Live monitoring and status updates
  • Progress tracking for long-running operations
  • Event-driven architectures
  • Applications requiring server push notifications

Configuring Remote Connections in Pylee

Using the Pylee Configuration Interface

Navigate to your server’s configuration page and select Remote Configuration to set up remote MCP connections:

  1. Go to Configuration

    /{organization}/server/{server}/configuration/remotes
    
  2. Add Remote Connection

    • Click “Add Remote” to create a new remote connection
    • Configure the transport type and endpoint URL
    • Set up authentication headers if required

Remote Configuration Options

Basic Configuration

Transport Type: Choose between streamable (recommended) or sse (deprecated)

URL: The endpoint URL for your remote MCP server

https://api.example.com/v1/mcp

Authentication Headers

Configure HTTP headers for authentication and custom requirements:

Common Authentication Patterns:

{
  "name": "Authorization",
  "value": "Bearer your-api-token",
  "description": "API authentication token",
  "is_required": true,
  "is_secret": true
}
{
  "name": "X-API-Key",
  "value": "your-api-key",
  "description": "Service API key",
  "is_required": true,
  "is_secret": true
}

Header Configuration Fields

  • Name: The HTTP header name (e.g., “Authorization”, “X-API-Key”)
  • Value: The header value (tokens, keys, etc.)
  • Description: Optional description of the header’s purpose
  • Required: Mark if this header is mandatory for the connection
  • Secret: Mark if this header contains sensitive information

Example Configurations

Production API with Authentication

{
  "transport_type": "streamable",
  "url": "https://mcp-api.yourcompany.com/v1/mcp",
  "headers": [
    {
      "name": "Authorization",
      "value": "Bearer prod_token_xyz123",
      "description": "Production API authentication",
      "is_required": true,
      "is_secret": true
    },
    {
      "name": "X-Client-Version",
      "value": "1.0.0",
      "description": "Client version identifier",
      "is_required": false,
      "is_secret": false
    }
  ]
}

Development Environment

{
  "transport_type": "streamable",
  "url": "http://localhost:3000/mcp",
  "headers": [
    {
      "name": "X-Environment",
      "value": "development",
      "description": "Environment identifier",
      "is_required": false,
      "is_secret": false
    }
  ]
}

Legacy Server Configuration

For reference, here’s how to configure an MCP server to accept remote connections:

Node.js Streamable Server
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StreamableTransport } from '@modelcontextprotocol/sdk/server/streamable.js';
import express from 'express';

const app = express();
const server = new Server(
  {
    name: 'remote-mcp-server',
    version: '1.0.0',
  },
  {
    capabilities: {
      resources: {},
      tools: {},
    },
  }
);

// Configure HTTP transport
const transport = new HTTPServerTransport({
  port: 8080,
  host: '0.0.0.0',
  cors: {
    origin: ['https://your-client-domain.com'],
    credentials: true
  }
});

await server.connect(transport);
console.log('MCP server listening on http://0.0.0.0:8080');
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { WebSocketServerTransport } from '@modelcontextprotocol/sdk/server/websocket.js';

const server = new Server(
  {
    name: 'websocket-mcp-server',
    version: '1.0.0',
  },
  {
    capabilities: {
      resources: {},
      tools: {},
    },
  }
);

const transport = new WebSocketServerTransport({
  port: 8080,
  host: '0.0.0.0',
  path: '/mcp',
  // Optional authentication
  authenticate: async (request) => {
    const token = request.headers.authorization;
    return validateToken(token);
  }
});

await server.connect(transport);
console.log('WebSocket MCP server listening on ws://0.0.0.0:8080/mcp');

Client Configuration

Configure your client to connect to remote MCP servers:

import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { HTTPClientTransport } from '@modelcontextprotocol/sdk/client/http.js';

const client = new Client(
  {
    name: 'mcp-client',
    version: '1.0.0',
  },
  {
    capabilities: {},
  }
);

const transport = new HTTPClientTransport({
  baseUrl: 'https://your-mcp-server.com:8080',
  headers: {
    'Authorization': 'Bearer your-api-token',
    'Content-Type': 'application/json'
  },
  timeout: 30000
});

await client.connect(transport);

// Use the client
const resources = await client.listResources();
console.log('Available resources:', resources);

Authentication and Security

Authentication Methods

Implement proper authentication for remote MCP servers:

// Token-based authentication
const authenticateToken = async (token) => {
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    return { valid: true, user: decoded };
  } catch (error) {
    return { valid: false, error: error.message };
  }
};

// API key authentication
const authenticateApiKey = async (apiKey) => {
  const validKeys = await loadValidApiKeys();
  return validKeys.includes(apiKey);
};

// Custom authentication middleware
server.setAuthenticationHandler(async (request) => {
  const authHeader = request.headers.authorization;
  
  if (!authHeader) {
    throw new Error('Authentication required');
  }
  
  if (authHeader.startsWith('Bearer ')) {
    const token = authHeader.substring(7);
    const result = await authenticateToken(token);
    if (!result.valid) {
      throw new Error('Invalid token');
    }
    return result.user;
  }
  
  if (authHeader.startsWith('ApiKey ')) {
    const apiKey = authHeader.substring(7);
    const isValid = await authenticateApiKey(apiKey);
    if (!isValid) {
      throw new Error('Invalid API key');
    }
    return { apiKey };
  }
  
  throw new Error('Unsupported authentication method');
});

Security Best Practices

Always implement these security measures for remote MCP servers:

  • Use HTTPS/WSS - Always encrypt connections in production
  • Implement authentication - Require valid credentials for all requests
  • Validate inputs - Sanitize and validate all tool parameters and resource requests
  • Rate limiting - Implement request rate limiting to prevent abuse
  • CORS configuration - Configure Cross-Origin Resource Sharing appropriately
  • Audit logging - Log all access attempts and operations
  • Regular updates - Keep MCP SDK and dependencies updated
// Security middleware example
import rateLimit from 'express-rate-limit';
import helmet from 'helmet';

// Rate limiting
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // limit each IP to 100 requests per windowMs
  message: 'Too many requests from this IP'
});

// Security headers
app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      connectSrc: ["'self'", "wss:"]
    }
  }
}));

app.use('/mcp', limiter);

// Input validation
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;
  
  // Validate tool name
  if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
    throw new Error('Invalid tool name format');
  }
  
  // Validate arguments
  const validated = await validateToolArguments(name, args);
  if (!validated.valid) {
    throw new Error(`Invalid arguments: ${validated.error}`);
  }
  
  return await executeTool(name, validated.args);
});

Load Balancing and Scaling

Multiple Server Instances

Deploy multiple MCP server instances for high availability:

// Load balancer configuration example
const servers = [
  'https://mcp-server-1.com:8080',
  'https://mcp-server-2.com:8080',
  'https://mcp-server-3.com:8080'
];

class LoadBalancedMCPClient {
  constructor(serverUrls) {
    this.servers = serverUrls;
    this.currentIndex = 0;
    this.clients = new Map();
  }
  
  async getClient() {
    const serverUrl = this.servers[this.currentIndex];
    
    if (!this.clients.has(serverUrl)) {
      const client = new Client({
        name: 'load-balanced-client',
        version: '1.0.0'
      }, { capabilities: {} });
      
      const transport = new HTTPClientTransport({
        baseUrl: serverUrl,
        timeout: 10000
      });
      
      await client.connect(transport);
      this.clients.set(serverUrl, client);
    }
    
    // Round-robin selection
    this.currentIndex = (this.currentIndex + 1) % this.servers.length;
    
    return this.clients.get(serverUrl);
  }
  
  async callTool(name, arguments) {
    const maxRetries = 3;
    let lastError;
    
    for (let i = 0; i < maxRetries; i++) {
      try {
        const client = await this.getClient();
        return await client.callTool({ name, arguments });
      } catch (error) {
        lastError = error;
        console.warn(`Server failed, trying next: ${error.message}`);
      }
    }
    
    throw new Error(`All servers failed: ${lastError.message}`);
  }
}

Docker Deployment

Deploy MCP servers using Docker for scalability:

# Dockerfile for MCP server
FROM node:18-slim

WORKDIR /app

# Install dependencies
COPY package*.json ./
RUN npm ci --only=production

# Copy application code
COPY . .

# Create non-root user
RUN useradd -m -u 1001 mcpuser
RUN chown -R mcpuser:mcpuser /app
USER mcpuser

# Expose port
EXPOSE 8080

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1

# Start server
CMD ["node", "dist/server.js"]
# docker-compose.yml for multiple instances
version: '3.8'
services:
  mcp-server-1:
    build: .
    ports:
      - "8081:8080"
    environment:
      - NODE_ENV=production
      - SERVER_ID=server-1
    restart: unless-stopped
    
  mcp-server-2:
    build: .
    ports:
      - "8082:8080"
    environment:
      - NODE_ENV=production
      - SERVER_ID=server-2
    restart: unless-stopped
    
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/nginx/ssl
    depends_on:
      - mcp-server-1
      - mcp-server-2
    restart: unless-stopped

Monitoring and Observability

Health Checks

Implement health monitoring for remote MCP servers:

// Health check endpoint
server.addHealthCheck('/health', async () => {
  const checks = {
    server: 'healthy',
    database: await checkDatabase(),
    externalServices: await checkExternalServices(),
    memory: process.memoryUsage(),
    uptime: process.uptime()
  };
  
  const allHealthy = Object.values(checks)
    .filter(v => typeof v === 'string')
    .every(status => status === 'healthy');
  
  return {
    status: allHealthy ? 'healthy' : 'unhealthy',
    timestamp: new Date().toISOString(),
    checks
  };
});

// Readiness check for load balancers
server.addHealthCheck('/ready', async () => {
  const isReady = await checkServerReadiness();
  return {
    status: isReady ? 'ready' : 'not-ready',
    timestamp: new Date().toISOString()
  };
});

Metrics Collection

Track server performance and usage:

// Prometheus metrics example
import prometheus from 'prom-client';

const requestCounter = new prometheus.Counter({
  name: 'mcp_requests_total',
  help: 'Total number of MCP requests',
  labelNames: ['method', 'status']
});

const requestDuration = new prometheus.Histogram({
  name: 'mcp_request_duration_seconds',
  help: 'Duration of MCP requests',
  labelNames: ['method']
});

const activeConnections = new prometheus.Gauge({
  name: 'mcp_active_connections',
  help: 'Number of active MCP connections'
});

// Instrument request handling
server.onRequest(async (request, response) => {
  const startTime = Date.now();
  const method = request.method;
  
  try {
    const result = await handleRequest(request);
    requestCounter.inc({ method, status: 'success' });
    return result;
  } catch (error) {
    requestCounter.inc({ method, status: 'error' });
    throw error;
  } finally {
    const duration = (Date.now() - startTime) / 1000;
    requestDuration.observe({ method }, duration);
  }
});

// Expose metrics endpoint
server.addRoute('/metrics', async (req, res) => {
  res.set('Content-Type', prometheus.register.contentType);
  res.end(await prometheus.register.metrics());
});

Security Best Practices

Authentication

  • Always use HTTPS for production deployments
  • Implement proper API key or token-based authentication
  • Mark sensitive headers as “secret” in the configuration
  • Rotate authentication credentials regularly

Network Security

  • Use secure transport protocols (HTTPS)
  • Configure proper CORS policies on your MCP servers
  • Implement rate limiting and request throttling
  • Monitor and log connection attempts

Troubleshooting Remote Connections

Configuration Issues

Remote endpoint not accessible:

  • Verify the URL is correct and reachable
  • Check network connectivity and firewall rules
  • Ensure the remote server is running and accepting connections

Authentication failures:

  • Verify API keys or tokens are correct and not expired
  • Check that required headers are properly configured
  • Ensure sensitive headers are marked as “secret”

Transport protocol issues:

  • Use streamable transport for new implementations
  • Migrate from sse to streamable for better performance
  • Verify the remote server supports the selected transport type

Debugging Steps

  1. Test connectivity:

    curl -I https://your-mcp-endpoint.com/v1/mcp
    
  2. Verify authentication:

    curl -H "Authorization: Bearer your-token" https://your-mcp-endpoint.com/v1/mcp
    
  3. Check server logs for connection attempts and errors

  4. Monitor network traffic to identify connection issues

Common Issues

Connection Timeouts

  • Check network connectivity between client and server
  • Verify firewall rules allow traffic on required ports
  • Increase client timeout settings if operations are slow
  • Monitor server resource usage and performance

Authentication Failures

  • Verify API keys or tokens are valid and not expired
  • Check authentication headers are properly formatted
  • Ensure server authentication configuration matches client
  • Review server logs for specific authentication errors

Protocol Errors

  • Validate MCP message format compliance using MCP Inspector
  • Check JSON-RPC 2.0 format adherence
  • Verify required fields are present in all messages
  • Test with minimal client to isolate issues

Performance Issues

  • Monitor server resource usage (CPU, memory, network)
  • Check for database connection pooling bottlenecks
  • Implement caching for frequently accessed resources
  • Consider using connection pooling on the client side

Debugging Tools

Use these tools to debug remote MCP connections:

# Test server connectivity
curl -v https://your-mcp-server.com:8080/health

# WebSocket connection testing
wscat -c wss://your-mcp-server.com:8080/mcp

# MCP protocol testing
npx @modelcontextprotocol/inspector http https://your-mcp-server.com:8080/mcp

# Load testing
npx autocannon -c 10 -d 30 https://your-mcp-server.com:8080/mcp

Protocol Selection Guide

Choose the right protocol based on your requirements:

Use CaseRecommended ProtocolReason
Web APIsHTTP/HTTPSStandard, cacheable, firewall-friendly
Real-time AppsWebSocketBidirectional, low-latency communication
Live DashboardsSSEServer push, automatic reconnection
Mobile AppsHTTP/HTTPSBetter battery life, intermittent connectivity
High-frequency ToolsWebSocketPersistent connection, lower overhead
Enterprise IntegrationHTTP/HTTPSSecurity policies, monitoring tools
MicroservicesHTTP/HTTPSService mesh compatibility, load balancing

Deployment Patterns

Cloud Deployment

Common patterns for deploying remote MCP servers:

  • Container orchestration - Use Kubernetes or Docker Swarm for scaling
  • Serverless functions - Deploy as AWS Lambda, Azure Functions, or Google Cloud Functions
  • API Gateway integration - Use cloud API gateways for routing and authentication
  • CDN deployment - Cache resources using content delivery networks
  • Multi-region deployment - Deploy servers across regions for global access

Edge Computing

Deploy MCP servers closer to users:

// Edge-optimized MCP server
const edgeServer = new Server({
  name: 'edge-mcp-server',
  version: '1.0.0'
}, {
  capabilities: {
    resources: {},
    tools: {},
    // Enable caching for edge deployment
    caching: {
      enabled: true,
      ttl: 300,
      regions: ['us-east-1', 'eu-west-1', 'ap-southeast-1']
    }
  }
});

// Implement geo-aware resource routing
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
  const clientRegion = request.headers['cf-ipcountry'] || 'US';
  const nearestCache = await findNearestCache(clientRegion);
  
  return await nearestCache.getResource(request.params.uri);
});

Next Steps

Once you have remote MCP server connections working:

Migration from SSE to Streamable

If you’re currently using SSE transport, consider migrating to Streamable HTTP:

Migration Steps

  1. Update transport type from sse to streamable in your remote configuration
  2. Verify endpoint compatibility with Streamable HTTP protocol
  3. Test the connection thoroughly in a development environment
  4. Update monitoring and logging to account for the new transport
  5. Deploy gradually using canary or blue-green deployment strategies

Benefits of Migration

  • Improved performance and reliability
  • Better error handling and recovery
  • Enhanced streaming capabilities
  • Future-proof protocol choice

Resources and Support

For additional help with remote MCP connections: