{"record":{"id":"aa0464cc1b0c2839","repo":"farion1231/cc-switch","slug":"error","errorCode":null,"errorMessage":"服务器配置必须是对象","messagePattern":"服务器配置必须是对象","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/utils/tomlUtils.ts","lineNumber":103,"sourceCode":"      if (serverIds.length > 0) {\n        const firstServer = mcpObj.servers[serverIds[0]];\n        return normalizeServerConfig(firstServer);\n      }\n    }\n  }\n\n  throw new Error(\n    \"无法识别的 TOML 格式。请提供单个 MCP 服务器配置，或使用 [mcp_servers.<id>] 格式\",\n  );\n};\n\n/**\n * 规范化服务器配置对象为 McpServer 格式\n * 保留所有字段（包括扩展字段如 timeout_ms）\n */\nfunction normalizeServerConfig(config: any): McpServerSpec {\n  if (!config || typeof config !== \"object\") {\n    throw new Error(\"服务器配置必须是对象\");\n  }\n\n  const type = (config.type as string) || \"stdio\";\n\n  // 已知字段列表（用于后续排除）\n  const knownFields = new Set<string>();\n\n  if (type === \"stdio\") {\n    if (!config.command || typeof config.command !== \"string\") {\n      throw new Error(\"stdio 类型的 MCP 服务器必须包含 command 字段\");\n    }\n\n    const server: McpServerSpec = {\n      type: \"stdio\",\n      command: config.command,\n    };\n    knownFields.add(\"type\");\n    knownFields.add(\"command\");","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/farion1231/cc-switch/blob/a2e22f330273a5b6ffa87cb8b82b624601bac562/src/utils/tomlUtils.ts#L85-L121","documentation":"normalizeServerConfig (reached via tomlToMcpServer) requires each server entry to be a table/object ('Server config must be an object'). It fires when the selected value - e.g. mcp_servers.<id> - is a scalar (string/number/boolean) instead of a table, or null/undefined from the tolerated mcp.servers extraction path.","triggerScenarios":"TOML like 'mcp_servers.foo = \"bar\"' (inline string instead of a [mcp_servers.foo] table), or an mcp.servers.<id> entry that extracts to null.","commonSituations":"Writing key = \"value\" where a [table] section was intended; a paste that loses the table header line so fields vanish.","solutions":["Use table syntax: [mcp_servers.foo] on its own line, then the field lines below it","Make sure every mcp_servers.<id> entry is a table, not an inline scalar"],"exampleFix":"# before (throws)\nmcp_servers.foo = \"bar\"\n\n# after\n[mcp_servers.foo]\ncommand = \"npx\"\nargs = [\"-y\", \"some-server\"]","handlingStrategy":"type-guard","validationCode":"const parsed = parseToml(normalizeTomlText(tomlText)) as Record<string, unknown>;\nconst entry = (parsed.mcp_servers as Record<string, unknown> | undefined)?.myServer;\nif (!isServerTable(entry)) {\n  setImportError(\"Server entry must be a [table], not key = value\");\n}","typeGuard":"function isServerTable(v: unknown): v is Record<string, unknown> {\n  return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  const server = tomlToMcpServer(tomlText);\n} catch (e) {\n  if (e instanceof Error && e.message === \"服务器配置必须是对象\") {\n    setImportError(\"Each mcp_servers.<id> entry must be a table\");\n  } else {\n    throw e;\n  }\n}","preventionTips":["Author server entries as [mcp_servers.<id>] tables, never inline scalars","Validate pasted TOML shape before converting","Keep table headers on their own line so entries parse as tables"],"tags":["toml","mcp","type-safety","import"],"backgroundTag":null,"analyzedSha":"a2e22f330273a5b6ffa87cb8b82b624601bac562","analyzedAt":"2026-08-16T03:46:07.889Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}