can1357/oh-my-pi · error · Error

Invalid server config: ${errors.join("; ")}

Error message

Invalid server config: ${errors.join("; ")}

What it means

addMCPServer() validates the server name and config shape before writing to the MCP config JSON file. This error is thrown when validateServerConfig() returns one or more problems: the config mixes "command" and "url", a stdio server lacks "command", an http/sse server lacks "url", or an unknown "type" was given. All problems are joined with "; " in the message so one throw reports everything wrong.

Source

Thrown at packages/coding-agent/src/mcp/config-writer.ts:120

}

/**
 * Add an MCP server to a config file.
 * Validates the config before writing.
 *
 * @throws Error if server name already exists or validation fails
 */
export async function addMCPServer(filePath: string, name: string, config: MCPServerConfig): Promise<void> {
	// Validate server name
	const nameError = validateServerName(name);
	if (nameError) {
		throw new Error(nameError);
	}

	// Validate the config
	const errors = validateServerConfig(name, config);
	if (errors.length > 0) {
		throw new Error(`Invalid server config: ${errors.join("; ")}`);
	}

	// Serialize the read-modify-write under a per-file lock so a concurrent
	// mutation cannot overwrite this one (lost update). The lock also guards
	// against cross-process writers sharing the same config file.
	await withConfigLock(filePath, async () => {
		const existing = await readMCPConfigFile(filePath);

		// Check for duplicate name
		if (existing.mcpServers?.[name]) {
			throw new Error(`Server "${name}" already exists in ${filePath}`);
		}

		const updated: MCPConfigFile = {
			...existing,
			mcpServers: {
				...existing.mcpServers,
				[name]: config,

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the joined messages in the error; each names the server and the exact missing/conflicting field.
  2. For stdio servers keep "command" (plus optional args/env) and delete any "url" field.
  3. For http/sse servers set "url" and delete "command"/"args".
  4. Set "type" to one of "stdio" (default), "http", or "sse".
  5. Pre-validate with validateServerConfig(name, config) before calling addMCPServer in scripts/UI flows.

Example fix

// before
await addMCPServer(cfgPath, "docs", { type: "stdio", command: "npx", url: "https://mcp.example.com" } as any);
// after
await addMCPServer(cfgPath, "docs", { type: "http", url: "https://mcp.example.com" });
Defensive patterns

Strategy: validation

Validate before calling

import { validateServerConfig } from "@oh-my-pi/pi-coding-agent/mcp/config";
const errors = validateServerConfig(name, config);
if (errors.length > 0) throw new Error(errors.join("; "));

Type guard

function isStdioConfig(c: { type?: string; command?: string; url?: string }): boolean {
  const t = c.type ?? "stdio";
  return t === "stdio" ? !!c.command && !c.url : false;
}

Try / catch

try {
  await addMCPServer(cfgPath, name, config);
} catch (e) {
  if (e instanceof Error && e.message.startsWith("Invalid server config:")) {
    showValidationHint(e.message);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling addMCPServer(filePath, name, config) (directly or via handleAddCommand or the MCP wizard's #handleWizardComplete) with: config containing both command and url; a stdio config with no command; type "http" or "sse" with no url; or type set to an unrecognized value.

Common situations: Copying a config entry from a different MCP client and leaving stale fields (e.g. adding a url while keeping command); hand-editing JSON and dropping the command field; misspelling type (e.g. "streamable" instead of "http"); a wizard/UI form submitting an empty command.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/13d1857bbcc240ef. Report an issue: GitHub.