Hmbown/CodeWhale · error · anyhow::Error
Invalid MCP entry; contents omitted
Error message
Invalid MCP entry; contents omitted
What it means
Each imported server entry must be a JSON object. If a value in the server map (or an array element) is a string, number, array, or null, checked_source throws this error instead of attempting to import it. Contents are omitted from the message.
Solutions
- Expand shorthand entries into full objects with a command field: "fs": {"command": "npx", "args": [...]}
- Remove or replace null/placeholder entries in the source map before importing
- If the source uses string shorthands, convert them manually — the importer only accepts object entries
Example fix
// before (string shorthand entry)
{ "mcpServers": { "fs": "npx -y fs" } }
// after
{ "mcpServers": { "fs": { "command": "npx", "args": ["-y", "fs"] } } } Defensive patterns
Strategy: validation
Validate before calling
fn entries_are_objects(path: &std::path::Path) -> bool {
std::fs::read_to_string(path).ok()
.and_then(|s| serde_json::from_str::<serde_json::Value>(&s).ok())
.and_then(|v| v.get("mcpServers").or_else(|| v.get("servers")).cloned())
.and_then(|m| m.as_object().cloned())
.map(|m| m.values().all(|e| e.is_object()))
.unwrap_or(false)
} Type guard
fn as_server_object(v: &serde_json::Value) -> Option<&serde_json::Map<String, serde_json::Value>> {
v.as_object()
} Try / catch
match discover(&path) {
Err(e) if e.to_string().contains("Invalid MCP entry") => {
eprintln!("a server entry is not a JSON object; expand shorthand strings to objects");
}
r => r?,
} Prevention
- Always write server entries as objects with a command (or url) field
- Avoid null placeholders in server maps; remove unused entries entirely
- Do not use string shorthand like "fs": "npx -y fs" in exported configs
- Lint the source map: every value must be a JSON object before import
When it happens
Trigger: discover / discover_from_json_file where any entry under mcpServers/servers (or any element of a top-level array) is not a JSON object — e.g. "fs": "npx some-server" shorthand, or null placeholders.
Common situations: Importing a config that uses string shorthand for commands; entries left as null after manual cleanup; a list of names rather than a map of objects; copy-paste dropped an object's braces.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Source contains an unsupported server name
- Source contains unsupported MCP fields; review it at its…
- A managed, project or plugin connector already uses this…
- bad_target
- bundle contains conflicting or rejected entries
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/53f0c03955cd124c.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/mcp/external_import.rs:157
.or_else(|| value.get("servers"))
.is_some_and(Value::is_object)
|| value.is_array(),
"Source has no supported MCP server map"
);
let mut out = Vec::new();
for (name, mut config) in extract_servers_map(&value) {
anyhow::ensure!(
super::mcp_name_is_command_safe(&name) && name.len() <= 128,
"Source contains an unsupported server name"
);
if value.is_array()
&& let Some(map) = config.as_object_mut()
{
map.remove("name");
}
let fields = config
.as_object()
.ok_or_else(|| anyhow::anyhow!("Invalid MCP entry; contents omitted"))?;
const ALLOWED: &[&str] = &[
"command",
"args",
"env",
"cwd",
"url",
"allow_private_network",
"transport",
"connect_timeout",
"execute_timeout",
"read_timeout",
"disabled",
"enabled",
"required",
"enabled_tools",
"disabled_tools",
"headers",
"env_headers",View on GitHub (pinned to 73e0f67d83)