Class ::nsmcp::ToolRegistry (public)
::nx::Class ::nsmcp::ToolRegistry
Defined in /usr/local/ns/tcl/nsmcp/01-tools.tcl
- Testcases:
- No testcase defined.
Source code: :variable tools {} :property {stateStore {}} # Nonempty context opts this registry into trusted module providers. :property {providerContext {}} :variable providers {} # Look up provider-owned settings without inserting defaults into either # section. Explicit false/empty values must not fall through to legacy data. :public object method providerConfig {context parameter default} { foreach key {section fallbackSection} { if {![dict exists $context $key]} {continue} set section [dict get $context $key] set name $parameter if {$key eq "fallbackSection" && [dict exists $context fallbackParameters $parameter]} { set name [dict get $context fallbackParameters $parameter] } set configuration [ns_configsection $section] if {$configuration ne "" && [ns_set ifind $configuration $name] >= 0} { return [ns_config $section $name] } } return $default } :public method refreshProviders {} { if {${:providerContext} eq ""} {return} set descriptors {} catch {set descriptors [nsv_array get nsmcp:providers]} # Registration is trusted startup Tcl, never an MCP/client operation. dict for {provider descriptor} $descriptors { if {[dict exists ${:providers} $provider]} {continue} foreach field {file factory} { if {![dict exists $descriptor $field]} {error "provider $provider lacks $field"} } if {[dict exists $descriptor requires] && [info commands [dict get $descriptor requires]] eq ""} {continue} set context ${:providerContext} if {[dict exists $descriptor section]} { dict set context fallbackSection [dict get $context section] dict set context section [dict get $descriptor section] } if {[dict exists $descriptor fallbackParameters]} { dict set context fallbackParameters [dict get $descriptor fallbackParameters] } if {[dict exists $descriptor enabledParameter]} { set parameter [dict get $descriptor enabledParameter] set enabled [::nsmcp::ToolRegistry providerConfig $context $parameter false] if {![string is boolean -strict $enabled]} { error "provider $provider requires a boolean $parameter" } if {!$enabled} {continue} } set file [dict get $descriptor file] if {[file pathtype $file] ne "absolute" || ![file isfile $file]} { error "provider $provider must provide an absolute readable Tcl file" } uplevel #0 [list source $file] set factory [dict get $descriptor factory] if {[llength $factory] != 1 || [info commands $factory] eq ""} { error "provider $provider must provide a factory command" } # Validate the entire batch before adding any tool. Factory failures # must not leave a partially registered provider or replace a tool. set candidates [$factory $context] set pending {} foreach tool $candidates { if {![nsf::object::exists $tool] || ![$tool info has type ::nsmcp::Tool]} { error "provider $provider returned a non-Tool object" } set name [$tool name] if {[dict exists ${:tools} $name] || [dict exists $pending $name]} { error "duplicate tool: $name" } dict set pending $name $tool } dict for {name tool} $pending {dict set :tools $name $tool} dict set :providers $provider [dict keys $pending] } return ${:providers} } :public method controlsAvailable {} { # An explicitly configured backend owns per-server runtime overrides. return [expr {${:stateStore} ne ""}] } :method readEnabled {name} { # Isolate storage access from discovery and invocation. An absent # override means enabled; NSV state is shared by this server's threads. if {${:stateStore} ne "" && [nsv_exists ${:stateStore} $name]} { return [nsv_get ${:stateStore} $name] } return true } :method writeEnabled {name enabled} { nsv_set ${:stateStore} $name $enabled } :public method enabled {name} { :refreshProviders # Administrative availability, independent of caller permissions. if {![dict exists ${:tools} $name]} { error "unknown tool: $name" } return [:readEnabled $name] } :public method setEnabled {name enabled:boolean} { # Trusted administrative interface, not an MCP tool. Disabling prevents # new invocations; it does not cancel existing jobs or stop collectors. # Overrides survive interpreter recreation/reload, not process restart. if {![:controlsAvailable]} { error "runtime tool controls are not configured" } :enabled $name set enabled [expr {!!$enabled}] :writeEnabled $name $enabled return $enabled } :public method register {tool} { set name [$tool name] if {[dict exists ${:tools} $name]} {error "duplicate tool: $name"} dict set :tools $name $tool } :public method describe {} { :refreshProviders # Administrative metadata for the registered tools. This does not # execute tools or change permission-filtered MCP tools/list results. set result {} foreach name [lsort [dict keys ${:tools}]] { set tool [dict get ${:tools} $name] set description [ns_json parse [ns_json value -- [$tool describe]]] foreach field {adminSummary adminExample} { set value [$tool cget -$field] if {$value ne ""} {dict set description $field $value} } dict set description permission [$tool permission] dict set description enabled [:readEnabled $name] lappend result $description } return $result } :public method list {context authorizer} { :refreshProviders set result {} foreach name [lsort [dict keys ${:tools}]] { set tool [dict get ${:tools} $name] if {[:readEnabled $name] && [$authorizer allowed $context [$tool permission]]} { lappend result [$tool describe] } } set members {}; set index 0 foreach description $result { lappend members $index object [lindex $description 2] incr index } return [list {} object [list tools array $members]] } :public method call {context authorizer name arguments} { :refreshProviders if {![dict exists ${:tools} $name]} { return -code error -errorcode {NSMCP RPC -32602} "Unknown tool" } set tool [dict get ${:tools} $name] $authorizer require $context [$tool permission] if {![:readEnabled $name]} { return -code error -errorcode {NSMCP RPC -32602} "Tool is disabled on this server" } $tool validate $arguments if {[catch {$tool execute $context $arguments} result options]} { if {[lrange [dict get $options -errorcode] 0 1] eq {NSMCP RPC}} { return -options $options $result } ns_log error "nsmcp: tool execution failed: $name" return [list {} object {content array {0 object {type string text text string {Tool execution failed; consult the server log.}}} isError boolean true}] } # Both structured output and text for clients without structured support. return [list {} object [list structuredContent object [lindex $result 2] content array [list 0 object [list type string text text string [ns_json value -- $result]]] isError boolean false]] }XQL Not present: Generic, PostgreSQL, Oracle
![[i]](/resources/acs-subsite/ZoomIn16.gif)