Class: McpToolkit::Tools::AuthorityBase
- Inherits:
-
Object
- Object
- McpToolkit::Tools::AuthorityBase
- Defined in:
- lib/mcp_toolkit/tools/authority_base.rb
Overview
Optional base class for a HOST's own tools served by the authority dispatcher (McpToolkit::Dispatcher). A host tool MAY subclass this, or may be any object satisfying the duck-typed tool contract the dispatcher calls:
tool.required_permissions_scope -> String | nil (gem's scope gate)
tool.call(context:, **arguments) -> Hash | String (gem wraps into
{ content: [...] })
The dispatcher treats the object returned by provider.find(name) as the tool;
an AuthorityBase SUBCLASS satisfies the contract as CLASS methods (the class
.call instantiates, runs, and error-maps a single invocation).
What this base adds over hand-rolling the contract:
* a class DSL (`tool_name` / `description` / `input_schema` /
`required_permissions_scope` / `definition`) mirroring the tool-definition
shape `tools/list` returns;
* per-request accessors (`account` / `principal` / `bearer_token` /
`superuser?`) read from the injected Authority::Context;
* `ensure_resource_accessible!` to gate a superuser-only resource;
* error mapping — an ArgumentError (e.g. a missing required kwarg) becomes an
InvalidParams, any other StandardError an InternalError, while a
deliberately-raised McpToolkit::Protocol::Error passes through with its own
code.
The gem NEVER references a host's API layer, serializers, or resource catalog —
all of that lives behind the host's #call.
Class Attribute Summary collapse
-
._description ⇒ Object
readonly
Returns the value of attribute _description.
-
._input_schema ⇒ Object
readonly
Returns the value of attribute _input_schema.
-
._tool_name ⇒ Object
readonly
Returns the value of attribute _tool_name.
Instance Attribute Summary collapse
-
#context ⇒ Object
readonly
Returns the value of attribute context.
Class Method Summary collapse
-
.call(context:, **arguments) ⇒ Object
The dispatcher's entry point: build an instance bound to this request's context and run it, mapping tool-level errors to protocol errors.
- .definition ⇒ Object
- .description(desc = nil) ⇒ Object
- .input_schema(&block) ⇒ Object
-
.required_permissions_scope(scope = nil) ⇒ Object
OAuth-style scope (
<app>__<action>) a token must carry to call this tool, enforced by the dispatcher before the tool runs. - .tool_name(name = nil) ⇒ Object
Instance Method Summary collapse
- #account ⇒ Object
- #bearer_token ⇒ Object
-
#call(**_arguments) ⇒ Object
The subclass implements its business logic here, receiving the tool arguments as keywords and returning a Hash or String.
-
#ensure_resource_accessible!(resource) ⇒ Object
Guards a resource flagged
superusers_only?: a non-superuser caller is refused. -
#execute(**arguments) ⇒ Object
Runs the tool's business logic (the subclass's
#call) with error mapping. -
#initialize(context:) ⇒ AuthorityBase
constructor
A new instance of AuthorityBase.
- #principal ⇒ Object
-
#superuser? ⇒ Boolean
Whether the caller is a superuser, per the Context (which duck-types it off the principal).
Constructor Details
#initialize(context:) ⇒ AuthorityBase
Returns a new instance of AuthorityBase.
77 78 79 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 77 def initialize(context:) @context = context end |
Class Attribute Details
._description ⇒ Object (readonly)
Returns the value of attribute _description.
31 32 33 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 31 def _description @_description end |
._input_schema ⇒ Object (readonly)
Returns the value of attribute _input_schema.
31 32 33 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 31 def _input_schema @_input_schema end |
._tool_name ⇒ Object (readonly)
Returns the value of attribute _tool_name.
31 32 33 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 31 def _tool_name @_tool_name end |
Instance Attribute Details
#context ⇒ Object (readonly)
Returns the value of attribute context.
75 76 77 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 75 def context @context end |
Class Method Details
.call(context:, **arguments) ⇒ Object
The dispatcher's entry point: build an instance bound to this request's context and run it, mapping tool-level errors to protocol errors.
70 71 72 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 70 def call(context:, **arguments) new(context:).execute(**arguments) end |
.definition ⇒ Object
60 61 62 63 64 65 66 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 60 def definition { name: tool_name, description: _description, inputSchema: _input_schema || { type: "object", properties: {} } } end |
.description(desc = nil) ⇒ Object
41 42 43 44 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 41 def description(desc = nil) @_description = desc if desc @_description end |
.input_schema(&block) ⇒ Object
46 47 48 49 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 46 def input_schema(&block) @_input_schema = yield if block @_input_schema || { type: "object", properties: {} } end |
.required_permissions_scope(scope = nil) ⇒ Object
OAuth-style scope (<app>__<action>) a token must carry to call this tool,
enforced by the dispatcher before the tool runs. Defaults to nil (no scope
required). NOT inherited — a subclass that doesn't declare its own scope is
unscoped, even if an ancestor declared one.
55 56 57 58 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 55 def (scope = nil) @_required_permissions_scope = scope.to_s if scope @_required_permissions_scope end |
.tool_name(name = nil) ⇒ Object
33 34 35 36 37 38 39 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 33 def tool_name(name = nil) if name @_tool_name = name.to_s else @_tool_name || self.name.to_s.demodulize.underscore.gsub(/_tool$/, "") end end |
Instance Method Details
#account ⇒ Object
81 82 83 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 81 def account context.account end |
#bearer_token ⇒ Object
89 90 91 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 89 def bearer_token context.bearer_token end |
#call(**_arguments) ⇒ Object
The subclass implements its business logic here, receiving the tool arguments as keywords and returning a Hash or String.
124 125 126 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 124 def call(**_arguments) raise NotImplementedError, "#{self.class} must implement #call" end |
#ensure_resource_accessible!(resource) ⇒ Object
Guards a resource flagged superusers_only?: a non-superuser caller is
refused. No-op for unrestricted resources.
101 102 103 104 105 106 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 101 def ensure_resource_accessible!(resource) return unless resource.superusers_only? return if superuser? raise McpToolkit::Protocol::InvalidRequest, "#{resource.name} is restricted to superuser (user-scoped) MCP tokens" end |
#execute(**arguments) ⇒ Object
Runs the tool's business logic (the subclass's #call) with error mapping.
Arrives with symbol-keyed arguments from the dispatcher.
110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 110 def execute(**arguments) call(**arguments) rescue McpToolkit::Protocol::Error # A deliberately-raised protocol error carries its own JSON-RPC code # (e.g. InvalidParams); let it bubble untouched so the client sees it. raise rescue ArgumentError => e raise McpToolkit::Protocol::InvalidParams, e. rescue StandardError => e raise McpToolkit::Protocol::InternalError, e. end |
#principal ⇒ Object
85 86 87 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 85 def principal context.principal end |
#superuser? ⇒ Boolean
Whether the caller is a superuser, per the Context (which duck-types it off the principal). Used to gate resources/tools that expose cross-tenant data.
95 96 97 |
# File 'lib/mcp_toolkit/tools/authority_base.rb', line 95 def superuser? context.superuser? end |