Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 8 additions & 39 deletions pkg/cli/mcp_inspect_mcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,49 +325,18 @@ func displayServerCapabilities(info *parser.MCPServerInfo, toolFilter string) {
} else {
fmt.Printf("\n%s\n", headerStyle.Render("πŸ› οΈ Tool Access Status"))

// Create a map for quick lookup of allowed tools
allowedMap := make(map[string]bool)
for _, allowed := range info.Config.Allowed {
allowedMap[allowed] = true
// Configure options for inspect command
// Use a slightly shorter truncation length than list-tools for better fit
opts := MCPToolTableOptions{
TruncateLength: 50,
ShowSummary: true,
ShowVerboseHint: false,
}

headers := []string{"Tool Name", "Allow", "Description"}
rows := make([][]string, 0, len(info.Tools))

for _, tool := range info.Tools {
description := tool.Description
if len(description) > 50 {
description = description[:47] + "..."
}

// Determine status
status := "🚫"
if len(info.Config.Allowed) == 0 {
// If no allowed list is specified, assume all tools are allowed
status = "βœ…"
} else if allowedMap[tool.Name] {
status = "βœ…"
}

rows = append(rows, []string{tool.Name, status, description})
}

table := console.RenderTable(console.TableConfig{
Headers: headers,
Rows: rows,
})
// Render the table using the shared helper
table := renderMCPToolTable(info, opts)
fmt.Print(table)

// Display summary
allowedCount := 0
for _, tool := range info.Tools {
if len(info.Config.Allowed) == 0 || allowedMap[tool.Name] {
allowedCount++
}
}
fmt.Printf("\nπŸ“Š Summary: %d allowed, %d not allowed out of %d total tools\n",
allowedCount, len(info.Tools)-allowedCount, len(info.Tools))

// Add helpful hint about how to allow tools in workflow frontmatter
displayToolAllowanceHint(info)
}
Expand Down
89 changes: 13 additions & 76 deletions pkg/cli/mcp_list_tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ var mcpListToolsLog = logger.New("cli:mcp_list_tools")
const (
// maxDescriptionLength is the maximum length for tool descriptions before truncation
maxDescriptionLength = 60
// truncationLength is the length at which to truncate descriptions (leaving room for "...")
truncationLength = 57
)

// ListToolsForMCP lists available tools for a specific MCP server
Expand Down Expand Up @@ -144,85 +142,24 @@ func displayToolsList(info *parser.MCPServerInfo, verbose bool) {

fmt.Printf("\n%s\n", console.FormatInfoMessage(fmt.Sprintf("πŸ› οΈ Available Tools (%d total)", len(info.Tools))))

// Create a map for quick lookup of allowed tools from workflow configuration
allowedMap := make(map[string]bool)

// Check for wildcard "*" which means all tools are allowed
hasWildcard := false
for _, allowed := range info.Config.Allowed {
if allowed == "*" {
hasWildcard = true
}
allowedMap[allowed] = true
// Configure options based on verbose flag
opts := MCPToolTableOptions{
ShowSummary: true,
}

if verbose {
// Detailed table with full descriptions
headers := []string{"Tool Name", "Allow", "Description"}
rows := make([][]string, 0, len(info.Tools))

for _, tool := range info.Tools {
// In verbose mode, show full descriptions without truncation
description := tool.Description

// Determine status
status := "🚫"
if len(info.Config.Allowed) == 0 || hasWildcard {
// If no allowed list is specified or "*" wildcard is present, assume all tools are allowed
status = "βœ…"
} else if allowedMap[tool.Name] {
status = "βœ…"
}

rows = append(rows, []string{tool.Name, status, description})
}

table := console.RenderTable(console.TableConfig{
Headers: headers,
Rows: rows,
})
fmt.Print(table)

// Display summary
allowedCount := 0
for _, tool := range info.Tools {
if len(info.Config.Allowed) == 0 || hasWildcard || allowedMap[tool.Name] {
allowedCount++
}
}
fmt.Printf("\nπŸ“Š Summary: %d allowed, %d not allowed out of %d total tools\n",
allowedCount, len(info.Tools)-allowedCount, len(info.Tools))
// In verbose mode, show full descriptions without truncation
opts.TruncateLength = 0
opts.ShowVerboseHint = false
} else {
// Compact table with truncated descriptions for single-line display
headers := []string{"Tool Name", "Allow", "Description"}
rows := make([][]string, 0, len(info.Tools))

for _, tool := range info.Tools {
// In non-verbose mode, truncate descriptions to keep tools on single lines
description := tool.Description
if len(description) > maxDescriptionLength {
description = description[:truncationLength] + "..."
}

// Determine status
status := "🚫"
if len(info.Config.Allowed) == 0 || hasWildcard {
// If no allowed list is specified or "*" wildcard is present, assume all tools are allowed
status = "βœ…"
} else if allowedMap[tool.Name] {
status = "βœ…"
}

rows = append(rows, []string{tool.Name, status, description})
}

table := console.RenderTable(console.TableConfig{
Headers: headers,
Rows: rows,
})
fmt.Print(table)
fmt.Printf("\nRun with --verbose for detailed information\n")
// In non-verbose mode, truncate descriptions to keep tools on single lines
opts.TruncateLength = maxDescriptionLength
opts.ShowVerboseHint = true
}

// Render the table using the shared helper
table := renderMCPToolTable(info, opts)
fmt.Print(table)
}

// NewMCPListToolsSubcommand creates the mcp list-tools subcommand
Expand Down
112 changes: 112 additions & 0 deletions pkg/cli/mcp_tool_table.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package cli

import (
"fmt"

"github.com/githubnext/gh-aw/pkg/console"
"github.com/githubnext/gh-aw/pkg/parser"
)

// MCPToolTableOptions configures how the MCP tool table is rendered
type MCPToolTableOptions struct {
// TruncateLength is the maximum length for tool descriptions before truncation
// A value of 0 means no truncation
TruncateLength int
// ShowSummary controls whether to display the summary line at the bottom
ShowSummary bool
// SummaryFormat is the format string for the summary (default: "πŸ“Š Summary: %d allowed, %d not allowed out of %d total tools\n")
SummaryFormat string
// ShowVerboseHint controls whether to show the "Run with --verbose" hint in non-verbose mode
ShowVerboseHint bool
}

// DefaultMCPToolTableOptions returns the default options for rendering MCP tool tables
func DefaultMCPToolTableOptions() MCPToolTableOptions {
return MCPToolTableOptions{
TruncateLength: 60,
ShowSummary: true,
SummaryFormat: "\nπŸ“Š Summary: %d allowed, %d not allowed out of %d total tools\n",
ShowVerboseHint: false,
}
}

// renderMCPToolTable renders an MCP tool table with configurable options
// This is the shared rendering logic used by both mcp list-tools and mcp inspect commands
func renderMCPToolTable(info *parser.MCPServerInfo, opts MCPToolTableOptions) string {
if len(info.Tools) == 0 {
return ""
}

// Create a map for quick lookup of allowed tools from workflow configuration
allowedMap := make(map[string]bool)

// Check for wildcard "*" which means all tools are allowed
hasWildcard := false
for _, allowed := range info.Config.Allowed {
if allowed == "*" {
hasWildcard = true
}
allowedMap[allowed] = true
}

// Build table headers and rows
headers := []string{"Tool Name", "Allow", "Description"}
rows := make([][]string, 0, len(info.Tools))

for _, tool := range info.Tools {
description := tool.Description

// Apply truncation if requested
if opts.TruncateLength > 0 && len(description) > opts.TruncateLength {
// Leave room for "..."
truncateAt := opts.TruncateLength - 3
if truncateAt > 0 {
description = description[:truncateAt] + "..."
}
}

// Determine status
status := "🚫"
if len(info.Config.Allowed) == 0 || hasWildcard {
// If no allowed list is specified or "*" wildcard is present, assume all tools are allowed
status = "βœ…"
} else if allowedMap[tool.Name] {
status = "βœ…"
}

rows = append(rows, []string{tool.Name, status, description})
}

// Render the table
table := console.RenderTable(console.TableConfig{
Headers: headers,
Rows: rows,
})

result := table

// Add summary if requested
if opts.ShowSummary {
allowedCount := 0
for _, tool := range info.Tools {
if len(info.Config.Allowed) == 0 || hasWildcard || allowedMap[tool.Name] {
allowedCount++
}
}

summaryFormat := opts.SummaryFormat
if summaryFormat == "" {
summaryFormat = "\nπŸ“Š Summary: %d allowed, %d not allowed out of %d total tools\n"
}

result += fmt.Sprintf(summaryFormat,
allowedCount, len(info.Tools)-allowedCount, len(info.Tools))
}

// Add verbose hint if requested
if opts.ShowVerboseHint {
result += "\nRun with --verbose for detailed information\n"
}

return result
}
Loading
Loading