aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2026-03-10 16:09:13 +0100
committerDmitry Vyukov <dvyukov@google.com>2026-03-10 15:36:44 +0000
commitb19feb243f1f2bdb7f04e5c6f3b693ee8cd2a8b7 (patch)
tree44c8b4434fffffde7b2a55f21a371b4f0a390ad3 /pkg
parent9eee85817edcc7ad7e20ffadf0e43e1ba748cb35 (diff)
pkg/aflow: ensure we don't register MCP tools with duplicate names
If we have duplicate names, then only one of the duplicates will be used at random. Add a check that we don't have duplicate names. Currently it's only "crash-reproducer" (both action and a tool). Also ignore "set-results" tool, and all tools created in tests.
Diffstat (limited to 'pkg')
-rw-r--r--pkg/aflow/flow/flows_test.go14
-rw-r--r--pkg/aflow/flow_test.go5
-rw-r--r--pkg/aflow/llm_agent.go4
-rw-r--r--pkg/aflow/mcp.go19
-rw-r--r--pkg/aflow/tool/syzlang/reproduce.go2
5 files changed, 40 insertions, 4 deletions
diff --git a/pkg/aflow/flow/flows_test.go b/pkg/aflow/flow/flows_test.go
index 3c01596b5..a66479d14 100644
--- a/pkg/aflow/flow/flows_test.go
+++ b/pkg/aflow/flow/flows_test.go
@@ -3,4 +3,16 @@
package flow
-// An empty test that runs registration and verification of all registered workflows via init functions.
+import (
+ "testing"
+
+ "github.com/google/syzkaller/pkg/aflow"
+)
+
+// Note: this test also runs registration and verification of all registered workflows via init functions.
+
+func TestMCPTools(t *testing.T) {
+ for tool := range aflow.MCPTools {
+ t.Log(tool.Name)
+ }
+}
diff --git a/pkg/aflow/flow_test.go b/pkg/aflow/flow_test.go
index 734781c41..94758c549 100644
--- a/pkg/aflow/flow_test.go
+++ b/pkg/aflow/flow_test.go
@@ -15,6 +15,11 @@ import (
"google.golang.org/genai"
)
+func init() {
+ // Tests register tools with duplicate names.
+ registerMCPTools = false
+}
+
func TestWorkflow(t *testing.T) {
type flowInputs struct {
InFoo int
diff --git a/pkg/aflow/llm_agent.go b/pkg/aflow/llm_agent.go
index 378f044a5..3529fa5b1 100644
--- a/pkg/aflow/llm_agent.go
+++ b/pkg/aflow/llm_agent.go
@@ -108,7 +108,7 @@ func Tools(tools ...any) []Tool {
// LLMOutputs creates a special tool that can be used by LLM to provide structured outputs.
func LLMOutputs[Args any]() *llmOutputs {
return &llmOutputs{
- tool: NewFuncTool("set-results", func(ctx *Context, state struct{}, args Args) (Args, error) {
+ tool: NewFuncTool(llmSetResultsTool, func(ctx *Context, state struct{}, args Args) (Args, error) {
return args, nil
}, "Use this tool to provide results of the analysis."),
provideOutputs: func(ctx *verifyContext, who string, many bool) {
@@ -129,6 +129,8 @@ func LLMOutputs[Args any]() *llmOutputs {
}
}
+const llmSetResultsTool = "set-results"
+
const llmOutputsInstruction = `
Use set-results tool to provide results of the analysis.
diff --git a/pkg/aflow/mcp.go b/pkg/aflow/mcp.go
index f94376113..5e0944e08 100644
--- a/pkg/aflow/mcp.go
+++ b/pkg/aflow/mcp.go
@@ -6,6 +6,7 @@ package aflow
import (
"context"
"errors"
+ "fmt"
"time"
"github.com/google/syzkaller/pkg/aflow/trajectory"
@@ -51,7 +52,7 @@ func registerMCPTool[State, Args, Results any](t *funcTool[State, Args, Results]
}
return reply, nil
}
- MCPTools[tool] = handler
+ registerMCP(tool, handler)
}
func registerMCPAction[Args, Results any](a *funcAction[Args, Results]) {
@@ -68,5 +69,21 @@ func registerMCPAction[Args, Results any](a *funcAction[Args, Results]) {
}
return reply, err
}
+ registerMCP(tool, handler)
+}
+
+var (
+ registerMCPTools = true
+ mcpToolNames = map[string]bool{}
+)
+
+func registerMCP(tool *mcp.Tool, handler MCPToolFunc) {
+ if !registerMCPTools || tool.Name == llmSetResultsTool {
+ return
+ }
+ if mcpToolNames[tool.Name] {
+ panic(fmt.Sprintf("MCP tool %q is already registered", tool.Name))
+ }
+ mcpToolNames[tool.Name] = true
MCPTools[tool] = handler
}
diff --git a/pkg/aflow/tool/syzlang/reproduce.go b/pkg/aflow/tool/syzlang/reproduce.go
index 3faa11563..2c22bddd9 100644
--- a/pkg/aflow/tool/syzlang/reproduce.go
+++ b/pkg/aflow/tool/syzlang/reproduce.go
@@ -9,7 +9,7 @@ import (
_ "github.com/google/syzkaller/sys"
)
-var Reproduce = aflow.NewFuncTool("crash-reproducer", reproduce, `
+var Reproduce = aflow.NewFuncTool("reproduce-crash", reproduce, `
Tool evaluates whether the given syz repro program crashes the kernel.
It will compile the program and execute it in a VM.
`)