How Cherry Studio Handles Deep Link Protocols (cherrystudio://)

Cherry Studio registers the custom URL scheme cherrystudio:// in the main process via Electron's setAsDefaultProtocolClient, routes incoming URLs through handleProtocolUrl() in ProtocolClient.ts, and dispatches them to specialized handlers for MCP server installation, provider configuration, or generic IPC messages to the renderer process.

Cherry Studio is an open-source AI client built with Electron that enables external applications and web services to launch and control the app through custom deep links. The repository at cherryhq/cherry-studio implements a complete protocol handling system that works consistently across macOS, Windows, and Linux (including AppImage distributions) by registering the cherrystudio:// scheme and parsing incoming URLs to trigger specific actions.

Protocol Registration and OS Integration

When the application starts, the main process immediately registers the custom protocol to ensure the OS recognizes cherrystudio:// links.

Registering the URL Scheme

The registerProtocolClient(app) function in src/main/services/ProtocolClient.ts (lines 15-25) calls Electron's app.setAsDefaultProtocolClient('cherrystudio'). This registers the scheme with the operating system so that any cherrystudio:// URL opens in Cherry Studio rather than the default browser.

For Linux AppImage builds, deep linking requires additional desktop integration. The setupAppImageDeepLink() function (lines 60-99 in src/main/services/ProtocolClient.ts) creates a cherrystudio-url-handler.desktop file containing:

MimeType=x-scheme-handler/cherrystudio;

The code then executes update-desktop-database to register the handler with the system MIME database, enabling AppImage users to open cherrystudio:// links from browsers and other applications.

Cherry Studio handles protocol activation differently depending on the operating system, as implemented in src/main/index.ts.

macOS open-url Events

On macOS, Electron emits the open-url event when a user clicks a cherrystudio:// link. The main process listens via app.on('open-url', (event, url) => { ... }) (lines 221-243) and immediately forwards the URL string to the protocol router.

Windows and Linux Second-Instance Handling

Windows and Linux do not use open-url. Instead, when a deep link activates an already-running instance, Electron fires the second-instance event. The code extracts the protocol URL from process.argv (lines 28-36 and 36-44 in src/main/index.ts), scanning for any argument that starts with cherrystudio://.

URL Routing and Action Dispatch

Once captured, all protocol URLs flow through handleProtocolUrl(url) in src/main/services/ProtocolClient.ts (lines 27-44). The function parses the URL and dispatches based on the hostname:

switch (urlObj.hostname.toLowerCase()) {
  case 'mcp':       handleMcpProtocolUrl(urlObj);   break;
  case 'providers': handleProvidersProtocolUrl(urlObj); break;
  default:          sendToRendererViaIPC(urlObj);
}

If the hostname matches neither mcp nor providers, the data is forwarded to the renderer process via the protocol-data IPC channel for custom handling.

Specialized Protocol Handlers

Cherry Studio implements specific handlers for common deep-link workflows, accepting Base64-encoded JSON payloads to configure the application state.

Installing MCP Servers via Protocol

The handleMcpProtocolUrl function in src/main/services/urlschema/mcp-install.ts processes URLs formatted as:


cherrystudio://mcp/install?servers=<base64-JSON>

The handler decodes the servers parameter and installs the specified Model Context Protocol (MCP) servers directly into the user's configuration. Each server installed via this method receives installSource: 'protocol' and defaults to isTrusted: false, triggering security warnings in the UI.

The providers handler in src/main/services/urlschema/handle-providers.ts manages URLs like:


cherrystudio://providers/api-keys?data=<base64-JSON>

This decodes the provider configuration (including API keys and base URLs) and navigates the renderer to the provider settings page, automatically populating the form fields with the supplied data.

Renderer Process Communication and Security

The protocol system includes security boundaries to protect users from malicious deep links.

IPC Bridge for Generic Protocol Data

The preload script in src/preload/index.ts (lines 65-74) exposes window.api.protocol.onReceiveData(), which wraps ipcRenderer.on('protocol-data', ...). Renderer code can subscribe to this API to receive arbitrary protocol URLs not handled by the main process sub-routes:

const unsubscribe = window.api.protocol.onReceiveData(({ url, params }) => {
  console.log('Deep link received:', url);
});

This mechanism powers OAuth callbacks, such as the PPIO implementation in src/renderer/src/utils/oauth.ts, where the provider redirects to cherrystudio://?code=XYZ and the renderer extracts the authorization code.

Security Warnings for Protocol-Installed MCPs

When an MCP server is installed via a deep link, the ProtocolInstallWarning.tsx component renders a prominent warning in the settings UI. Because isTrusted defaults to false for protocol-installed servers, users must explicitly review and trust the configuration before the server becomes active, mitigating risks from malicious cherrystudio://mcp/install links.

Practical Code Examples

// Define the MCP server configuration
const config = {
  mcpServers: {
    everything: {
      command: 'npx',
      args: ['-y', '@modelcontextprotocol/server-everything']
    }
  }
};

// Encode and construct the URL
const base64 = Buffer.from(JSON.stringify(config)).toString('base64');
const url = `cherrystudio://mcp/install?servers=${base64}`;

// Trigger from a web page or external app
window.open(url);
const provider = {
  id: 'tokenflux',
  baseUrl: 'https://tokenflux.ai/v1',
  apiKey: 'sk-xxxx',
  name: 'TokenFlux',
  type: 'openai'
};

// URL-safe Base64 encoding
const json = JSON.stringify(provider);
const base64 = Buffer.from(json).toString('base64')
               .replace(/\+/g, '_')
               .replace(/\//g, '-');

const url = `cherrystudio://providers/api-keys?v=1&data=${base64}`;
window.open(url); // Opens Cherry Studio and navigates to provider settings

Listening for Protocol Data in the Renderer

import { useEffect } from 'react';

useEffect(() => {
  const unsubscribe = window.api.protocol.onReceiveData(({ url, params }) => {
    // Handle OAuth callbacks or custom deep link data
    console.log('Protocol data:', url, params);
  });
  
  return unsubscribe;
}, []);

Summary

  • Protocol Registration: registerProtocolClient() in src/main/services/ProtocolClient.ts registers cherrystudio:// via Electron APIs and creates Linux desktop entries for AppImage support.
  • Cross-Platform Capture: macOS uses open-url events while Windows/Linux extract URLs from second-instance argv, as implemented in src/main/index.ts.
  • Central Router: handleProtocolUrl() parses the hostname and dispatches to handleMcpProtocolUrl(), handleProvidersProtocolUrl(), or falls back to IPC.
  • Secure Installation: MCP servers installed via protocol receive installSource: 'protocol' and isTrusted: false, triggering UI warnings in ProtocolInstallWarning.tsx.
  • Renderer Bridge: The preload script exposes protocol.onReceiveData() for OAuth flows and custom deep-link handling via the protocol-data IPC channel.

Frequently Asked Questions

Cherry Studio registers the cherrystudio:// scheme (not cherry://). This is defined in src/main/services/ProtocolClient.ts where app.setAsDefaultProtocolClient('cherrystudio') is called during application startup.

The setupAppImageDeepLink() function creates a .desktop file with MimeType=x-scheme-handler/cherrystudio; and runs update-desktop-database to register the handler with the system. This allows AppImage distributions to intercept cherrystudio:// URLs without requiring system-wide installation.

Can I trigger OAuth flows using Cherry Studio's protocol handler?

Yes. The renderer can listen for protocol data via window.api.protocol.onReceiveData() (exposed in src/preload/index.ts). When an OAuth provider redirects to cherrystudio://?code=XYZ, the URL is captured in the main process and forwarded via IPC to the renderer, which extracts the code and completes the token exchange, as demonstrated in the PPIO OAuth implementation.

What security measures exist for protocol-installed MCP servers?

Servers installed via cherrystudio://mcp/install are marked with installSource: 'protocol' and default to isTrusted: false. The UI renders a warning component (ProtocolInstallWarning.tsx) alerting users that the server originated from an external link and requires explicit trust verification before activation.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →