- Methods: All Methods Documented Methods Hide Methods
- Source: Display Source Hide Source
- Variables: Show Variables Hide Variables
Class ::nsmcp::ToolRegistry
::nsmcp::ToolRegistrycreate ... \
[ -providerContext (default "") ] \
[ -providers (default "") ] \
[ -stateStore (default "") ] \
[ -tools (default "") ]
Defined in /usr/local/ns/tcl/nsmcp/01-tools.tcl
Class Relations
::nx::Class create ::nsmcp::ToolRegistry \ -superclass ::nsmcp::ObjectMethods (to be applied on the object)
providerConfig (scripted, public)
nsmcp::ToolRegistryproviderConfig context parameter default
Read a provider setting from the configured sections. Try the primary and fallback sections in order, using the supplied default when neither supplies the parameter.
- Parameters:
- context (required)
- Provider configuration dictionary with primary and fallback section names.
- parameter (required)
- NaviServer configuration parameter name.
- default (required)
- Value used when the requested configuration entry is absent.
- Returns:
- The configured setting, or the default.
- Testcases:
- No testcase defined.
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 $defaultMethods (to be applied on instances)
call (scripted, public)
<instance of nsmcp::ToolRegistry> call context authorizer name \ arguments
Authorize, validate and invoke a registered tool. Check enable state, permissions and question pins before handing arguments to the tool.
- Parameters:
- context (required)
- Authenticated request context carrying the principal, grants and selected server.
- authorizer (required)
- Authorizer used to enforce the request context's permissions and targets.
- name (required)
- Name of the configured or registered item to resolve.
- arguments (required)
- Rooted ns_json typed triples for the tool's JSON argument object.
- Returns:
- The tool's rooted JSON result; policy and validation failures raise RPC errors.
- Testcases:
- No testcase defined.
: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" } :verifyQuestionPin $context $name $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]]controlsAvailable (scripted, public)
<instance of nsmcp::ToolRegistry> controlsAvailable
Report whether runtime tool enable controls are configured. The state store determines availability of administrative overrides.
- Returns:
- True when a runtime state store is present, otherwise false.
- Testcases:
- No testcase defined.
# An explicitly configured backend owns per-server runtime overrides. return [expr {${:stateStore} ne ""}]describe (scripted, public)
<instance of nsmcp::ToolRegistry> describe
List administrative metadata for registered tools. Include permission and enable-state information without executing tools or applying a caller's permission filter.
- Returns:
- A list of tool metadata dictionaries.
- Testcases:
- No testcase defined.
: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 $resultenabled (scripted, public)
<instance of nsmcp::ToolRegistry> enabled name
Report whether a named tool is administratively enabled. Refresh provider registrations first; caller permissions are checked separately during listing and invocation.
- Parameters:
- name (required)
- Registered MCP tool name.
- Returns:
- The effective enabled flag, or false for an unknown tool.
- Testcases:
- No testcase defined.
:refreshProviders # Administrative availability, independent of caller permissions. if {![dict exists ${:tools} $name]} { error "unknown tool: $name" } return [:readEnabled $name]fingerprint (scripted, public)
<instance of nsmcp::ToolRegistry> fingerprint name
Hash a registered tool's permission and descriptor. Question conversations use this bounded descriptor fingerprint to detect a changed tool definition.
- Parameters:
- name (required)
- Registered MCP tool name whose descriptor is pinned.
- Returns:
- The hexadecimal SHA-256 fingerprint; unknown tools raise an error.
- Testcases:
- No testcase defined.
:refreshProviders if {![dict exists ${:tools} $name]} { error "Unknown question tool" } set tool [dict get ${:tools} $name] set data [list [$tool permission] [ns_json value -- [$tool describe]]] if {[string bytelength $data]>1048576} { error "Question tool descriptor exceeds limit" } return [ns_crypto::md string -digest sha256 -- $data]list (scripted, public)
<instance of nsmcp::ToolRegistry> list context authorizer
List the tools available to an authenticated caller. Refresh providers and apply administrative enable flags and the supplied authorizer.
- Parameters:
- context (required)
- Authenticated request context carrying the principal, grants and selected server.
- authorizer (required)
- Authorizer used to enforce the request context's permissions and targets.
- Returns:
- A rooted JSON object containing the tools array.
- Testcases:
- No testcase defined.
:refreshProviders set result {} foreach name [lsort [dict keys ${:tools}]] { set tool [dict get ${:tools} $name] if {[:readEnabled $name] && [$authorizer allowed $context [$tool permission]]} { if {[$context cget -questionRestricted]} { if {![dict exists [$context cget -questionPins] $name]} { continue } :verifyQuestionPin $context $name } 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]]questionSnapshot (scripted, public)
<instance of nsmcp::ToolRegistry> questionSnapshot context \ authorizer
Pin the permitted tool inventory for a new question. Apply request authorization and question allowlists; outbound upstream comparison additionally requires its configured provider and switches.
- Parameters:
- context (required)
- Authenticated request context carrying the principal, grants and selected server.
- authorizer (required)
- Authorizer used to enforce the request context's permissions and targets.
- Returns:
- A dictionary mapping allowed tool names to descriptor fingerprints.
- Testcases:
- No testcase defined.
set pins {} set listed [:list $context $authorizer] foreach {index type members} [ns_json triples getvalue -output triples -path tools -- $listed] { set metadata [ns_json parse [ns_json value -- [list {} object $members]]] if {![dict exists $metadata annotations readOnlyHint] || ![dict get $metadata annotations readOnlyHint]} { continue } set name [dict get $metadata name] if {$name ni [::nsmcp::questionAllowedTools]} { continue } if {![dict exists $metadata annotations destructiveHint] || [dict get $metadata annotations destructiveHint] || ![dict exists $metadata annotations openWorldHint]} { continue } if {[dict get $metadata annotations openWorldHint]} { # This one outbound tool has a fixed GitHub transport and # administrator-owned repository mappings. All other external # tools remain excluded from question execution. if {$name ne "code_upstream_compare" || ![nsf::is object,type=::nsmcp::CodeUpstreamTool [dict get ${:tools} $name]] || ![ns_config -bool ns/server/[ns_info server]/module/nsmcp enableCodeTools false] || ![ns_config -bool ns/server/[ns_info server]/module/nsmcp enableCodeUpstream false]} { continue } } if {[dict size $pins]>=256 || [string bytelength $name]>128} { error "Question tool inventory exceeds limit" } dict set pins $name [:fingerprint $name] } if {$pins eq {}} { error "No permitted read-only question tools are available" } return $pinsrefreshProviders (scripted, public)
<instance of nsmcp::ToolRegistry> refreshProviders
Refresh registrations supplied by configured tool providers. Reconcile provider descriptors with registry state; this is registration work, not a tool invocation.
- Returns:
- The provider dictionary when a provider context is configured, otherwise an empty result.
- Testcases:
- No testcase defined.
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}register (scripted, public)
<instance of nsmcp::ToolRegistry> register tool
Register a tool object under its configured name. Reject duplicate names so dispatch cannot silently replace an existing registration.
- Parameters:
- tool (required)
- Tool object to register.
- Returns:
- The updated internal registration dictionary.
- Testcases:
- No testcase defined.
set name [$tool name] if {[dict exists ${:tools} $name]} { error "duplicate tool: $name" } dict set :tools $name $toolsetEnabled (scripted, public)
<instance of nsmcp::ToolRegistry> setEnabled name enabled
Change the administrative enable flag for a registered tool. This trusted interface affects new calls, not jobs already running or background collectors.
- Parameters:
- name (required)
- Registered MCP tool name.
- enabled (required, boolean)
- Boolean administrative enable flag.
- Returns:
- The enabled flag written to the state store.
- Testcases:
- No testcase defined.
# 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
- Methods: All Methods Documented Methods Hide Methods
- Source: Display Source Hide Source
- Variables: Show Variables Hide Variables
![[i]](/resources/acs-subsite/ZoomIn16.gif)