googleapis/mcp-toolbox · error

tool does not exist: %s

Error message

tool does not exist: %s

What it means

GenerateListToolsResult iterates the group's tool names and looks each up in the PrimitiveManager via pMgr.GetTool. If a name in g.ToolNames has no registered tool, it returns "tool does not exist: %s". This means the group references a tool that the manager never registered, so the tools/list manifest cannot be built.

Source

Thrown at internal/server/mcp/v20260728/manifests.go:122

		}
		if len(authParamList) > 0 {
			authParam[name] = authParamList
		}
	}
	return InputSchema{
		Type:       "object",
		Properties: properties,
		Required:   required,
	}, authParam
}

// GenerateListToolsResult generates tools/list method result according to mcp schema
func GenerateListToolsResult(pMgr *primitives.PrimitiveManager, g group.Group, urlParams map[string]string, supportsSecureParams bool) (ListToolsResult, error) {
	mcpManifest := make([]Tool, 0, len(g.ToolNames))
	for _, toolName := range g.ToolNames {
		tool, ok := pMgr.GetTool(toolName)
		if !ok {
			return ListToolsResult{}, fmt.Errorf("tool does not exist: %s", toolName)
		}
		srcName := tool.GetSourceName()
		var src sources.Source
		if srcName != "" {
			src, ok = pMgr.GetSource(srcName)
			if !ok {
				return ListToolsResult{}, fmt.Errorf("unable to retrieve %s source for tool %q", srcName, tool.GetName())
			}
		}
		params, err := tool.GetParameters(src)
		if err != nil {
			return ListToolsResult{}, fmt.Errorf("error getting parameters for tool %q: %w", toolName, err)
		}

		// Skip a Tool that requires secure params extension if the client doesn't support it.
		if tool.HasSecureParams() && !supportsSecureParams {
			continue
		}

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Check server startup logs for tool load/registration failures for the named tool.
  2. Ensure the tool is defined in the YAML and its `kind` is supported by this server version.
  3. Update the group's `tools:` list to match exact registered tool names.
  4. Restart the server after config edits so groups and registered tools stay consistent.

Example fix

// before (group references undefined tool)
group:
  tools:
    - execute_sql   # not defined
// after
group:
  tools:
    - execute_sql
tools:
  execute_sql:
    kind: postgres-execute-sql
    source: my-pg-instance
Defensive patterns

Strategy: validation

Validate before calling

// Config sanity check before serving (server side):
// every group tool name must have a tools: entry with a valid kind
for (const t of group.tools) {
  if (!(t in config.tools)) throw new Error(`group references undefined tool: ${t}`);
}

Try / catch

try {
  const {tools} = await client.request({method:'tools/list'});
} catch (e) {
  if (String(e.message).includes('tool does not exist')) {
    console.error('Server group references an unregistered tool; check server config:', e.message);
  } else throw e;
}

Prevention

When it happens

Trigger: A group's `tools:` list (or URL-selected group) contains a tool name that is absent from the server's registered tools — usually because the tool failed to load from the YAML config, was renamed, or the group config is out of sync.

Common situations: YAML config lists a tool under a group but the tool definition is missing or its kind is unrecognized, startup registration failed silently, config edited to rename a tool without updating the group, or using a prebuilt config where tool names changed across versions.

Related errors


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