Skip to content

Agent graph omits tools from Toolsets (MCP, skills) and draws llmagent sub-agents without edges #1726

Description

@alexyslozada

🔴 Required Information

Describe the Bug:
The agent graph generator leaves out part of an llmagent tree:

  1. Tools from Toolsets are not drawn. buildGraph only reads the agent's Tools field, so tools that come from a tool.Toolset (for example an MCP toolset or a skills toolset) never appear in the graph:
    https://github.com/google/adk-go/blob/8c7ab1baf9bc/server/adkrest/internal/services/agentgraphgenerator.go#L292
  2. Sub-agents of an llmagent are drawn without an edge to their parent. buildGraph visits SubAgents() only to draw their nodes, so a coordinator and its sub-agents show up as unconnected nodes:
    https://github.com/google/adk-go/blob/8c7ab1baf9bc/server/adkrest/internal/services/agentgraphgenerator.go#L304-L309

adk-python handles both cases in agent_graph.py: it draws tools from await agent.canonical_tools(), which resolves toolsets, and it draws an edge from a non-workflow agent to each of its sub-agents (draw_edge(agent.name, sub_agent.name)).

Steps to Reproduce:

  1. Save the minimal reproduction code below as main.go in a new module (go mod init graphrepro && go get google.golang.org/adk/[email protected]). It uses a fake model that is never called, so no API key is needed.
  2. Run go run . web -port 8097 api -include_debug_api
  3. Request the graph: curl http://localhost:8097/api/dev/apps/root/build_graph_image
  4. Or open the web UI (go run . web -port 8097 api -include_debug_api webui) and look at the graph panel.

Expected Behavior:
The graph shows root connected to direct_tool, to toolset_tool (from the toolset) and to its sub-agent helper.

Observed Behavior:
Only direct_tool is connected. toolset_tool is missing and helper is a loose node:

digraph AgentGraph {
	bgcolor="#ffffff";
	rankdir=LR;
	root->direct_tool[ arrowhead=none, color="#3c4043" ];
	direct_tool [ color="#3c4043", fontcolor="#3c4043", label="🔧 direct_tool", shape=box, style=rounded ];
	helper [ color="#3c4043", fontcolor="#3c4043", label="🤖 helper", shape=ellipse, style=rounded ];
	root [ color="#3c4043", fontcolor="#3c4043", label="🤖 root", shape=ellipse, style=rounded ];

}

Environment Details:

  • ADK Library Version: v2.5.0 (the code is unchanged on main at 8c7ab1b)
  • OS: macOS
  • Go Version: go1.26.6 darwin/arm64

Model Information:

  • Which model is being used: N/A (the reproduction uses a fake model; originally found with Gemini agents using an MCP toolset and sub-agents)

🟡 Optional Information

Regression:
Unknown.

Minimal Reproduction Code:

package main

import (
	"context"
	"iter"
	"log"
	"os"

	"google.golang.org/adk/v2/agent"
	"google.golang.org/adk/v2/agent/llmagent"
	"google.golang.org/adk/v2/cmd/launcher"
	"google.golang.org/adk/v2/cmd/launcher/full"
	"google.golang.org/adk/v2/model"
	"google.golang.org/adk/v2/tool"
	"google.golang.org/adk/v2/tool/functiontool"
)

// fakeModel is never called: rendering the graph does not need a model.
type fakeModel struct{}

func (fakeModel) Name() string { return "fake" }
func (fakeModel) GenerateContent(context.Context, *model.LLMRequest, bool) iter.Seq2[*model.LLMResponse, error] {
	return func(func(*model.LLMResponse, error) bool) {}
}

type args struct{}

func newTool(name string) tool.Tool {
	t, err := functiontool.New(functiontool.Config{Name: name, Description: name},
		func(agent.Context, args) (string, error) { return "", nil })
	if err != nil {
		log.Fatal(err)
	}
	return t
}

// staticToolset stands in for an MCP toolset (mcptoolset) or a skills toolset.
type staticToolset struct{}

func (staticToolset) Name() string { return "my_toolset" }
func (staticToolset) Tools(agent.ReadonlyContext) ([]tool.Tool, error) {
	return []tool.Tool{newTool("toolset_tool")}, nil
}

func main() {
	helper, err := llmagent.New(llmagent.Config{Name: "helper", Description: "helper", Model: fakeModel{}})
	if err != nil {
		log.Fatal(err)
	}

	root, err := llmagent.New(llmagent.Config{
		Name:      "root",
		Model:     fakeModel{},
		Tools:     []tool.Tool{newTool("direct_tool")},
		Toolsets:  []tool.Toolset{staticToolset{}},
		SubAgents: []agent.Agent{helper},
	})
	if err != nil {
		log.Fatal(err)
	}

	cfg := &launcher.Config{AgentLoader: agent.NewSingleLoader(root)}
	if err := full.NewLauncher().Execute(context.Background(), cfg, os.Args[1:]); err != nil {
		log.Fatal(err)
	}
}

Additional Context:

How often has this issue occurred?:

  • Always (100%)

Activity

  1. karthik-0306 commented on Oct 5, 2026

    @karthik-0306
    Contributor

    I have checked and verified that this issue exists. I'll be working on a fix for this!

    My approach to solving this is:

    1. Pass down a context.Context to buildGraph so that we can wrap it in an icontext.NewReadonlyContext to call toolset.Tools(ctx) and draw the toolset tools.
    2. Add an explicit drawEdge for sub-agents recursively when the parent is not a workflow cluster.

    I will open a PR with these changes shortly.

  2. added 2 commits that reference this issue on Oct 8, 2026
    4cff038
    d0be297
  3. indurireddy-TF commented on Oct 9, 2026

    @indurireddy-TF
    Contributor

    Hi @alexyslozada Thank you for reporting this issue. We were able to reproduce both behaviors via the /api/dev/apps/{agent}/build_graph_image endpoint:

    1.Tools provided via Toolsets are omitted from the generated DOT graph.
    2.Sub-agents are declared as nodes without connecting edges from the parent coordinator agent.

    Image
  4. added 3 commits that reference this issue on Oct 9, 2026
    290c5dc
    47489ed
    c0ab228
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions