{"record":{"id":"7a96e310a809128f","repo":"CherryHQ/cherry-studio","slug":"invalid-manifest-missing-server-mcp-config","errorCode":null,"errorMessage":"Invalid manifest: missing server.mcp_config","messagePattern":"Invalid manifest: missing server\\.mcp_config","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/mcp/McpPackageService.ts","lineNumber":559,"sourceCode":"        }\n        manifest = { ...parsedManifest, manifest_version: parsedManifest.manifest_version }\n      } else {\n        if (!parsedManifest.dxt_version) {\n          throw new Error('Invalid manifest: missing dxt_version')\n        }\n        manifest = { ...parsedManifest, dxt_version: parsedManifest.dxt_version }\n      }\n      if (!manifest.name) {\n        throw new Error('Invalid manifest: missing name')\n      }\n      if (!manifest.version) {\n        throw new Error('Invalid manifest: missing version')\n      }\n      if (!manifest.server) {\n        throw new Error('Invalid manifest: missing server configuration')\n      }\n      if (!manifest.server.mcp_config) {\n        throw new Error('Invalid manifest: missing server.mcp_config')\n      }\n      if (!manifest.server.mcp_config.command) {\n        throw new Error('Invalid manifest: missing server.mcp_config.command')\n      }\n      if (!Array.isArray(manifest.server.mcp_config.args)) {\n        throw new Error('Invalid manifest: server.mcp_config.args must be an array')\n      }\n\n      // Use server name as the final extract directory for automatic version management\n      const serverDirName = `server-${manifest.name}`\n      const finalExtractDir = ensurePathWithin(this.mcpDir, path.join(this.mcpDir, serverDirName))\n\n      // Stage the new package first, then swap directories so a failed install\n      // does not destroy the last working version.\n      await this.replacePackageDirectory(tempExtractDir, finalExtractDir, serverDirName)\n      logger.debug(`${packageLabel} server extracted to: ${finalExtractDir}`)\n\n      // Clean up the uploaded package file if it's in temp directory","sourceCodeStart":541,"sourceCodeEnd":577,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/McpPackageService.ts#L541-L577","documentation":"Thrown during manifest validation when the server object exists but has no mcp_config field. The mcp_config object holds the command, args, and env that the service ultimately resolves via applyPlatformOverrides and uses to spawn the MCP server process. server.type and server.entry_point are present in the type but mcp_config is the load-bearing field for launch.","triggerScenarios":"manifest.json has a server object that includes type and entry_point but omits mcp_config, or sets it to null. The author may have assumed entry_point alone is enough to launch.","commonSituations":"Schema confusion: an author who saw both entry_point and mcp_config in examples included only entry_point; a generator that emits server but leaves mcp_config for the user to fill; a manifest copied from a runtime (e.g. Claude Desktop) that nests config under a different key.","solutions":["Add server.mcp_config with at minimum { command, args } so the service knows how to launch the server.","If you intended to use entry_point only, note that this service still requires mcp_config; set command to the runtime (e.g. \"node\") and args to [\"${__dirname}/<entry_point>\"] referencing server.entry_point.","Repackage and re-upload."],"exampleFix":"// manifest.json - before\n\"server\": { \"type\": \"node\", \"entry_point\": \"./server.js\" }\n// after\n\"server\": { \"type\": \"node\", \"entry_point\": \"./server.js\",\n  \"mcp_config\": { \"command\": \"node\", \"args\": [\"${__dirname}/server.js\"] } }","handlingStrategy":"validation","validationCode":"function serverHasMcpConfig(manifest: any): boolean {\n  return !!manifest?.server && typeof manifest.server.mcp_config === 'object' && manifest.server.mcp_config !== null\n}","typeGuard":"function hasMcpConfig(m: any): m is { server: { mcp_config: object } } {\n  return !!m?.server && typeof m.server.mcp_config === 'object' && m.server.mcp_config !== null\n}","tryCatchPattern":null,"preventionTips":["Always include server.mcp_config with at least { command, args } when authoring a manifest.","Validate the manifest against the published JSON Schema in CI so a missing mcp_config fails the build.","If you only set entry_point, remember this service still requires mcp_config; set command to the runtime and args to the entry point."],"tags":["mcp","manifest","validation","mcp-config"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}