fix(tools): exempt MCP discovery tools from agent allowlists
This commit is contained in:
parent
b8f4257cee
commit
871892ff15
3 changed files with 39 additions and 2 deletions
|
|
@ -172,6 +172,13 @@ func (r *ToolRegistry) toolAllowedLocked(name string) bool {
|
||||||
if r.allowlist == nil {
|
if r.allowlist == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if isToolDiscoveryToolName(name) {
|
||||||
|
// Discovery tools are part of the MCP control plane: they must remain
|
||||||
|
// available whenever configured so deferred MCP tools can still be
|
||||||
|
// unlocked. Per-agent allowlists still apply to the hidden MCP tools
|
||||||
|
// themselves during RegisterHidden.
|
||||||
|
return true
|
||||||
|
}
|
||||||
_, ok := r.allowlist[strings.ToLower(strings.TrimSpace(name))]
|
_, ok := r.allowlist[strings.ToLower(strings.TrimSpace(name))]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,25 @@ func TestToolRegistry_AllowlistFiltersRegistrations(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestToolRegistry_AllowlistStillAllowsDiscoveryTools(t *testing.T) {
|
||||||
|
r := NewToolRegistry()
|
||||||
|
r.SetAllowlist([]string{"mcp_github_search"})
|
||||||
|
|
||||||
|
r.Register(newMockTool(BM25SearchToolName, "discover hidden tools"))
|
||||||
|
r.Register(newMockTool(RegexSearchToolName, "discover hidden tools via regex"))
|
||||||
|
r.Register(newMockTool("blocked_tool", "blocked"))
|
||||||
|
|
||||||
|
if _, ok := r.Get(BM25SearchToolName); !ok {
|
||||||
|
t.Fatal("expected BM25 discovery tool to bypass allowlist filtering")
|
||||||
|
}
|
||||||
|
if _, ok := r.Get(RegexSearchToolName); !ok {
|
||||||
|
t.Fatal("expected regex discovery tool to bypass allowlist filtering")
|
||||||
|
}
|
||||||
|
if _, ok := r.Get("blocked_tool"); ok {
|
||||||
|
t.Fatal("blocked_tool should not be registered")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestToolRegistry_HasRegisteredIncludesHiddenTools(t *testing.T) {
|
func TestToolRegistry_HasRegisteredIncludesHiddenTools(t *testing.T) {
|
||||||
r := NewToolRegistry()
|
r := NewToolRegistry()
|
||||||
r.SetAllowlist([]string{"visible", "hidden"})
|
r.SetAllowlist([]string{"visible", "hidden"})
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MaxRegexPatternLength = 200
|
MaxRegexPatternLength = 200
|
||||||
|
RegexSearchToolName = "tool_search_tool_regex"
|
||||||
|
BM25SearchToolName = "tool_search_tool_bm25"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RegexSearchTool struct {
|
type RegexSearchTool struct {
|
||||||
|
|
@ -27,7 +29,7 @@ func NewRegexSearchTool(r *ToolRegistry, ttl int, maxSearchResults int) *RegexSe
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *RegexSearchTool) Name() string {
|
func (t *RegexSearchTool) Name() string {
|
||||||
return "tool_search_tool_regex"
|
return RegexSearchToolName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *RegexSearchTool) Description() string {
|
func (t *RegexSearchTool) Description() string {
|
||||||
|
|
@ -96,7 +98,7 @@ func NewBM25SearchTool(r *ToolRegistry, ttl int, maxSearchResults int) *BM25Sear
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *BM25SearchTool) Name() string {
|
func (t *BM25SearchTool) Name() string {
|
||||||
return "tool_search_tool_bm25"
|
return BM25SearchToolName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *BM25SearchTool) Description() string {
|
func (t *BM25SearchTool) Description() string {
|
||||||
|
|
@ -294,6 +296,15 @@ func (t *BM25SearchTool) getOrBuildEngine() *bm25CachedEngine {
|
||||||
return cached
|
return cached
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isToolDiscoveryToolName(name string) bool {
|
||||||
|
switch strings.ToLower(strings.TrimSpace(name)) {
|
||||||
|
case BM25SearchToolName, RegexSearchToolName:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SearchBM25 ranks hidden tools against query using BM25 via utils.BM25Engine.
|
// SearchBM25 ranks hidden tools against query using BM25 via utils.BM25Engine.
|
||||||
// This non-cached variant rebuilds the engine on every call. Used by tests
|
// This non-cached variant rebuilds the engine on every call. Used by tests
|
||||||
// and any code that doesn't hold a BM25SearchTool instance.
|
// and any code that doesn't hold a BM25SearchTool instance.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue