multica-ai/multica · error
missing required field `type` (must be "local" or "remote",
Error message
missing required field `type` (must be "local" or "remote", or use bare {"enabled": bool} to override an inherited server) What it means
Returned when a mcp_config entry has no `type` field and is not the bare {"enabled": bool} override shape that OpenCode supports for disabling an inherited server. The validator deliberately collapses two failure modes (strict-decode failure on unknown fields, or a missing/nullable `enabled`) into one friendly message, because the user usually tried to write a local/remote server and forgot `type`.
Source
Thrown at server/pkg/agent/opencode_mcp.go:260
}
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))
}
}
case "":
// No `type` field. The bare `{"enabled": bool}` override shape
// is OpenCode's third native variant; anything else without a
// type is a malformed local/remote attempt. Surface a single
// friendly "missing type" error instead of the strict-decode
// "json: unknown field" leak — the user usually didn't realise
// they were mis-using the override shape.
var entry opencodeMCPEnabledOnly
if err := strictDecode(raw, &entry); err != nil || entry.Enabled == nil {
return nil, wrap(errors.New("missing required field `type` (must be \"local\" or \"remote\", or use bare {\"enabled\": bool} to override an inherited server)"))
}
default:
return nil, wrap(fmt.Errorf("invalid type %q (must be \"local\" or \"remote\")", typeStr))
}
// Validation passed; re-decode the raw bytes into map[string]any for
// the output. Identical observable representation, just typed as a
// generic map for the caller.
var out map[string]any
if err := json.Unmarshal(raw, &out); err != nil {
return nil, wrap(fmt.Errorf("parse: %w", err))
}
return out, nil
}
// strictDecode runs a json.Decoder with DisallowUnknownFields so any
// field outside the target struct's tags is rejected, enforcing the
// schema's `additionalProperties: false`.View on GitHub (pinned to 2c0912b6ec)
Solutions
- Add "type": "local" (with `command`) or "type": "remote" (with `url`) to the entry.
- For pure enable/disable of an inherited server, use exactly {"enabled": true} or {"enabled": false} with no other keys.
- Move any transport fields (command/url/env) into the typed form rather than mixing them with the override shape.
Example fix
// before
"mcp_config": { "fs": { "command": ["npx", "-y", "server-fs"] } }
// after
"mcp_config": { "fs": { "type": "local", "command": ["npx", "-y", "server-fs"] } } Defensive patterns
Strategy: validation
Validate before calling
function validateMCPEntryShape(e: Record<string, unknown>): string | null {
const keys = Object.keys(e);
if (!('type' in e)) {
const bare = keys.length === 1 && typeof e['enabled'] === 'boolean';
if (!bare) return 'entry needs `type` (local/remote) or must be exactly {"enabled": boolean}';
}
return null;
} Type guard
function isMCPOverrideEntry(e: Record<string, unknown>): e is { enabled: boolean } {
return Object.keys(e).length === 1 && typeof e['enabled'] === 'boolean';
} Prevention
- Remember the three legal shapes: {"type":"local",...}, {"type":"remote",...}, and exactly {"enabled": bool}.
- Mixing transport fields into the override shape is always an error — pick the typed form instead.
When it happens
Trigger: Writing {"command": ["npx", ...]} or {"url": "https://..."} without "type"; writing {"enabled": "true"} (string, fails strict decode); writing {} (empty object, `enabled` is nil).
Common situations: Assuming the server kind is inferred from which fields are present; copying configs from tools that don't require a discriminator; attempting the override shape but with extra fields or a non-boolean enabled.
Related errors
- entry must be a JSON object
- local server missing required field `command`
- remote server missing required field `url`
- config must be a JSON object
- config must not be empty
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/0811335995545cc5.
Report an issue: GitHub.