Avatar of Mahmoud AbdelwahabMahmoud Abdelwahab

AI working with Infra? Sounds like a terrible idea but we made it work

Letting AI work with infrastructure sounds like a recipe for disaster. Surely, it’ll end up wiping out your database or accidentally deleting your app, right?

https://x.com/adxtya_jha/status/1955997840398016638

https://x.com/adxtya_jha/status/1955997840398016638

We’ve been experimenting with this at Railway, and in this post we’ll share what we’ve learned. If this is your first time hearing about Railway, welcome!

Railway is a platform for deploying and scaling apps without worrying about infrastructure. With built-in CI/CD, observability, and networking, you can deploy long-running services and databases while paying only for active compute time and resources you actually use. You can get started for free by going to dev.new

Before we dive in, it’s worth looking back at how we ended up here, at a point where we want AI to do everything.

Large Language Models (LLMs) started out as text-only chatbots and then became multimodal systems capable of calling external tools (e.g. web search, information retrieval, etc.).

This capability soon made its way into code editors like VS Code and Cursor, which integrated AI assistants. You could ask questions about your codebase or describe how you wanted code updated, and the assistant could provide accurate responses by pulling in the right context (e.g. including the file in view, fetching terminal logs, or running actions like listing directories/files).

GitHub Copilot Chat

GitHub Copilot Chat

The next phase involved moving beyond a back-and-forth with an assistant. You could simply specify a task and have a “coding agent” figure out how to complete it. The agent would run as a process until the task was finished. Over time this workflow became even more powerful, with agents that could run in the background or even multiple agents that could work in parallel.

GitHub Copilot Agent

But what if you wanted the coding agent to go beyond just writing code? What if you wanted it to actually simulate what you’d do as a developer with other tools outside the code editor?

For example, if you’re working on a project and ask Cursor to deploy it to Railway, you’ll find that it just doesn’t know how to do it or will ask you to manually run CLI commands. Here’s what that looks like:

Trying to get Cursor Agent to use Railway

This meant that for a coding agent to use Railway, Railway had to be exposed as a tool for it to be used. In the past, this was difficult because adding new tools required custom implementations that were hard to maintain and incompatible across different AI systems. The good news is that the Model Context Protocol (MCP) solves this.

MCP is a standard that defines how AI applications (hosts) interact with external tools and data sources using a client-server architecture.

  • Hosts: Applications like Cursor, VS Code, Claude Desktop, or Windsurf that connect to MCP servers
  • Clients: The layer inside hosts that manages one-to-one connections with individual MCP servers
  • Servers: Standalone programs that provide tools and workflows

Since its launch in November 2024, thousands of servers have been built, registries have appeared, events have been organized, and companies like OpenAI and Google have adopted it. The spec has also evolved with support for Remote MCP servers over HTTP.

It feels like we finally have a standard that will stick (fingers crossed). Of course, we’re still drowning in config files.

https://x.com/shadcn/status/1955254151807635602

https://x.com/shadcn/status/1955254151807635602

This also means that building an MCP server for Railway felt like an experiment worth pursuing.

Yes, yes we know it can feel like “just one more MCP server, bro. I swear this one’s different.” But in all honesty, we think you’ll like what the Railway MCP server can do. 

You can have your coding agent spin up a project, attach a domain, search and deploy a template from the Templates marketplace, or pull logs from a running service without leaving your editor.

Here’s a quick video demo where we create a Next.js app, set up a project on Railway, deploy it, and give it a domain.

Railway MCP sever demo

To start using the MCP server, you’ll need to have the Railway CLI installed and authenticated (we’ll explain this design choice later on).

You can install the MCP server in Cursor with a single click by following this link. If you prefer, you can also add the configuration manually to your .cursor/mcp.json file:

{
  "mcpServers": {
    "Railway": {
      "command": "npx",
      "args": ["-y", "@railway/mcp-server"]
    }
  }
}

If you’re using VS Code, you can add the following configuration to your .vscode/mcp.json file:

{
  "servers": {
    "Railway": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@railway/mcp-server"]
    }
  }
}

If you’re using Claude Code, you can install the MCP server in Claude Code, by running the following command:

claude mcp add Railway npx @railway/mcp-server

Here are some example prompts you can use

  • Create and deploy a new app
    • Create a Next.js app in this directory and deploy it to Railway.
      Also assign it a domain.
  • Deploy from a template
    • Deploy a Postgres database
      Deploy a single-node ClickHouse database
  • Pull environment variables
    • Pull environment variables for my project and save them to a .env file
  • Create a new environment
    • Create a development environment called `development`
      cloned from production and set it as linked

You can find the complete list of available MCP tools in the project’s README on GitHub.

We made a few design decisions along the way. None of them are set in stone, but we thought it would be useful to share our reasoning and the trade-offs that led us here.

This one is the most obvious one. If there are no delete-x MCP tools, the odds of the coding agent running a destructive action goes down significantly. However, coding agents can still run arbitrary CLI commands, so you should be careful.

MCP has a transport layer responsible for how clients and servers talk to each other and how authentication is handled. It takes care of setting up connections, framing messages, and making sure communication between MCP participants is secure.

MCP currently supports two types of transport:

  • Stdio transport: This uses standard input and output streams for communication between local processes on the same machine. It’s the fastest option since there’s no network overhead, which makes it ideal when everything is running locally.
  • Streamable HTTP transport: This uses HTTP POST for sending messages from client to server, with optional Server-Sent Events for streaming responses. It’s what enables remote servers to work and supports common HTTP authentication methods like bearer tokens, API keys, and custom headers. MCP recommends OAuth as the way to obtain these tokens.

Remote MCP servers make a lot of sense in the broader vision of MCP. In that world, any AI tool could act as a host, connect to multiple remote MCP servers, and pick the right tool for the job.

For Railway, though, most of our users are developers working inside editors like VS Code, Cursor, or Claude Code. In that context, a remote MCP server doesn’t bring much benefit.

Another limitation is authentication. Since Railway doesn’t yet support OAuth, the only way to connect to a remote MCP server would be to hardcode API tokens. That means going to the Railway dashboard, generating an API key in your account settings, and then manually adding it to your MCP config file. Not exactly a great experience.

We also haven’t come across a real use case where an MCP host only works with remote servers, nor have users asked us to integrate Railway that way. So instead, we went with a local MCP server. The Railway CLI already offers a seamless authentication flow, so setup is as simple as:

  1. Install the CLI
  2. Run railway login
  3. Install the MCP server

There’s also a nice side effect of using the CLI as a dependency. If something breaks or the agent hits an edge case, it can fall back to the same workflows a developer would use manually. Rather than getting stuck, it just calls the CLI, which makes the system more resilient and avoids frustrating dead ends.

Under the hood, the MCP server runs CLI commands. This approach helped us spot gaps in the experience of integrating with the CLI programmatically, which gives us valuable feedback for improving it.

import { exec } from "node:child_process";
import { promisify } from "node:util";
import { analyzeRailwayError } from "./error-handling";

const execAsync = promisify(exec);

export const runRailwayCommand = async (command: string, cwd?: string) => {
	const { stdout, stderr } = await execAsync(command, { cwd });
	return { stdout, stderr, output: stdout + stderr };
};

export const checkRailwayCliStatus = async (): Promise<void> => {
	try {
		await runRailwayCommand("railway --version");
		await runRailwayCommand("railway whoami");
	} catch (error: unknown) {
		return analyzeRailwayError(error, "railway whoami");
	}
};

At the end of the day, agents need deployment targets that are reliable, scalable, and cost-efficient. Railway is a natural fit for this role because you only pay for active compute time and resources you actually use. If an agent spins up resources that go idle shortly after, you don’t get stuck with a big bill. This makes Railway especially well-suited for experimentation, automation, and fast iteration.

We’d love to hear how you’re using the Railway MCP server and what improvements you’d like to see. Share your feedback with us on Central Station and help us shape future versions. And if you’re building an agent platform and want to use Railway to power the underlying infrastructure, we’d be excited to chat.

Your train has arrived!

Join thousands of developers deploying hundreds of thousands of applications effortlessly on Railway.

Start a New Project