How the Network Sync Feature Works in ChatMCP for LAN Data Synchronization
The network sync feature in ChatMCP enables real-time LAN data synchronization by running an HTTP server on each device that exports chat history, settings, and MCP configurations via REST endpoints, allowing peers to discover and exchange data across the local network using a singleton NetworkSyncService.
ChatMCP, an open-source MCP (Model Context Protocol) client, includes a built-in network sync capability that transforms any device on the same Wi-Fi network into a sync server. This allows users to seamlessly migrate chat data, application settings, and custom MCP server configurations between devices without cloud dependencies.
Core Architecture of the Network Sync Service
The NetworkSyncService Singleton
The entire synchronization system is orchestrated by NetworkSyncService, implemented as a singleton in lib/services/network_sync_service.dart. This service manages both server-side HTTP operations and client-side sync logic, maintaining state through callbacks like onServerStateChanged to update the UI when the server starts or stops.
HTTP Server Implementation with Shelf
The sync server leverages the shelf package ecosystem (shelf, shelf_router, shelf_cors_headers) to handle HTTP requests. When startServer() is invoked, the service binds to 0.0.0.0:<port> (default 8080) using io.serve(handler, InternetAddress.anyIPv4, _port), making the device discoverable on all network interfaces.
The server exposes four critical endpoints:
/health– Returns server status for discovery validation/info– Supplies device metadata (hostname, OS, version) via_handleDeviceInfo()/export– Serializes all local data via_handleExportData()/import– Accepts and applies remote data via_handleImportData()
Data Export and Import Endpoints
The /export endpoint returns a comprehensive JSON payload containing:
- SQLite chat tables (
chat,chat_message) from the local database SharedPreferencessettings (user preferences and configuration)- MCP server definitions and connection parameters
- Device metadata for identification
When /import receives this payload, _handleImportData() writes the data to the local SQLite store and SharedPreferences, then triggers _reinitializeProviders() to refresh the application state.
LAN Discovery Mechanism
ChatMCP discovers peers using a subnet scanning approach. The discoverServers() method scans the local network range (e.g., 192.168.1.xxx) targeting IPs 100–110, probing each address with a /health request to identify active sync servers.
Once discovered, servers are returned as complete URLs (http://<ip>:<port>) and presented in the UI for user selection.
Synchronization Workflows
Pulling Data with syncFromRemote()
The syncFromRemote(serverUrl) method implements the client-side download logic. It performs a health check on the target server, downloads the JSON export via the /export endpoint, and executes _importAllData() to merge remote data into the local database. Following a successful import, the service calls ProviderManager through _reinitializeProviders() to reload settings, chat histories, and MCP server definitions instantly.
Pushing Data with pushToRemote()
Conversely, pushToRemote(serverUrl) exports the local database and settings into a JSON blob, then POSTs this data to the remote device's /import endpoint. This enables one-way synchronization from the current device to a peer, useful for backup or migration scenarios.
Provider Re-initialization After Import
After any data import operation, the service must reconcile the UI with the new underlying data. The _reinitializeProviders() function signals ProviderManager (defined in lib/provider/provider_manager.dart) to reload all stateful components, ensuring that chat lists, settings panels, and MCP server configurations reflect the synchronized data without requiring an application restart.
Code Examples for Implementing LAN Sync
Starting the Sync Server
To activate the server mode and begin accepting connections:
await NetworkSyncService().startServer(port: 8080);
This binds to the device's Wi-Fi address (retrieved via _getLocalIPAddress()) and announces the server state through onServerStateChanged callbacks.
Discovering Peers on the Network
Scan the local subnet for available sync servers:
final servers = await NetworkSyncService().discoverServers();
print('Found servers: $servers');
This returns a list of reachable URLs like http://192.168.1.101:8080 that can be presented to the user for selection.
Downloading Data from a Remote Device
Pull all chat history and settings from a discovered server:
await NetworkSyncService().syncFromRemote('http://192.168.1.101:8080');
This executes the full download-and-import pipeline, including database writes and provider re-initialization.
Uploading Data to a Remote Device
Push local configuration and chat data to another device:
await NetworkSyncService().pushToRemote('http://192.168.1.102:8080');
This serializes the local state and transmits it to the target server's /import handler.
Stopping the Server
To gracefully terminate the HTTP listener:
await NetworkSyncService().stopServer();
This closes the socket and broadcasts onServerStateChanged(false) to update the UI.
Summary
- NetworkSyncService in
lib/services/network_sync_service.dartacts as both server and client for LAN synchronization - The shelf HTTP server exposes REST endpoints for health checks, device info, data export, and data import
- Subnet scanning (IPs 100-110) discovers peers automatically without requiring manual IP entry
syncFromRemote()downloads and imports remote data, whilepushToRemote()uploads local state_reinitializeProviders()ensures the UI reflects synchronized data immediately by reloadingProviderManagerstate- The system synchronizes SQLite chat tables,
SharedPreferencessettings, and MCP server configurations across devices
Frequently Asked Questions
How does ChatMCP discover other devices on the same network?
ChatMCP scans the local subnet (typically 192.168.1.xxx) by iterating through IP addresses 100–110 and sending /health requests to each. Active servers respond with a 200 status, allowing the discoverServers() method to compile a list of available sync endpoints for the user to select.
What data is included when exporting chat data via the network sync feature?
The export includes three primary data categories: SQLite database tables (chat and chat_message storing conversation history), SharedPreferences settings (user preferences and app configuration), and MCP server definitions (connection parameters and custom server setups). This comprehensive export ensures complete state migration between devices.
Can I sync data from an older version of ChatMCP to a newer version?
While the NetworkSyncService handles data import/export agnostically, compatibility depends on database schema changes in lib/dao/init_db.dart. If the SQLite schema differs between versions, the _importAllData() method may need to handle migration logic. Always ensure both devices run compatible versions for seamless LAN data synchronization.
Is the network sync feature secure for sensitive chat data?
The current implementation uses unencrypted HTTP over the local network. According to the source code in lib/services/network_sync_service.dart, there is no TLS encryption or authentication layer on the endpoints. Users should only enable the sync server on trusted private networks, as the /export and /import endpoints expose full application state without access controls.
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 →