Skip to content

opencode-config-valid

opencode.json and opencode.jsonc must parse and use keys and MCP server shapes OpenCode reads

Severity error (auto)
Autofix -
Since v0.20.0
Repo Types opencode
Category OpenCode

Why

opencode.json is where an OpenCode project declares its MCP servers, its agents and its slash commands. It ships in the repository, so a shape its loader rejects stops OpenCode from starting for everyone on the team, and a misspelled key fails quietly: OpenCode does not find the key it wanted and carries on with a default. An MCP server whose command was written as a string rather than an argv array makes OpenCode refuse to start at all.

OpenCode configuration schemas have evolved: 1.x spellings (agent, command, permission, flat MCP server declarations) and 2.0 spellings (agents, commands, permissions, nested mcp.servers) are both supported.

OpenCode merges agent/agents and command/commands by entry name. Different names may appear in both sections; only conflicting definitions of the same name are reported. One-to-one renamed settings still accept either spelling but report when both are present.

The MCP servers declared in OpenCode configuration are also evaluated by policy rules such as mcp-prohibited.

Severity

Errors — OpenCode refuses to load a project configuration with any of these, so opencode exits before it starts:

  • The top-level document is not an object, or the file has syntax errors (comments and trailing commas in .jsonc are supported).
  • An agent or command section that is not an object, an entry that is not an object, a template that is not a non-empty string, or an entry field of the wrong type.
  • An MCP server with a missing or unknown type, a command that is not a non-empty array of strings, a non-string or empty url, an environment, headers or oauth that is not an object (oauth: false is the documented way to switch OAuth off), a timeout that is neither a number nor an object of startup/catalog/execution/request, or a non-boolean enabled/disabled.
  • Committed credentials or secrets detected in MCP server URLs, headers, or environment mappings.

The one shape OpenCode tolerates is a server carrying a boolean enabled: the 1.x mcp union has a bare {"enabled": …} toggle branch that ignores other properties, so a broken server with enabled loads as a toggle and simply never starts. Its shape findings are warnings.

Warnings — the file loads, but one setting is dead: both spellings of one renamed key (including the 1.x and 2.0 OAuth field names), a server declared under both layouts at once, a $schema that is not a string, and a $schema pointing at https://opencode.ai/tui.json, which describes tui.json rather than this file.

Information-level findings never fail a build:

  • An unrecognized top-level key. OpenCode's schema changes weekly, so a key this release has not heard of is more likely new than wrong — extra-keys accepts it without waiting for a skillsaw release.
  • An unrecognized key on an MCP server. Same reasoning, same remedy: extra-keys covers these too.
  • A $schema that is neither the documented URL nor the TUI one. A vendored or mirrored copy is legitimate, so this is a note rather than a defect.

Examples

Bad — a Claude-shaped MCP server in an OpenCode config, and a file that declares one setting twice:

{
  "$schema": "https://opencode.ai/config.json",
  "agent": { "reviewer": { "prompt": "Review this change." } },
  "agents": { "reviewer": { "system": "Review this change." } },
  "mcp": {
    "playwright": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@playwright/mcp@latest"]
    }
  }
}

type: "stdio" is not a transport OpenCode knows, command must be the argv array, there is no args key, and agent/agents define reviewer differently. OpenCode merges those sections and keeps the agent entry when names overlap. The unknown transport is reported first and on its own: the rest of a server's shape depends on which transport it is, so those checks resume once type is fixed and the file is linted again.

Good, 1.x spelling — comments and a trailing comma are fine:

{
  "$schema": "https://opencode.ai/config.json",
  // Local servers are spawned directly, so command is argv.
  "mcp": {
    "playwright": {
      "type": "local",
      "command": ["npx", "-y", "@playwright/mcp@latest"],
      "enabled": true,
    }
  },
  "agent": {
    "reviewer": {
      "description": "Reviews a diff for correctness bugs",
      "prompt": "Review this change.",
      "disable": false
    }
  }
}

Good, 2.0 spelling — the same configuration after migrating:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "servers": {
      "playwright": {
        "type": "local",
        "command": ["npx", "-y", "@playwright/mcp@latest"],
        "disabled": false,
        "timeout": { "catalog": 30000, "execution": 30000 }
      }
    }
  },
  "agents": {
    "reviewer": {
      "description": "Reviews a diff for correctness bugs",
      "system": "Review this change.",
      "disabled": false
    }
  }
}

How to fix

  • Give every MCP server a type of local or remote. A local server needs command as a non-empty array of strings; a remote server needs a url.
  • Entries with different names may be split between agent/agents or command/commands; OpenCode merges them. Keep only one definition when the same name occurs in both sections. For one-to-one settings, keep one spelling: prompt or system, enabled or disabled. enabled and disabled are the same switch with the sense inverted, so a server carrying both is saying two different things.
  • Replace a committed credential with OpenCode's substitution syntax:
{ "headers": { "Authorization": "Bearer {env:MY_API_KEY}" } }

{env:VAR} and {file:./path} both work, and skillsaw recognises them as placeholders.

  • For a key newer than this skillsaw release, accept it without waiting. One list covers both places a key can be unrecognized — the top level and an MCP server entry:
rules:
  opencode-config-valid:
    extra-keys:
      - somethingNew      # a new top-level key
      - elicitation       # a new key on an MCP server

Configuration

rules:
  opencode-config-valid:
    enabled: auto  # true | false | auto
    severity: error
Parameter Description Default
extra-keys Additional config keys to accept, at the top level or on an MCP server entry, for keys newer than this skillsaw release []

Run skillsaw explain opencode-config-valid to see this documentation and the rule's effective configuration in your terminal.