multica-ai/multica · error

local server missing required field `command`

Error message

local server missing required field `command`

What it means

Returned when a mcp_config entry declares "type": "local" but its strict-decoded object has an empty or absent `command` field. Local servers in OpenCode's native MCP config are launched from a command argv, so `command` is mandatory. The strict decoder also means unknown fields fail first, so reaching this error means the object decoded cleanly and only `command` is missing.

Source

Thrown at server/pkg/agent/opencode_mcp.go:230

	}
	if err := json.Unmarshal(raw, &probe); err != nil {
		return nil, wrap(fmt.Errorf("parse: %w", err))
	}
	var typeStr string
	if probe.Type != nil {
		if err := json.Unmarshal(*probe.Type, &typeStr); err != nil {
			return nil, wrap(fmt.Errorf("`type` must be a string, got %s", strings.TrimSpace(string(*probe.Type))))
		}
	}

	switch typeStr {
	case "local":
		var entry opencodeMCPLocal
		if err := strictDecode(raw, &entry); err != nil {
			return nil, wrap(err)
		}
		if len(entry.Command) == 0 {
			return nil, wrap(errors.New("local server missing required field `command`"))
		}
		if entry.Timeout != nil && *entry.Timeout <= 0 {
			return nil, wrap(fmt.Errorf("`timeout` must be a positive integer, got %d", *entry.Timeout))
		}
	case "remote":
		var entry opencodeMCPRemote
		if err := strictDecode(raw, &entry); err != nil {
			return nil, wrap(err)
		}
		if entry.URL == "" {
			return nil, wrap(errors.New("remote server missing required field `url`"))
		}
		if entry.Timeout != nil && *entry.Timeout <= 0 {
			return nil, wrap(fmt.Errorf("`timeout` must be a positive integer, got %d", *entry.Timeout))
		}
		if len(entry.OAuth) > 0 {
			if err := validateOpenCodeOAuth(entry.OAuth); err != nil {
				return nil, wrap(fmt.Errorf("`oauth`: %w", err))

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Add the launch argv: "command": ["npx", "-y", "@modelcontextprotocol/server-foo"].
  2. Check for typos in the key name (must be exactly `command`) and ensure it is a non-empty array of strings.
  3. Verify no unknown fields like `cmd` are present — strict decoding rejects those with a different error before this check.

Example fix

// before
"mcp_config": { "fs": { "type": "local" } }

// after
"mcp_config": { "fs": { "type": "local", "command": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/data"] } }
Defensive patterns

Strategy: validation

Validate before calling

function validateLocalEntry(e: { type: string; command?: unknown }): string | null {
  if (e.type === 'local' && (!Array.isArray(e.command) || e.command.length === 0)) {
    return 'local MCP server requires a non-empty `command` array';
  }
  return null;
}

Type guard

function isLocalMCPEntry(e: Record<string, unknown>): e is { type: 'local'; command: string[]; timeout?: number } {
  return e.type === 'local' && Array.isArray(e.command) && e.command.length > 0 &&
    e.command.every((c) => typeof c === 'string');
}

Prevention

When it happens

Trigger: Setting {"type": "local"} or {"type": "local", "timeout": 30} with no "command" key, or with "command": [] (zero-length array), for a named server in mcp_config.

Common situations: Authoring a local stdio MCP server entry and forgetting the command argv; using an env-var substitution that expands to empty; migrating a config that stored the command under a different key (e.g. "cmd" or "args" only).

Related errors


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/27c9d30f2898e49f. Report an issue: GitHub.