Skip to content

Commit

Permalink
✨ Tune tail command
Browse files Browse the repository at this point in the history
  • Loading branch information
wesen committed Feb 11, 2025
1 parent be881a1 commit 3966140
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 27 deletions.
32 changes: 25 additions & 7 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -985,7 +985,7 @@ Updated the Claude desktop configuration documentation with:

Added ability to temporarily disable MCP servers without removing their configuration:
- ✨ Added `disable-server` and `enable-server` commands to claude-config
- 🏗️ Added `DisabledMCPServers` field to configuration format
- 🏗️ Added `DisabledServers` map to store configurations of disabled servers
- 📝 Updated list-servers command to show disabled status
- 🔧 Added helper functions for managing server state

Expand All @@ -998,10 +998,28 @@ Added ability to tail Claude log files in real-time:
- 🛠️ Graceful shutdown support with Ctrl+C
- 📝 Real-time log monitoring with automatic file reopening

# Added File Helpers Package
# Enhanced Log Tailing with Line History

Added a new package for file manipulation helpers:
- ✨ Added `FindStartPosForLastNLines` function for efficient seeking to last N lines
- 🧪 Added comprehensive table-driven tests with various edge cases
- 📝 Added detailed documentation and examples
- 🔍 Optimized for large files with buffered reading
Enhanced the tail command with line history support:
- ✨ Added `--lines/-n` flag to show last N lines when starting to tail
- 🔍 Efficient seeking to last N lines without reading entire file
- 🛠️ Proper handling of files without newline at end
- 📝 Updated command documentation with new flag

## Improved MCP Server Enable/Disable Functionality

Improved the enable/disable functionality for MCP servers to properly preserve server configurations when enabling/disabling them.

- Added `DisabledServers` map to store configurations of disabled servers
- Updated `EnableMCPServer` to move server config from disabled to enabled state
- Updated `DisableMCPServer` to move server config from enabled to disabled state
- Updated `ListServers` to show both enabled and disabled server configurations

## Parameter Value Validation and Casting

Enhanced parameter validation to return cast values along with validation errors. This allows for proper type conversion and sanitization of input values.

- Modified `CheckValueValidity` to return both the cast value and any validation errors
- Added `setReflectValue` method to handle setting reflect values with proper type casting
- Updated tests to verify cast values
- Improved error messages for invalid choices
21 changes: 20 additions & 1 deletion cmd/go-go-mcp/cmds/claude_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmds
import (
"context"
"fmt"
"io"
"os"
"os/exec"
"os/signal"
Expand All @@ -12,6 +13,7 @@ import (
"syscall"

"github.com/go-go-golems/go-go-mcp/pkg/config"
"github.com/go-go-golems/go-go-mcp/pkg/helpers"
"github.com/hpcloud/tail"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -326,14 +328,16 @@ func newClaudeConfigDisableServerCommand() *cobra.Command {

func newClaudeConfigTailCommand() *cobra.Command {
var all bool
var lines int

cmd := &cobra.Command{
Use: "tail [server-names...]",
Short: "Tail Claude log files",
Long: `Tail the Claude log files in real-time.
Without arguments, tails the main mcp.log file.
With server names, tails the corresponding mcp-server-XXX.log files.
Use --all to tail all log files.`,
Use --all to tail all log files.
Use --lines/-n to output the last N lines of each file before tailing.`,
RunE: func(cmd *cobra.Command, args []string) error {
xdgConfigPath, err := os.UserConfigDir()
if err != nil {
Expand Down Expand Up @@ -385,10 +389,24 @@ Use --all to tail all log files.`,
go func(filename string) {
defer wg.Done()

// Find the starting position based on requested lines
startPos := int64(0)
if lines > 0 {
var err error
startPos, err = helpers.FindStartPosForLastNLines(filename, lines)
if err != nil && !os.IsNotExist(err) {
fmt.Fprintf(os.Stderr, "Error finding start position in %s: %v\n", filename, err)
}
}

t, err := tail.TailFile(filename, tail.Config{
Follow: true,
ReOpen: true,
Logger: tail.DiscardingLogger,
Location: &tail.SeekInfo{
Offset: startPos,
Whence: io.SeekStart,
},
})
if err != nil {
fmt.Fprintf(os.Stderr, "Error tailing %s: %v\n", filename, err)
Expand Down Expand Up @@ -426,6 +444,7 @@ Use --all to tail all log files.`,
}

cmd.Flags().BoolVarP(&all, "all", "a", false, "Tail all log files")
cmd.Flags().IntVarP(&lines, "lines", "n", 10, "Output the last N lines of each file before tailing")

return cmd
}
6 changes: 6 additions & 0 deletions cmd/go-go-mcp/cmds/client/tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ func NewCallToolCommand() (*CallToolCommand, error) {
parameters.WithHelp("Tool arguments as JSON string"),
parameters.WithDefault(""),
),
parameters.NewParameterDefinition(
"json-file",
parameters.ParameterTypeStringFromFile,
parameters.WithHelp("Tool arguments as JSON file"),
parameters.WithDefault(""),
),
parameters.NewParameterDefinition(
"args",
parameters.ParameterTypeKeyValue,
Expand Down
15 changes: 12 additions & 3 deletions examples/github/list-github-issues.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ flags:
- name: json
type: stringList
help: Output JSON with specified fields (e.g. number,title,state)
default: [number,title,state,author,assignees,body,closed,closedAt,createdAt,updatedAt,url]

- name: web
type: bool
Expand All @@ -56,7 +57,7 @@ shell-script: |
CMD=(gh issue list -R team-mento/mento-playground)
# Add filters
{{ if ne .Args.state "open" }}
{{ if not (eq .Args.state "open") }}
CMD+=(--state "{{ .Args.state }}")
{{ end }}
Expand All @@ -80,7 +81,11 @@ shell-script: |
CMD+=(--search "{{ .Args.search }}")
{{ end }}
{{ if ne .Args.limit 30 }}
{{ if .Args.json }}
CMD+=(--json "{{ .Args.json | join "," }}")
{{ end }}
{{ if not (eq .Args.limit 30) }}
CMD+=(--limit "{{ .Args.limit }}")
{{ end }}
Expand All @@ -91,4 +96,8 @@ shell-script: |
# Execute the command
echo "DEBUG: Executing: ${CMD[@]}"
"${CMD[@]}"
"${CMD[@]}" >/dev/stderr 2>&1
echo "DEBUG: Result: $?"
echo "DEBUG: Command executed"
capture-stderr: true
3 changes: 2 additions & 1 deletion examples/github/list-github-pull-requests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,5 @@ shell-script: |
# Execute the command
echo "DEBUG: Executing: ${CMD[@]}"
"${CMD[@]}"
"${CMD[@]}"
capture-stderr: true
5 changes: 3 additions & 2 deletions pkg/cmds/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import (
"io"
"os"
"os/exec"
"text/template"

"github.com/go-go-golems/glazed/pkg/cmds"
"github.com/go-go-golems/glazed/pkg/cmds/layers"
"github.com/go-go-golems/glazed/pkg/cmds/parameters"
"github.com/go-go-golems/glazed/pkg/helpers/templating"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"gopkg.in/yaml.v3"
Expand Down Expand Up @@ -112,7 +112,8 @@ func (c *ShellCommand) processTemplate(
Env: c.Environment,
}

tmpl, err := template.New("shell").Parse(templateStr)
tmpl := templating.CreateTemplate("shell")
tmpl, err := tmpl.Parse(templateStr)
if err != nil {
return "", errors.Wrap(err, "failed to parse template")
}
Expand Down
36 changes: 30 additions & 6 deletions pkg/config/claude_desktop.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
type ClaudeDesktopConfig struct {
MCPServers map[string]MCPServer `json:"mcpServers"`
DisabledMCPServers []string `json:"disabledMCPServers,omitempty"`
DisabledServers map[string]MCPServer `json:"disabledServersConfig,omitempty"`
GoGoMCP MCPServer `json:"go-go-mcp"`
}

Expand Down Expand Up @@ -148,11 +149,18 @@ func (e *ClaudeDesktopEditor) ListServers() map[string]MCPServer {
servers["go-go-mcp"] = e.config.GoGoMCP
}

// Add other MCP servers
// Add enabled MCP servers
for name, server := range e.config.MCPServers {
servers[name] = server
}

// Add disabled MCP servers
if e.config.DisabledServers != nil {
for name, server := range e.config.DisabledServers {
servers[name] = server
}
}

return servers
}

Expand All @@ -162,12 +170,20 @@ func (e *ClaudeDesktopEditor) EnableMCPServer(name string) error {
return fmt.Errorf("MCP server '%s' is not disabled", name)
}

// Check if server exists
if _, exists := e.config.MCPServers[name]; !exists {
return fmt.Errorf("MCP server '%s' not found", name)
// Check if server exists in disabled servers
server, exists := e.config.DisabledServers[name]
if !exists {
return fmt.Errorf("MCP server '%s' configuration not found in disabled servers", name)
}

// Move server from disabled to enabled
if e.config.MCPServers == nil {
e.config.MCPServers = make(map[string]MCPServer)
}
e.config.MCPServers[name] = server
delete(e.config.DisabledServers, name)

// Find and remove from disabled list
// Remove from disabled list
for i, disabled := range e.config.DisabledMCPServers {
if disabled == name {
e.config.DisabledMCPServers = append(e.config.DisabledMCPServers[:i], e.config.DisabledMCPServers[i+1:]...)
Expand All @@ -184,7 +200,8 @@ func (e *ClaudeDesktopEditor) EnableMCPServer(name string) error {
// DisableMCPServer disables an MCP server without removing its configuration
func (e *ClaudeDesktopEditor) DisableMCPServer(name string) error {
// Check if server exists
if _, exists := e.config.MCPServers[name]; !exists {
server, exists := e.config.MCPServers[name]
if !exists {
return fmt.Errorf("MCP server '%s' not found", name)
}

Expand All @@ -197,6 +214,13 @@ func (e *ClaudeDesktopEditor) DisableMCPServer(name string) error {
}
}

// Move server from enabled to disabled
if e.config.DisabledServers == nil {
e.config.DisabledServers = make(map[string]MCPServer)
}
e.config.DisabledServers[name] = server
delete(e.config.MCPServers, name)

// Add to disabled list
if e.config.DisabledMCPServers == nil {
e.config.DisabledMCPServers = make([]string, 0)
Expand Down
14 changes: 7 additions & 7 deletions pkg/server/transports/stdio/stdio.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ func (s *Server) handleRequest(request protocol.Request) error {
if err := json.Unmarshal(request.Params, &params); err != nil {
return s.sendError(&request.ID, -32602, "Invalid params", err)
}
s.logger.Info().Interface("params", params).Msg("Handling initialize request")
s.logger.Debug().Interface("params", params).Msg("Handling initialize request")

result, err := s.initializeService.Initialize(ctx, params)
if err != nil {
Expand All @@ -223,7 +223,7 @@ func (s *Server) handleRequest(request protocol.Request) error {
cursor = params.Cursor
}

s.logger.Info().Str("cursor", cursor).Msg("Listing prompts")
s.logger.Debug().Str("cursor", cursor).Msg("Listing prompts")

prompts, nextCursor, err := s.promptService.ListPrompts(ctx, cursor)
if err != nil {
Expand All @@ -244,7 +244,7 @@ func (s *Server) handleRequest(request protocol.Request) error {
return s.sendError(&request.ID, -32602, "Invalid params", err)
}

s.logger.Info().Str("name", params.Name).Str("arguments", fmt.Sprintf("%v", params.Arguments)).Msg("Getting prompt")
s.logger.Debug().Str("name", params.Name).Str("arguments", fmt.Sprintf("%v", params.Arguments)).Msg("Getting prompt")

message, err := s.promptService.GetPrompt(ctx, params.Name, params.Arguments)
if err != nil {
Expand All @@ -268,7 +268,7 @@ func (s *Server) handleRequest(request protocol.Request) error {
cursor = params.Cursor
}

s.logger.Info().Str("cursor", cursor).Msg("Listing resources")
s.logger.Debug().Str("cursor", cursor).Msg("Listing resources")

resources, nextCursor, err := s.resourceService.ListResources(ctx, cursor)
if err != nil {
Expand All @@ -288,7 +288,7 @@ func (s *Server) handleRequest(request protocol.Request) error {
return s.sendError(&request.ID, -32602, "Invalid params", err)
}

s.logger.Info().Str("uri", params.URI).Msg("Reading resource")
s.logger.Debug().Str("uri", params.URI).Msg("Reading resource")

content, err := s.resourceService.ReadResource(ctx, params.URI)
if err != nil {
Expand All @@ -311,7 +311,7 @@ func (s *Server) handleRequest(request protocol.Request) error {
cursor = params.Cursor
}

s.logger.Info().Str("cursor", cursor).Msg("Listing tools")
s.logger.Debug().Str("cursor", cursor).Msg("Listing tools")

tools, nextCursor, err := s.toolService.ListTools(ctx, cursor)
if err != nil {
Expand All @@ -332,7 +332,7 @@ func (s *Server) handleRequest(request protocol.Request) error {
return s.sendError(&request.ID, -32602, "Invalid params", err)
}

s.logger.Info().Str("name", params.Name).Str("arguments", fmt.Sprintf("%v", params.Arguments)).Msg("Calling tool")
s.logger.Debug().Str("name", params.Name).Str("arguments", fmt.Sprintf("%v", params.Arguments)).Msg("Calling tool")

result, err := s.toolService.CallTool(ctx, params.Name, params.Arguments)
if err != nil {
Expand Down

0 comments on commit 3966140

Please sign in to comment.