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:
Streamable HTTP (Recommended)
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:
Go to Configuration
/{organization}/server/{server}/configuration/remotes
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
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
}
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' );
WebSocket Server
Python HTTP Server
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:
HTTP Client
WebSocket Client
cURL Testing
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
Test connectivity:
curl -I https://your-mcp-endpoint.com/v1/mcp
Verify authentication:
curl -H "Authorization: Bearer your-token" https://your-mcp-endpoint.com/v1/mcp
Check server logs for connection attempts and errors
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
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 Case Recommended Protocol Reason Web APIs HTTP/HTTPS Standard, cacheable, firewall-friendly Real-time Apps WebSocket Bidirectional, low-latency communication Live Dashboards SSE Server push, automatic reconnection Mobile Apps HTTP/HTTPS Better battery life, intermittent connectivity High-frequency Tools WebSocket Persistent connection, lower overhead Enterprise Integration HTTP/HTTPS Security policies, monitoring tools Microservices HTTP/HTTPS Service 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
Update transport type from sse
to streamable
in your remote configuration
Verify endpoint compatibility with Streamable HTTP protocol
Test the connection thoroughly in a development environment
Update monitoring and logging to account for the new transport
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:
Responses are generated using AI and may contain mistakes.