← Blog Guides & tutorials • 4 min read Deploy an app from Claude Code with MCP, step by step
Follow this on your own server. Start free, no card needed
You’ve just finished a feature in Claude Code. The usual next step is leaving the terminal: open a dashboard, find the app, click deploy, watch logs in another tab. With Railyard’s MCP server connected, the same session that wrote the code can ship it, watch the build, fix what breaks and tell you the URL.
This tutorial goes from zero to a deployed app with a custom domain, all inside Claude Code.
What you’ll need
- Claude Code installed (
claude --versionshould work). - A Railyard account with at least one server connected. The free plan is enough. Any DigitalOcean, Hetzner or Vultr box works; Railyard installs its agent on it.
- A Git repository Railyard can read. A public repo works as-is. For a private one, connect GitHub, GitLab or Bitbucket in Railyard first.
- Admin or owner role on the team, so you can grant
writeaccess. Creating apps needs it. A deployer can follow along from Step 4.
Step 1: Add the MCP server
claude mcp add --transport http railyard https://app.railyard.run/api/mcp
That registers a remote MCP server named railyard over Streamable HTTP. No token goes on the command line.
Step 2: Sign in
Start Claude Code and run:
/mcp
Pick railyard, then Authenticate. Your browser opens Railyard’s consent page. Choose the team, choose Full (write) access, and approve. Claude Code catches the redirect on a local port and stores the token. Back in the terminal, /mcp shows Railyard as connected, with its tools.
What happened in those few seconds is a full OAuth 2.1 + PKCE flow, covered request by request in MCP authorization explained.
Step 3: Check where you landed
Ask:
> Which Railyard team am I connected to, and what servers do I have?
Claude calls whoami and list_servers. You’ll see something like:
Team: Acme (Pro plan) — this connection has write access.
Servers: misty-puffin (online, AWS, CPU 12%, memory 41%, no pending security updates)
If the access level reads read or deploy when you picked write, your role on that team doesn’t allow write. Ask an admin, or reconnect to a team where you’re an admin.
Step 4: Create the app from your repository
> Create a Railyard app from https://github.com/acme/storefront and deploy it.
Claude calls create_app with the repository URL. Railyard inspects the repo to work out how to build it: a Dockerfile if there is one, otherwise the framework’s conventions for Rails, Django, Laravel, Next.js, Go and others. It picks the default branch, names the app after the repo, and starts the first deploy:
Created storefront and started deploy #1201. Call get_deploy to follow it.
To pick the server, say so: “…on misty-puffin”. Otherwise the app goes on the team’s first online server.
Step 5: Follow the build
> Follow that deploy and tell me when it's done or why it failed.
Claude polls get_deploy for status and reads deploy_logs for the build output. If the deploy succeeds, you get the URL. If it fails, you get the actual error from the log, not a guess:
Deploy #1201 failed during release:
ActiveSupport::MessageEncryptor::InvalidMessage
The app needs RAILS_MASTER_KEY to read its credentials.
Step 6: Set the variables it needs
> Set RAILS_MASTER_KEY on storefront to the value in config/master.key and redeploy.
Claude reads the file locally, calls set_env, then deploy_app. Two things to know:
set_envis marked destructive because it overwrites a value, so Claude Code asks you to confirm the call. That’s intended.- Variables apply on the next deploy, which is why the redeploy follows.
You can check what’s set with “list storefront’s environment variables”. That uses get_env, which needs write access, and sealed variables show as (sealed).
Step 7: Add a custom domain
> Add shop.acme.com to storefront and tell me which DNS records to create.
Claude calls add_domain and passes on the records Railyard returns:
shop.acme.com added. Create these records in the acme.com zone:
TXT _railyard-verify.shop railyard-verify=…
A shop 203.0.113.24
Railyard verifies them and issues the certificate automatically.
Once DNS propagates, “is shop.acme.com live yet?” calls list_domains and reports verification and certificate state.
Step 8: Check it’s healthy
> How is storefront doing over the last hour? Any errors?
Claude combines three tools:
app_trafficfor request rate, 5xx rate and p95 latencylist_processesfor container health and restartsapp_logsat levelerror
The answer is a short health report. You can also invoke the built-in app_health_report prompt from Claude Code’s prompt menu.
What Claude can and can’t do from here
With write access, the same session can scale workers, run bin/rails db:migrate with run_command, roll back with rollback_app, or spin up a staging copy. It can’t delete the app, remove a variable or domain, restore a backup or reboot the server on its own. Those create a request an admin approves in Railyard.
If you’d rather the agent only look and deploy, reconnect with deploy access. Run /mcp, remove the server, add it again, and pick Deploy on the consent page.
Troubleshooting
- “This API token can’t create app — create a write token.” The connection has
deployorread. Reconnect withwrite; your role has to allow it. - “No app named …” App names come from
list_apps. Claude usually checks, but you can say “list my apps first”. - The deploy waits for approval. The app has deploy approval turned on, so an admin approves it in Railyard. Agents can’t approve.
- “…is outside its deploy window.” The app only accepts deploys during set hours. Deploy inside the window, or change the window in the dashboard.
Next: debug a failed deploy with Claude, or read how the MCP server works under the hood.
Why people pick Railyard for this
- Your own cloud account. Deploy to DigitalOcean, Hetzner, Vultr, AWS, OVHcloud, or any Linux server over SSH, billed directly by your provider with no markup.
- One flat price per team. Free is free forever: one server plus a database server, three apps, no card. Pro is $19 a month for up to five servers and unlimited apps. Team is $99 a month with unlimited servers. No per-app, per-deploy, per-seat or per-gigabyte charges.
- One-click templates. Deploy open-source apps, like databases, analytics and dev tools, to your own server in one click.
- Managed databases. Postgres, MySQL and Redis with scheduled, restore-verified backups and point-in-time recovery.
- Push-to-deploy. Deploy from GitHub, GitLab or the CLI, with automatic HTTPS and zero-downtime releases.