PM

pstrzalk/mcp-on-rails

Developer tools
145 stars 0 forks Quality 60 Trend 60

A Rails application template that integrates the Model Context Protocol (MCP) with Ruby on Rails. During setup, the template asks whether to add OAuth 2.

Overview

A Rails application template that integrates the Model Context Protocol (MCP) with Ruby on Rails. During setup, the template asks whether to add OAuth 2.

README

MCP on Rails (with optional OAuth)

A Rails application template that integrates the Model Context Protocol (MCP) with Ruby on Rails. During setup, the template asks whether to add OAuth 2.1 protection using Devise and Doorkeeper — so one template supports both plain MCP and fully authenticated setups.

Quick Start

git clone https://github.com/pstrzalk/mcp-on-rails.git
rails new myapp -m mcp-on-rails/mcp
cd myapp
rails db:migrate
rails server

The template will prompt:

Add Devise + Doorkeeper OAuth 2.1 authentication? (y/n)

Answer n for a plain MCP server or y for full OAuth protection.

Adding the MCP template to an existing Rails application

You may just as easily apply this template to an existing Rails app.

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

Plain MCP (answer “n”)

Creates a Rails app with an open MCP server — no authentication required.

What you get

  • mcp gem added to Gemfile
  • McpController at /mcp — inherits ActionController::API, handles MCP protocol
  • MCP routes — POST /mcp, GET /mcp
  • Scaffold hook — rails generate scaffold automatically creates MCP tools
  • Custom tool generator — rails generate mcp_tool ToolName field:type
  • Custom prompt generator — rails generate mcp_prompt PromptName arg arg:required
  • to_mcp_response on ApplicationRecord for consistent text formatting
  • rake mcp:tools and rake mcp:prompts to list all registered tools and prompts (use mcp:tools:verbose / mcp:prompts:verbose for full details)

Usage

rails new myapp -m mcp-on-rails/mcp   # answer n
cd myapp && rails db:migrate

rails generate scaffold Post title:string body:text
rails db:migrate
rails server

Test it:

# MCP initialize
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'

# List tools
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

Project structure (plain mode)

app/
├── controllers/
│   └── mcp_controller.rb              # Open MCP endpoint (no auth)
├── models/
│   └── application_record.rb          # Extended with to_mcp_response
├── prompts/                           # MCP prompts (created via generator)
└── tools/                             # MCP tools (auto-generated per scaffold)

config/
├── initializers/
│   └── mcp.rb                         # MCP tool and prompt autoloading
└── routes.rb                          # MCP routes

lib/
├── generators/                        # MCP tool and prompt generators
└── tasks/
    └── mcp.rake                       # rake mcp:tools, rake mcp:prompts (and verbose variants)

Connecting AI assistants (plain mode)

{
  "name": "my-rails-app",
  "type": "StreamableHttp",
  "url": "http://localhost:3000/mcp"
}

No authentication needed — the /mcp endpoint is open.


OAuth MCP (answer “y”)

Creates a Rails app with an OAuth 2.1-protected MCP server, including PKCE, dynamic client registration, and resource indicator support — everything needed for MCP’s OAuth authorization flow.

What you get

Everything from plain mode, plus:

  • devise + doorkeeper gems added to Gemfile
  • Devise user authentication (sign-up, sign-in, password reset)
  • Doorkeeper OAuth 2.1 provider with PKCE enforcement (S256)
  • McpController protected by doorkeeper_authorize! with token audience validation (RFC 8707)
  • Dynamic client registration at POST /oauth/register (RFC 7591)
  • Protected resource metadata at GET /.well-known/oauth-protected-resource (RFC 9728)
  • Authorization server metadata at GET /.well-known/oauth-authorization-server (RFC 8414)
  • Resource indicators — tokens are scoped to the /mcp resource (RFC 8707)

Usage

rails new myapp -m mcp-on-rails/mcp   # answer y
cd myapp && rails db:migrate

rails generate scaffold Post title:string body:text
rails db:migrate
rails server

The /mcp endpoint now requires a Bearer token — unauthenticated requests return 401.

OAuth flow

The full authorization flow follows MCP’s OAuth specification:

  1. Discovery — Client fetches GET /.well-known/oauth-protected-resource to find the authorization server
  2. Server metadata — Client fetches GET /.well-known/oauth-authorization-server for endpoints and capabilities
  3. Client registration — POST /oauth/register with client metadata (RFC 7591)
  4. Authorization — GET /oauth/authorize with PKCE code_challenge (S256) and resource parameter
  5. User authentication — Devise handles sign-in/sign-up
  6. Token exchange — POST /oauth/token with code_verifier and resource parameter
  7. MCP requests — POST /mcp with Authorization: Bearer

Supported RFCs

RFC Description Endpoint
OAuth 2.1 + PKCE Authorization with Proof Key for Code Exchange (S256) /oauth/authorize, /oauth/token
RFC 7591 Dynamic Client Registration POST /oauth/register
RFC 8414 Authorization Server Metadata GET /.well-known/oauth-authorization-server
RFC 8707 Resource Indicators resource parameter in auth + token requests
RFC 9728 Protected Resource Metadata GET /.well-known/oauth-protected-resource

Project structure (OAuth mode)

app/
├── controllers/
│   ├── mcp_controller.rb                              # OAuth-protected MCP endpoint
│   ├── oauth_client_registration_controller.rb        # RFC 7591
│   └── oauth_authorization_server_metadata_controller.rb  # RFC 8414 + 9728
├── models/
│   ├── user.rb                                        # Devise user with OAuth associations
│   ├── oauth_application.rb
│   ├── oauth_access_token.rb
│   └── oauth_access_grant.rb
├── prompts/                                           # MCP prompts (created via generator)
├── tools/                                             # MCP tools (auto-generated per scaffold)
└── views/
    └── devise/                                        # Customizable auth views

config/
├── initializers/
│   ├── doorkeeper.rb                                  # OAuth + PKCE config
│   ├── devise.rb                                      # User auth config
│   └── mcp.rb                                         # MCP tool autoloading
└── routes.rb                                          # All OAuth + MCP routes

db/migrate/
├── *_devise_create_users.rb
├── *_create_doorkeeper_tables.rb
├── *_enable_pkce.rb
└── *_add_resource_to_oauth_tables.rb

Connecting AI assistants (OAuth mode)

{
  "name": "my-rails-app",
  "type": "StreamableHttp",
  "url": "http://localhost:3000/mcp"
}

The client must complete the OAuth PKCE flow before making MCP requests — the /mcp endpoint returns 401 without a valid Bearer token.


Common Features (both modes)

Scaffolding models with MCP tools

rails generate scaffold Post title:string content:text
rails db:migrate

This creates standard Rails files plus 5 MCP tools in app/tools/posts/:

  • show_tool.rb — Retrieve a single post by ID
  • index_tool.rb — List posts with pagination
  • create_tool.rb — Create new posts
  • update_tool.rb — Update existing posts
  • delete_tool.rb — Delete posts

Creating custom MCP tools

rails generate mcp_tool WeatherCheck location:string

Creating custom MCP prompts

rails generate mcp_prompt hotel_finder location:required check_in_date:required adults price_max

This creates app/prompts/hotel_finder.rb with a prompt class inheriting from MCP::Prompt. Arguments are optional by default — append :required to make them required.

Prompts are automatically loaded from app/prompts/ and registered with the MCP server. Unlike tools, prompts are not auto-generated during scaffolding — they are created explicitly via the generator.

Listing available tools and prompts

rake mcp:tools             # compact one-line-per-tool summary
rake mcp:tools:verbose     # full details with schema
rake mcp:prompts           # compact one-line-per-prompt summary
rake mcp:prompts:verbose   # full details with arguments

License

MIT License

View this README on GitHub

Install

This server does not publish a one-line install command.

Open the repository installation guide