googleapis/mcp-toolbox · critical

tool type %q already registered

Error message

tool type %q already registered

What it means

This is a startup panic thrown by the tool package's init() when tools.Register (internal/tools/tools.go:43) detects that the shared toolRegistry map already holds a factory for the type string. Each tool package registers a unique `resourceType` constant at init time; registering "oracle-sql" twice means two factories claim the same YAML `type`, so the process panics rather than silently overwriting an existing registration. The failure happens before main() runs.

Source

Thrown at internal/tools/oracle/oraclesql/oraclesql.go:22

import (
	"context"
	"database/sql"
	"fmt"
	"net/http"

	yaml "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/util"
	"github.com/googleapis/mcp-toolbox/internal/util/parameters"
)

const resourceType string = "oracle-sql"

func init() {
	if !tools.Register(resourceType, newConfig) {
		panic(fmt.Sprintf("tool type %q already registered", resourceType))
	}
}

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
}

type compatibleSource interface {
	OracleDB() *sql.DB
	RunSQL(context.Context, string, []any, bool) (any, error)
}

type Config struct {
	tools.ConfigBase   `yaml:",inline"`

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Search the codebase for a second "oracle-sql" registration (rg '"oracle-sql"' internal/ cmd/) and make one `resourceType` constant unique.
  2. For an intentional variant, rename the `resourceType` constant (and package) to a distinct kebab-case tool type such as "oracle-sql-readonly".
  3. Remove the duplicate/forked package and its import if it is unintended dead code.
  4. Run `go build ./...` and `go test ./internal/tools/...` to verify startup succeeds.

Example fix

// before (forked package)
const resourceType string = "oracle-sql"
// after
const resourceType string = "oracle-sql-readonly"
Defensive patterns

Strategy: validation

Validate before calling

// In a CI check or pre-build script, assert the type string is registered exactly once:
//   go test -run TestUniqueToolTypes ./internal/tools/...
// or search the tree:
//   rg -F '"oracle-sql"' internal/ cmd/   # expect exactly one hit in internal/tools/oracle/oraclesql/oraclesql.go

Type guard

// Pre-registration guard usable before shipping a new tool package:
func isTypeStringUnique(sourceTree string, typ string) bool {
	// count literal occurrences of `"oracle-sql"` in *.go; return count <= 1
	return countLiteral(sourceTree, "\""+typ+"\"") <= 1
}

Prevention

When it happens

Trigger: Importing internal/tools/oracle/oraclesql (resourceType "oracle-sql") into a binary that also imports another package calling tools.Register with the same string — usually a duplicated/renamed copy of oraclesql.go whose `resourceType` constant was not changed, or a same-named constant declared in two files of one package.

Common situations: Copy-pasting oraclesql.go to create a variant Oracle tool and renaming only the directory; a merge that kept both an old and new copy of the package; accidentally importing the same tool package under an alias twice is safe, but importing a forked copy is not.

Related errors


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