Module: RosettAi::Mcp::Governance

Defined in:
lib/rosett_ai/mcp/governance.rb

Overview

Centralized MCP tool, resource, and prompt registration.

Always loaded before plugins. Registers all built-in tools, resources, and prompts with the MCP server instance.

Author:

  • hugo

  • claude

Constant Summary collapse

TOOL_CLASSES =
[
  Tools::ValidateTool,
  Tools::CompileTool,
  Tools::BehaviourListTool,
  Tools::BehaviourShowTool,
  Tools::BehaviourDisplayTool,
  Tools::BehaviourManageTool,
  Tools::DesignListTool,
  Tools::DesignShowTool,
  Tools::ConfigStatusTool,
  Tools::ConfigCompileTool,
  Tools::AdoptTool,
  Tools::ComplyTool,
  Tools::DoctorTool,
  Tools::EnginesTool,
  Tools::HooksStatusTool,
  Tools::LicenseStatusTool,
  Tools::ProjectTool,
  Tools::ProvenanceTool,
  Tools::ProvenanceWriteTool,
  Tools::ToolingTool,
  Tools::WorkflowTool,
  Tools::WorkflowExecuteTool,
  Tools::DocumentationStatusTool,
  Tools::InitTool,
  Tools::BackupTool,
  Tools::ContentTool,
  Tools::RetrofitTool
].freeze
RESOURCE_CLASSES =
[
  Resources::BehaviourResource,
  Resources::DesignResource,
  Resources::ProvenanceResource,
  Resources::ConfigResource
].freeze
PROMPT_CLASSES =
[
  Prompts::ValidationPrompt,
  Prompts::CompilationPrompt,
  Prompts::CompliancePrompt,
  Prompts::DiagnosticsPrompt
].freeze
KEYWORD_PARAM_TYPES =
[:keyreq, :key].freeze

Class Method Summary collapse

Class Method Details

.build_kwargs(tool, args) ⇒ Object

Parameters:

  • tool (Object)

    tool instance with #call

  • args (Hash, nil)

    MCP arguments



127
128
129
130
131
132
133
134
135
136
137
# File 'lib/rosett_ai/mcp/governance.rb', line 127

def build_kwargs(tool, args)
  return {} unless args.is_a?(Hash)

  method_params = tool.method(:call).parameters
  param_names = method_params.filter_map { |type, name| name if KEYWORD_PARAM_TYPES.include?(type) }

  args.each_with_object({}) do |(key, value), kwargs|
    sym = key.to_sym
    kwargs[sym] = value if param_names.include?(sym)
  end
end

.find_resource_for_uri(resources, uri) ⇒ Object



117
118
119
# File 'lib/rosett_ai/mcp/governance.rb', line 117

def find_resource_for_uri(resources, uri)
  resources.find { |r| resource_matches_uri?(r, uri) }
end

.register(server) ⇒ Object

Parameters:

  • server (MCP::Server)


65
66
67
68
69
# File 'lib/rosett_ai/mcp/governance.rb', line 65

def register(server)
  register_tools(server)
  register_resources(server)
  register_prompts(server)
end

.register_prompts(server) ⇒ Object

Parameters:

  • server (MCP::Server)


89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/rosett_ai/mcp/governance.rb', line 89

def register_prompts(server)
  PROMPT_CLASSES.each do |klass|
    prompt = klass.new
    server.define_prompt(
      name: klass::PROMPT_NAME,
      description: klass::DESCRIPTION
    ) do |args|
      kwargs = (args || {}).transform_keys(&:to_sym)
      prompt.call(**kwargs)
    end
  end
end

.register_resources(server) ⇒ Object

Parameters:

  • server (MCP::Server)


77
78
79
80
81
82
83
84
85
86
# File 'lib/rosett_ai/mcp/governance.rb', line 77

def register_resources(server)
  resources = RESOURCE_CLASSES.map(&:new)
  server.resources_list_handler { resources.flat_map(&:list) }
  server.resources_read_handler do |uri:|
    resource_name = uri.split('/').last
    resource_class = find_resource_for_uri(resources, uri)
    result = resource_class&.read(resource_name)
    result&.fetch(:content, '')
  end
end

.register_tool(server, klass) ⇒ Object

Parameters:

  • server (MCP::Server)
  • klass (Class)

    tool class with TOOL_NAME, DESCRIPTION, ANNOTATIONS



104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/rosett_ai/mcp/governance.rb', line 104

def register_tool(server, klass)
  server.define_tool(
    name: klass::TOOL_NAME,
    description: klass::DESCRIPTION,
    annotations: klass::ANNOTATIONS
  ) do |args|
    tool = klass.new
    kwargs = build_kwargs(tool, args)
    result = kwargs.empty? ? tool.call : tool.call(**kwargs)
    JSON.generate(result)
  end
end

.register_tools(server) ⇒ Object

Parameters:

  • server (MCP::Server)


72
73
74
# File 'lib/rosett_ai/mcp/governance.rb', line 72

def register_tools(server)
  TOOL_CLASSES.each { |klass| register_tool(server, klass) }
end

.resource_matches_uri?(resource, uri) ⇒ Boolean

Returns:

  • (Boolean)


121
122
123
# File 'lib/rosett_ai/mcp/governance.rb', line 121

def resource_matches_uri?(resource, uri)
  resource.list.any? { |entry| entry[:uri] == uri }
end