Class: McpAuthorization::FacadeBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/mcp_authorization/facade_builder.rb

Overview

Builds grouped facade tools for a faceted domain.

A facade is a per-request synthetic MCP::Tool subclass — one per non-empty category — whose description carries routing signal only (group summary + RBAC-filtered tool one-liners) and whose inputSchema defers per-tool argument schemas out of the selection prompt. A tools/call on a facade names the inner tool (+tool_name+) and its arguments; dispatch resolves the real tool through ToolRegistry.tool_class_for — re-running permitted? — and delegates to its materialized call, so authorization, gating, and input/output filtering apply exactly as if the tool had been called directly.

Facades are never registered in ToolRegistry; they are produced on demand by facades_for. See docs/designs/tool-grouping-facades.md.

Defined Under Namespace

Classes: FacadeNameCollisionError, UncategorizedToolError

Constant Summary collapse

FALLBACK_CATEGORY =

Fallback group for uncategorized tools (default mode).

:uncategorized

Class Method Summary collapse

Class Method Details

.facade_for(domain:, name:, server_context:) ⇒ Object

A single facade by its tool name (e.g. "orders_tools"), or nil when the name matches no non-empty group for this caller. Used by tools/call routing so one call doesn't build every facade. : (domain: String, name: String, server_context: untyped) -> singleton(MCP::Tool)?



49
50
51
52
53
54
55
56
57
# File 'lib/mcp_authorization/facade_builder.rb', line 49

def facade_for(domain:, name:, server_context:)
  config = McpAuthorization.config.facet_config(domain)
  return nil unless config

  group_tools(domain, server_context, config).each do |category, tools|
    return build_facade(domain, category, tools, server_context, config) if facade_name(category, config) == name
  end
  nil
end

.facade_name(category, config) ⇒ Object

The MCP tool name a category's facade is exposed under. The suffix is per-domain (facet config facade_suffix, default "tools"): category :ordersorders_tools (or orders_hire, etc.). : (Symbol, Hash[Symbol, untyped]) -> String



63
64
65
66
# File 'lib/mcp_authorization/facade_builder.rb', line 63

def facade_name(category, config)
  suffix = config[:facade_suffix] || Configuration::DEFAULT_FACADE_SUFFIX
  "#{category}_#{suffix}"
end

.facades_for(domain:, server_context:) ⇒ Object

All facades for a domain, one per non-empty group the caller has at least one permitted tool in. Empty groups produce no facade — which also guarantees no facade ever advertises an empty enum. : (domain: String, server_context: untyped) -> Array



36
37
38
39
40
41
42
43
# File 'lib/mcp_authorization/facade_builder.rb', line 36

def facades_for(domain:, server_context:)
  config = McpAuthorization.config.facet_config(domain)
  return [] unless config

  group_tools(domain, server_context, config).map do |category, tools|
    build_facade(domain, category, tools, server_context, config)
  end
end