@@ -47,13 +47,88 @@ const _retentionManager = new RetentionManager(dbManager);
4747// Initialize feature flag manager
4848const _featureFlagManager = new FeatureFlagManager ( dbManager ) ;
4949
50+ // Initialize debug logging flag if it doesn't exist
51+ try {
52+ if ( ! _featureFlagManager . getFlagByKey ( 'debug_logging' ) ) {
53+ _featureFlagManager . createFlag ( {
54+ name : 'Debug Logging' ,
55+ key : 'debug_logging' ,
56+ enabled : Boolean ( process . env . MCP_DEBUG_LOGGING ) ,
57+ description : 'Enable debug logging for development and troubleshooting' ,
58+ category : 'debug' ,
59+ tags : [ 'debug' , 'logging' ] ,
60+ } ) ;
61+ }
62+ } catch ( _error ) {
63+ // Silently continue if flag creation fails (migrations might not be complete)
64+ }
65+
5066// Migration manager is no longer needed - watcher migrations are now applied by DatabaseManager
5167
5268// Tables are now created by DatabaseManager in utils/database.ts
5369
5470// Track current session
5571let currentSessionId : string | null = null ;
5672
73+ // Debug logging utility
74+ function debugLog ( message : string , ...args : any [ ] ) : void {
75+ try {
76+ if ( _featureFlagManager . isEnabled ( 'debug_logging' ) || process . env . MCP_DEBUG_LOGGING ) {
77+ // eslint-disable-next-line no-console
78+ console . log ( `[MCP-Memory-Keeper DEBUG] ${ message } ` , ...args ) ;
79+ }
80+ } catch ( _error ) {
81+ // Silently fail if feature flags aren't available yet
82+ }
83+ }
84+
85+ // Pagination validation utility
86+ interface PaginationParams {
87+ limit ?: any ;
88+ offset ?: any ;
89+ }
90+
91+ interface ValidatedPagination {
92+ limit : number ;
93+ offset : number ;
94+ errors : string [ ] ;
95+ }
96+
97+ function validatePaginationParams ( params : PaginationParams ) : ValidatedPagination {
98+ const errors : string [ ] = [ ] ;
99+ let limit = 25 ; // default
100+ let offset = 0 ; // default
101+
102+ // Validate limit
103+ if ( params . limit !== undefined && params . limit !== null ) {
104+ const rawLimit = params . limit ;
105+ if ( ! Number . isInteger ( rawLimit ) || rawLimit <= 0 ) {
106+ errors . push ( `Invalid limit: expected positive integer, got ${ typeof rawLimit } '${ rawLimit } '` ) ;
107+ debugLog ( `Pagination validation: Invalid limit ${ rawLimit } , using default ${ limit } ` ) ;
108+ } else {
109+ limit = Math . min ( Math . max ( 1 , rawLimit ) , 100 ) ; // clamp between 1-100
110+ if ( limit !== rawLimit ) {
111+ debugLog ( `Pagination validation: Clamped limit from ${ rawLimit } to ${ limit } ` ) ;
112+ }
113+ }
114+ }
115+
116+ // Validate offset
117+ if ( params . offset !== undefined && params . offset !== null ) {
118+ const rawOffset = params . offset ;
119+ if ( ! Number . isInteger ( rawOffset ) || rawOffset < 0 ) {
120+ errors . push (
121+ `Invalid offset: expected non-negative integer, got ${ typeof rawOffset } '${ rawOffset } '`
122+ ) ;
123+ debugLog ( `Pagination validation: Invalid offset ${ rawOffset } , using default ${ offset } ` ) ;
124+ } else {
125+ offset = rawOffset ;
126+ }
127+ }
128+
129+ return { limit, offset, errors } ;
130+ }
131+
57132// Helper function to get or create default session
58133function ensureSession ( ) : string {
59134 if ( ! currentSessionId ) {
@@ -2814,14 +2889,15 @@ Event ID: ${id.substring(0, 8)}`,
28142889 includeMetadata = false ,
28152890 } = args ;
28162891
2817- // CRITICAL FIX: Ensure pagination parameters are properly typed and validated
2818- const limit =
2819- Number . isInteger ( rawLimit ) && rawLimit > 0 ? Math . min ( Math . max ( 1 , rawLimit ) , 100 ) : 25 ;
2820- const offset = Number . isInteger ( rawOffset ) && rawOffset >= 0 ? rawOffset : 0 ;
2892+ // Enhanced pagination validation with proper error handling
2893+ const paginationValidation = validatePaginationParams ( { limit : rawLimit , offset : rawOffset } ) ;
2894+ const { limit, offset, errors : paginationErrors } = paginationValidation ;
28212895 const currentSession = currentSessionId || ensureSession ( ) ;
28222896
2823- // PAGINATION FIX: Enhanced parameter validation to prevent type conversion issues
2824- // This ensures that string numbers, floats, or invalid values don't break pagination
2897+ // Log pagination validation errors for debugging
2898+ if ( paginationErrors . length > 0 ) {
2899+ debugLog ( 'Pagination validation errors:' , paginationErrors ) ;
2900+ }
28252901
28262902 try {
28272903 // Use enhanced search across sessions with pagination
@@ -2846,8 +2922,8 @@ Event ID: ${id.substring(0, 8)}`,
28462922
28472923 // PAGINATION VALIDATION: Ensure pagination is working as expected
28482924 if ( result . items . length > limit && limit < result . totalCount ) {
2849- console . warn (
2850- `⚠️ Pagination warning: Expected max ${ limit } items, got ${ result . items . length } `
2925+ debugLog (
2926+ `Pagination warning: Expected max ${ limit } items, got ${ result . items . length } . This may indicate a pagination implementation issue. `
28512927 ) ;
28522928 }
28532929
@@ -2892,11 +2968,28 @@ Event ID: ${id.substring(0, 8)}`,
28922968 ] ,
28932969 } ;
28942970 } catch ( error : any ) {
2971+ // Enhanced error handling to distinguish pagination errors from search errors
2972+ let errorMessage = 'Search failed' ;
2973+
2974+ if ( paginationErrors . length > 0 ) {
2975+ errorMessage = `Search failed due to pagination validation errors: ${ paginationErrors . join ( ', ' ) } . ${ error . message } ` ;
2976+ } else if (
2977+ error . message . includes ( 'pagination' ) ||
2978+ error . message . includes ( 'limit' ) ||
2979+ error . message . includes ( 'offset' )
2980+ ) {
2981+ errorMessage = `Search failed due to pagination parameter issue: ${ error . message } ` ;
2982+ } else {
2983+ errorMessage = `Search failed: ${ error . message } ` ;
2984+ }
2985+
2986+ debugLog ( 'Search error:' , { error : error . message , paginationErrors, limit, offset } ) ;
2987+
28952988 return {
28962989 content : [
28972990 {
28982991 type : 'text' ,
2899- text : `Search failed: ${ error . message } ` ,
2992+ text : errorMessage ,
29002993 } ,
29012994 ] ,
29022995 } ;
@@ -3853,8 +3946,16 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
38533946 enum : [ 'created_desc' , 'created_asc' , 'updated_desc' , 'key_asc' , 'key_desc' ] ,
38543947 description : 'Sort order for results' ,
38553948 } ,
3856- limit : { type : 'number' , description : 'Maximum items to return' } ,
3857- offset : { type : 'number' , description : 'Pagination offset' } ,
3949+ limit : {
3950+ type : 'number' ,
3951+ description :
3952+ 'Maximum items to return. Must be a positive integer. Invalid values will cause validation error. (default: auto-derived)' ,
3953+ } ,
3954+ offset : {
3955+ type : 'number' ,
3956+ description :
3957+ 'Pagination offset. Must be a non-negative integer. Invalid values will cause validation error. (default: 0)' ,
3958+ } ,
38583959 createdAfter : {
38593960 type : 'string' ,
38603961 description : 'ISO date - items created after this time' ,
@@ -4046,8 +4147,16 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
40464147 enum : [ 'created_desc' , 'created_asc' , 'updated_desc' , 'key_asc' , 'key_desc' ] ,
40474148 description : 'Sort order for results' ,
40484149 } ,
4049- limit : { type : 'number' , description : 'Maximum items to return' } ,
4050- offset : { type : 'number' , description : 'Pagination offset' } ,
4150+ limit : {
4151+ type : 'number' ,
4152+ description :
4153+ 'Maximum items to return. Must be a positive integer. Invalid values will cause validation error. (default: auto-derived)' ,
4154+ } ,
4155+ offset : {
4156+ type : 'number' ,
4157+ description :
4158+ 'Pagination offset. Must be a non-negative integer. Invalid values will cause validation error. (default: 0)' ,
4159+ } ,
40514160 includeMetadata : {
40524161 type : 'boolean' ,
40534162 description : 'Include timestamps and size info' ,
@@ -4117,14 +4226,16 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
41174226 } ,
41184227 limit : {
41194228 type : 'number' ,
4120- description : 'Maximum number of items to return (1-100, default: 25)' ,
4229+ description :
4230+ 'Maximum number of items to return. Must be a positive integer between 1-100. Non-integer values will be rejected with validation error. (default: 25)' ,
41214231 minimum : 1 ,
41224232 maximum : 100 ,
41234233 default : 25 ,
41244234 } ,
41254235 offset : {
41264236 type : 'number' ,
4127- description : 'Number of items to skip for pagination (default: 0)' ,
4237+ description :
4238+ 'Number of items to skip for pagination. Must be a non-negative integer (0 or higher). Non-integer values will be rejected with validation error. (default: 0)' ,
41284239 minimum : 0 ,
41294240 default : 0 ,
41304241 } ,
@@ -4923,6 +5034,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
49235034 } ;
49245035} ) ;
49255036
5037+ // Export utilities for testing and verification
5038+ export { debugLog , validatePaginationParams , _featureFlagManager , dbManager } ;
5039+
49265040// Start server
49275041const transport = new StdioServerTransport ( ) ;
49285042server . connect ( transport ) ;
0 commit comments