diff --git a/internal/mcp/handlers.go b/internal/mcp/handlers.go index 0a53c9f..43cadfc 100644 --- a/internal/mcp/handlers.go +++ b/internal/mcp/handlers.go @@ -103,8 +103,8 @@ func (s *Server) handleGetOption(ctx context.Context, args map[string]interface{ return ErrorContent(fmt.Errorf("option '%s' not found", name)), nil } - // Get declarations - declarations, err := s.store.GetDeclarations(ctx, option.ID) + // Get declarations with file metadata + declarations, err := s.store.GetDeclarationsWithMetadata(ctx, rev.ID, option.ID) if err != nil { s.logger.Printf("Failed to get declarations: %v", err) } @@ -134,10 +134,15 @@ func (s *Server) handleGetOption(ctx context.Context, args map[string]interface{ sb.WriteString("\n**Declared in:**\n") for _, decl := range declarations { if decl.Line > 0 { - sb.WriteString(fmt.Sprintf("- %s:%d\n", decl.FilePath, decl.Line)) + sb.WriteString(fmt.Sprintf("- %s:%d", decl.FilePath, decl.Line)) } else { - sb.WriteString(fmt.Sprintf("- %s\n", decl.FilePath)) + sb.WriteString(fmt.Sprintf("- %s", decl.FilePath)) } + // Add file metadata if available + if decl.HasFile && decl.ByteSize > 0 { + sb.WriteString(fmt.Sprintf(" (%d bytes, %d lines)", decl.ByteSize, decl.LineCount)) + } + sb.WriteString("\n") } } @@ -199,16 +204,34 @@ func (s *Server) handleGetFile(ctx context.Context, args map[string]interface{}) return ErrorContent(fmt.Errorf("no indexed revision available")), nil } - file, err := s.store.GetFile(ctx, rev.ID, path) + // Parse range parameters + var offset, limit int + if o, ok := args["offset"].(float64); ok { + offset = int(o) + } + if l, ok := args["limit"].(float64); ok { + limit = int(l) + } + + // Use GetFileWithRange + fileRange := database.FileRange{Offset: offset, Limit: limit} + result, err := s.store.GetFileWithRange(ctx, rev.ID, path, fileRange) if err != nil { return ErrorContent(fmt.Errorf("failed to get file: %w", err)), nil } - if file == nil { + if result == nil { return ErrorContent(fmt.Errorf("file '%s' not found (files may not be indexed for this revision)", path)), nil } + // Format output with range metadata + var sb strings.Builder + if result.TotalLines > 0 && (result.StartLine > 1 || result.EndLine < result.TotalLines) { + sb.WriteString(fmt.Sprintf("Showing lines %d-%d of %d total\n\n", result.StartLine, result.EndLine, result.TotalLines)) + } + sb.WriteString(fmt.Sprintf("```%s\n%s\n```", strings.TrimPrefix(result.Extension, "."), result.Content)) + return CallToolResult{ - Content: []Content{TextContent(fmt.Sprintf("```%s\n%s\n```", strings.TrimPrefix(file.Extension, "."), file.Content))}, + Content: []Content{TextContent(sb.String())}, }, nil } diff --git a/internal/mcp/server.go b/internal/mcp/server.go index 1b2f3b8..9a066a2 100644 --- a/internal/mcp/server.go +++ b/internal/mcp/server.go @@ -28,7 +28,7 @@ type ServerConfig struct { func DefaultNixOSConfig() ServerConfig { return ServerConfig{ Name: "nixos-options", - Version: "0.1.1", + Version: "0.1.2", DefaultChannel: "nixos-stable", SourceName: "nixpkgs", Instructions: `NixOS Options MCP Server - Search and query NixOS configuration options. @@ -47,7 +47,7 @@ This ensures option documentation matches the nixpkgs version the project actual func DefaultHomeManagerConfig() ServerConfig { return ServerConfig{ Name: "hm-options", - Version: "0.1.1", + Version: "0.1.2", DefaultChannel: "hm-stable", SourceName: "home-manager", Instructions: `Home Manager Options MCP Server - Search and query Home Manager configuration options. @@ -291,6 +291,16 @@ func (s *Server) getToolDefinitions() []Tool { Type: "string", Description: "Git hash or channel name. Uses default if not specified.", }, + "offset": { + Type: "integer", + Description: "Line offset (0-based). Default: 0", + Default: 0, + }, + "limit": { + Type: "integer", + Description: "Maximum lines to return. Default: 250, use 0 for all lines", + Default: 250, + }, }, Required: []string{"path"}, },