@crazyrabbitltc/railway-mcp
Version:
Railway MCP Server - 146+ tools with 100% Railway API coverage, comprehensive MCP testing framework, and real infrastructure management through AI assistants. Enhanced version with enterprise features, based on original work by Jason Tan.
390 lines (389 loc) • 17.2 kB
JavaScript
import { BaseService } from "./base.service.js";
import { createSuccessResponse, createErrorResponse, formatError } from "../utils/responses.js";
export class NetworkingService extends BaseService {
constructor() {
super();
}
async listPrivateNetworks(projectId) {
try {
const networks = await this.client.networking.listPrivateNetworks(projectId);
const activeCount = networks.filter(n => n.isActive).length;
const totalEndpoints = networks.reduce((sum, n) => sum + n.endpoints.length, 0);
const regions = [...new Set(networks.map(n => n.region))];
return createSuccessResponse({
text: `Found ${networks.length} private networks (${activeCount} active, ${totalEndpoints} endpoints)`,
data: {
projectId,
summary: {
totalNetworks: networks.length,
activeCount,
totalEndpoints,
regions
},
networks: networks.map(network => ({
id: network.id,
name: network.name,
cidr: network.cidr,
region: network.region,
isActive: network.isActive,
endpointCount: network.endpoints.length,
endpoints: network.endpoints.map(ep => ({
serviceId: ep.serviceId,
serviceName: ep.serviceName,
ipAddress: ep.ipAddress,
port: ep.port
})),
createdAt: network.createdAt,
updatedAt: network.updatedAt
}))
}
});
}
catch (error) {
return createErrorResponse(`Failed to list private networks: ${formatError(error)}`);
}
}
async createPrivateNetwork(projectId, name, cidr, region) {
try {
const network = await this.client.networking.createPrivateNetwork(projectId, name, cidr, region);
return createSuccessResponse({
text: `Private network "${name}" created in ${region}`,
data: {
id: network.id,
name: network.name,
cidr: network.cidr,
region: network.region,
isActive: network.isActive,
projectId: network.projectId,
createdAt: network.createdAt
}
});
}
catch (error) {
return createErrorResponse(`Failed to create private network: ${formatError(error)}`);
}
}
async addNetworkEndpoint(networkId, serviceId, port, protocol) {
try {
const endpoint = await this.client.networking.addNetworkEndpoint(networkId, serviceId, port, protocol);
return createSuccessResponse({
text: `Service endpoint added to private network`,
data: {
id: endpoint.id,
networkId: endpoint.networkId,
serviceId: endpoint.serviceId,
serviceName: endpoint.serviceName,
ipAddress: endpoint.ipAddress,
port: endpoint.port,
protocol: endpoint.protocol,
isActive: endpoint.isActive,
createdAt: endpoint.createdAt
}
});
}
catch (error) {
return createErrorResponse(`Failed to add network endpoint: ${formatError(error)}`);
}
}
async removeNetworkEndpoint(endpointId) {
try {
const success = await this.client.networking.removeNetworkEndpoint(endpointId);
if (success) {
return createSuccessResponse({
text: "Network endpoint removed successfully"
});
}
else {
return createErrorResponse("Failed to remove network endpoint");
}
}
catch (error) {
return createErrorResponse(`Failed to remove network endpoint: ${formatError(error)}`);
}
}
async listLoadBalancers(projectId) {
try {
const loadBalancers = await this.client.networking.listLoadBalancers(projectId);
const activeCount = loadBalancers.filter(lb => lb.status === 'ACTIVE').length;
const totalTargets = loadBalancers.reduce((sum, lb) => sum + lb.targets.length, 0);
const healthyTargets = loadBalancers.reduce((sum, lb) => sum + lb.targets.filter(t => t.isHealthy).length, 0);
return createSuccessResponse({
text: `Found ${loadBalancers.length} load balancers (${activeCount} active, ${healthyTargets}/${totalTargets} healthy targets)`,
data: {
projectId,
summary: {
totalLoadBalancers: loadBalancers.length,
activeCount,
totalTargets,
healthyTargets,
healthyTargetPercentage: totalTargets > 0 ? `${((healthyTargets / totalTargets) * 100).toFixed(1)}%` : 'N/A'
},
loadBalancers: loadBalancers.map(lb => ({
id: lb.id,
name: lb.name,
type: lb.type,
algorithm: lb.algorithm,
status: lb.status,
targetCount: lb.targets.length,
healthyTargets: lb.targets.filter(t => t.isHealthy).length,
listeners: lb.listeners.map(l => `${l.protocol}:${l.port}`).join(', '),
healthCheck: {
path: lb.healthCheck.path,
protocol: lb.healthCheck.protocol,
interval: `${lb.healthCheck.interval}s`
},
targets: lb.targets.map(target => ({
serviceId: target.serviceId,
serviceName: target.serviceName,
weight: target.weight,
isHealthy: target.isHealthy
})),
createdAt: lb.createdAt,
updatedAt: lb.updatedAt
}))
}
});
}
catch (error) {
return createErrorResponse(`Failed to list load balancers: ${formatError(error)}`);
}
}
async createLoadBalancer(projectId, name, type, algorithm, healthCheck, listeners) {
try {
const loadBalancer = await this.client.networking.createLoadBalancer(projectId, name, type, algorithm, healthCheck, listeners);
return createSuccessResponse({
text: `Load balancer "${name}" created with ${type} type`,
data: {
id: loadBalancer.id,
name: loadBalancer.name,
type: loadBalancer.type,
algorithm: loadBalancer.algorithm,
status: loadBalancer.status,
healthCheck: loadBalancer.healthCheck,
listeners: loadBalancer.listeners,
projectId: loadBalancer.projectId,
createdAt: loadBalancer.createdAt
}
});
}
catch (error) {
return createErrorResponse(`Failed to create load balancer: ${formatError(error)}`);
}
}
async addLoadBalancerTarget(loadBalancerId, serviceId, weight) {
try {
const loadBalancer = await this.client.networking.addLoadBalancerTarget(loadBalancerId, serviceId, weight);
return createSuccessResponse({
text: `Service added to load balancer with weight ${weight}`,
data: {
loadBalancerId: loadBalancer.id,
targetCount: loadBalancer.targets.length,
targets: loadBalancer.targets.map(target => ({
serviceId: target.serviceId,
serviceName: target.serviceName,
weight: target.weight,
isHealthy: target.isHealthy
})),
updatedAt: loadBalancer.updatedAt
}
});
}
catch (error) {
return createErrorResponse(`Failed to add load balancer target: ${formatError(error)}`);
}
}
async removeLoadBalancerTarget(loadBalancerId, serviceId) {
try {
const loadBalancer = await this.client.networking.removeLoadBalancerTarget(loadBalancerId, serviceId);
return createSuccessResponse({
text: `Service removed from load balancer`,
data: {
loadBalancerId: loadBalancer.id,
targetCount: loadBalancer.targets.length,
targets: loadBalancer.targets.map(target => ({
serviceId: target.serviceId,
serviceName: target.serviceName,
weight: target.weight,
isHealthy: target.isHealthy
})),
updatedAt: loadBalancer.updatedAt
}
});
}
catch (error) {
return createErrorResponse(`Failed to remove load balancer target: ${formatError(error)}`);
}
}
async updateLoadBalancerHealthCheck(loadBalancerId, healthCheck) {
try {
const loadBalancer = await this.client.networking.updateLoadBalancerHealthCheck(loadBalancerId, healthCheck);
return createSuccessResponse({
text: `Load balancer health check updated`,
data: {
id: loadBalancer.id,
healthCheck: {
path: loadBalancer.healthCheck.path,
port: loadBalancer.healthCheck.port,
protocol: loadBalancer.healthCheck.protocol,
interval: `${loadBalancer.healthCheck.interval}s`,
timeout: `${loadBalancer.healthCheck.timeout}s`,
healthyThreshold: loadBalancer.healthCheck.healthyThreshold,
unhealthyThreshold: loadBalancer.healthCheck.unhealthyThreshold
},
updatedAt: loadBalancer.updatedAt
}
});
}
catch (error) {
return createErrorResponse(`Failed to update health check: ${formatError(error)}`);
}
}
async deleteLoadBalancer(loadBalancerId) {
try {
const success = await this.client.networking.deleteLoadBalancer(loadBalancerId);
if (success) {
return createSuccessResponse({
text: "Load balancer deleted successfully"
});
}
else {
return createErrorResponse("Failed to delete load balancer");
}
}
catch (error) {
return createErrorResponse(`Failed to delete load balancer: ${formatError(error)}`);
}
}
async listNetworkRoutes(networkId) {
try {
const routes = await this.client.networking.listNetworkRoutes(networkId);
const activeCount = routes.filter(r => r.isActive).length;
return createSuccessResponse({
text: `Found ${routes.length} network routes (${activeCount} active)`,
data: {
networkId,
summary: {
totalRoutes: routes.length,
activeCount
},
routes: routes.map(route => ({
id: route.id,
destination: route.destination,
gateway: route.gateway,
metric: route.metric,
isActive: route.isActive,
createdAt: route.createdAt
}))
}
});
}
catch (error) {
return createErrorResponse(`Failed to list network routes: ${formatError(error)}`);
}
}
async createNetworkRoute(networkId, destination, gateway, metric) {
try {
const route = await this.client.networking.createNetworkRoute(networkId, destination, gateway, metric);
return createSuccessResponse({
text: `Network route created for ${destination}`,
data: {
id: route.id,
networkId: route.networkId,
destination: route.destination,
gateway: route.gateway,
metric: route.metric,
isActive: route.isActive,
createdAt: route.createdAt
}
});
}
catch (error) {
return createErrorResponse(`Failed to create network route: ${formatError(error)}`);
}
}
async deleteNetworkRoute(routeId) {
try {
const success = await this.client.networking.deleteNetworkRoute(routeId);
if (success) {
return createSuccessResponse({
text: "Network route deleted successfully"
});
}
else {
return createErrorResponse("Failed to delete network route");
}
}
catch (error) {
return createErrorResponse(`Failed to delete network route: ${formatError(error)}`);
}
}
async listSecurityGroups(networkId) {
try {
const securityGroups = await this.client.networking.listSecurityGroups(networkId);
const activeCount = securityGroups.filter(sg => sg.isActive).length;
const totalRules = securityGroups.reduce((sum, sg) => sum + sg.rules.length, 0);
return createSuccessResponse({
text: `Found ${securityGroups.length} security groups (${activeCount} active, ${totalRules} rules)`,
data: {
networkId,
summary: {
totalSecurityGroups: securityGroups.length,
activeCount,
totalRules
},
securityGroups: securityGroups.map(sg => ({
id: sg.id,
name: sg.name,
description: sg.description,
isActive: sg.isActive,
ruleCount: sg.rules.length,
rules: sg.rules.map(rule => ({
id: rule.id,
direction: rule.direction,
protocol: rule.protocol,
portRange: rule.portRange,
source: rule.source,
action: rule.action,
priority: rule.priority
})),
createdAt: sg.createdAt,
updatedAt: sg.updatedAt
}))
}
});
}
catch (error) {
return createErrorResponse(`Failed to list security groups: ${formatError(error)}`);
}
}
async createSecurityGroup(networkId, name, description, rules) {
try {
const securityGroup = await this.client.networking.createSecurityGroup(networkId, name, description, rules);
return createSuccessResponse({
text: `Security group "${name}" created with ${rules.length} rules`,
data: {
id: securityGroup.id,
networkId: securityGroup.networkId,
name: securityGroup.name,
description: securityGroup.description,
isActive: securityGroup.isActive,
ruleCount: securityGroup.rules.length,
rules: securityGroup.rules.map(rule => ({
id: rule.id,
direction: rule.direction,
protocol: rule.protocol,
portRange: rule.portRange,
source: rule.source,
action: rule.action,
priority: rule.priority
})),
createdAt: securityGroup.createdAt
}
});
}
catch (error) {
return createErrorResponse(`Failed to create security group: ${formatError(error)}`);
}
}
}
export const networkingService = new NetworkingService();