@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.
152 lines (151 loc) • 6.33 kB
JavaScript
import { BaseService } from '../services/base.service.js';
import { createSuccessResponse, createErrorResponse, formatError } from '../utils/responses.js';
export class ServiceService extends BaseService {
constructor() {
super();
}
async listServices(projectId) {
try {
const services = await this.client.services.listServices(projectId);
if (services.length === 0) {
return createSuccessResponse({
text: "No services found in this project.",
data: []
});
}
// Get latest deployment status for each service
const serviceDetails = await Promise.all(services.map(async (service) => {
try {
const deployments = await this.client.deployments.listDeployments({
projectId,
serviceId: service.id,
limit: 1
});
const latestDeployment = deployments[0];
if (latestDeployment) {
return `🚀 ${service.name} (ID: ${service.id})
Status: ${latestDeployment.status}
URL: ${latestDeployment.url || 'Not deployed'}`;
}
return `🚀 ${service.name} (ID: ${service.id})
Status: No deployments`;
}
catch {
return `🚀 ${service.name} (ID: ${service.id})`;
}
}));
return createSuccessResponse({
text: `Services in project:\n\n${serviceDetails.join('\n\n')}`,
data: services
});
}
catch (error) {
return createErrorResponse(`Error listing services: ${formatError(error)}`);
}
}
async getServiceInfo(projectId, serviceId, environmentId) {
try {
const [serviceInstance, deployments] = await Promise.all([
this.client.services.getServiceInstance(serviceId, environmentId),
this.client.deployments.listDeployments({ projectId, serviceId, environmentId, limit: 5 })
]);
if (!serviceInstance) {
return createErrorResponse(`Service instance not found.`);
}
const deploymentStatus = deployments.length > 0
? `\nLatest Deployment: ${deployments[0].status} (${deployments[0].id})`
: '\nNo recent deployments';
const info = `🚀 Service: ${serviceInstance.serviceName}
ID: ${serviceInstance.serviceId}
Region: ${serviceInstance.region || 'Not set'}
Replicas: ${serviceInstance.numReplicas || 1}
Root Directory: ${serviceInstance.rootDirectory || '/'}
Build Command: ${serviceInstance.buildCommand || 'Not set'}
Start Command: ${serviceInstance.startCommand || 'Not set'}
Health Check Path: ${serviceInstance.healthcheckPath || 'Not set'}
Sleep Mode: ${serviceInstance.sleepApplication ? 'Enabled' : 'Disabled'}${deploymentStatus}`;
return createSuccessResponse({
text: info,
data: { serviceInstance, deployments }
});
}
catch (error) {
return createErrorResponse(`Error getting service details: ${formatError(error)}`);
}
}
async createServiceFromRepo(projectId, repo, name) {
try {
const service = await this.client.services.createService({
projectId,
name: name || 'service-' + Date.now(),
source: {
repo,
}
});
return createSuccessResponse({
text: `Created new service "${service.name}" (ID: ${service.id}) from GitHub repo "${repo}"`,
data: service
});
}
catch (error) {
return createErrorResponse(`Error creating service: ${formatError(error)}`);
}
}
async createServiceFromImage(projectId, image, name) {
try {
const service = await this.client.services.createService({
projectId,
name: name || 'service-' + Date.now(),
source: {
image,
}
});
return createSuccessResponse({
text: `Created new service "${service.name}" (ID: ${service.id}) from Docker image "${image}"`,
data: service
});
}
catch (error) {
return createErrorResponse(`Error creating service: ${formatError(error)}`);
}
}
async updateService(projectId, serviceId, environmentId, config) {
try {
const updated = await this.client.services.updateServiceInstance(serviceId, environmentId, config);
if (!updated) {
return createErrorResponse(`Error updating service: Failed to update service instance of ${serviceId} in environment ${environmentId}`);
}
return createSuccessResponse({
text: `Service configuration updated successfully`
});
}
catch (error) {
return createErrorResponse(`Error updating service: ${formatError(error)}`);
}
}
async deleteService(projectId, serviceId) {
try {
await this.client.services.deleteService(serviceId);
return createSuccessResponse({
text: `Service deleted successfully`
});
}
catch (error) {
return createErrorResponse(`Error deleting service: ${formatError(error)}`);
}
}
async restartService(serviceId, environmentId) {
try {
await this.client.services.restartService(serviceId, environmentId);
await new Promise(resolve => setTimeout(resolve, 5000)); // TEMPORARY UNTIL WEBHOOKS ARE IMPLEMENTED: Wait for 5 seconds to ensure the service is restarted
return createSuccessResponse({
text: `Service restarted successfully`
});
}
catch (error) {
return createErrorResponse(`Error restarting service: ${formatError(error)}`);
}
}
}
// Initialize and export the singleton instance
export const serviceService = new ServiceService();