github/github-mcp-server · error
failed to unmarshal tools: %w
Error message
failed to unmarshal tools: %w
What it means
Returned by runListScopes when viper.UnmarshalKey("tools", &enabledTools) fails — the configured 'tools' value cannot be decoded into []string. Like the toolsets key, it only runs when viper.IsSet("tools") is true. Because tool names are later fed to inventory WithTools, a successful decode with wrong names will subsequently surface as ErrUnknownTools at Build(); this error is specifically a decode/type failure.
Source
Thrown at cmd/github-mcp-server/list_scopes.go:100
}
return scope
}
func runListScopes() error {
// Get toolsets configuration (same logic as stdio command)
var enabledToolsets []string
if viper.IsSet("toolsets") {
if err := viper.UnmarshalKey("toolsets", &enabledToolsets); err != nil {
return fmt.Errorf("failed to unmarshal toolsets: %w", err)
}
}
// else: enabledToolsets stays nil, meaning "use defaults"
// Get specific tools (similar to toolsets)
var enabledTools []string
if viper.IsSet("tools") {
if err := viper.UnmarshalKey("tools", &enabledTools); err != nil {
return fmt.Errorf("failed to unmarshal tools: %w", err)
}
}
readOnly := viper.GetBool("read-only")
outputFormat := viper.GetString("list-scopes-output")
// Create translation helper
t, _ := translations.TranslationHelper()
// Build inventory using the same logic as the stdio server
inventoryBuilder := github.NewInventory(t).
WithReadOnly(readOnly)
// Configure toolsets (same as stdio)
if enabledToolsets != nil {
inventoryBuilder = inventoryBuilder.WithToolsets(enabledToolsets)
}
View on GitHub (pinned to 0ea1f775a7)
Solutions
- Write tools as a string list in the config: tools: ["issue", "issue_comment"]
- Drop the key to use defaults, or list toolsets instead if you meant whole toolsets
- Lint the config file for syntax and shape before running list-scopes
- Confirm tool names against current docs so the value survives the later WithTools validation
Example fix
# before (config.yml)
tools:
- name: issue
enabled: true
# after
tools: ["issue", "issue_comment"] Defensive patterns
Strategy: validation
Validate before calling
// Ensure the 'tools' config value is a plain string list before decoding
raw := viper.Get("tools")
if raw != nil {
arr, ok := raw.([]any)
if !ok {
log.Fatalf("'tools' must be a list of tool names, got %T", raw)
}
for _, e := range arr {
if _, ok := e.(string); !ok {
log.Fatalf("'tools' entries must be strings, got %T", e)
}
}
} Try / catch
var enabledTools []string
if viper.IsSet("tools") {
if err := viper.UnmarshalKey("tools", &enabledTools); err != nil {
log.Fatalf("invalid 'tools' config (must be a list of strings): %v", err)
}
} Prevention
- Write tools as an array of quoted names in config files
- Use toolset names under 'toolsets', not 'tools'
- After decoding, validate names against current docs to avoid the later ErrUnknownTools failure
When it happens
Trigger: Config sets tools to a non-list shape (map, number, nested object); an env/flag value that cannot be split/converted into a []string; malformed config syntax under the 'tools' key.
Common situations: Editing the config and writing 'tools: create_issue' (bare scalar in strict contexts) or a key/value block instead of a list; JSON configs using an object instead of an array; stale configs from older versions with a different schema.
Related errors
- failed to unmarshal toolsets: %w
- failed to build inventory: %w
- private key is %T, want an RSA key
- building installation token URL: %w
- creating installation token request: %w
AI-assisted analysis of github/github-mcp-server@0ea1f775a7 (2026-08-15).
Data as JSON: /api/errors/f2baee4d44efd0b0.
Report an issue: GitHub.