How the Remote MCP in DesktopCommanderMCP Enables Access from ChatGPT and Claude Web Interfaces
The Remote MCP in DesktopCommanderMCP establishes a bidirectional, real-time bridge between browser-based LLM interfaces and local desktop automation tools using Supabase's Postgres and Realtime infrastructure.
DesktopCommanderMCP (commonly referred to as the Remote MCP) eliminates the barrier between cloud-based AI assistants and local desktop environments. This open-source solution allows users of ChatGPT, Claude, and other web-based LLM interfaces to invoke automation tools directly on their personal computers through a robust architecture built on Supabase's real-time capabilities.
Architecture Overview: Bridging Cloud LLMs to Local Devices
The Remote MCP operates through three interconnected layers that manage device identity, real-time messaging, and command execution lifecycle. According to the DesktopCommanderMCP source code, this architecture ensures reliable delivery of tool calls from web interfaces to local desktop clients.
Device Registration and Presence Tracking
When the MCP client initializes, it creates a persistent device record in the Supabase mcp_devices table via the registerDevice() method. This registration stores the device's capabilities, human-readable name, and maintains a last_seen timestamp through a periodic heartbeat mechanism.
The implementation in src/remote-device/remote-channel.ts (lines 43-70) handles device creation, while trackPresenceWithRetry() and updateHeartbeat() (lines 94-119) ensure the server can determine device availability. Presence is published on a per-device key, allowing the system to distinguish between online and offline states.
Private Realtime Channels and Dual Transport Layers
Each authenticated user connects through a private Realtime channel named user:<userId>. This channel supports two transport mechanisms for redundancy:
- Broadcast "new_call" events - The primary mechanism where the LLM backend pushes a doorbell notification when remote tool calls are created
- Legacy postgres_changes listener - A fallback that monitors the
mcp_remote_callstable directly if the private channel encounters configuration issues
The createChannel() method (lines 27-50) initializes the private channel with presence tracking, while createLegacyChannel() (lines 92-104) registers the table-change listener as a backup.
Remote Call Lifecycle: From Browser to Desktop
The process of executing a local command from a web-based LLM interface follows a precise orchestration between the ChatGPT or Claude backend and the local DesktopCommanderMCP client.
Authentication and Call Insertion
The LLM UI authenticates to Supabase through a server-side OAuth flow to obtain an access token. When a user requests a tool execution, the backend calls the /api/remote-call endpoint defined in src/server.ts, which inserts a row into the mcp_remote_calls table with status pending.
The Doorbell Pattern and Local Execution
After inserting the call record, the backend broadcasts a new_call event on the private channel. The local MCP client receives this doorbell through the onDoorbell() method (lines 22-78 in src/remote-device/remote-channel.ts), which fetches the complete call row and invokes the configured local tool-call callback.
The dispatchToolCall() method forwards the request to the local handler, while markCallExecuting() ensures exactly-once execution semantics by atomically updating the call status.
Result Propagation and Completion
After the local tool executes, the client writes the result back via updateCallResult() (lines 108-138), storing the final status and output. The notifyResult() method (lines 84-99) then broadcasts a "result" event, allowing the LLM UI to retrieve the outcome immediately without polling.
Connection Resilience and Health Monitoring
Production deployments require handling network instability. The RemoteChannel class implements a health-check mechanism that runs every 10 seconds via checkConnectionHealth() (lines 122-171).
When the channel drops, enters a prolonged "joining" state, or suffers socket half-opens, the system recreates the connection through recreateChannel() (lines 176-215). This logic includes exponential backoff with jitter and gracefully falls back to the legacy transport if reconnection repeatedly fails, ensuring the device only appears online when the channel is genuinely healthy.
Implementation Examples
Initializing the RemoteChannel client requires Supabase credentials and session management:
import { RemoteChannel } from './remote-device/remote-channel.js';
const remote = new RemoteChannel();
remote.initialize(process.env.SUPABASE_URL!, process.env.SUPABASE_KEY!);
await remote.setSession({
access_token: process.env.SUPABASE_ACCESS!,
refresh_token: process.env.SUPABASE_REFRESH,
});
Device registration establishes the presence tracking and defines the callback for incoming tool requests:
await remote.registerDevice(
{ /* device capabilities */ },
process.env.DEVICE_ID,
'My-Laptop',
async (payload) => {
// Called when a tool request arrives from ChatGPT/Claude
await handleToolCall(payload);
}
);
remote.startHeartbeat(remote.deviceId!);
The local tool handler implements the execution and result reporting workflow:
async function handleToolCall(payload: any) {
const callId = payload.new.id;
if (await remote.markCallExecuting(callId)) {
const result = await runTool(payload.new.args);
await remote.updateCallResult(callId, 'succeeded', result);
await remote.notifyResult(callId);
}
}
On the server side, the backend endpoint creates remote calls and triggers the doorbell:
// src/server.ts (simplified)
app.post('/api/remote-call', async (req, res) => {
const { userId, tool, args } = req.body;
const { data, error } = await supabase
.from('mcp_remote_calls')
.insert({ user_id: userId, tool, args, status: 'pending' })
.select()
.single();
if (error) return res.status(500).json({ error });
await supabase
.channel(`user:${userId}`)
.send({ type: 'broadcast', event: 'new_call', payload: { call_id: data.id } });
res.json({ callId: data.id });
});
Summary
- The Remote MCP in DesktopCommanderMCP uses Supabase Realtime channels to create a persistent bridge between web-based LLMs and local desktop environments.
- Device registration in
mcp_deviceswith heartbeat tracking ensures accurate presence detection for local machines. - The doorbell pattern via broadcast events on private channels (
user:<userId>) enables immediate notification of pending tool calls without polling. - Dual transport layers (broadcast + postgres_changes) provide fallback mechanisms for message delivery reliability.
- Health monitoring with automatic reconnection and backoff logic in
checkConnectionHealth()maintains stable connections despite network instability. - End-to-end JWT encryption ensures secure communication between ChatGPT, Claude web interfaces, and local automation tools.
Frequently Asked Questions
What infrastructure does DesktopCommanderMCP use to connect web LLMs to local devices?
DesktopCommanderMCP leverages Supabase's Postgres database and Realtime infrastructure to establish connections. The system uses private Realtime channels for bidirectional messaging and presence tracking, eliminating the need for custom socket servers or VPN configurations.
How does the Remote MCP ensure that tool calls are executed exactly once?
The implementation uses markCallExecuting() to atomically update the call status from pending to executing before processing. This check-and-set pattern prevents race conditions where multiple clients might attempt to process the same call, ensuring exactly-once execution semantics even during network reconnections.
What happens if the connection between the local device and Supabase drops?
The RemoteChannel class runs a health check every 10 seconds via checkConnectionHealth(). If the connection drops or becomes unstable, recreateChannel() automatically rebuilds the connection with exponential backoff and jitter. The system also falls back to a legacy postgres_changes listener if the primary broadcast channel fails repeatedly.
Can multiple local devices receive calls from the same ChatGPT or Claude account?
Yes. Each device registers independently in the mcp_devices table with a unique device ID and presence key. However, the current implementation typically routes calls to the most recently active device or specific device IDs based on the registration flow defined in registerDevice(), allowing users to specify which machine should handle automation requests.
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 →