Invalid input mcp.mcp-image
The config looked right. It matched the MCP examples I’d seen. It worked in Claude Desktop. But OpenCode rejected it on startup.
The Symptom
I copied an MCP server configuration that worked elsewhere:
{
"mcp": {
"mcp-image": {
"type": "stdio",
"command": "npx",
"args": ["-y", "mcp-image"],
"env": {
"GEMINI_API_KEY": "...",
"IMAGE_OUTPUT_DIR": "..."
}
}
}
}
OpenCode’s validation failed immediately. No helpful error message—just “Invalid input.”
The Investigation
First attempt: maybe I needed "type": "stdio" explicitly? Added it. Still failed.
The breakthrough came from reading OpenCode’s actual documentation instead of assuming MCP configs were universal. The schema was different:
Claude Desktop / Cline format:
{
"type": "stdio",
"command": "npx",
"args": ["-y", "mcp-image"],
"env": { ... }
}
OpenCode format:
{
"type": "local",
"command": ["npx", "-y", "mcp-image"],
"environment": { ... }
}
Three differences:
type: "local"instead oftype: "stdio"commandis an array including all args, no separateargsfieldenvironmentinstead ofenv
The Fix
{
"mcp": {
"mcp-image": {
"type": "local",
"command": ["npx", "-y", "mcp-image"],
"environment": {
"GEMINI_API_KEY": "...",
"IMAGE_OUTPUT_DIR": "..."
}
}
}
}
Validation passed. Server started.
Why Schemas Differ
MCP (Model Context Protocol) defines the wire protocol—how the host and server communicate. It doesn’t mandate how hosts should configure servers.
Each host implements its own configuration layer:
- Claude Desktop: JSON with
command+argsseparation - OpenCode: JSON with
commandas array - Cline: Similar to Claude Desktop
- Continue: YAML-based config
The MCP spec covers message formats and capabilities. Configuration is a host implementation detail.
The Broader Lesson
Don’t assume config portability across MCP hosts. When moving servers between hosts:
- Find the host’s docs - Not generic MCP docs
- Check schema differences - Field names, value types, structure
- Test in isolation - Validate config before assuming it works
Common differences across hosts:
| Aspect | May Vary |
|---|---|
| Type names | stdio vs local vs process |
| Command format | String vs array vs object |
| Env var field | env vs environment vs envVars |
| Args handling | Separate field vs in command array |
| Working dir | Different field names |
Prevention Pattern
Keep host-specific configs in separate files:
~/.config/
├── claude-desktop/
│ └── mcp-servers.json # Claude format
├── opencode/
│ └── opencode.json # OpenCode format
└── mcp-servers/
└── mcp-image/
└── README.md # Server-specific notes
When adding a new server, don’t copy from other hosts. Start from the host’s documentation or example configs.
Minimal Configs That Load
When debugging, start with the simplest possible config:
OpenCode minimal:
{
"mcp": {
"echo-test": {
"type": "local",
"command": ["echo", "hello"]
}
}
}
Claude Desktop minimal:
{
"mcpServers": {
"echo-test": {
"command": "echo",
"args": ["hello"]
}
}
}
If the minimal config loads, add fields one at a time until you find the problematic one.
Validation Checklist
Before starting the host:
# 1. Check JSON syntax
python3 -m json.tool < opencode.json > /dev/null && echo "JSON OK"
# 2. Check required fields exist
jq '.mcp | to_entries[] | select(.value.type == null) | .key' opencode.json
# Should return nothing if all servers have "type"
# 3. Check command is array (OpenCode)
jq '.mcp | to_entries[] | select(.value.command | type != "array") | .key' opencode.json
# Should return nothing
The Takeaway
MCP is a protocol, not a configuration standard. Each host that speaks MCP can configure servers however it wants. The wire format is compatible; the config files are not.
The error “Invalid input” was correct—my input was invalid for OpenCode’s schema. It just happened to be valid for a different host’s schema.
When “it works elsewhere” doesn’t work here, you’re looking at a schema mismatch, not a broken server.
When config works in one place but fails in another, check if you’re using the right schema for the right host. Same protocol doesn’t mean same config.
