How ChatMCP Handles Cross-Platform Data Storage on macOS, Windows, Linux, iOS, and Android
ChatMCP uses a platform-detection utility to automatically select appropriate user data directories—such as XDG directories on Linux, %APPDATA% on Windows, and Application Support on macOS—while using platform-specific SQLite implementations (FFI for desktop, native for mobile) to ensure consistent database storage across all supported operating systems.
ChatMCP, an open-source Flutter-based chat client available at daodao97/chatmcp, implements a unified data persistence layer that adapts automatically to desktop and mobile environments. The implementation abstracts file system complexities through three core utility files that handle runtime platform detection, directory selection, and SQLite initialization without requiring manual user configuration.
Platform Detection at Runtime
ChatMCP determines the host operating system using constants defined in lib/utils/platform.dart. These boolean flags are derived from dart:io and flutter/foundation to categorize devices into desktop, mobile, or web environments:
kIsDesktop— matches Linux, Windows, or macOSkIsMobile— matches Android or iOSkIsWeb— fallback for browser environments
These constants enable conditional logic throughout the storage layer, ensuring that code paths for file system access remain platform-appropriate without compile-time directives.
Adaptive Storage Directory Selection
The StorageManager class in lib/utils/storage_manager.dart centralizes directory selection through the getAppDataDirectory() method. This function returns a platform-specific path where application data—including the SQLite database—resides.
Linux: XDG Base Directory Compliance
On Linux systems, ChatMCP follows the XDG Base Directory specification. The implementation checks for the $XDG_DATA_HOME environment variable first, defaulting to $HOME/.local/share when the variable is unset. This ensures compliance with modern Linux standards while maintaining compatibility with sandboxed environments like Flatpak or Snap.
Windows: Application Data Roaming
For Windows platforms, the storage manager reads the $APPDATA environment variable to locate the user's roaming application data folder. This places ChatMCP data in the standard %APPDATA% directory, typically resolving to C:\Users\<username>\AppData\Roaming.
macOS: Application Support Directory
On macOS, ChatMCP stores data under $HOME/Library/Application Support, the canonical location for application-specific files that should persist across updates but remain user-specific. This avoids cluttering the Documents folder while ensuring Time Machine backups capture the data.
iOS and Android: Application Documents
Mobile platforms use the path_provider Flutter package to retrieve the application documents directory. If the primary documents folder is unavailable, the implementation falls back to a temporary directory to prevent crashes during initialization. This approach respects mobile sandboxing restrictions while ensuring data persists between app sessions.
Fallback Mechanisms
For unsupported platforms or when path_provider fails, the system attempts to use any available application directory from the Flutter framework, ultimately falling back to the system's temporary directory. This guarantees the app remains functional even in unusual environments.
SQLite Database Initialization
Database handling is implemented in lib/dao/init_db.dart, where the DatabaseHelper class manages SQLite backend selection and file path resolution.
Platform-Specific SQLite Backends
The _initializeSqlite() method selects the appropriate database implementation based on the platform constants:
- Desktop (Linux/Windows/macOS) — initializes
sqflite_ffiviasqfliteFfiInit()and usesdatabaseFactoryFfifor native library access - Mobile (iOS/Android) — uses the standard
sqflitepackage withsqflite.databaseFactoryfor optimized mobile performance - Web — falls back to
sqflite_ffi_webusingdatabaseFactoryFfiWebfor browser compatibility
Database File Path Resolution
The getDatabasePath() method in StorageManager concatenates the platform-specific directory from getAppDataDirectory() with the filename chatmcp.db. Before opening the database, the implementation ensures the parent directory exists by calling Directory(...).create(recursive: true), preventing "file not found" errors on first run.
After path resolution, DatabaseHelper opens the database, applies versioned migrations, and validates schema integrity, completing the storage initialization pipeline.
End-to-End Implementation Example
The following Dart code demonstrates how ChatMCP initializes its storage layer across platforms:
import 'package:chatmcp/utils/storage_manager.dart';
import 'package:chatmcp/dao/init_db.dart';
// Retrieve the platform-specific data directory
Future<void> printAppDataDir() async {
final dir = await StorageManager.getAppDataDirectory();
print('ChatMCP data directory -> $dir');
}
// Get the full SQLite file path
Future<void> printDbPath() async {
final dbPath = await StorageManager.getDatabasePath();
print('SQLite DB stored at -> $dbPath');
}
// Initialize the database (runs platform-specific logic internally)
Future<void> initialiseDatabase() async {
await initDb(); // Calls DatabaseHelper._initializeSqlite() under the hood
print('Database ready');
}
void main() async {
await printAppDataDir();
await printDbPath();
await initialiseDatabase();
}
Running this code on macOS, Windows, Linux, iOS, or Android automatically resolves to the correct storage location and SQLite driver without platform-specific conditional code in the consumer.
Summary
- Platform abstraction —
lib/utils/platform.dartprovides runtime detection viakIsDesktop,kIsMobile, andkIsWebconstants - Directory selection —
StorageManager.getAppDataDirectory()inlib/utils/storage_manager.dartimplements XDG, %APPDATA%, Application Support, and mobile documents directory logic - Database paths —
StorageManager.getDatabasePath()combines the platform directory withchatmcp.dband ensures parent directories exist - SQLite backends —
lib/dao/init_db.dartselectssqflite_ffifor desktop, standardsqflitefor mobile, andsqflite_ffi_webfor web environments - Automatic initialization — The
initDb()function orchestrates the entire flow, running migrations after establishing the platform-appropriate connection
Frequently Asked Questions
Where does ChatMCP store data on Linux systems?
ChatMCP follows the XDG Base Directory specification on Linux. It checks the $XDG_DATA_HOME environment variable first, defaulting to $HOME/.local/share if the variable is not set. This ensures compatibility with standard Linux conventions and sandboxed distribution formats.
How does ChatMCP handle SQLite on desktop versus mobile platforms?
According to the source code in lib/dao/init_db.dart, ChatMCP uses sqflite_ffi with databaseFactoryFfi on desktop platforms (Linux, Windows, macOS) to access native SQLite libraries, while mobile platforms (iOS, Android) use the standard sqflite package optimized for mobile architectures. Web platforms use sqflite_ffi_web as a fallback.
What happens if the application documents directory is unavailable on mobile devices?
If path_provider fails to return a valid application documents directory on iOS or Android, the StorageManager implementation falls back to a temporary directory provided by the system. This ensures the app remains functional even when encountering permission issues or storage constraints, though data persistence depends on the temporary directory's retention policy.
Is the database file name consistent across all platforms?
Yes. The getDatabasePath() method in lib/utils/storage_manager.dart consistently appends chatmcp.db to the platform-specific application data directory. This uniform naming convention simplifies backup, migration, and debugging across different operating systems.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →