@@ -263,3 +263,62 @@ func (tg *ToolsetGroup) GetToolset(name string) (*Toolset, error) {
263263 }
264264 return toolset , nil
265265}
266+
267+ type ToolDoesNotExistError struct {
268+ Name string
269+ }
270+
271+ func (e * ToolDoesNotExistError ) Error () string {
272+ return fmt .Sprintf ("tool %s does not exist" , e .Name )
273+ }
274+
275+ func NewToolDoesNotExistError (name string ) * ToolDoesNotExistError {
276+ return & ToolDoesNotExistError {Name : name }
277+ }
278+
279+ // FindToolByName searches all toolsets (enabled or disabled) for a tool by name.
280+ // Returns the tool, its parent toolset name, and an error if not found.
281+ func (tg * ToolsetGroup ) FindToolByName (toolName string ) (* server.ServerTool , string , error ) {
282+ for toolsetName , toolset := range tg .Toolsets {
283+ // Check read tools
284+ for _ , tool := range toolset .readTools {
285+ if tool .Tool .Name == toolName {
286+ return & tool , toolsetName , nil
287+ }
288+ }
289+ // Check write tools
290+ for _ , tool := range toolset .writeTools {
291+ if tool .Tool .Name == toolName {
292+ return & tool , toolsetName , nil
293+ }
294+ }
295+ }
296+ return nil , "" , NewToolDoesNotExistError (toolName )
297+ }
298+
299+ // RegisterSpecificTools registers only the specified tools, bypassing toolset enablement.
300+ // Respects read-only mode (skips write tools if readOnly=true).
301+ // Returns error if any tool is not found.
302+ func (tg * ToolsetGroup ) RegisterSpecificTools (s * server.MCPServer , toolNames []string , readOnly bool ) error {
303+ for _ , toolName := range toolNames {
304+ tool , toolsetName , err := tg .FindToolByName (toolName )
305+ if err != nil {
306+ return fmt .Errorf ("tool %s not found: %w" , toolName , err )
307+ }
308+
309+ // Check if it's a write tool and we're in read-only mode
310+ // ReadOnlyHint should always be set, but add defensive check
311+ if tool .Tool .Annotations .ReadOnlyHint != nil {
312+ isWriteTool := ! * tool .Tool .Annotations .ReadOnlyHint
313+ if isWriteTool && readOnly {
314+ // Skip write tools in read-only mode
315+ continue
316+ }
317+ }
318+
319+ // Register the tool
320+ s .AddTool (tool .Tool , tool .Handler )
321+ _ = toolsetName // toolsetName is available for potential future use (logging, etc.)
322+ }
323+ return nil
324+ }
0 commit comments