googleapis/mcp-toolbox · error

unable to retrieve source for tool %s

Error message

unable to retrieve source for tool %s

What it means

A tool was found, but runInvoke could not fetch its backing source from the PrimitiveManager by the tool's GetSourceName(). This indicates an inconsistent state: the tool references a source name that was not successfully initialized/registered. Tools without a source (srcName == "") skip this path entirely, so this only fires for source-backed tools whose source is missing.

Source

Thrown at cmd/internal/invoke/command.go:91

	}

	primitiveMgr := primitives.NewPrimitiveManager(sourcesMap, authServicesMap, embeddingModelsMap, toolsMap, promptsMap, groupsMap)

	// Execute Tool
	toolName := args[0]
	tool, ok := primitiveMgr.GetTool(toolName)
	if !ok {
		errMsg := fmt.Errorf("tool %q not found", toolName)
		opts.Logger.ErrorContext(ctx, errMsg.Error())
		return errMsg
	}

	srcName := tool.GetSourceName()
	var src sources.Source
	if srcName != "" {
		src, ok = primitiveMgr.GetSource(srcName)
		if !ok {
			errMsg := fmt.Errorf("unable to retrieve source for tool %s", toolName)
			opts.Logger.ErrorContext(ctx, errMsg.Error())
			return errMsg
		}
	}

	err = tool.ValidateSource(src)
	if err != nil {
		opts.Logger.ErrorContext(ctx, err.Error())
		return err
	}

	var paramsInput string
	if len(args) > 1 {
		paramsInput = args[1]
	}

	params := make(map[string]any)
	if paramsInput != "" {

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Inspect the tools file: confirm the source name referenced by the tool matches a defined source exactly (name/case-sensitive)
  2. Run `toolbox validate --tools-file tools.yaml` to catch dangling source references before invoking
  3. Re-add the missing source block or correct the tool's source reference
  4. If merging multiple configs, ensure the config providing the tool also provides (or shares) its source

Example fix

// before
sources:
  pg:
    kind: postgres
    ...  # tool references "mydb", source is named "pg"
tools:
  run-query:
    kind: postgres-sql
    source: mydb
// after
sources:
  mydb:
    kind: postgres
    ...
tools:
  run-query:
    kind: postgres-sql
    source: mydb
Defensive patterns

Strategy: validation

Validate before calling

cfg, _ := os.ReadFile(cfgPath)
for _, m := range toolSourceRefs.FindAllStringSubmatch(string(cfg), -1) {
    srcName := m[1]
    if !strings.Contains(string(cfg), "  "+srcName+":") {
        return fmt.Errorf("tool references source %q which is not defined", srcName)
    }
}

Try / catch

if err := runInvoke(ctx, opts); err != nil {
    if strings.Contains(err.Error(), "unable to retrieve source for tool") {
        log.Printf("tool's source is missing from the loaded config: %v", err)
        return ErrConfigIncomplete
    }
    return err
}

Prevention

When it happens

Trigger: runInvoke finds the tool, tool.GetSourceName() is non-empty, but primitiveMgr.GetSource(srcName) returns ok=false — e.g. the source failed to register while the tool still resolved, a renamed/deleted sourceKey in the tools file, or a custom config where the source block is missing but the tool references it.

Common situations: Hand-edited tools files where a tool's sourceService/sourceConfig name doesn't match any defined source, partial config load errors that still registered the tool, composed configs merging a tool from one file with sources from another.

Related errors


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