How MCP Connectors Bridge External Agents to the Instatic Live Editor Workspace
The MCP connector establishes a persistent ND-JSON stream that registers a user-scoped bridge entry, enabling external AI agents to dispatch tool requests to the Instatic live editor and receive execution results through a bidirectional callback mechanism.
The CoreBunch/Instatic platform allows external AI agents to control the visual editor workspace through a specialized bridge architecture. This system connects server-side MCP tools to the browser-based live editor using a long-lived stream that maintains real-time synchronization. Understanding this mechanism reveals how AI-driven content operations execute safely within user-scoped sessions.
Creating the Live Editor Bridge
The connection initiates when the editor UI mounts and invokes createEditorBridgeStream(userId, scope, abortSignal) from server/ai/mcp/editorBridge.ts. This function establishes a persistent ND-JSON stream that serves as the communication backbone between the MCP server and the browser.
The bridge registers itself using a composite key of user ID and workspace scope. The scope parameter accepts either 'site' or 'content', determining whether the connector targets site-level configuration or content editing tools. The registry enforces a singleton pattern per user-scope combination: if a new connection opens for an existing user and scope, it automatically replaces the previous bridge entry.
// Client-side bridge initialization
const abort = new AbortController();
const ndjsonStream = createEditorBridgeStream(
currentUser.id,
'site',
abort.signal
);
// The UI reads events through this reader
ndjsonStream.getReader();
Server-Side Bridge Registry
The bridge registry stores active connections in a nested Map structure: Map<string, Map<EditorBridgeScope, EditorBridgeEntry>> (referenced as byUser in the source). This data structure enables efficient lookup and scope separation.
Two helper functions expose bridge availability to MCP tools:
getEditorBridgeForUser(userId, scope)returns the concreteAiBrowserBridgeinstance ornullif disconnectedhasEditorBridge(userId, scope)provides a boolean check for quick validation
Tools like those defined in server/ai/mcp/tools/contextTool.ts utilize these helpers to verify workspace reachability before attempting operations. The registry lives alongside the stream handling logic in server/ai/mcp/editorBridge.ts, while HTTP handlers in server/ai/mcp/handlers/editorBridge.ts wire the bridge into the MCP server via tryHandleAiEditorBridge.
Dispatching Tool Calls
When an external MCP client invokes a browser-side tool, the server executes a three-phase round-trip:
- Emission: The server retrieves the bridge via
getEditorBridgeForUserand callsbridge.callBrowser(), emitting atoolRequestevent down the ND-JSON stream containing the tool name and payload - Execution: The editor consumes the event through its stream reader, executes the requested operation (such as inserting HTML or applying CSS), and captures the result
- Resolution: The editor POSTs the result to
/admin/api/ai/tool-result, which resolves the original promise held by the bridge, completing the MCP tool invocation
// Server-side tool dispatch
if (hasEditorBridge(userId, 'site')) {
const bridge = getEditorBridgeForUser(userId, 'site')!;
bridge.callBrowser({
type: 'toolRequest',
tool: 'insertHtml',
payload: { html: '<p>Hello</p>' }
});
}
Security Model and Scope Isolation
The bridge implements strict user-scoped isolation. The registry keys entries by user ID, ensuring MCP connectors can only reach workspaces owned by their authenticated user. This prevents cross-user workspace access even if connection identifiers are compromised.
EditorBridgeScope provides secondary isolation between site and content contexts. A tool designed for site-level operations (such as theme adjustments) cannot dispatch to a content editor instance, and vice versa. This scope separation runs parallel to the user scoping, creating a two-dimensional permission boundary.
Connection Lifecycle and Cleanup
The bridge maintains connection health through active management mechanisms:
- Heartbeat: The stream writes empty lines every 25 seconds to prevent proxy timeouts and keep the connection alive
- Lease Timer: A
STREAM_LEASE_MSof 120,000 milliseconds (2 minutes) defines the maximum idle time before automatic cleanup - Signal Abort: Passing an
AbortControllersignal allows immediate bridge termination when the user navigates away or closes the editor - Replacement: New connections for the same user-scope pair automatically evict old entries, preventing stale bridge references
When cleanup triggers—whether through lease expiration, signal abortion, or explicit stream closing—the registry removes the entry from the byUser Map, ensuring no dangling references persist.
Summary
- The MCP connector creates a persistent ND-JSON stream via
createEditorBridgeStreaminserver/ai/mcp/editorBridge.tsto link external agents with the live editor - A user-scoped registry Map prevents unauthorized cross-user workspace access while
EditorBridgeScopeisolates site and content contexts - Tool execution follows a complete request-response cycle: emit via
callBrowser, execute in editor, POST result to/admin/api/ai/tool-result, resolve promise - Connection maintenance relies on 25-second heartbeats and a 120-second lease timer to handle disconnections gracefully
Frequently Asked Questions
What protocol does the MCP connector use to stream data to the Instatic editor?
The connector uses an ND-JSON (Newline Delimited JSON) stream format over a persistent HTTP connection. This protocol allows the server to push individual JSON messages to the browser as events occur, with each message separated by newline characters. The implementation includes empty-line heartbeats every 25 seconds to prevent connection timeouts through proxies and load balancers.
How does the system prevent MCP tools from accessing another user's workspace?
The bridge registry enforces user-scoped isolation by keying all entries with the user's unique ID. When an MCP tool calls getEditorBridgeForUser(userId, scope), it receives null if the requested user ID does not match the authenticated session that established the bridge. This design ensures that external agents can only manipulate workspaces explicitly connected to their own authenticated user session.
What happens if the editor disconnects while an MCP tool is executing?
The bridge implements a lease-based cleanup mechanism with STREAM_LEASE_MS set to 120,000 milliseconds. If the browser disconnects or stops responding, the lease expires and automatically removes the bridge entry from the registry. Additionally, the AbortController signal provided during createEditorBridgeStream initialization allows immediate cleanup when the user closes the tab or navigates away, preventing stale connections from accumulating server-side.
Where does the MCP server check if a live editor connection exists before dispatching tools?
MCP tools verify connection availability using the hasEditorBridge(userId, scope) helper function, as demonstrated in server/ai/mcp/tools/contextTool.ts. This boolean check queries the byUser registry Map without retrieving the full bridge instance, providing an efficient way to validate workspace reachability before attempting tool dispatch operations.
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 →