claude-code-conversation-search-mcp
Version:
Never lose your Claude Code conversations again. Search across all projects, find old chats, and resume where you left off.
158 lines (136 loc) • 5.59 kB
text/typescript
export class ConversationSearchError extends Error {
constructor(
public readonly code: string,
message: string,
public readonly userMessage: string,
public readonly cause?: Error
) {
super(message);
this.name = 'ConversationSearchError';
}
}
export class DatabaseError extends ConversationSearchError {
constructor(message: string, cause?: Error) {
const userMessage = 'Database operation failed. Try refreshing the index or check if the database file is accessible.';
super('DATABASE_ERROR', message, userMessage, cause);
}
}
export class FileAccessError extends ConversationSearchError {
constructor(filePath: string, cause?: Error) {
const userMessage = `Cannot access conversation file. Please check if Claude Code has proper file permissions and the file exists.`;
super('FILE_ACCESS_ERROR', `Failed to access file: ${filePath}`, userMessage, cause);
}
}
export class ParsingError extends ConversationSearchError {
constructor(filePath: string, lineNumber?: number, cause?: Error) {
const locationInfo = lineNumber ? ` at line ${lineNumber}` : '';
const userMessage = `Conversation file format is invalid${locationInfo}. This file may be corrupted or not a valid Claude conversation.`;
super('PARSING_ERROR', `Failed to parse conversation file: ${filePath}${locationInfo}`, userMessage, cause);
}
}
export class ConfigurationError extends ConversationSearchError {
constructor(setting: string, cause?: Error) {
const userMessage = `Configuration issue with ${setting}. Please check your environment variables or MCP server configuration.`;
super('CONFIG_ERROR', `Configuration error: ${setting}`, userMessage, cause);
}
}
export class SearchError extends ConversationSearchError {
constructor(query: string, cause?: Error) {
const userMessage = 'Search failed. Try simplifying your query or check if the database is properly indexed.';
super('SEARCH_ERROR', `Search failed for query: ${query}`, userMessage, cause);
}
}
export class IndexingError extends ConversationSearchError {
constructor(message: string, cause?: Error) {
const userMessage = 'Failed to index conversations. Check if Claude Code projects directory exists and contains valid conversation files.';
super('INDEXING_ERROR', message, userMessage, cause);
}
}
export function createUserFriendlyError(error: unknown, fallbackMessage: string = 'An unexpected error occurred'): ConversationSearchError {
if (error instanceof ConversationSearchError) {
return error;
}
if (error instanceof Error) {
// Try to identify common error patterns and create appropriate user-friendly errors
if (error.message.includes('ENOENT') || error.message.includes('no such file')) {
return new FileAccessError(error.message, error);
}
if (error.message.includes('EACCES') || error.message.includes('permission denied')) {
return new ConfigurationError('file permissions', error);
}
if (error.message.includes('database') || error.message.includes('SQL')) {
return new DatabaseError(error.message, error);
}
if (error.message.includes('JSON') || error.message.includes('parse')) {
return new ParsingError('unknown file', undefined, error);
}
}
return new ConversationSearchError('UNKNOWN_ERROR', String(error), fallbackMessage);
}
export function getErrorResponse(error: unknown, context: string): { isError: true; content: [{ type: 'text'; text: string }] } {
const searchError = createUserFriendlyError(error);
const errorText = [
`❌ ${context} failed`,
'',
`**Error:** ${searchError.userMessage}`,
'',
'**Troubleshooting tips:**'
];
switch (searchError.code) {
case 'FILE_ACCESS_ERROR':
errorText.push(
'• Check if ~/.claude/projects directory exists',
'• Verify Claude Code has read permissions',
'• Ensure conversation files are not corrupted'
);
break;
case 'DATABASE_ERROR':
errorText.push(
'• Try running refresh_index() to rebuild the database',
'• Check if database file is not locked by another process',
'• Verify disk space is available'
);
break;
case 'PARSING_ERROR':
errorText.push(
'• Some conversation files may be corrupted',
'• Try restarting Claude Code to regenerate files',
'• Check if specific files can be manually opened'
);
break;
case 'CONFIG_ERROR':
errorText.push(
'• Check MCP server configuration in claude_desktop_config.json',
'• Verify environment variables are set correctly',
'• Ensure proper file paths and permissions'
);
break;
case 'SEARCH_ERROR':
errorText.push(
'• Try a simpler search query',
'• Check if database is indexed (run refresh_index())',
'• Verify search terms are not empty'
);
break;
case 'INDEXING_ERROR':
errorText.push(
'• Check if ~/.claude/projects contains conversation files',
'• Verify Claude Code is creating conversation files',
'• Try restarting the MCP server'
);
break;
default:
errorText.push(
'• Try restarting the MCP server',
'• Check the console for detailed error logs',
'• Verify Claude Code is working properly'
);
}
return {
isError: true,
content: [{
type: 'text',
text: errorText.join('\n')
}]
};
}