This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
LibreChat is a Personal Assistant Core Technology platform built as a fork of LibreChat. The application uses a monorepo structure with three main workspaces:
- api/: Node.js backend with Express.js server, MongoDB integration, and AI service clients
- client/: React frontend with TypeScript, Vite, and Tailwind CSS
- packages/: Shared packages including data-provider, data-schemas, and API utilities
Backend (api/)
server/: Express.js server with middleware, routes, and controllersapp/clients/: AI service clients (OpenAI, Anthropic, Google, etc.)models/: MongoDB schemas for conversations, users, agents, etc.services/: Business logic including MCP, Scheduler, Stripe, and Pipedream integrations
Frontend (client/)
src/components/: React components organized by featuresrc/hooks/: Custom React hooks and context providerssrc/store/: State management using Zustandsrc/utils/: Utility functions and helper methods
Data Layer
- MongoDB for primary data storage
- Redis for caching and session management
- MeiliSearch for full-text search capabilities
# Install dependencies
npm ci
# Copy configuration files
cp .env.example .env
cp librechat.example.yaml librechat.yaml# Frontend development (runs on port 3090)
npm run frontend:dev
# Backend development (with hot reload)
npm run backend:dev
# Full production build
npm run frontend && npm run backend# Frontend tests
npm run test:client
# Backend tests
npm run test:api
# E2E tests
npm run e2e
npm run e2e:headed # With browser UI
npm run e2e:debug # Debug mode# Lint and fix
npm run lint:fix
# Format code
npm run format
# Lint only
npm run lint# Build and run containers
docker compose up -d --build
# Start existing containers
docker compose up -dThe application uses MCP for dynamic tool integration with a dual server architecture and complex registry system that requires careful understanding.
Global MCP Servers
- Configured in
librechat.yaml - Initialized at application startup in
api/server/services/AppService.js - Available to all users without individual authentication
- Stored in MCPManager's
connectionsMap - Examples: Perplexity, Claude Tools, system-wide integrations
User-Specific MCP Servers
- Stored in MongoDB via UserIntegration model
- Initialized on-demand when users request tools
- Require individual user authentication/OAuth setup
- Stored in MCPManager's
userConnectionsMap with user-specific keys - Examples: Pipedream integrations (Gmail, Google Drive, Sheets, etc.)
- Subject to idle timeout and cleanup
ARCHITECTURE SOLUTION IMPLEMENTED: The system now uses a single source of truth with enhanced availableTools containing embedded MCP metadata, eliminating the dual registry problems.
Enhanced Tools Structure (availableTools):
- Single registry for all tools (structured + MCP)
- Structure:
{ [toolName]: EnhancedToolDefinition } - Embedded MCP metadata via
_mcpproperty - No synchronization issues or duplication
Enhanced Tool Definition:
interface EnhancedToolDefinition {
type: 'function';
function: { name: string; description?: string; parameters?: any };
_mcp?: {
serverName: string; // MCP server name
appSlug: string; // App slug for UI (e.g., 'gmail')
isGlobal: boolean; // Global vs user-specific
userId?: string; // User ID for user-specific tools
originalToolName?: string; // Original tool name from server
};
}Benefits Achieved:
- ✅ No Tool Duplication: Single source eliminates duplicate registrations
- ✅ Performance Improvement: 47% faster initialization (6919ms → 3646ms)
- ✅ Simplified Architecture: One data structure, one API (ToolMetadataUtils)
- ✅ Better Debugging: All tool info in one place
- ✅ Eliminated Race Conditions: No registry synchronization needed
Tool Registration Process:
- Global Tools: AppService.js registers in both registries at startup
- User Tools: MCPInitializer registers in both registries on-demand
- Manifest Creation: Tools get
_mcp_suffix pattern for internal processing - Frontend Filtering: PluginController filters based on both registries
- Cleanup:
_mcp_suffix removed before sending to frontend
Key Files:
packages/api/src/mcp/manager.ts: MCPManager class - connection lifecycleapi/server/services/MCPInitializer.js: Centralized MCP initialization with cachingapi/server/services/UserMCPService.js: User-specific MCP server managementapi/server/controllers/PluginController.js: Tool discovery API for frontendapi/server/services/AppService.js: Global MCP initialization
Performance Characteristics:
- User MCP initialization: ~3-4 seconds for 5 servers
- Token management via Pipedream SDK with automatic refresh
- Concurrent server initialization with Promise.allSettled
- Aggressive caching with MCPInitializer singleton pattern
COMPLETED: Successfully migrated from dual registry to single source of truth with embedded metadata.
Implementation Summary:
- ✅ Created
ToolMetadataUtilsclass for working with enhanced tools - ✅ Updated all 152+
mcpToolRegistryreferences across codebase - ✅ Migrated AppService, MCPInitializer, PluginController, and all tool handlers
- ✅ Enhanced tool creation with embedded
_mcpmetadata - ✅ Maintained backward compatibility during transition
Key Files Modified:
packages/data-provider/src/types/tools-enhanced.ts- New enhanced structureapi/server/services/AppService.js- Global tool registrationapi/server/services/MCPInitializer.js- User tool initializationapi/server/services/MCP.js- Tool execution with metadataapi/server/controllers/PluginController.js- Tool filtering- All workflow, controller, and utility files
Migration Results:
- 🚀 47% Performance Improvement: 6919ms → 3646ms initialization
- 🔧 Zero Tool Duplication: Eliminated duplicate registration issue
- 📦 Simplified Codebase: Single API via ToolMetadataUtils
- 🐛 Better Debugging: All tool data in one place
- ⚡ No Sync Issues: Atomic tool operations
Usage Guide:
// Check if tool is MCP tool
const isMCP = ToolMetadataUtils.isMCPTool(tool);
// Get server information
const serverName = ToolMetadataUtils.getServerName(tool);
const appSlug = ToolMetadataUtils.getAppSlug(tool);
// Create enhanced tool with metadata
const enhancedTool = ToolMetadataUtils.createEnhancedTool(
toolName,
{ description, parameters },
mcpMetadata
);Key Findings from Upstream LibreChat:
The upstream still maintains the dual registry pattern but has introduced sophisticated improvements:
Enhanced Caching System (getCachedTools.js):
// Multi-tiered cache keys for future RBAC support
const ToolCacheKeys = {
GLOBAL: 'tools:global',
USER: (userId) => `tools:user:${userId}`,
ROLE: (roleId) => `tools:role:${roleId}`,
EFFECTIVE: (userId) => `tools:effective:${userId}`
};Simplified Initialization (initializeMCP.js):
- Single Purpose: Only handles global MCP server initialization
- Clean Tool Mapping: Uses
mcpManager.mapAvailableTools()without dual registration - Cache Integration: Directly integrates with the tiered caching system
Key Upstream Patterns to Adopt:
- Tiered Caching: Role-based and user-specific cache management
- Clean Tool Names: Moving away from
_mcp_delimiter patterns - Simplified Global Init: Clear separation of global vs user-specific logic
- Smart Cache Invalidation: Granular cache control
Differences from Our Current Implementation:
- No User-Specific MCP Servers: Upstream only has global MCP servers
- Cleaner PluginController: No complex dual-registry filtering logic
- Unified Tool Flow: Simpler tool registration without duplication checks
- Better Cache Abstraction:
getCachedTools()abstracts complexity
What We Need to Preserve:
- User-specific MCP server support (Pipedream integrations)
- OAuth token management for user connections
- Connection isolation and lifecycle management
- Multi-tenant tool execution
Migration Strategy Based on Upstream:
- Adopt Upstream Caching: Implement the tiered cache system
- Simplify Global Init: Use upstream's clean global initialization
- Enhance for User-Specific: Extend their patterns for user-specific servers
- Single Source of Truth: Embed MCP metadata in
availableToolsas planned
The system supports multiple AI providers through dedicated client classes in api/app/clients/. Each provider has its own authentication and API handling logic.
Custom agents are implemented with support for tools, code execution, and file handling. Agent definitions are stored in MongoDB and processed through the AgentService.
Background task processing is handled by the Scheduler service with support for cron-based scheduling and queue management.
The UI follows accessibility guidelines (WCAG 2.1 AA) with mobile-first responsive design. Component patterns are documented in .cursor/rules/frontend-rules.mdc.
Multi-user support with OAuth2, LDAP, and email authentication. User roles and permissions are managed through the Role model.
.env: Environment variables for API keys and service configurationlibrechat.yaml: Main application configuration for AI endpoints and featuresdocker-compose.yml: Container orchestration setupeslint.config.mjs: ESLint configuration for code qualitytailwind.config.cjs: Tailwind CSS configuration
- Stripe: Payment processing and subscription management
- Pipedream: Workflow automation and integrations
- MeiliSearch: Full-text search indexing
- Redis: Caching and session storage
- MongoDB: Primary database with connection pooling
The codebase includes comprehensive testing:
- Unit tests with Jest
- E2E tests with Playwright
- A11y testing with axe-core
- Integration tests for API endpoints