{"record":{"id":"4c43d2d6b5bf8159","repo":"CherryHQ/cherry-studio","slug":"invalid-server-type","errorCode":null,"errorMessage":"Invalid server type","messagePattern":"Invalid server type","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/mcp/McpRuntimeService.ts","lineNumber":538,"sourceCode":"              getServerLogger(server).debug(`StreamableHTTPClientTransport options`, {\n                options: redactSensitive(options)\n              })\n              return new StreamableHTTPClientTransport(new URL(server.baseUrl), options)\n            } else if (urlBasedType === 'sse') {\n              const options: SSEClientTransportOptions = {\n                eventSourceInit: {\n                  fetch: async (url, init) => {\n                    return net.fetch(typeof url === 'string' ? url : url.toString(), init)\n                  }\n                },\n                requestInit: {\n                  headers: prepareHeaders()\n                },\n                authProvider\n              }\n              return new SSEClientTransport(new URL(server.baseUrl), options)\n            } else {\n              throw new Error('Invalid server type')\n            }\n          } else if (server.command) {\n            let cmd = server.command\n            let effectiveCommand = server.command\n\n            // Build a local env for the transport instead of mutating `server.env`. getServerKey(server)\n            // serializes server.env, so mutating it here would shift the key after connect — connect-time\n            // logs (emitServerLog) and list-changed cache invalidations would then land under a key that\n            // getServerLogs / the caches (which see the un-mutated server) never query. Keep server.env\n            // untouched so the key stays stable everywhere; see the \"deep-copy don't mutate\" pattern.\n            const connectEnv: Record<string, string> = { ...server.env }\n\n            // Get login shell environment first - needed for command detection and server execution\n            // Note: getShellEnv() is memoized, so subsequent calls are fast\n            const loginShellEnv = await getShellEnv()\n\n            // For package servers, use resolved configuration with platform overrides and variable substitution\n            if (server.dxtPath) {","sourceCodeStart":520,"sourceCodeEnd":556,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/McpRuntimeService.ts#L520-L556","documentation":"Thrown during transport creation when a server has a `baseUrl` set but its type (after applying typeOverride ?? server.type ?? 'sse') is neither 'streamableHttp' nor 'sse'. The URL-based transport branch only handles these two protocols; 'stdio' and 'inMemory' types with a baseUrl are contradictory and fall through to this guard.","triggerScenarios":"A server entity has `baseUrl` populated and `type` set to 'stdio' or 'inMemory'. The transport selection logic checks `server.baseUrl` first, then branches on `urlBasedType`; if urlBasedType isn't 'sse' or 'streamableHttp', it throws.","commonSituations":"Server was configured with a remote URL but type was accidentally set to 'stdio'; a migration or import set the type incorrectly; the user mixed up local (command-based) and remote (URL-based) server configurations.","solutions":["Set the server type to 'sse' or 'streamableHttp' when using a baseUrl","If the server is command-based (local), remove the baseUrl and set the command field instead","Check the MCP settings UI to ensure the type dropdown matches the connection method (URL vs command)","If importing a server config programmatically, validate that type and baseUrl/command are consistent"],"exampleFix":"// before\nconst server = {\n  name: 'my-server',\n  baseUrl: 'https://mcp.example.com/sse',\n  type: 'stdio'  // contradictory\n}\n\n// after\nconst server = {\n  name: 'my-server',\n  baseUrl: 'https://mcp.example.com/sse',\n  type: 'sse'\n}","handlingStrategy":"validation","validationCode":"function validateServerTypeConsistency(server: McpServer): void {\n  if (server.baseUrl && server.type && !['sse', 'streamableHttp'].includes(server.type)) {\n    throw new Error(`Server with baseUrl must use type 'sse' or 'streamableHttp', got '${server.type}'`)\n  }\n  if (server.command && server.type && !['stdio'].includes(server.type) && !server.baseUrl) {\n    // command-based servers typically use stdio\n  }\n}","typeGuard":"function isUrlBasedServerType(type: McpServerType | undefined): boolean {\n  return type === 'sse' || type === 'streamableHttp'\n}","tryCatchPattern":"try {\n  await runtime.getOrCreateClient(server)\n} catch (e) {\n  if (e instanceof Error && e.message === 'Invalid server type') {\n    // Fix the type field or remove baseUrl, then retry\n    server.type = server.baseUrl ? 'sse' : 'stdio'\n  }\n  throw e\n}","preventionTips":["When creating or editing a server, derive the type from whether baseUrl or command is set","Add a UI validation that prevents saving inconsistent type + baseUrl/command combinations","Use the getTransportCandidates helper to understand valid type mappings"],"tags":["mcp","transport","configuration","server-type"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}