2
.
09
.
2025
2
.
09
.
2025
Ruby on Rails
LLM

MCP Template for Rails applications

Paweł Strzałkowski
Chief Technology Officer
MCP Template for Rails applications by Paweł Strzałkowski

After building several MCP servers with Rails using different approaches in my previous posts in this series, I started noticing a pattern. Every time I wanted to create a new MCP-enabled Rails application, I had to go through the same setup steps: add the gem, create the controller, configure routes, set up tool autoloading, prepare MCP response formatting. It was becoming repetitive.

This repetition got me thinking about one of Rails core principles: Convention over Configuration. What if integrating MCP with Rails could be as simple as scaffolding a regular Rails application?

The Rails Way of Thinking

Rails has always been about reducing boilerplate and focusing on the essential parts of your application. When you scaffold a model, you get the controller, views, routes, and tests automatically generated. The framework handles the repetitive parts so you can focus on your business logic.

The same principle should apply to MCP integration. But rather than just automating setup, what if we could enhance Rails scaffolding to generate AI tools alongside the standard files?

Enhancing Rails Scaffolding with MCP Tools

The premise isn't just about automation - it's about extending Rails capabilities. What if rails generate scaffold could create not only controllers and views, but also MCP tools that make your models immediately accessible to AI assistants?

I built a Rails application template that does exactly this. The template is available at https://github.com/pstrzalk/mcp-on-rails and you can use it to create a new Rails application like this:

$ git clone https://github.com/pstrzalk/mcp-on-rails.git
$ rails new myapp -m mcp-on-rails/mcp

This creates a Rails application that serves MCP requests at /mcp using streamable HTTP transport, but more importantly, it enhances the scaffolding process to automatically generate MCP tools.

Alternatively, you may apply this template to an existing application:

$ git clone https://github.com/pstrzalk/mcp-on-rails.git
$ cd your-project/
$ rails app:template LOCATION=../mcp-on-rails/mcp

Generator Hooks: Extending Rails Functionality

The key insight was using Rails generator hook system to extend existing functionality rather than replacing it. This is the same pattern used by gems like jbuilder - they enhance the scaffold generator without overriding it.

When you run rails generate scaffold Post title:string content:text, the enhanced scaffolding process creates the standard Rails files plus five MCP tools:

  • Show tool for retrieving individual records
  • Index tool with filtering and listing the last N records
  • Create tool with validation
  • Update tool with partial updates
  • Delete tool

The beauty of this approach is that it feels like a natural extension of Rails. You're not learning a new workflow - you're using the same scaffolding commands you already know, just with enhanced output.

Smart Tool Generation

The generated tools include intelligent features based on your model structure. For models with references, the tools automatically handle relationships. If you scaffold Comment post:references content:text, the create tool will require a post_id parameter, and the index tool will allow filtering by post.

Type mapping is handled automatically. String fields become type: "string" in the JSON schema, integers become type: "integer", and so on.

Error handling is comprehensive, covering validation errors, not found errors, and general exceptions with meaningful messages.

Generate MCP Tools with ActiveRecord models

Let's say you're building a blog application. After creating the Rails app with the MCP template, you scaffold your models:

$ rails generate scaffold Post title:string content:text author:string
$ rails generate scaffold Comment post:references content:text author:string

You now have a fully functional blog, but also a complete set of MCP tools. An AI assistant can immediately:

  • List the most recent posts (with configurable count)
  • Create new posts with validation
  • Filter comments by post
  • Update existing content
  • Delete records

All without writing a single line of MCP-specific code. The scaffolding process handled both the web interface and the AI interface.

Scaffolded MCP Tools

The full list of MCP Tools generated alongside the ActiveRecord objects is:

app/tools/posts/
  - create_tool.rb
  - delete_tool.rb
  - index_tool.rb
  - show_tool.rb
  - update_tool.rb
app/tools/comments/
  - create_tool.rb
  - delete_tool.rb
  - index_tool.rb
  - show_tool.rb
  - update_tool.rb

Let’s take a look at some example implementations. Remember, those have been scaffolded automatically!

# app/tools/posts/create_tool.rb

module Posts
  class CreateTool < MCP::Tool
    tool_name "post-create-tool"
    description "Create a new Post entity"

    input_schema(
      properties: {
        title: { type: "string" },
        body: { type: "string" }
      },
      required: []
    )

    def self.call(title: nil, body: nil, server_context:)
      post = Post.new(
        title: title,
        body: body
      )

      if post.save
        MCP::Tool::Response.new([ { type: "text", text: "Created #{post.to_mcp_response}" } ])
      else
        MCP::Tool::Response.new([ { type: "text", text: "Post was not created due to the following errors: #{post.errors.full_messages.join(', ')}" } ])
      end
    rescue StandardError => e
      MCP::Tool::Response.new([ { type: "text", text: "An error occurred, what happened was #{e.message}" } ])
    end
  end
end

Additionally, when you look at the comments-related tools, you may see that they include the post_id parameter, as the underlying ActiveRecord object does.

module Comments
  class IndexTool < MCP::Tool
    tool_name "comment-index-tool"
    description "List the last count of Comments entities. The count parameter is an integer and defaults to 10. post_id property may be used to filter by integer identifier of the related Post entity."

    input_schema(
      properties: {
        count: { type: "integer" },
        post_id: { type: "integer" }
      },
      required: []
    )

    def self.call(count: 10, post_id: nil, server_context:)
      comments = Comment.all
      comments = comments.where(post_id: post_id) if post_id.present?
      comments = comments.last(count)

      response = comments.map(&:to_mcp_response).join("\n")
      response = "Nothing was found" unless response.present?

      MCP::Tool::Response.new([ { type: "text", text: response } ])
    rescue StandardError => e
      MCP::Tool::Response.new([ { type: "text", text: "An error occurred, what happened was #{e.message}" } ])
    end
  end
end

Should tools implement CRUD actions?

While the template generates CRUD tools automatically, it's important to understand that effective MCP tools often need to go beyond simple database operations. LLMs aren't particularly good at following long procedural lists of small partial steps. They work better when given tools accomplish bigger, more meaningful tasks.

For example, instead of having an AI assistant call three separate tools to create a post, add tags, and notify subscribers, you might want a single "publish post" tool that handles all these operations together. Similarly, instead of multiple calls to search, filter, and format results, a "generate report" tool could handle the entire workflow.

This is where the custom tool generator becomes valuable. While scaffolding gives you the basic CRUD operations, real-world applications often need tools that:

  • Aggregate multiple database operations into business workflows
  • Handle complex validation and business rules
  • Integrate with external services as part of larger processes
  • Provide domain-specific functionality that maps to how users actually think about the problem

The CRUD tools serve as building blocks, but the most effective MCP integrations often involve creating higher-level tools that encapsulate complete user intentions rather than exposing low-level data operations.

Custom tool generator

The template also includes a generator for custom tools when you need functionality beyond basic CRUD:

$ rails generate mcp_tool EmailSender recipient:string subject:string body:text

This creates a tool with the proper structure and type mapping, ready for you to implement your custom logic.

Scaffolding as a learning exercise

It's worth noting that having Active Record scaffolding generate MCP tools serves an important educational purpose. Just as early Ruby on Rails taught developers about CRUD operations in web development - lessons that helped us progress to thinking at scale and building more complex products - this approach teaches Rails developers how to think about MCP integration. The scaffolded tools provide a solid foundation for understanding how AI assistants can interact with your data, even if your production tools end up being more sophisticated.

The future of MCP in Rails ecosystem

The Model Context Protocol is still evolving, and so is the Rails ecosystem around it. This template represents one approach to enhancing Rails built-in capabilities, but there's room for many more patterns and tools.

What interests me most is how this changes the development workflow. When every scaffolded model automatically becomes available to AI assistants, it opens up new possibilities for how we build and interact with web applications.

The MCP Rails template is available at https://github.com/pstrzalk/mcp-on-rails. I'm looking forward to seeing how the Rails community adopts and evolves these enhanced scaffolding patterns.

Articles in this series

Paweł Strzałkowski
Chief Technology Officer

Check my Twitter

Check my Linkedin

Did you like it? 

Sign up To VIsuality newsletter

READ ALSO

Why do we like to be together?

11
.
06
.
2025
Michał Krochecki
Visuality
HR

Wallboards - a great value for our teams and clients

11
.
06
.
2025
Michał Krochecki
Ruby on Rails
Design
Project Management
Backend

2018 Clutch Global Leader

11
.
06
.
2025
Maciej Zdunek
Ruby on Rails
Visuality
Business
Marketing

Hot topic: Progressive Web Apps instead of native mobile apps

11
.
06
.
2025
Michał Krochecki
Ruby on Rails
Business
Backend
Frontend

Docker hosted on Jelastic

11
.
06
.
2025
Marcin Prokop
Ruby on Rails
Backend
Tutorial

All the pieces matter - Visuality DNA

11
.
06
.
2025
Michał Piórkowski
Visuality
HR

Tech conferences 2018/2019 you definitely should attend

11
.
06
.
2025
Michał Krochecki
Conferences

Visuality Poznań is here!

11
.
06
.
2025
Michał Piórkowski
Visuality
Business
HR

Why we chose Ruby on Rails and React.js for our main technologies? (FAQ).

11
.
06
.
2025
Michał Krochecki
Ruby on Rails
Backend
Frontend
Visuality

Branding: How to style your Jira?

11
.
06
.
2025
Lukasz Jackiewicz
Tutorial
Design
Project Management

How to start your UX/UI designer career

11
.
06
.
2025
Bartłomiej Bednarski
Design
Tutorial
HR

WebUSB - Bridge between USB devices and web browsers

11
.
06
.
2025
Burak Aybar
Ruby on Rails
Frontend
Backend
Tutorial

Visuality comes to town - this time it's Poznań

11
.
06
.
2025
Michał Piórkowski
Visuality
HR

How to choose a software house.

11
.
06
.
2025
Michał Piórkowski
Ruby on Rails
Business
Visuality

CSS Modules in Rails

11
.
06
.
2025
Adam Król
Ruby on Rails
Tutorial
Backend
Frontend

JSON API versus the NIH syndrome

11
.
06
.
2025
Nadia Miętkiewicz
Backend
Frontend
Tutorial

From Idea to Concept

11
.
06
.
2025
Michał Krochecki
Ruby on Rails
Business
Startups

Styling React Components

11
.
06
.
2025
Umit Naimian
Ruby on Rails
Frontend
Tutorial

How good design can help your business grow

11
.
06
.
2025
Lukasz Jackiewicz
Design
Business
Marketing

TODO not. Do, or do not.

11
.
06
.
2025
Stanisław Zawadzki
Ruby on Rails
Software

CS Lessons #003: Density map in three ways

11
.
06
.
2025
Michał Młoźniak
Ruby
Backend
Tutorial
Software

Clean code for the win

11
.
06
.
2025
Michał Piórkowski
Ruby on Rails
Backend
Frontend
Business

Crowd-operated Christmas Lights

11
.
06
.
2025
Nadia Miętkiewicz
Ruby on Rails
Backend