googleapis/mcp-toolbox · error

unable to parse tool %q as type %q: %w

Error message

unable to parse tool %q as type %q: %w

What it means

After DecodeConfig finds the factory for the tool type, it invokes the factory to parse the tool's YAML block. If that factory returns an error, it is wrapped with this message naming the tool and the type. This means the tool's kind was valid but the tool-specific configuration could not be parsed or initialized.

Source

Thrown at internal/tools/tools.go:63

		// 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)
}

// https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations
type ToolAnnotations struct {
	DestructiveHint *bool `json:"destructiveHint,omitempty" yaml:"destructiveHint,omitempty"`
	IdempotentHint  *bool `json:"idempotentHint,omitempty" yaml:"idempotentHint,omitempty"`
	OpenWorldHint   *bool `json:"openWorldHint,omitempty" yaml:"openWorldHint,omitempty"`
	ReadOnlyHint    *bool `json:"readOnlyHint,omitempty" yaml:"readOnlyHint,omitempty"`
}

// NewReadOnlyAnnotations creates default annotations for a read-only tool.

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Read the wrapped cause at the end of the error chain for the underlying problem (e.g. "description is required for tool \"x\"")
  2. Fix the offending field in the named tool's YAML block
  3. Validate required fields for the tool type per its documentation
  4. Run the config through a YAML linter to catch structural issues

Example fix

// before (tools.yaml)
my-tool:
  kind: trino-execute-sql
  source: my-trino
// after
my-tool:
  kind: trino-execute-sql
  source: my-trino
  description: Runs a SQL query against Trino
Defensive patterns

Strategy: validation

Validate before calling

// Before parsing, check required fields for each tool block
for name, t := range toolsRaw {
    if t["description"] == "" {
        return fmt.Errorf("tool %q: description is required", name)
    }
}

Try / catch

toolConfig, err := tools.DecodeConfig(ctx, kind, name, dec)
if err != nil {
    var pe *fmt.WrapError // or inspect the chain
    log.Printf("tool %q (kind %q) rejected: %v", name, kind, err)
    return fmt.Errorf("config error in tool %q: %w", name, err)
}

Prevention

When it happens

Trigger: Any registered factory (e.g. trinoexecutesql's Config.Initialize reached through the YAML decoder) returns an error — bad fields, missing required values like description, invalid parameter definitions — while decoding a tool named <name> as type <resourceType>.

Common situations: Missing required fields (e.g. `description`), malformed parameter definitions, invalid YAML structure inside the tool block, source names that fail validation during Initialize.

Understand the failure class

Related errors


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