Module: Rails::Hyperdrive::Resources::Skill
- Defined in:
- lib/rails/hyperdrive/resources/skill.rb
Constant Summary collapse
- URI_TEMPLATE =
"hyperdrive://skills/{name}"- URI_PREFIX =
"hyperdrive://skills/"- NAME_PATTERN =
Skill names follow the SKILL.md/.claude convention: lowercase letters, digits, hyphens. Anything else is rejected to prevent path traversal via
hyperdrive://skills/../../etc/passwd. /\A[a-z0-9][a-z0-9_\-]*\z/.freeze
Class Method Summary collapse
-
.installed_resources ⇒ Object
Enumerated once at server build time, so skills installed by a fresh
hyperdrive:initonly appear after a dev-server restart. - .read(params) ⇒ Object
- .template ⇒ Object
Class Method Details
.installed_resources ⇒ Object
Enumerated once at server build time, so skills installed by a fresh
hyperdrive:init only appear after a dev-server restart.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/rails/hyperdrive/resources/skill.rb', line 28 def installed_resources return [] unless defined?(::Rails) && ::Rails.respond_to?(:root) && ::Rails.root skills_root = ::Rails.root.join(InstallLayout::SKILLS_DIR) return [] unless Dir.exist?(skills_root) Dir.glob(::Rails.root.join(InstallLayout.dest_for(:skill, "*")).to_s).sort.map do |path| name = InstallLayout.installed_name(:skill, path) next unless name.match?(NAME_PATTERN) ::MCP::Resource.new( uri: "#{URI_PREFIX}#{name}", name: name, description: "Skill: #{name}", mime_type: "text/markdown" ) end.compact end |
.read(params) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/rails/hyperdrive/resources/skill.rb', line 44 def read(params) uri = params[:uri] || params["uri"] name = uri.to_s.sub(URI_PREFIX, "") unless name.match?(NAME_PATTERN) raise ::MCP::Server::RequestHandlerError.new( "Resource not found: #{uri}", params, error_type: :invalid_params ) end path = ::Rails.root.join(InstallLayout.dest_for(:skill, name)) unless File.exist?(path) raise ::MCP::Server::RequestHandlerError.new( "Resource not found: #{uri}", params, error_type: :invalid_params ) end [{ uri: uri, mimeType: "text/markdown", text: File.read(path) }] end |
.template ⇒ Object
17 18 19 20 21 22 23 24 |
# File 'lib/rails/hyperdrive/resources/skill.rb', line 17 def template ::MCP::ResourceTemplate.new( uri_template: URI_TEMPLATE, name: "Installed skill", description: "Markdown body of an installed #{InstallLayout::SKILLS_DIR}/<name>/SKILL.md", mime_type: "text/markdown" ) end |