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 postgreslistactivequeries' init(): tools.Register (internal/tools/tools.go:43) returned false, meaning another package already registered a factory under the same resourceType string ("postgres-list-active-queries") in the shared toolRegistry map. Since tool YAML configs resolve by `type` string, a duplicate would be ambiguous, so the binary panics during init before serving.
Source
Thrown at internal/tools/postgres/postgreslistactivequeries/postgreslistactivequeries.go:58
wait_event_type,
wait_event,
backend_start,
xact_start,
query_start,
now() - query_start AS query_duration,
query
FROM pg_stat_activity
WHERE state = 'active'
AND backend_type = 'client backend'
AND ($1::INTERVAL IS NULL OR now() - query_start >= $1::INTERVAL)
AND ($2::text IS NULL OR application_name NOT IN (SELECT trim(app) FROM unnest(string_to_array($2, ',')) AS app))
ORDER BY query_duration DESC
LIMIT COALESCE($3::int, 50);
`
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
- Locate the second registration via rg '"postgres-list-active-queries"' internal/ cmd/ and make one `resourceType` unique.
- For an intentional variant, rename the constant (and package) to a new kebab-case type such as "postgres-list-active-queries-extended".
- Remove the duplicate package/import if it is dead code.
- Verify startup with `go build ./...` and unit tests.
Example fix
// before (copied variant) const resourceType string = "postgres-list-active-queries" // after const resourceType string = "postgres-list-active-queries-extended"
Defensive patterns
Strategy: validation
Validate before calling
// Uniqueness check before build/CI:
// rg -F '"postgres-list-active-queries"' internal/ cmd/ # expect exactly 1 hit
// Smoke test linking all tool packages:
func TestToolRegistryInit(t *testing.T) {
// panics on duplicate registration; must pass
} Type guard
func typeStringAppearsOnce(root, resourceType string) bool {
return countLiterals(root, "\""+resourceType+"\"") == 1
} Prevention
- Rename `resourceType` in the same commit when copying a tool into a new package.
- Keep `resourceType` identical to the tool's kebab-case name and folder name.
- Add an init-touching smoke test to CI to catch duplicate registrations early.
- Grep the type string before importing any new tool package.
- Prune dead/forked copies of tools from the module.
When it happens
Trigger: Importing a second package whose init() registers "postgres-list-active-queries" — typically a copy-pasted postgreslistactivequeries.go with an unchanged `resourceType` constant — or two files in the build declaring the same constant.
Common situations: Cloning the tool to add filters or a different LIMIT default while renaming only the package; a merge resolution that kept duplicate directories; importing a forked/vendored variant alongside the original in a custom toolbox build.
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/df9dbbfaa49b9aa9.
Report an issue: GitHub.