googleapis/mcp-toolbox · error · ErrUnknownToolType

unknown tool type

Error message

unknown tool type

What it means

ErrUnknownToolType is the sentinel error returned by DecodeConfig when the `tool` (resourceType) found in the config has no entry in the toolRegistry — i.e., no tool package registered that kind (registration happens via init() in each tool package). Callers like the server use errors.Is to detect it and may skip unknown tools when configured to.

Source

Thrown at internal/tools/tools.go:52

type ToolConfigFactory func(ctx context.Context, name string, decoder *yaml.Decoder) (ToolConfig, error)

var toolRegistry = make(map[string]ToolConfigFactory)

// Register allows individual tool packages to register their configuration
// factory function. This is typically called from an init() function in the
// tool's package. It associates a 'type' string with a function that can
// produce the specific ToolConfig type. It returns true if the registration was
// successful, and false if a tool with the same type was already registered.
func Register(resourceType string, factory ToolConfigFactory) bool {
	if _, exists := toolRegistry[resourceType]; exists {
		// Tool with this type already exists, do not overwrite.
		return false
	}
	toolRegistry[resourceType] = factory
	return true
}

var ErrUnknownToolType = fmt.Errorf("unknown tool type")

// DecodeConfig looks up the registered factory for the given type and uses it
// to decode the tool configuration.
func DecodeConfig(ctx context.Context, resourceType string, name string, decoder *yaml.Decoder) (ToolConfig, error) {
	factory, found := toolRegistry[resourceType]
	if !found {
		return nil, fmt.Errorf("%w: %q", ErrUnknownToolType, resourceType)
	}
	toolConfig, err := factory(ctx, name, decoder)
	if err != nil {
		return nil, fmt.Errorf("unable to parse tool %q as type %q: %w", name, resourceType, err)
	}
	return toolConfig, nil
}

type ToolConfig interface {
	ToolConfigType() string
	Initialize(context.Context) (Tool, error)

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Fix the tool's `kind:` in the YAML to a registered type exactly as documented (kebab-case).
  2. Upgrade the toolbox binary to a version that supports the tool kind.
  3. If building custom binaries, ensure the tool packages are imported (blank imports) so init() registers them.
  4. If intentional, enable ignore-unknown-tools so unknown tool kinds are skipped with a warning.

Example fix

# before
tools:
  q:
    kind: sqlite-execute-sqlx   # typo, unregistered
    source: my-sqlite
# after
tools:
  q:
    kind: sqlite-execute-sql
    source: my-sqlite
    description: "Run SQL."
Defensive patterns

Strategy: try-catch

Validate before calling

# check kind is recognized by your binary:
toolbox --tools-file tools.yaml --prebuilt my-config 2>&1 | grep -i 'unknown tool type'
# or verify against the docs list of supported tool kinds for your version

Type guard

var knownKinds = map[string]bool{"sqlite-execute-sql": true, "spanner-execute-sql": true /* ... */}
func kindRegistered(kind string) bool { return knownKinds[kind] }

Try / catch

toolCfg, err := tools.DecodeConfig(ctx, resourceType, name, dec)
if err != nil {
    if errors.Is(err, tools.ErrUnknownToolType) {
        log.Warnf("skipping unknown tool kind %q", resourceType)
        return nil // or fail fast, per your policy
    }
    return err
}

Prevention

When it happens

Trigger: YAML tool config with a `kind:` that is misspelled, unsupported, or from a newer toolbox version than the binary; building a custom binary without importing the package that registers the desired tool (blank import), so the registry lacks the type.

Common situations: Typo in kind (e.g. `sqlite-executesql` vs `sqlite-execute-sql`); using a prebuilt config from docs with an older toolbox binary; trimming tool imports in a custom build and losing registry entries.

Related errors


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