Skip to main content

August 4, 2026

Why I Removed execute_ruby from Rails MCP Server

Mario Alberto Chávez Cárdenas
Rails MCP Server 2.0.0 — execute_ruby removed, introspection-only

I built the first version of Rails MCP Server before Claude Code, Codex, and tools like them were the popular way to work with AI on a codebase. Back then, Claude Desktop could talk to me and read whatever I pasted into the chat. Nothing else. If I wanted it to see a model’s associations, check a route, or run a quick query against my own data, I copied and pasted. Every question meant leaving the conversation, going to the terminal, and bringing the answer back by hand.

That’s the itch Rails MCP Server scratched: let Claude Desktop introspect a Rails project directly (routes, schema, models) without me being the copy-paste layer between every question and its answer. A companion tool, nvim-mcp-server, closed the other half of the loop, letting Claude Desktop write code changes straight into my Neovim buffers instead of me pasting a diff and applying it by hand.

execute_ruby made sense inside that setup. Claude Desktop had no way to touch my filesystem or run anything on its own. The MCP server was its only hands. Giving it a tool that could run real Ruby inside my running Rails app meant one call could answer what would otherwise take a dozen round trips: an ad-hoc scope, or a quick Model.find to check a hunch. It was the sharpest tool in the server, and it earned its place.

What changed

That gap doesn’t exist for most people building with AI anymore. Claude Code, Codex, and the agentic coding tools that followed sit directly on top of the codebase. They already have a shell and the same Ruby your app runs on. If an agent wants to check User.where(inactive: true).count, it doesn’t need a special MCP tool for that. It can just run it, the way I would from my own terminal.

That’s most of the reasoning that justified execute_ruby, gone. The tool wasn’t wrong when I built it. It answered a real constraint, and that constraint has largely gone away.

Hardening a tool I was already rethinking

I didn’t arrive here in one step. Yesterday’s 1.6.0 release closed several real bypasses in the execute_ruby sandbox: file reads that slipped past validation and symlinks that walked out of the project, on top of database writes that weren’t actually being rolled back. Today’s 1.6.1 went further: a researcher at Pluto Security responsibly disclosed a command-execution path through require "pty", and the fix restricted require to a small allowlist of data-only libraries, cutting off that path along with a few adjacent ones.

Both releases were worth shipping on their own. But writing 1.6.1 is what made the actual problem visible to me: I was patching individual escapes out of a tool whose entire premise is running caller-supplied Ruby with the privileges of the server process. A static scan and some runtime overrides can raise the floor, but they were never going to be a hard boundary. Path validation, transaction rollback, the confirm_risky gate: every fence I’ve put around execute_ruby has been best-effort, and 1.6.0 said so plainly. Best-effort is a reasonable trade when a tool is filling a real gap. It stops paying off once that’s no longer true.

What 2.0.0 does

Version 2.0.0 removes execute_ruby outright, rather than hardening it again. The server is introspection-only now, and its dedicated analyzers already cover the ground execute_ruby was built for:

Instead of execute_ruby for… Use
Reading a file get_file
Finding files list_files
Routes, schema, models, controllers, env, structure get_routes, get_schema, analyze_models, analyze_controller_views, analyze_environment_config, project_info

Ad-hoc data queries (a custom scope, a one-off count) are the one thing this doesn’t replace, on purpose. That was always the part of execute_ruby doing the most work and carrying the most risk, and it’s exactly the part an agent sitting on top of your code no longer needs a server tool for.

Bootstrap tools drop from four to three: switch_project, search_tools, execute_tool. The internal analyzers haven’t changed. They’re still discovered through search_tools and invoked through execute_tool, same as before.

If you’re on a client without direct code execution and still want execute_ruby, the 1.6.x line keeps it, now with the 1.6.1 hardening. It isn’t disappearing; it’s just not where the project is headed.

Upgrading

gem update rails-mcp-server

If you have execute_ruby wired into a client’s tool config, remove it from there. Replace file reads with get_file and globs with list_files. Everything else keeps working the way it did.

For new installations:

gem install rails-mcp-server
rails-mcp-config

Where this leaves the project

A tool that runs arbitrary code is always going to be the most interesting line in a security report, no matter how many layers sit around it. I’d rather ship a Rails MCP Server that doesn’t have that line at all than one that keeps explaining, release after release, why the latest patch finally closes the gap. What’s gone is the one tool whose risk had stopped being worth what it saved me.

Thanks again to Pluto Security for the responsible disclosure that shaped both 1.6.1 and this release. If you find a gap, the issue tracker is open.


Need help with your Rails project?

I'm Mario Alberto Chávez—Rails architect available for consulting, AI integration, and code review.