googleapis/mcp-toolbox · critical
tool type %q already registered
Error message
tool type %q already registered
What it means
This is a startup panic from postgresdatabaseoverview's init(): tools.Register (internal/tools/tools.go:43) returned false because a factory for the resourceType string ("postgres-database-overview") is already in the global toolRegistry map. The registry maps YAML config `type` strings to factory functions; a collision is treated as a programmer error and the binary panics during package initialization, before any server code runs.
Source
Thrown at internal/tools/postgres/postgresdatabaseoverview/postgresdatabaseoverview.go:48
const resourceType string = "postgres-database-overview"
const databaseOverviewStatement = `
SELECT
current_setting('server_version') AS pg_version,
pg_is_in_recovery() AS is_replica,
(now() - pg_postmaster_start_time())::TEXT AS uptime,
current_setting('max_connections')::int AS max_connections,
(SELECT count(*) FROM pg_stat_activity) AS current_connections,
(SELECT count(*) FROM pg_stat_activity WHERE state = 'active') AS active_connections,
round(
(100.0 * (SELECT count(*) FROM pg_stat_activity) / current_setting('max_connections')::int),
2
) AS pct_connections_used;
`
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 {
PostgresPool() *pgxpool.Pool
RunSQL(context.Context, string, []any) (any, error)
}
type Config struct {
tools.ConfigBase `yaml:",inline"`View on GitHub (pinned to 8cc6e09de2)
Solutions
- rg '"postgres-database-overview"' across internal/ and cmd/ to find the colliding registration; change one `resourceType` constant.
- If the copy is a legitimate new tool, give it its own kebab-case type (e.g. "postgres-database-overview-detailed") and matching package name.
- Delete the redundant copied package and import if it is leftover.
- Verify with `go build ./...` and the postgres tool unit tests.
Example fix
// before (duplicate copy) const resourceType string = "postgres-database-overview" // after const resourceType string = "postgres-database-overview-detailed"
Defensive patterns
Strategy: validation
Validate before calling
// Pre-build uniqueness check (script or test):
// rg -F '"postgres-database-overview"' internal/ cmd/ # expect exactly 1 match
// Go-side smoke test:
func TestToolboxInit(t *testing.T) {
// importing all tool packages + calling any code path that triggers init()
// must not panic with "already registered"
_ = tools.ErrUnknownToolType
} Type guard
func typeIsTaken(resourceType string) bool {
return !tools.Register(resourceType, func(ctx context.Context, name string, d *yaml.Decoder) (tools.ToolConfig, error) {
return nil, fmt.Errorf("probe")
})
} Prevention
- When creating a variant of a postgres tool, change `resourceType` first, then the SQL and package name.
- Keep the constant equal to the tool's kebab-case name and directory name.
- Add an init-touching smoke test to CI so duplicate registrations surface before release.
- Run `rg -F '"<type>"'` before importing any new/forked tool package.
- Delete dead copied packages promptly instead of leaving them importable.
When it happens
Trigger: Linking a binary that imports two packages whose init() both register the same postgres tool type string — almost always a copied postgresdatabaseoverview.go whose `resourceType` constant kept the original value, or two files declaring the same constant in one package.
Common situations: Cloning the file to add a tweaked overview tool and renaming only the package; a bad merge leaving duplicate directories; vendoring/forking the package and importing both versions into cmd/toolbox.
Related errors
- tool type %q already registered
- tool type %q already registered
- tool type %q already registered
- tool type %q already registered
- tool type %q already registered
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/263fd8ed31ebd2dd.
Report an issue: GitHub.