googleapis/mcp-toolbox · critical

tool type %q already registered

Error message

tool type %q already registered

What it means

This is a fail-fast panic raised during package initialization. The neo4jschema package registers its factory under resourceType "neo4j-schema" in the global toolRegistry via tools.Register() (internal/tools/tools.go:43). Register() returns false when another init() already stored that type key, and init() deliberately panics (as its comment notes, this is the application's tool registry) because two factories for one `kind` would make YAML tool config decoding nondeterministic.

Source

Thrown at internal/tools/neo4j/neo4jschema/neo4jschema.go:41

	"github.com/goccy/go-yaml"
	"github.com/googleapis/mcp-toolbox/internal/sources"
	"github.com/googleapis/mcp-toolbox/internal/tools"
	"github.com/googleapis/mcp-toolbox/internal/tools/neo4j/neo4jschema/cache"
	"github.com/googleapis/mcp-toolbox/internal/tools/neo4j/neo4jschema/helpers"
	"github.com/googleapis/mcp-toolbox/internal/tools/neo4j/neo4jschema/types"
	"github.com/googleapis/mcp-toolbox/internal/util"
	"github.com/googleapis/mcp-toolbox/internal/util/parameters"
	"github.com/neo4j/neo4j-go-driver/v6/neo4j"
)

// type defines the unique identifier for this tool.
const resourceType string = "neo4j-schema"

// init registers the tool with the application's tool registry when the package is initialized.
func init() {
	if !tools.Register(resourceType, newConfig) {
		panic(fmt.Sprintf("tool type %q already registered", resourceType))
	}
}

// newConfig decodes a YAML configuration into a Config struct.
// This function is called by the tool registry to create a new configuration object.
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.ToolConfig, error) {
	actual := Config{ConfigBase: tools.ConfigBase{Name: name}}
	if err := decoder.DecodeContext(ctx, &actual); err != nil {
		return nil, err
	}
	return actual, nil
}

// compatibleSource defines the interface a data source must implement to be used by this tool.
// It ensures that the source can provide a Neo4j driver and database name.
type compatibleSource interface {
	Neo4jDriver() neo4j.Driver
	Neo4jDatabase() string

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. grep -rn '"neo4j-schema"' to find all registering packages; keep one and give the other a unique resourceType.
  2. Delete the obsolete duplicate package or remove its import from cmd/root.go.
  3. Deduplicate module versions (go mod tidy; review replace/vendor).
  4. Verify with `go build ./...` and `go test ./internal/tools/neo4j/neo4jschema/...`.

Example fix

// before
const resourceType string = "neo4j-schema" // duplicated

// after
const resourceType string = "neo4j-schema" // original only; new tool uses "neo4j-schema-deep"
Defensive patterns

Strategy: validation

Validate before calling

// Verify uniqueness before building:
// grep -rn '"neo4j-schema"' --include='*.go' . | grep 'resourceType\|tools.Register'
// Exactly one match expected. Soft guard for custom tools:
func init() {
	if !tools.Register(resourceType, newConfig) {
		fmt.Printf("WARNING: %s already registered; skipping duplicate init\n", resourceType)
		return
	}
}

Type guard

func isRegistered(resourceType string) bool {
	_, exists := registrySnapshot[resourceType]
	return exists
}

Try / catch

// Recover at the process boundary:
func main() {
	defer func() {
		if r := recover(); r != nil {
			if s, ok := r.(string); ok && strings.Contains(s, "already registered") {
				log.Fatalf("duplicate tool registration: %s", s)
			}
			panic(r)
		}
	}()
	rootCmd.Execute()
}

Prevention

When it happens

Trigger: Two packages register "neo4j-schema": a duplicated copy of neo4jschema still carrying the const, the package linked twice via different module paths, or a new schema-inspection tool reusing the built-in type string.

Common situations: Copying the schema tool as a template for a new introspection tool without renaming the type; a merge conflict resolution that kept both old and new package directories; vendoring duplicates of the module.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/e5e08d5e318c6e33. Report an issue: GitHub.