farion1231/cc-switch · warning · Error

服务器配置必须是对象

Error message

服务器配置必须是对象

What it means

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.

Source

Thrown at src/utils/tomlUtils.ts:103

      if (serverIds.length > 0) {
        const firstServer = mcpObj.servers[serverIds[0]];
        return normalizeServerConfig(firstServer);
      }
    }
  }

  throw new Error(
    "无法识别的 TOML 格式。请提供单个 MCP 服务器配置,或使用 [mcp_servers.<id>] 格式",
  );
};

/**
 * 规范化服务器配置对象为 McpServer 格式
 * 保留所有字段(包括扩展字段如 timeout_ms)
 */
function normalizeServerConfig(config: any): McpServerSpec {
  if (!config || typeof config !== "object") {
    throw new Error("服务器配置必须是对象");
  }

  const type = (config.type as string) || "stdio";

  // 已知字段列表(用于后续排除)
  const knownFields = new Set<string>();

  if (type === "stdio") {
    if (!config.command || typeof config.command !== "string") {
      throw new Error("stdio 类型的 MCP 服务器必须包含 command 字段");
    }

    const server: McpServerSpec = {
      type: "stdio",
      command: config.command,
    };
    knownFields.add("type");
    knownFields.add("command");

View on GitHub (pinned to a2e22f3302)

Solutions

  1. Use table syntax: [mcp_servers.foo] on its own line, then the field lines below it
  2. Make sure every mcp_servers.<id> entry is a table, not an inline scalar

Example fix

# before (throws)
mcp_servers.foo = "bar"

# after
[mcp_servers.foo]
command = "npx"
args = ["-y", "some-server"]
Defensive patterns

Strategy: type-guard

Validate before calling

const parsed = parseToml(normalizeTomlText(tomlText)) as Record<string, unknown>;
const entry = (parsed.mcp_servers as Record<string, unknown> | undefined)?.myServer;
if (!isServerTable(entry)) {
  setImportError("Server entry must be a [table], not key = value");
}

Type guard

function isServerTable(v: unknown): v is Record<string, unknown> {
  return typeof v === "object" && v !== null && !Array.isArray(v);
}

Try / catch

try {
  const server = tomlToMcpServer(tomlText);
} catch (e) {
  if (e instanceof Error && e.message === "服务器配置必须是对象") {
    setImportError("Each mcp_servers.<id> entry must be a table");
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: Writing key = "value" where a [table] section was intended; a paste that loses the table header line so fields vanish.

Related errors


AI-assisted analysis of farion1231/cc-switch@a2e22f3302 (2026-08-16). Data as JSON: /api/errors/aa0464cc1b0c2839. Report an issue: GitHub.