Class: SimpleCovMcp::BaseTool

Inherits:
MCP::Tool
  • Object
show all
Defined in:
lib/simplecov_mcp/base_tool.rb

Constant Summary collapse

COMMON_PROPERTIES =
{
  root: {
    type: 'string',
    description: 'Project root used to resolve relative paths ' \
                 '(defaults to current workspace).',
    default: '.'
  },
  resultset: {
    type: 'string',
    description: 'Path to the SimpleCov .resultset.json file (absolute or relative to root).'
  },
  staleness: {
    type: 'string',
    description: 'How to handle missing/outdated coverage data. ' \
                 "'off' skips checks; 'error' raises.",
    enum: [:off, :error],
    default: :off
  },
  error_mode: {
    type: 'string',
    description: "Error handling mode: 'off' (silent), 'log' (log errors), " \
        "'debug' (verbose with backtraces).",
    enum: %w[off log debug],
    default: 'log'
  }
}.freeze
ERROR_MODE_PROPERTY =
COMMON_PROPERTIES[:error_mode].freeze
TRACKED_GLOBS_PROPERTY =
{
  type: 'array',
  description: 'Glob patterns for files that should exist in the coverage report' \
               '(helps flag new files).',
  items: { type: 'string' }
}.freeze
PATH_PROPERTY =
{
  type: 'string',
  description: 'Repo-relative or absolute path to the file whose coverage data you need.',
  examples: ['lib/simple_cov_mcp/model.rb']
}.freeze
FILE_INPUT_SCHEMA =
coverage_schema(
  additional_properties: { path: PATH_PROPERTY },
  required: ['path']
)

Class Method Summary collapse

Class Method Details

.coverage_schema(additional_properties: {}, required: []) ⇒ Object



52
53
54
55
56
57
58
59
# File 'lib/simplecov_mcp/base_tool.rb', line 52

def self.coverage_schema(additional_properties: {}, required: [])
  {
    type: 'object',
    additionalProperties: false,
    properties: COMMON_PROPERTIES.merge(additional_properties),
    required: required
  }.freeze
end

.handle_mcp_error(error, tool_name, error_mode: :log) ⇒ Object

Handle errors consistently across all MCP tools Returns an MCP::Tool::Response with appropriate error message



78
79
80
81
82
83
84
85
86
87
# File 'lib/simplecov_mcp/base_tool.rb', line 78

def self.handle_mcp_error(error, tool_name, error_mode: :log)
  # Create error handler with the specified mode
  error_handler = ErrorHandlerFactory.for_mcp_server(error_mode: error_mode.to_sym)

  # Normalize to a SimpleCovMcp::Error so we can handle/log uniformly
  normalized = error.is_a?(SimpleCovMcp::Error) \
    ? error : error_handler.convert_standard_error(error)
  log_mcp_error(normalized, tool_name, error_handler)
  ::MCP::Tool::Response.new([{ 'type' => 'text', 'text' => "Error: #{normalized.user_friendly_message}" }])
end

.input_schema_defObject



65
# File 'lib/simplecov_mcp/base_tool.rb', line 65

def self.input_schema_def = FILE_INPUT_SCHEMA

.respond_json(payload, name: 'data.json', pretty: false) ⇒ Object

Respond with JSON as a resource to avoid clients mutating content types. The resource embeds the JSON string with a clear MIME type.



91
92
93
94
# File 'lib/simplecov_mcp/base_tool.rb', line 91

def self.respond_json(payload, name: 'data.json', pretty: false)
  json = pretty ? JSON.pretty_generate(payload) : JSON.generate(payload)
  ::MCP::Tool::Response.new([{ 'type' => 'text', 'text' => json }])
end

.with_error_handling(tool_name, error_mode:) ⇒ Object

Wrap tool execution with consistent error handling. Yields to the block and rescues any error, delegating to handle_mcp_error. This eliminates duplicate rescue blocks across all tools.



70
71
72
73
74
# File 'lib/simplecov_mcp/base_tool.rb', line 70

def self.with_error_handling(tool_name, error_mode:)
  yield
rescue => e
  handle_mcp_error(e, tool_name, error_mode: error_mode)
end