cmd: add --list-tools flag to display available MCP servers

Add a new --list-tools flag to the root ollama command that displays
all configured MCP servers with their descriptions, auto-enable modes,
path requirements, and capabilities.

Usage: ollama --list-tools

Also fixes test cases to include the tools flag definition.

Relates to #7865

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
code4me2 2025-12-15 10:43:14 -08:00
parent aacb25e1be
commit 738c253cb0
2 changed files with 66 additions and 0 deletions

View File

@ -829,6 +829,62 @@ func ListRunningHandler(cmd *cobra.Command, args []string) error {
return nil
}
func ListToolsHandler(cmd *cobra.Command, args []string) {
servers, err := server.ListMCPServers()
if err != nil {
fmt.Fprintf(os.Stderr, "Error loading MCP servers: %v\n", err)
return
}
if len(servers) == 0 {
fmt.Println("No MCP servers configured.")
fmt.Println("\nTo add MCP servers, create ~/.ollama/mcp-servers.json")
fmt.Println("See https://ollama.com/docs/mcp for configuration details.")
return
}
fmt.Println("Available MCP Servers:")
fmt.Println()
var data [][]string
for _, s := range servers {
autoEnable := string(s.AutoEnable)
if autoEnable == "" {
autoEnable = "never"
}
capabilities := "-"
if len(s.Capabilities) > 0 {
capabilities = strings.Join(s.Capabilities, ", ")
}
requiresPath := "no"
if s.RequiresPath {
requiresPath = "yes"
}
data = append(data, []string{s.Name, s.Description, autoEnable, requiresPath, capabilities})
}
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"NAME", "DESCRIPTION", "AUTO-ENABLE", "REQUIRES PATH", "CAPABILITIES"})
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
table.SetAlignment(tablewriter.ALIGN_LEFT)
table.SetHeaderLine(false)
table.SetBorder(false)
table.SetNoWhiteSpace(true)
table.SetTablePadding(" ")
table.AppendBulk(data)
table.Render()
fmt.Println()
fmt.Println("Auto-enable modes:")
fmt.Println(" never - Must be explicitly configured via API")
fmt.Println(" always - Enables whenever --tools is used")
fmt.Println(" with_path - Enables when --tools has a path argument")
fmt.Println(" if_match - Enables when conditions match (e.g., file exists)")
}
func DeleteHandler(cmd *cobra.Command, args []string) error {
client, err := api.ClientFromEnvironment()
if err != nil {
@ -2077,11 +2133,17 @@ func NewCLI() *cobra.Command {
return
}
if listTools, _ := cmd.Flags().GetBool("list-tools"); listTools {
ListToolsHandler(cmd, args)
return
}
cmd.Print(cmd.UsageString())
},
}
rootCmd.Flags().BoolP("version", "v", false, "Show version information")
rootCmd.Flags().Bool("list-tools", false, "List available MCP servers and their tools")
createCmd := &cobra.Command{
Use: "create MODEL",

View File

@ -425,6 +425,7 @@ func TestRunEmbeddingModel(t *testing.T) {
cmd.Flags().String("format", "", "")
cmd.Flags().String("think", "", "")
cmd.Flags().Bool("hidethinking", false, "")
cmd.Flags().String("tools", "", "")
oldStdout := os.Stdout
r, w, _ := os.Pipe()
@ -517,6 +518,7 @@ func TestRunEmbeddingModelWithFlags(t *testing.T) {
cmd.Flags().String("format", "", "")
cmd.Flags().String("think", "", "")
cmd.Flags().Bool("hidethinking", false, "")
cmd.Flags().String("tools", "", "")
if err := cmd.Flags().Set("truncate", "true"); err != nil {
t.Fatalf("failed to set truncate flag: %v", err)
@ -618,6 +620,7 @@ func TestRunEmbeddingModelPipedInput(t *testing.T) {
cmd.Flags().String("format", "", "")
cmd.Flags().String("think", "", "")
cmd.Flags().Bool("hidethinking", false, "")
cmd.Flags().String("tools", "", "")
// Capture stdin
oldStdin := os.Stdin
@ -693,6 +696,7 @@ func TestRunEmbeddingModelNoInput(t *testing.T) {
cmd.Flags().String("format", "", "")
cmd.Flags().String("think", "", "")
cmd.Flags().Bool("hidethinking", false, "")
cmd.Flags().String("tools", "", "")
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)