Active MCP ๐
๐ Table of Contents
- Active MCP ๐
- ๐ Table of Contents
- โจ Features
- ๐ฆ Installation
- ๐ Setup
- Using the Install Generator (Recommended)
- Manual Setup
- ๐ MCP Connection Methods
- 1. Direct HTTP Connection
- 2. Standalone MCP Server
- ๐ Rails Generators
- Install Generator
- Tool Generator
- ๐งฐ Creating MCP Tools
- ๐ Input Schema
- ๐ Authorization & Authentication
- Authorization for Tools
- Authentication Options
- โ๏ธ Advanced Configuration
- Custom Controller
- ๐ก Best Practices
- 1. Create Specific Tool Classes
- 2. Validate and Sanitize Inputs
- 3. Return Structured Responses
- ๐งช Development
- ๐ฅ Contributing
- ๐ License
โจ Features
- Simple Integration: Easily expose Rails functionality as MCP tools
- Powerful Generators: Quickly scaffold MCP tools with Rails generators
- Authentication Support: Built-in authentication and authorization capabilities
- Flexible Configuration: Multiple deployment and connection options
๐ฆ Installation
Add this line to your application's Gemfile:
gem 'active_mcp'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install active_mcp
๐ Setup
Using the Install Generator (Recommended)
The easiest way to set up Active MCP in your Rails application is to use the install generator:
$ rails generate active_mcp:install
This generator will:
- Create a configuration initializer at
config/initializers/active_mcp.rb - Mount the ActiveMcp engine in your routes
- Create an MCP server script at
script/mcp_server.rb - Show instructions for next steps
After running the generator, follow the displayed instructions to create and configure your MCP tools.
Manual Setup
If you prefer to set up manually:
- Mount the ActiveMcp engine in your
config/routes.rb:
Rails.application.routes.draw do
mount ActiveMcp::Engine, at: "/mcp"
# Your other routes
end
- Create a tool by inheriting from
ActiveMcp::Tool:
class CreateNoteTool < ActiveMcp::Tool
description "Create Note"
argument :title, :string, required: true
argument :content, :string, required: true
def call(title:, content:)
note = Note.create(title: title, content: content)
"Created note with ID: #{note.id}"
end
end
๐ MCP Connection Methods
Active MCP supports two connection methods:
1. Direct HTTP Connection
Set your MCP client to connect directly to your Rails application:
https://your-app.example.com/mcp
2. Standalone MCP Server
Start a dedicated MCP server that communicates with your Rails app:
# script/mcp_server.rb
server = ActiveMcp::Server.new(
name: "My App MCP Server",
uri: 'https://your-app.example.com/mcp'
)
server.start
Then configure your MCP client:
{
"mcpServers": {
"my-rails-app": {
"command": "/path/to/ruby",
"args": ["/path/to/script/mcp_server.rb"]
}
}
}
๐ Rails Generators
Active MCP provides generators to help you quickly set up and extend your MCP integration:
Install Generator
Initialize Active MCP in your Rails application:
$ rails generate active_mcp:install
Tool Generator
Create new MCP tools quickly:
$ rails generate active_mcp:tool search_users
This creates a new tool file at app/tools/search_users_tool.rb with ready-to-customize starter code.
๐งฐ Creating MCP Tools
MCP tools are Ruby classes that inherit from ActiveMcp::Tool and define an interface for AI to interact with your application:
class SearchUsersTool < ActiveMcp::Tool
description 'Search users by criteria'
argument :email, :string, required: false, description: 'Email to search for'
argument :name, :string, required: false, description: 'Name to search for'
argument :limit, :integer, required: false, description: 'Maximum number of records to return'
def call(email: nil, name: nil, limit: 10)
criteria = {}
criteria[:email] = email if email.present?
criteria[:name] = name if name.present?
users = User.where(criteria).limit(limit)
{
type: "text",
content: users.to_json(only: [:id, :name, :email, :created_at])
}
end
end
๐ Input Schema
Define arguments for your tools using the argument method:
argument :name, :string, required: true, description: 'User name'
argument :age, :integer, required: false, description: 'User age'
argument :addresses, :array, required: false, description: 'User addresses'
argument :preferences, :object, required: false, description: 'User preferences'
Supported types:
| Type | Description |
|---|---|
:string |
Text values |
:integer |
Whole numbers |
:number |
Decimal numbers (float/decimal) |
:boolean |
True/false values |
:array |
Lists of values |
:object |
Hash/dictionary structures |
:null |
Null values |
๐ Authorization & Authentication
Authorization for Tools
Control access to tools by overriding the visible? class method:
class AdminOnlyTool < ActiveMcp::Tool
description "Admin-only tool"
argument :command, :string, required: true, description: "Admin command"
# Only allow admins to access this tool
def self.visible?(auth_info)
return false unless auth_info
return false unless auth_info[:type] == :bearer
# Check if the token belongs to an admin
auth_info[:token] == "admin-token" || User.find_by_token(auth_info[:token])&.admin?
end
def call(command:, auth_info: nil)
# Tool implementation
end
end
Authentication Options
1. Server Configuration
server = ActiveMcp::Server.new(
name: "My Secure MCP Server",
uri: 'http://localhost:3000/mcp',
auth: {
type: :bearer,
token: ENV['MCP_AUTH_TOKEN']
}
)
server.start
2. Token Verification in Tools
def call(resource_id:, auth_info: nil, **args)
# Check if authentication is provided
unless auth_info.present?
raise "Authentication required"
end
# Verify the token
user = User.authenticate_with_token(auth_info[:token])
unless user
raise "Invalid authentication token"
end
# Proceed with authenticated operation
# ...
end
โ๏ธ Advanced Configuration
Custom Controller
Create a custom controller for advanced needs:
class CustomMcpController < ActiveMcp::BaseController
# Custom MCP handling logic
end
Update routes:
Rails.application.routes.draw do
post "/mcp", to: "custom_mcp#index"
end
๐ก Best Practices
1. Create Specific Tool Classes
Create dedicated tool classes for each model or operation instead of generic tools:
# โ
GOOD: Specific tool for a single purpose
class SearchUsersTool < ActiveMcp::Tool
# ...specific implementation
end
# โ BAD: Generic tool that dynamically loads models
class GenericSearchTool < ActiveMcp::Tool
# Avoid this pattern - security and maintainability issues
end
2. Validate and Sanitize Inputs
Always validate and sanitize inputs in your tool implementations:
def call(user_id:, **args)
# Validate input
unless user_id.is_a?(Integer) || user_id.to_s.match?(/^\d+$/)
return { error: "Invalid user ID format" }
end
# Proceed with validated data
user = User.find_by(id: user_id)
# ...
end
3. Return Structured Responses
Return structured responses that are easy for AI to parse:
def call(query:, **args)
results = User.search(query)
{
type: "text",
content: results.to_json(only: [:id, :name, :email]),
metadata: {
count: results.size,
query: query
}
}
end
๐งช Development
After checking out the repo, run bundle install to install dependencies. Then, run bundle exec rake to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
๐ฅ Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/moekiorg/active_mcp. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
๐ License
The gem is available as open source under the terms of the MIT License.