Cosmo Docs
Desktop App

ConnectorManager

MCP OAuth flows and connector instance management

packages/desktop/src/main/connector-manager.ts handles everything related to adding, authenticating, and removing MCP connector instances in the desktop app.

ConnectorType

ConnectorType is an interface for provider catalog entries (not a string union):

FieldTypeDescription
serverIdstringProvider slug (e.g. "notion", "google-drive")
displayNamestringHuman-readable name
descriptionstringShort description
iconUrlstring?Provider logo URL
categorystring?Category for grouping
authModestringSERVER_MEDIATED / REMOTE_OAUTH / API_KEY / NONE
mcpTransportstringSTDIO / SSE / HTTP
mcpUrlstring?Remote server URL

ConnectorInfo

The type returned by listInstances:

FieldDescription
idDatabase record ID
instanceIdUnique ID for this connector instance
serverIdProvider ID (e.g. "notion", "google-drive")
labelHuman-readable name
hostingCLOUD / LOCAL
transportSTDIO / SSE / HTTP
statusCONNECTED / DISCONNECTED / CONNECTING / ERROR
lastErrorError message if status is ERROR
lastUsedAtLast usage timestamp
createdByuserId who created this instance
createdAtCreation timestamp

Key Methods

getAvailableConnectors()

Fetches the public connector provider catalog from GET /api/v1/connector-providers. Returns all enabled providers with display metadata (name, icon, category, auth mode). No authentication required.

listInstances(token, orgId)

Returns the combined list of connector instances:

  1. Fetches org-level instances from GET /api/v1/connectors (cloud DB).
  2. For REMOTE_OAUTH and NONE connectors, also checks the local registry (~/.cosmo/mcp.json).
  3. Merges both lists, deduplicating by instanceId.

addInstance(token, orgId, serverId, label)

Starts the appropriate auth flow based on the provider's authMode:

SERVER_MEDIATED

  1. Calls POST /api/v1/mcp-oauth/start to get an authUrl.
  2. Opens the URL in the system browser.
  3. The backend handles the OAuth exchange and stores credentials.
  4. Polls GET /api/v1/mcp-oauth/poll?state=... until credentials are ready.
  5. Creates the connector record via POST /api/v1/connectors.

REMOTE_OAUTH

  1. Calls ConnectorManager.startRemoteOAuth(serverId, instanceId).
  2. The OAuthCallbackServer binds to http://localhost:52625/oauth/callback.
  3. Opens the MCP server's authorization URL in the browser.
  4. Waits for the redirect with the authorization code.
  5. Exchanges the code for tokens using the MCP server's token endpoint.
  6. Saves tokens to userData/mcp-tokens/{instanceId}.json.
  7. Saves OAuth client info to userData/mcp-client/{instanceId}.json.
  8. Creates the connector record in the backend with hosting: CLOUD.

API_KEY

  1. The renderer collects the API key from the user.
  2. addInstance stores it via POST /api/v1/connectors/:id/credentials.

NONE

Connector is created immediately with no credential exchange.

removeInstance(token, orgId, instanceId)

  1. Deletes the connector from the backend via DELETE /api/v1/connectors/:instanceId.
  2. Removes local token files (mcp-tokens/{instanceId}.json, mcp-client/{instanceId}.json).
  3. Removes the entry from the local MCP registry.

OAuthCallbackServer

packages/desktop/src/main/oauth-callback-server.ts runs a local HTTP server on port 52625 (fixed, so it can be pre-registered as a redirect URI with OAuth providers).

MethodDescription
start()Binds to port 52625
waitForCode(state?)Returns Promise<code> — resolves when the browser redirects back
cancelPending(state?)Cancel without rejecting
stop()Shut down the server

The callback endpoint is GET /oauth/callback?code=...&state=.... After the redirect it shows a success or error page in the browser.

Timeout: 2 minutes per auth attempt.

Token Persistence

Remote OAuth tokens are stored per-instance in the app's userData directory:

All files live in the single mcp-tokens/ directory:

userData/
└── mcp-tokens/
    ├── {instanceId}.json           ← OAuth tokens { accessToken, refreshToken, expiresAt }
    └── {instanceId}-client.json    ← OAuth client info { clientId, clientSecret, ... }

saveRemoteTokens(instanceId, tokens) / loadRemoteTokens(instanceId) handle token reads and writes.
saveClientInfo(instanceId, info) / loadClientInfo(instanceId) handle client info reads and writes.