rails-mcp-server 1.1.4 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +216 -0
- data/README.md +156 -46
- data/config/resources.yml +203 -0
- data/docs/RESOURCES.md +339 -0
- data/exe/rails-mcp-server +8 -5
- data/exe/rails-mcp-server-download-resources +120 -0
- data/lib/rails-mcp-server/config.rb +7 -1
- data/lib/rails-mcp-server/extensions/resource_templating.rb +182 -0
- data/lib/rails-mcp-server/extensions/server_templating.rb +333 -0
- data/lib/rails-mcp-server/helpers/resource_base.rb +143 -0
- data/lib/rails-mcp-server/helpers/resource_downloader.rb +104 -0
- data/lib/rails-mcp-server/helpers/resource_importer.rb +113 -0
- data/lib/rails-mcp-server/resources/base_resource.rb +7 -0
- data/lib/rails-mcp-server/resources/custom_guides_resource.rb +54 -0
- data/lib/rails-mcp-server/resources/custom_guides_resources.rb +37 -0
- data/lib/rails-mcp-server/resources/guide_content_formatter.rb +130 -0
- data/lib/rails-mcp-server/resources/guide_error_handler.rb +85 -0
- data/lib/rails-mcp-server/resources/guide_file_finder.rb +100 -0
- data/lib/rails-mcp-server/resources/guide_framework_contract.rb +65 -0
- data/lib/rails-mcp-server/resources/guide_loader_template.rb +122 -0
- data/lib/rails-mcp-server/resources/guide_manifest_operations.rb +52 -0
- data/lib/rails-mcp-server/resources/kamal_guides_resource.rb +80 -0
- data/lib/rails-mcp-server/resources/kamal_guides_resources.rb +110 -0
- data/lib/rails-mcp-server/resources/rails_guides_resource.rb +29 -0
- data/lib/rails-mcp-server/resources/rails_guides_resources.rb +37 -0
- data/lib/rails-mcp-server/resources/stimulus_guides_resource.rb +29 -0
- data/lib/rails-mcp-server/resources/stimulus_guides_resources.rb +37 -0
- data/lib/rails-mcp-server/resources/turbo_guides_resource.rb +29 -0
- data/lib/rails-mcp-server/resources/turbo_guides_resources.rb +37 -0
- data/lib/rails-mcp-server/tools/analyze_models.rb +1 -1
- data/lib/rails-mcp-server/tools/load_guide.rb +370 -0
- data/lib/rails-mcp-server/version.rb +1 -1
- data/lib/rails_mcp_server.rb +51 -283
- metadata +49 -6
@@ -0,0 +1,122 @@
|
|
1
|
+
module RailsMcpServer
|
2
|
+
# Template module that provides complete guide loading implementation
|
3
|
+
# Eliminates the need to implement load_specific_guide in each resource
|
4
|
+
module GuideLoaderTemplate
|
5
|
+
def self.included(base)
|
6
|
+
# Ensure all required modules are included
|
7
|
+
base.include GuideFrameworkContract unless base.included_modules.include?(GuideFrameworkContract)
|
8
|
+
base.include GuideManifestOperations unless base.included_modules.include?(GuideManifestOperations)
|
9
|
+
base.include GuideFileFinder unless base.included_modules.include?(GuideFileFinder)
|
10
|
+
base.include GuideContentFormatter unless base.included_modules.include?(GuideContentFormatter)
|
11
|
+
base.include GuideErrorHandler unless base.included_modules.include?(GuideErrorHandler)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Complete single guide content implementation
|
15
|
+
def content
|
16
|
+
guide_name = params[:guide_name]
|
17
|
+
|
18
|
+
begin
|
19
|
+
manifest = load_manifest
|
20
|
+
rescue => e
|
21
|
+
return handle_manifest_error(e)
|
22
|
+
end
|
23
|
+
|
24
|
+
if !guide_name.nil? && !guide_name.strip.empty?
|
25
|
+
log(:debug, "Loading #{framework_name} guide: #{guide_name}")
|
26
|
+
load_specific_guide(guide_name, manifest)
|
27
|
+
else
|
28
|
+
log(:debug, "Provide a name for a #{framework_name} guide")
|
29
|
+
"Provide a name for a #{framework_name} guide"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Complete guides list implementation
|
34
|
+
def list_content
|
35
|
+
begin
|
36
|
+
manifest = load_manifest
|
37
|
+
rescue => e
|
38
|
+
return handle_manifest_error(e)
|
39
|
+
end
|
40
|
+
|
41
|
+
log(:debug, "Loading #{framework_name} guides...")
|
42
|
+
format_guides_index(manifest)
|
43
|
+
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
|
47
|
+
# Template method for loading a specific guide
|
48
|
+
def load_specific_guide(guide_name, manifest)
|
49
|
+
normalized_guide_name = guide_name.gsub(/[^a-zA-Z0-9_\/.-]/, "")
|
50
|
+
|
51
|
+
begin
|
52
|
+
filename, guide_data = find_guide_file(normalized_guide_name, manifest)
|
53
|
+
|
54
|
+
if filename && guide_data
|
55
|
+
guides_path = File.dirname(File.join(config_dir, "resources", resource_directory, "manifest.yaml"))
|
56
|
+
guide_file_path = File.join(guides_path, filename)
|
57
|
+
|
58
|
+
if File.exist?(guide_file_path)
|
59
|
+
log(:debug, "Loading guide: #{filename}")
|
60
|
+
content = File.read(guide_file_path)
|
61
|
+
|
62
|
+
# Allow customization of display name
|
63
|
+
display_name = customize_display_name(guide_name, guide_data)
|
64
|
+
format_guide_content(content, display_name, guide_data, filename)
|
65
|
+
else
|
66
|
+
format_not_found_message(guide_name, manifest)
|
67
|
+
end
|
68
|
+
else
|
69
|
+
format_not_found_message(guide_name, manifest)
|
70
|
+
end
|
71
|
+
rescue => e
|
72
|
+
handle_guide_loading_error(guide_name, e)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Template method for formatting guides index
|
77
|
+
def format_guides_index(manifest)
|
78
|
+
guides = []
|
79
|
+
|
80
|
+
guides << "# Available #{framework_name} Guides\n"
|
81
|
+
guides << "Use the `load_guide` tool with `guides: \"#{framework_name.downcase}\"` and `guide: \"guide_name\"` to load a specific guide.\n"
|
82
|
+
|
83
|
+
if supports_sections?
|
84
|
+
guides << "You can use either the full path (e.g., `handbook/01_introduction`) or just the filename (e.g., `01_introduction`).\n"
|
85
|
+
end
|
86
|
+
|
87
|
+
guide_files = get_guide_files(manifest)
|
88
|
+
|
89
|
+
if supports_sections?
|
90
|
+
guides.concat(format_sectioned_guides(guide_files))
|
91
|
+
else
|
92
|
+
guides.concat(format_flat_guides(guide_files))
|
93
|
+
end
|
94
|
+
|
95
|
+
# Add examples if this is a list resource
|
96
|
+
if respond_to?(:example_guides) && example_guides.any?
|
97
|
+
guides << format_usage_examples
|
98
|
+
end
|
99
|
+
|
100
|
+
guides.join("\n")
|
101
|
+
end
|
102
|
+
|
103
|
+
# Template method for not found messages
|
104
|
+
def format_not_found_message(guide_name, manifest)
|
105
|
+
guide_files = get_guide_files(manifest)
|
106
|
+
available_guides = guide_files.keys.map { |f| f.sub(".md", "") }
|
107
|
+
|
108
|
+
message = create_not_found_message(guide_name, available_guides)
|
109
|
+
|
110
|
+
# Allow framework-specific additions to not found message
|
111
|
+
message = customize_not_found_message(message, guide_name) if respond_to?(:customize_not_found_message, true)
|
112
|
+
|
113
|
+
log(:error, "Guide not found: #{guide_name}")
|
114
|
+
message
|
115
|
+
end
|
116
|
+
|
117
|
+
# Hook for customizing display name (override in resources if needed)
|
118
|
+
def customize_display_name(guide_name, guide_data)
|
119
|
+
guide_name
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module RailsMcpServer
|
2
|
+
# Module for handling guide manifest operations
|
3
|
+
module GuideManifestOperations
|
4
|
+
protected
|
5
|
+
|
6
|
+
# Load and validate manifest file
|
7
|
+
def load_manifest
|
8
|
+
manifest_file = File.join(config_dir, "resources", resource_directory, "manifest.yaml")
|
9
|
+
|
10
|
+
unless File.exist?(manifest_file)
|
11
|
+
error_message = "No #{framework_name} guides found. Run '#{download_command}' first."
|
12
|
+
log(:error, error_message)
|
13
|
+
raise StandardError, error_message
|
14
|
+
end
|
15
|
+
|
16
|
+
YAML.load_file(manifest_file)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Extract guide metadata from manifest entry
|
20
|
+
def extract_guide_metadata(filename, file_data)
|
21
|
+
{
|
22
|
+
filename: filename,
|
23
|
+
guide_name: filename.sub(".md", ""),
|
24
|
+
title: file_data["title"] || generate_title_from_filename(filename),
|
25
|
+
description: file_data["description"] || "",
|
26
|
+
original_filename: file_data["original_filename"] # For custom guides
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
# Generate title from filename if not in manifest
|
31
|
+
def generate_title_from_filename(filename)
|
32
|
+
base_name = filename.sub(".md", "").split("/").last
|
33
|
+
base_name.gsub(/[_-]/, " ").split.map(&:capitalize).join(" ")
|
34
|
+
end
|
35
|
+
|
36
|
+
# Get all guide files from manifest
|
37
|
+
def get_guide_files(manifest)
|
38
|
+
manifest["files"].select { |filename, _| filename.end_with?(".md") }
|
39
|
+
end
|
40
|
+
|
41
|
+
# Get guide files organized by sections
|
42
|
+
def get_sectioned_guide_files(manifest)
|
43
|
+
guide_files = get_guide_files(manifest)
|
44
|
+
|
45
|
+
{
|
46
|
+
handbook: guide_files.select { |filename, _| filename.start_with?("handbook/") },
|
47
|
+
reference: guide_files.select { |filename, _| filename.start_with?("reference/") },
|
48
|
+
other: guide_files.reject { |filename, _| filename.start_with?("handbook/", "reference/") }
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module RailsMcpServer
|
2
|
+
class KamalGuidesResource < BaseResource
|
3
|
+
include GuideLoaderTemplate
|
4
|
+
|
5
|
+
uri "kamal://guides/{guide_name}"
|
6
|
+
resource_name "Kamal Guides"
|
7
|
+
description "Access to specific Kamal deployment documentation"
|
8
|
+
mime_type "text/markdown"
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def framework_name
|
13
|
+
"Kamal"
|
14
|
+
end
|
15
|
+
|
16
|
+
def resource_directory
|
17
|
+
"kamal"
|
18
|
+
end
|
19
|
+
|
20
|
+
def download_command
|
21
|
+
"rails-mcp-server-download-resources kamal"
|
22
|
+
end
|
23
|
+
|
24
|
+
# Kamal guides have subdirectories but not handbook/reference sections
|
25
|
+
def supports_sections?
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
# Override for Kamal's directory structure
|
30
|
+
def framework_specific_filenames(normalized_guide_name)
|
31
|
+
possible_files = []
|
32
|
+
|
33
|
+
if normalized_guide_name.include?("/")
|
34
|
+
possible_files << normalized_guide_name
|
35
|
+
possible_files << "#{normalized_guide_name}.md"
|
36
|
+
else
|
37
|
+
%w[installation configuration commands hooks upgrading].each do |section|
|
38
|
+
possible_files << "#{section}/#{normalized_guide_name}.md"
|
39
|
+
possible_files << "#{section}/index.md" if normalized_guide_name == section
|
40
|
+
end
|
41
|
+
possible_files << "#{normalized_guide_name}/index.md"
|
42
|
+
end
|
43
|
+
|
44
|
+
possible_files
|
45
|
+
end
|
46
|
+
|
47
|
+
# Override for Kamal's section detection
|
48
|
+
def framework_specific_section(filename)
|
49
|
+
case filename
|
50
|
+
when /^installation\// then "Installation"
|
51
|
+
when /^configuration\// then "Configuration"
|
52
|
+
when /^commands\// then "Commands"
|
53
|
+
when /^hooks\// then "Hooks"
|
54
|
+
when /^upgrading\// then "Upgrading"
|
55
|
+
else; "Documentation"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Enhanced fuzzy matching for hierarchical structure
|
60
|
+
def fuzzy_match_files(normalized_guide_name, manifest)
|
61
|
+
search_term = normalized_guide_name.downcase
|
62
|
+
|
63
|
+
manifest["files"].select do |file, _|
|
64
|
+
next false unless file.end_with?(".md")
|
65
|
+
|
66
|
+
file_path = file.downcase
|
67
|
+
file_name_base = file.sub(".md", "").split("/").last.downcase
|
68
|
+
file_full_path = file.sub(".md", "").downcase
|
69
|
+
|
70
|
+
file_path.include?(search_term) ||
|
71
|
+
file_name_base.include?(search_term) ||
|
72
|
+
search_term.include?(file_name_base) ||
|
73
|
+
file_full_path.include?(search_term) ||
|
74
|
+
search_term.include?(file_full_path) ||
|
75
|
+
file_name_base.gsub(/[_-]/, "").include?(search_term.gsub(/[_-]/, "")) ||
|
76
|
+
search_term.gsub(/[_-]/, "").include?(file_name_base.gsub(/[_-]/, ""))
|
77
|
+
end.to_a
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module RailsMcpServer
|
2
|
+
class KamalGuidesResources < BaseResource
|
3
|
+
include GuideLoaderTemplate
|
4
|
+
|
5
|
+
uri "kamal://guides"
|
6
|
+
resource_name "Kamal Guides"
|
7
|
+
description "Access to available Kamal deployment guides"
|
8
|
+
mime_type "text/markdown"
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def framework_name
|
13
|
+
"Kamal"
|
14
|
+
end
|
15
|
+
|
16
|
+
def resource_directory
|
17
|
+
"kamal"
|
18
|
+
end
|
19
|
+
|
20
|
+
def download_command
|
21
|
+
"rails-mcp-server-download-resources kamal"
|
22
|
+
end
|
23
|
+
|
24
|
+
def example_guides
|
25
|
+
[
|
26
|
+
{guide: "installation/index", comment: "Load installation guide"},
|
27
|
+
{guide: "configuration/environment-variables", comment: "Load environment variables configuration"},
|
28
|
+
{guide: "commands/deploy", comment: "Load deploy command guide"},
|
29
|
+
{guide: "hooks/overview", comment: "Load hooks overview"},
|
30
|
+
{guide: "upgrading/overview", comment: "Load upgrading overview"}
|
31
|
+
]
|
32
|
+
end
|
33
|
+
|
34
|
+
# Kamal guides have subdirectories but not handbook/reference sections
|
35
|
+
def supports_sections?
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
# Override to format guides organized by Kamal's directory structure
|
40
|
+
def format_flat_guides(manifest)
|
41
|
+
guides = []
|
42
|
+
|
43
|
+
# Group guides by their directory structure
|
44
|
+
sections = {
|
45
|
+
"installation" => [],
|
46
|
+
"configuration" => [],
|
47
|
+
"commands" => [],
|
48
|
+
"hooks" => [],
|
49
|
+
"upgrading" => []
|
50
|
+
}
|
51
|
+
|
52
|
+
other_guides = []
|
53
|
+
|
54
|
+
manifest["files"].each do |filename, file_data|
|
55
|
+
next unless filename.end_with?(".md")
|
56
|
+
|
57
|
+
log(:debug, "Processing guide: #{filename}")
|
58
|
+
|
59
|
+
guide_name = filename.sub(".md", "")
|
60
|
+
title = file_data["title"] || guide_name.split("/").last.gsub(/[_-]/, " ").split.map(&:capitalize).join(" ")
|
61
|
+
description = file_data["description"] || ""
|
62
|
+
|
63
|
+
# Categorize by directory
|
64
|
+
case filename
|
65
|
+
when /^installation\//
|
66
|
+
sections["installation"] << {name: guide_name, title: title, description: description}
|
67
|
+
when /^configuration\//
|
68
|
+
sections["configuration"] << {name: guide_name, title: title, description: description}
|
69
|
+
when /^commands\//
|
70
|
+
sections["commands"] << {name: guide_name, title: title, description: description}
|
71
|
+
when /^hooks\//
|
72
|
+
sections["hooks"] << {name: guide_name, title: title, description: description}
|
73
|
+
when /^upgrading\//
|
74
|
+
sections["upgrading"] << {name: guide_name, title: title, description: description}
|
75
|
+
else
|
76
|
+
other_guides << {name: guide_name, title: title, description: description}
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Format each section
|
81
|
+
sections.each do |section_name, section_guides|
|
82
|
+
next if section_guides.empty?
|
83
|
+
|
84
|
+
guides << "\n## #{section_name.capitalize}\n"
|
85
|
+
section_guides.each do |guide|
|
86
|
+
guides << format_guide_entry(guide[:title], guide[:name], guide[:name], guide[:description])
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Add any other guides that don't fit the standard structure
|
91
|
+
if other_guides.any?
|
92
|
+
guides << "\n## Other\n"
|
93
|
+
other_guides.each do |guide|
|
94
|
+
guides << format_guide_entry(guide[:title], guide[:name], guide[:name], guide[:description])
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
guides
|
99
|
+
end
|
100
|
+
|
101
|
+
# Format individual guide entry
|
102
|
+
def format_guide_entry(title, short_name, full_name, description)
|
103
|
+
<<~GUIDE
|
104
|
+
### #{title}
|
105
|
+
**Guide name:** `#{short_name}`
|
106
|
+
#{description.empty? ? "" : "**Description:** #{description}"}
|
107
|
+
GUIDE
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module RailsMcpServer
|
2
|
+
class RailsGuidesResource < BaseResource
|
3
|
+
include GuideLoaderTemplate
|
4
|
+
|
5
|
+
uri "rails://guides/{guide_name}"
|
6
|
+
resource_name "Rails Guides"
|
7
|
+
description "Access to specific Rails documentation"
|
8
|
+
mime_type "text/markdown"
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def framework_name
|
13
|
+
"Rails"
|
14
|
+
end
|
15
|
+
|
16
|
+
def resource_directory
|
17
|
+
"rails"
|
18
|
+
end
|
19
|
+
|
20
|
+
def download_command
|
21
|
+
"rails-mcp-server-download-resources rails"
|
22
|
+
end
|
23
|
+
|
24
|
+
# Rails guides don't use handbook/reference sections
|
25
|
+
def supports_sections?
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RailsMcpServer
|
2
|
+
class RailsGuidesResources < BaseResource
|
3
|
+
include GuideLoaderTemplate
|
4
|
+
|
5
|
+
uri "rails://guides"
|
6
|
+
resource_name "Rails Guides List"
|
7
|
+
description "Access to available Rails guides"
|
8
|
+
mime_type "text/markdown"
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def framework_name
|
13
|
+
"Rails"
|
14
|
+
end
|
15
|
+
|
16
|
+
def resource_directory
|
17
|
+
"rails"
|
18
|
+
end
|
19
|
+
|
20
|
+
def download_command
|
21
|
+
"rails-mcp-server-download-resources rails"
|
22
|
+
end
|
23
|
+
|
24
|
+
def example_guides
|
25
|
+
[
|
26
|
+
{guide: "active_record_validations", comment: "Load validations guide"},
|
27
|
+
{guide: "getting_started", comment: "Load getting started guide"},
|
28
|
+
{guide: "routing", comment: "Load routing guide"}
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Rails guides don't use handbook/reference sections
|
33
|
+
def supports_sections?
|
34
|
+
false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module RailsMcpServer
|
2
|
+
class StimulusGuidesResource < BaseResource
|
3
|
+
include GuideLoaderTemplate
|
4
|
+
|
5
|
+
uri "stimulus://guides/{guide_name}"
|
6
|
+
resource_name "Stimulus Guides"
|
7
|
+
description "Access to specific Stimulus documentation"
|
8
|
+
mime_type "text/markdown"
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def framework_name
|
13
|
+
"Stimulus"
|
14
|
+
end
|
15
|
+
|
16
|
+
def resource_directory
|
17
|
+
"stimulus"
|
18
|
+
end
|
19
|
+
|
20
|
+
def download_command
|
21
|
+
"rails-mcp-server-download-resources stimulus"
|
22
|
+
end
|
23
|
+
|
24
|
+
# Stimulus guides use handbook/reference sections
|
25
|
+
def supports_sections?
|
26
|
+
true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RailsMcpServer
|
2
|
+
class StimulusGuidesResources < BaseResource
|
3
|
+
include GuideLoaderTemplate
|
4
|
+
|
5
|
+
uri "stimulus://guides"
|
6
|
+
resource_name "Stimulus Guides"
|
7
|
+
description "Access to available Stimulus guides"
|
8
|
+
mime_type "text/markdown"
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def framework_name
|
13
|
+
"Stimulus"
|
14
|
+
end
|
15
|
+
|
16
|
+
def resource_directory
|
17
|
+
"stimulus"
|
18
|
+
end
|
19
|
+
|
20
|
+
def download_command
|
21
|
+
"rails-mcp-server-download-resources stimulus"
|
22
|
+
end
|
23
|
+
|
24
|
+
def example_guides
|
25
|
+
[
|
26
|
+
{guide: "actions", comment: "Load actions reference"},
|
27
|
+
{guide: "01_introduction", comment: "Load introduction"},
|
28
|
+
{guide: "reference/targets", comment: "Load targets with full path"}
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Stimulus guides use handbook/reference sections
|
33
|
+
def supports_sections?
|
34
|
+
true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module RailsMcpServer
|
2
|
+
class TurboGuidesResource < BaseResource
|
3
|
+
include GuideLoaderTemplate
|
4
|
+
|
5
|
+
uri "turbo://guides/{guide_name}"
|
6
|
+
resource_name "Turbo Guides"
|
7
|
+
description "Access to specific Turbo documentation"
|
8
|
+
mime_type "text/markdown"
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def framework_name
|
13
|
+
"Turbo"
|
14
|
+
end
|
15
|
+
|
16
|
+
def resource_directory
|
17
|
+
"turbo"
|
18
|
+
end
|
19
|
+
|
20
|
+
def download_command
|
21
|
+
"rails-mcp-server-download-resources turbo"
|
22
|
+
end
|
23
|
+
|
24
|
+
# Turbo guides use handbook/reference sections
|
25
|
+
def supports_sections?
|
26
|
+
true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RailsMcpServer
|
2
|
+
class TurboGuidesResources < BaseResource
|
3
|
+
include GuideLoaderTemplate
|
4
|
+
|
5
|
+
uri "turbo://guides"
|
6
|
+
resource_name "Turbo Guides"
|
7
|
+
description "Access to available Turbo guides"
|
8
|
+
mime_type "text/markdown"
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def framework_name
|
13
|
+
"Turbo"
|
14
|
+
end
|
15
|
+
|
16
|
+
def resource_directory
|
17
|
+
"turbo"
|
18
|
+
end
|
19
|
+
|
20
|
+
def download_command
|
21
|
+
"rails-mcp-server-download-resources turbo"
|
22
|
+
end
|
23
|
+
|
24
|
+
def example_guides
|
25
|
+
[
|
26
|
+
{guide: "drive", comment: "Load drive reference"},
|
27
|
+
{guide: "02_drive", comment: "Load drive handbook"},
|
28
|
+
{guide: "reference/frames", comment: "Load frames with full path"}
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Turbo guides use handbook/reference sections
|
33
|
+
def supports_sections?
|
34
|
+
true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module RailsMcpServer
|
2
2
|
class AnalyzeModels < BaseTool
|
3
|
-
tool_name "
|
3
|
+
tool_name "analyze_models"
|
4
4
|
|
5
5
|
description "Retrieve detailed information about Active Record models in the project. When called without parameters, lists all model files. When a specific model is specified, returns its schema, associations (has_many, belongs_to, has_one), and complete source code."
|
6
6
|
|