rails-lens
  
MCP server that reveals implicit Rails dependencies for AI coding tools.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ DEAR RAILS DEVELOPERS,
All your hidden callbacks are belong to us. All your implicit concerns are belong to us. All your monkey-patched methods are belong to us.
You have no chance to survive make your code.
— rails-lens ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Overview
rails-lens is an MCP (Model Context Protocol) server that extracts and exposes Ruby on Rails application structure to AI coding tools like Claude Code and Cursor. It helps AI tools understand Rails implicit dependencies such as callbacks, associations, concerns, and dynamic method generation.
19 tools are provided to give AI assistants deep insight into Rails applications:
Phase 1–4 (Core Introspection)
- Introspect models with callbacks, associations, validations
- Find all references to a method or class across the codebase
- Trace full callback chains including inherited and concern-injected hooks
- Generate dependency graphs between models
- Dump database schema and routes
- Analyze shared concerns
- Manage the introspection cache
Phase 5–8 (Advanced Analysis)
- Explain method resolution order (MRO) and ancestor chains
- Introspect Gem-injected methods and callbacks
- Analyze the impact of changing a column or method
- Map models and methods to their test files
- Detect dead code (unused methods, callbacks, scopes)
- Detect circular dependencies between models
- Identify Concern extraction candidates from Fat Models
- Trace data flow from HTTP request to database
- Provide migration context and safety warnings
Phase 9–10 (Screen Mapping)
- Map screens to source files (templates, partials, helpers, models)
- Reverse-map source files to affected screens with impact analysis
- Auto-generate a full screen inventory (Markdown/JSON)
Requirements
Required:
- Python >= 3.11
Optional (for full functionality):
- Ruby + Bundler — enables Rails runner for live introspection
(e.g., accurate association traversal, runtime method resolution)
- ripgrep (
rg) — used by search-based tools (find_references, etc.)
Without Ruby: rails-lens works with file-based analysis fallback. Most tools return useful results by parsing Ruby files directly. Results include _metadata.source: "file_analysis" to indicate fallback mode. Some tools return limited data compared to Rails runner mode.
| Feature | With Ruby | Without Ruby | |---------|-----------|-------------| | Model listing | Live ActiveRecord scan | File glob + regex | | Schema info | DB introspection | db/schema.rb parse | | Associations | Runtime evaluation | Regex extraction | | Method resolution | Full ancestor chain | include/extend/prepend inference | | Gem introspection | Runtime method injection | Gemfile/Gemfile.lock parse only |
Installation
pip install rails-lens
Tools
Phase 1–4: Core Introspection
---
rails_lens_introspect_model
Introspects a single Rails model and returns its callbacks, associations, validations, scopes, and class methods.
Use case: Understand a model's full behavior before modifying it.
Parameters:
model_name(string, required): Rails model class name (e.g."User","Order")include_inherited(boolean, optional): Include inherited callbacks. Default:true
Example output: `` Model: User Callbacks: before_save: :downcase_email, :strip_whitespace after_create: :send_welcome_email Associations: has_many: :orders, :posts belongs_to: :organization Validations: validates :email, presence: true, uniqueness: true ``
---
rails_lens_list_models
Lists all ActiveRecord model classes found in the Rails application.
Use case: Get an overview of the data model before exploring specific models.
Parameters: none
Example output: `` Models (12): User, Order, Product, Category, Tag, Comment, Organization, Role, Permission, Session, AuditLog, Setting ``
---
rails_lens_find_references
Searches the codebase for all references to a given method or class name using fast text search.
Use case: Find everywhere a method is called before renaming or removing it.
Parameters:
name(string, required): Method or class name to search forfile_pattern(string, optional): Glob pattern to restrict search (e.g."app/*/.rb")
Example output: `` References to "send_welcome_email" (3 found): app/models/user.rb:42 after_create :send_welcome_email app/mailers/user_mailer.rb:8 def send_welcome_email(user) spec/models/user_spec.rb:15 expect(user).to receive(:send_welcome_email) ``
---
rails_lens_trace_callback_chain
Traces the full callback chain for a model event, including hooks from concerns and parent classes.
Use case: Debug unexpected behavior triggered by callbacks before modifying a model event.
Parameters:
model_name(string, required): Rails model class nameevent(string, required): Callback event (e.g."before_save","after_create")
Example output (Mermaid diagram): ``mermaid graph TD A[before_save] --> B[:downcase_email] A --> C[:strip_whitespace] B --> D[defined in Concerns::Normalizable] C --> E[defined in User] ``
---
rails_lens_dependency_graph
Generates a dependency graph showing associations between models.
Use case: Understand cross-model dependencies before a refactoring or data migration.
Parameters:
root_model(string, optional): Starting model for the graph. If omitted, graphs all models.depth(integer, optional): Maximum traversal depth. Default:2
Example output (Mermaid diagram): ``mermaid graph TD User -->|has_many| Order User -->|has_many| Post Order -->|belongs_to| User Order -->|has_many| LineItem LineItem -->|belongs_to| Product ``
---
rails_lens_get_schema
Dumps the current database schema (from db/schema.rb) in a structured format.
Use case: Inspect column types and constraints before writing a migration.
Parameters:
table_name(string, optional): Filter to a specific table. If omitted, returns all tables.
Example output: `` Table: users id: bigint, primary key email: string, not null, unique created_at: datetime, not null updated_at: datetime, not null ``
---
rails_lens_get_routes
Returns all defined Rails routes from config/routes.rb or rails routes output.
Use case: Verify available routes and their controller mappings.
Parameters:
filter(string, optional): Filter routes by path or controller name
Example output: `` GET /users users#index POST /users users#create GET /users/:id users#show PATCH /users/:id users#update DELETE /users/:id users#destroy ``
---
rails_lens_analyze_concern
Analyzes a Rails concern module and lists the methods, callbacks, and validations it injects.
Use case: Understand what a concern adds to a model before including or removing it.
Parameters:
concern_name(string, required): Concern module name (e.g."Normalizable","Auditable")
Example output: `` Concern: Concerns::Auditable Injects callbacks: before_create: :set_creator before_update: :set_updater Injects methods: :created_by_name, :updated_by_name Injects validations: validates :creator, presence: true ``
---
rails_lens_refresh_cache
Clears and rebuilds the introspection cache by re-running Rails scripts.
Use case: Refresh stale cache after adding new models or modifying existing ones.
Parameters:
model_name(string, optional): Refresh cache for a specific model only. If omitted, refreshes all.
Example output: `` Cache refreshed for: User, Order, Product (3 models) Duration: 4.2s ``
---
Phase 5: Method Resolution & Gem Introspection
---
rails_lens_explain_method_resolution
Returns the method resolution order (MRO), ancestor chain, and method owner for a Rails model.
Use case: Understand where a method is defined when multiple modules and concerns are included.
Parameters:
model_name(string, required): Rails model class namemethod_name(string, optional): Specific method to locate. If omitted, returns the full ancestor chain.show_internal(boolean, optional): Include Ruby/Rails internal modules. Default:false
Example output: ``json { "model_name": "User", "method_owner": "Concerns::Normalizable", "ancestors": ["User", "Concerns::Auditable", "Concerns::Normalizable", "ApplicationRecord"], "super_chain": ["Concerns::Normalizable#downcase_email"], "monkey_patches": [] } ``
---
rails_lens_gem_introspect
Returns methods, callbacks, and routes injected by Gems into a Rails model.
Use case: Discover what Devise, Paranoia, PaperTrail, or other gems add to a model.
Parameters:
model_name(string, required): Rails model class namegem_name(string, optional): Filter results to a specific gem. If omitted, returns all gems.
Example output: ``json { "model_name": "User", "gem_methods": [ {"gem_name": "devise", "method_name": "authenticate", "source_file": null} ], "gem_callbacks": [ {"gem_name": "paper_trail", "kind": "after_update", "event": "after_update", "method_name": "record_update"} ], "gem_routes": [] } ``
---
Phase 6: Change Safety
---
rails_lens_analyze_impact
Analyzes the impact of modifying or removing a column or method — including callbacks, validations, views, mailers, and cascade effects.
Use case: Assess risk before renaming a column or changing a method signature.
Parameters:
model_name(string, required): Rails model class nametarget(string, required): Column or method name to analyzechange_type(string, optional):remove,rename,type_change, ormodify. Default:modify
Example output (Mermaid diagram): ``mermaid graph LR TARGET["User.email"] I0["VL: validates :email, presence: true"] I1["CB: before_save :downcase_email"] I2["VW: app/views/users/show.html.erb"] style I0 fill:#fa4 style I1 fill:#fa4 style I2 fill:#8f8 TARGET --> I0 TARGET --> I1 TARGET --> I2 ``
---
rails_lens_test_mapping
Detects test files related to a model or method and returns the run command.
Use case: Find which specs to run after modifying a model or method.
Parameters:
target(string, required): Model name (e.g."User") or method spec (e.g."User#activate")include_indirect(boolean, optional): Include indirectly related specs (shared examples, feature specs). Default:true
Example output: ``json { "target": "User#activate", "test_framework": "rspec", "direct_tests": [ {"file": "spec/models/user_spec.rb", "type": "unit", "relevance": "direct"} ], "indirect_tests": [ {"file": "spec/features/user_registration_spec.rb", "type": "feature", "relevance": "indirect"} ], "run_command": "bundle exec rspec spec/models/user_spec.rb spec/features/user_registration_spec.rb" } ``
---
Phase 7: Refactoring
---
rails_lens_dead_code
Detects unused methods, callbacks, and scopes with confidence ratings.
Use case: Find safe candidates for removal during a cleanup or refactoring session.
Parameters:
scope(string, optional): Detection scope:models,controllers, orall. Default:modelsmodel_name(string, optional): Limit detection to a specific model.confidence(string, optional):high(certainly unused) ormedium(possibly dynamic). Default:high
Example output: ``json { "scope": "models", "total_methods_analyzed": 42, "total_dead_code_found": 3, "items": [ { "type": "method", "name": "legacy_export", "file": "app/models/user.rb", "line": 87, "confidence": "high", "reason": "No references found", "reference_count": 0, "dynamic_call_risk": false } ] } ``
---
rails_lens_circular_dependencies
Detects circular dependencies between models (mutual callback updates, bidirectional associations) and visualizes them as a Mermaid diagram.
Use case: Identify models that mutually trigger each other's callbacks, causing stack overflows or data corruption.
Parameters:
entry_point(string, optional): Filter to cycles containing this model.format(string, optional):mermaidorjson. Default:mermaid
Example output (Mermaid diagram): ``mermaid graph LR Order["Order"] Invoice["Invoice"] Order -->|"after_save → update_invoice"| Invoice Invoice -->|"after_save → update_order"| Order style Order fill:#f88 style Invoice fill:#f88 ``
---
rails_lens_extract_concern_candidate
Analyzes a Fat Model's methods by cohesion and suggests Concern extraction candidates with rationale.
Use case: Identify groups of related methods in a large model that should be extracted into concerns.
Parameters:
model_name(string, required): Rails model class namemin_cluster_size(integer, optional): Minimum number of methods per cluster. Default:3
Example output: ``json { "model_name": "User", "total_methods": 45, "candidates": [ { "suggested_name": "Notifiable", "methods": ["send_welcome_email", "send_reset_password", "notify_admin"], "cohesion_score": 0.87, "rationale": "All methods relate to email/notification dispatch" } ] } ``
---
Phase 8: Data Flow & Migration
---
rails_lens_data_flow
Traces data flow from an HTTP request through routing, strong parameters, callbacks, and into the database.
Use case: Understand the full lifecycle of a user-submitted attribute before modifying it.
Parameters:
controller_action(string, optional): Controller#action (e.g."UsersController#create")model_name(string, optional): Model name as an alternative entry pointattribute(string, optional): Specific attribute to trace. If omitted, traces all.
Example output (Mermaid sequence diagram): ``mermaid sequenceDiagram participant Client participant Router participant Controller as UsersController participant Params as StrongParameters participant Model participant DB Client->>Router: POST /users Router->>Controller: #create Controller->>Params: permit(:name, :email, :password) Params->>Model: User.new(params) Model->>Model: before_save :downcase_email Model->>DB: INSERT INTO users ``
---
rails_lens_migration_context
Provides migration context for a table: current schema, migration history, safety warnings, and a migration template.
Use case: Get all relevant context and safety checks before writing a migration for a large table.
Parameters:
table_name(string, required): Table name (e.g."users")operation(string, optional): Planned operation:add_column,remove_column,add_index,change_column,add_reference, orgeneral. Default:general
Example output: ``json { "table_name": "users", "operation": "add_column", "estimated_row_count": 2500000, "warnings": [ { "type": "large_table", "message": "Table has ~2.5M rows. Adding a non-null column without a default will lock the table.", "suggestion": "Use add_column with a default, then backfill and add NOT NULL constraint separately." } ], "template": { "description": "Add column with default for large table", "code": "add_column :users, :new_column, :string, default: nil\n# backfill...\nchange_column_null :users, :new_column, false" } } ``
---
Phase 9–10: Screen Mapping
---
rails_lens_screen_map
Maps between screens (URLs/controller actions) and source files bidirectionally, and generates a full screen inventory. Supports three modes.
Mode: screen_to_source
Given a URL or controller#action, returns all related source files including templates, partials, helpers, models, decorators, assets, and i18n keys.
Use case: Understand all the files involved in rendering a specific screen before modifying it.
Parameters:
mode(string, required):"screen_to_source"url(string, optional): URL path (e.g."/users/123")controller_action(string, optional): Controller#action (e.g."UsersController#show")locale(string, optional): Language for screen name inference. Default:"ja"
Example output: ``json { "screen": { "url_pattern": "/users/:id", "http_method": "GET", "controller_action": "UsersController#show", "screen_name": "User Detail", "screen_name_source": "restful_convention" }, "layout": { "file": "app/views/layouts/application.html.erb", "content_for_blocks": ["sidebar", "header"] }, "template": { "file": "app/views/users/show.html.erb" }, "partials": [ { "name": "users/header", "file": "app/views/users/_header.html.erb", "called_from": "app/views/users/show.html.erb", "locals_passed": ["user"] } ], "helpers": [ {"method": "format_date", "file": "app/helpers/application_helper.rb", "line": 12} ], "models": [ {"model": "User", "attributes_accessed": ["name", "email"]} ] } ``
---
Mode: source_to_screens
Given a source file path, returns all screens that use it and the impact level of changes.
Use case: Before modifying a partial or helper, understand which screens will be affected.
Parameters:
mode(string, required):"source_to_screens"file_path(string, required): Path to the source file (e.g."app/views/shared/_navigation.html.erb")method_name(string, optional): Helper method name to narrow the analysis
Example output: ``json { "source_file": "app/views/shared/_navigation.html.erb", "source_type": "partial", "affected_screens": [ { "controller_action": "UsersController#index", "screen_name": "User List", "url_pattern": "/users", "impact_level": "high" }, { "controller_action": "OrdersController#show", "screen_name": "Order Detail", "url_pattern": "/orders/:id", "impact_level": "high" } ] } ``
---
Mode: full_inventory
Auto-generates a complete screen inventory covering all web screens and API endpoints.
Use case: Create a screen inventory document for the project, or get an overview of all screens at a glance.
Parameters:
mode(string, required):"full_inventory"format(string, optional): Output format:"json"or"markdown". Default:"json"include_api(boolean, optional): Include API endpoints. Default:truegroup_by(string, optional): Grouping:"namespace","resource", or"flat". Default:"namespace"locale(string, optional): Language for screen name inference. Default:"ja"
Example output (markdown): ```markdown
Screen Inventory
Auto-generated by rails-lens
Summary
- Total screens: 24
- Web screens: 18
- API endpoints: 6
Web Screens
| Screen Name | URL | Controller#Action | Partials | Models | |-------------|-----|-------------------|----------|--------| | User List | GET /users | UsersController#index | 3 | User | | User Detail | GET /users/:id | UsersController#show | 5 | User | ```
---
Web Dashboard
rails-lens includes a built-in web dashboard to visualize your Rails project structure in the browser.
Installation
pip install rails-lens[web]
Usage
uvicorn rails_lens.web.app:app --host 0.0.0.0 --port 8000
Or using Python module:
python -m rails_lens.web
Pages
Core (6 pages) | Page | URL | Description | |------|-----|-------------| | Dashboard TOP | / | Project overview, model count, cache status | | Models List | /models | All models with column/association counts | | Model Detail | /models/{name} | Schema, callbacks, Mermaid callback chain | | ER Diagram | /er | Entity-Relationship diagram (Mermaid erDiagram) | | Dependency Graph | /graph/{name} | Model dependency graph (Mermaid graph LR) | | Cache Management | /cache | Cache status, invalidation controls |
Extended (5 pages) | Page | URL | Description | |------|-----|-------------| | Project Health | /health | Circular dependencies + dead code overview | | Request Flow | /flow | HTTP request → DB flow (Mermaid sequenceDiagram) | | Impact Analysis | /impact/{name} | Change impact visualization | | Refactoring Support | /refactor/{name} | Concern extraction candidates | | Gem Info | /gems | Installed gems and their Rails integrations |
Tech Stack
FastAPI + Jinja2 + PicoCSS + Mermaid.js
All diagrams are rendered in the browser via Mermaid.js — no server-side image generation needed.
Configuration
RAILS_LENS_PROJECT_PATH
The absolute path to the root directory of the Rails application you want to analyze (the directory containing Gemfile, app/, config/, db/, etc.).
This can be configured in the following ways (listed in order of priority):
- Environment variable
RAILS_LENS_PROJECT_PATH— Required when running as an MCP server (Claude Code / Cursor), since the server process does not run from the Rails project directory. rails.project_pathin.rails-lens.toml— Explicit path setting in the config file..rails-lens.tomllocation — If.rails-lens.tomlis placed in the Rails project root, the project path is automatically inferred from the file's parent directory. No explicitproject_pathsetting is needed.
Claude Code (~/.claude/claude_desktop_config.json)
{
"mcpServers": {
"rails-lens": {
"command": "rails-lens",
"env": {
"RAILS_LENS_PROJECT_PATH": "/path/to/your/rails/project"
}
}
}
}
Cursor (.cursor/mcp.json)
{
"mcpServers": {
"rails-lens": {
"command": "rails-lens",
"env": {
"RAILS_LENS_PROJECT_PATH": "/path/to/your/rails/project"
}
}
}
}
.rails-lens.toml (optional, in your Rails project root)
When placed in the Rails project root, project_path can be omitted — it is automatically resolved from the file's location.
[rails]
# project_path is inferred from this file's location
timeout = 30
[cache]
auto_invalidate = true
[search]
command = "rg"
Developer Setup
git clone https://github.com/ei-nakamura/rails-lens.git
cd rails-lens
pip install -e ".[dev]"
pytest tests/
Run with coverage:
pytest tests/ --cov=src/rails_lens --cov-report=term-missing
See CONTRIBUTING.md for contribution guidelines.
License
MIT






