rails-lens

ei-nakamura/rails-lens
0 starsCommunity

Install to Claude Code

This server doesn't publish a one-line install command. Follow the setup in the source repository.

Summary

An MCP server that exposes Ruby on Rails implicit dependencies like callbacks, associations, and concerns to AI coding tools.

README.md

日本語

rails-lens

![CI](https://github.com/ei-nakamura/rails-lens/actions/workflows/ci.yml) ![PyPI version](https://badge.fury.io/py/rails-lens) ![Python Versions](https://pypi.org/project/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 for
  • file_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 name
  • event (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 name
  • method_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 name
  • gem_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 name
  • target (string, required): Column or method name to analyze
  • change_type (string, optional): remove, rename, type_change, or modify. 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, or all. Default: models
  • model_name (string, optional): Limit detection to a specific model.
  • confidence (string, optional): high (certainly unused) or medium (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): mermaid or json. 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 name
  • min_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 point
  • attribute (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, or general. 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: true
  • group_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):

  1. 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.
  2. rails.project_path in .rails-lens.toml — Explicit path setting in the config file.
  3. .rails-lens.toml location — If .rails-lens.toml is placed in the Rails project root, the project path is automatically inferred from the file's parent directory. No explicit project_path setting 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

Related MCP servers

Browse all →