Tooling And Dependencies
This doc lists every gem, library, and runtime component the generic MCP feature relies on β including authentication. Use it as a pre-flight checklist before copying code into a target project.
Required Gems
These are non-optional for the MCP runtime itself.
| Gem | Version | Purpose |
|---|---|---|
rails |
7+ (8.x recommended) | Framework. Rack mount, Active Record, routes, thread-locals, Current attributes. |
mcp |
~> 0.10.0 |
The Ruby Model Context Protocol gem. Provides MCP::Server, MCP::Tool, MCP::Tool::Response, and MCP::Server::Transports::StreamableHTTPTransport. |
puma |
>= 5.0 |
Threaded web server. The Rack app assumes thread-local state cleanup under a threaded server. |
Add to the Gemfile:
gem "rails", "~> 8.1"
gem "mcp", "~> 0.10.0"
gem "puma", ">= 5.0"
Recommended Gems
Used by this package for authentication, authorization, and UX polish. If your target app uses a different stack, map the equivalents.
Authentication
| Gem | Purpose | Alternatives |
|---|---|---|
devise |
Session-based user authentication. Provides authenticate_user!, current_user, and authenticated :user do ... end route blocks. |
Rails 8 built-in auth generator, Clearance, Sorcery, custom session layer |
devise-passwordless |
Magic-link login. Optional if you want users to receive a tokenized email instead of typing a password. | β |
devise_invitable |
Invite-based signup. Optional. | β |
devise-i18n |
Localized Devise messages. Optional. | β |
omniauth + omniauth-google-oauth2 + omniauth-rails_csrf_protection |
OAuth login. Optional. | omniauth-github, omniauth-apple, etc. |
What the MCP runtime actually needs:
- a
current_userhelper available in controllers - a way to run
before_action :authenticate_user!onMcp::BaseController - a
Usermodel with anidthat can ownmcp_tokens
Any auth stack that provides those three things will work. Devise is the default assumption because Rails apps most commonly use it.
Authorization
| Gem | Purpose |
|---|---|
pundit |
Policy classes. Used by Mcp::TokenPolicy to scope token CRUD to current_user.mcp_tokens. |
If you do not use Pundit, inline the scoping in the controller:
@token = current_user.mcp_tokens.find(params[:id])
Frontend / View Layer
| Gem | Purpose |
|---|---|
turbo-rails |
Hotwire Turbo for the token management UI. Optional if you are not shipping a UI. |
stimulus-rails |
Copy-to-clipboard and permission-toggle interactivity. Optional. |
tailwindcss-rails |
Styling for token forms. Optional. |
importmap-rails |
ES module imports without a bundler. Optional. |
None of these are required by the MCP runtime itself β they only matter if you port the token management UI.
Runtime Components You Need In The App
Current attributes
This package relies on a thread-safe Current singleton for propagating the acting user during MCP dispatch:
# app/models/current.rb
class Current < ActiveSupport::CurrentAttributes
attribute :user
end
Used in Mcp::RackApp#before_dispatch to set Current.user = mcp_token.user so any downstream Active Record callback can see the acting user. It is cleared in after_dispatch.
Rails 8 ships ActiveSupport::CurrentAttributes as standard β no extra gem required.
ActiveSupport::Concern
Used by Mcp::Tools::Concerns::Formattable, Listable, and ToolMetadata. Ships with Rails.
SecureRandom and Digest::SHA256
Standard library. Used for:
- generating raw tokens (
SecureRandom.hex(32)) - hashing them for storage (
Digest::SHA256.hexdigest(raw))
No extra gems needed.
ActiveModel::Type::Boolean
Ships with Rails. Used in Mcp::Token.sanitize_permissions to coerce form checkbox values ("1"/"0"/true/false) to real booleans before writing to the permissions JSON column.
ActionController::Parameters
Standard Rails. The token controller uses params.dig(:mcp_token, :permissions) to read permission checkboxes from the form.
MCP SDK Contract
The mcp gem exposes:
MCP::Toolβ base class for all tools.Mcp::BaseToolinherits from it.MCP::Tool::Responseβ wrapper for tool output. TheFormattableconcern uses it to emit{ type: "text", text: ... }content blocks.MCP::Serverβ the JSON-RPC dispatcher. Built per request byMcp::ServerBuilder.build(context).MCP::Server::Transports::StreamableHTTPTransportβ the HTTP transport this package uses. Streamable HTTP is the transport MCP hosts like Claude Desktop and Claude Code accept via a URL.
Version pin: gem "mcp", "~> 0.10.0". Other 0.x versions may introduce breaking changes to MCP::Tool::Response or the transport constructor β pin strictly.
Client-Side Requirements
The MCP host (the AI client) must speak Streamable HTTP transport with token-in-URL authentication.
Known-good clients:
- Claude Desktop β add the server under
mcpServersin the desktop config with aurlfield - Claude Code (CLI) β
claude mcp addwith a URL argument - Claude web/API β wherever Streamable HTTP MCP is supported
Sample configuration:
{
"mcpServers": {
"my-app": {
"url": "https://your-app.com/mcp/YOUR_TOKEN"
}
}
}
If your target MCP client only supports stdio transport, you need an adapter or a local proxy β the package does not cover that case.
Database
- Primary database: any Active Record adapter (SQLite, PostgreSQL, MySQL). The migrations use standard column types (
:string,:json,:datetime,:integer). - JSON column:
permissionsonmcp_tokensandarguments/result_summaryonmcp_activity_logsuset.json. On SQLite and MySQL this is aTEXTunder the hood. On PostgreSQL, switch tot.jsonbif you want indexed queries on specific permission keys. - No caching gem required. The in-memory rate limiter lives in the Rack app instance.
Background Jobs
The generic package does not require any background job processing. Mcp::ActivityLog.log_tool_call runs synchronously inside the tool call.
If you want to offload logging under high load, wrap the logging call in your project's existing job framework (ActiveJob, Sidekiq, solid_queue, GoodJob). Keep the synchronous default until you have measured contention.
Testing
| Gem | Purpose |
|---|---|
| Minitest (Rails default) | Model, controller, Rack, and tool tests |
rack-test |
Required for Rack app tests β simulates requests against the mounted MCP endpoint |
If your project uses RSpec, swap in rspec-rails and rack-test equivalents. The test matrix in 05_security_ops_and_testing.md is framework-agnostic.
Optional But Nice To Have
| Gem | Why you might want it |
|---|---|
pagy |
Pagination for the activity log viewer. Not needed for tool-level pagination β Listable does that inline. |
pretender |
Admin impersonation for debugging a user's MCP surface. Optional. |
noticed |
In-app notifications when tokens are revoked or created. Optional. |
Minimum Viable Dependency List
If you want the absolute smallest Gemfile addition to stand up the MCP endpoint:
gem "rails"
gem "mcp", "~> 0.10.0"
gem "puma"
# + whatever auth stack gives you `current_user` and `authenticate_user!`
Everything else is ergonomics.
Dependency Check Before You Start Porting
Before copying any files into the target project, confirm:
- Rails 7+ (ideally 8.x)
current_userhelper available in controllers (any auth stack)- A
Usermodel with a primary key suitable for a foreign key ActiveSupport::CurrentAttributesavailable (standard in modern Rails)mcpgem version pin agreed (~> 0.10.0)- Routes file can accept
mount Mcp::RackApp.new, at: "/mcp"before anyauthenticatedblocks - A target resource model to back the
ItemCRUD example (or plan to rename before porting)
Once all six are green, proceed with Phase 1 of the playbook.