Skip to main content
Glama
railwayapp

Railway MCP Server

Official
by railwayapp

Link Railway Service

link-service

Link a Railway service to your project workspace to integrate deployments. Specify a service name to connect it or list available services for selection.

Instructions

Link a service to the current Railway project. If no service is specified, it will list available services

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
workspacePathYesThe path to the workspace to link the service to
serviceNameNoThe service name to link

Implementation Reference

  • The async handler function for the 'link-service' tool. Handles linking a specific service or listing available services in the linked Railway project.
    handler: async ({ workspacePath, serviceName }: LinkServiceOptions) => {
    	try {
    		if (serviceName) {
    			// Link the specified service
    			const result = await linkRailwayService({
    				workspacePath,
    				serviceName,
    			});
    			return createToolResponse(
    				`✅ Successfully linked service '${serviceName}':\n\n${result}`,
    			);
    		} else {
    			// List available services
    			const servicesResult = await getRailwayServices({ workspacePath });
    			if (!servicesResult.success) {
    				return createToolResponse(
    					"❌ Failed to get Railway services\n\n" +
    						`**Error:** ${servicesResult.error}\n\n` +
    						"**Next Steps:**\n" +
    						"• Ensure you have a Railway project linked\n" +
    						"• Check that you have permissions to view services\n" +
    						"• Run `railway link` to ensure proper project connection",
    				);
    			}
    
    			if (!servicesResult.services || servicesResult.services.length === 0) {
    				return createToolResponse(
    					"ℹ️ No services found in this project. Create a service first.",
    				);
    			}
    
    			const result = `Available services:\n${servicesResult.services.map((s) => `- ${s}`).join("\n")}\n\nRun with a service name to link it.`;
    			return createToolResponse(result);
    		}
    	} catch (error: unknown) {
    		const errorMessage =
    			error instanceof Error ? error.message : "Unknown error occurred";
    		return createToolResponse(
    			"❌ Failed to link Railway service\n\n" +
    				`**Error:** ${errorMessage}\n\n` +
    				"**Next Steps:**\n" +
    				"• Ensure you have a Railway project linked\n" +
    				"• Check that the service name is correct\n" +
    				"• Verify you have permissions to link services\n" +
    				"• Run `railway link` to ensure proper project connection",
    		);
    	}
    },
  • Zod-based input schema for the tool, requiring workspacePath and optionally serviceName.
    inputSchema: {
    	workspacePath: z
    		.string()
    		.describe("The path to the workspace to link the service to"),
    	serviceName: z.string().optional().describe("The service name to link"),
    },
  • src/index.ts:21-31 (registration)
    Dynamic registration of all tools (including 'link-service') to the MCP server via server.registerTool in a loop over exported tools.
    Object.values(tools).forEach((tool) => {
    	server.registerTool(
    		tool.name,
    		{
    			title: tool.title,
    			description: tool.description,
    			inputSchema: tool.inputSchema,
    		},
    		tool.handler,
    	);
    });
  • src/tools/index.ts:9-9 (registration)
    Exports the linkServiceTool object from its implementation file for use in the central tools index.
    export { linkServiceTool } from "./link-service";
  • Helper function called by the tool handler to perform the actual service linking via Railway CLI.
    export const linkRailwayService = async ({
    	workspacePath,
    	serviceName,
    }: LinkServiceOptions): Promise<string> => {
    	try {
    		await checkRailwayCliStatus();
    		const result = await getLinkedProjectInfo({ workspacePath });
    		if (!result.success) {
    			throw new Error(result.error);
    		}
    
    		const { output } = await runRailwayCommand(
    			`railway service ${serviceName}`,
    			workspacePath,
    		);
    
    		return output;
    	} catch (error: unknown) {
    		return analyzeRailwayError(error, "railway service");
    	}
    };
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It describes the dual behavior (linking or listing based on parameter presence), which is useful. However, it lacks details on permissions required, whether linking is reversible, rate limits, or what happens if the service is already linked—critical for a mutation tool with zero annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, front-loaded with the primary purpose and followed by conditional behavior. Every word earns its place with no redundancy or fluff, making it highly efficient and easy to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no annotations and no output schema, the description is moderately complete: it covers the tool's dual functionality and parameter dependency. However, as a mutation tool (linking implies a write operation), it should ideally mention authentication needs, side effects, or response format to be fully helpful, leaving some gaps in context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both parameters (workspacePath and serviceName) with descriptions. The description adds value by explaining the conditional behavior: if serviceName is omitted, it lists services instead of linking. This provides context beyond the schema, but doesn't elaborate on parameter formats or constraints, meeting the baseline for high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Link a service to the current Railway project' specifies the action (link) and resource (service). However, it doesn't explicitly differentiate from sibling tools like 'link-environment' or 'create-project-and-link', which also involve linking operations in the Railway context.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides implied usage guidance: it mentions that if no service is specified, it will list available services, suggesting this tool can be used for both linking and listing. However, it doesn't explicitly state when to use this tool versus alternatives like 'list-services' (for listing) or other linking tools, nor does it mention prerequisites or exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/railwayapp/railway-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server