Hmbown/CodeWhale · error · anyhow::Error
Source contains unsupported OAuth fields
Error message
Source contains unsupported OAuth fields
What it means
When discovering MCP servers from an external source file (Claude config, marketplace catalog), checked_source validates each server entry's fields against an allow-list before importing. If an entry declares an `oauth` object, only `client_id` is an accepted key; any other OAuth key causes this error and the whole source is rejected rather than partially imported.
Solutions
- Remove every key from the `oauth` object except `client_id`, keeping credentials in the environment instead
- Move secret material (client_secret, tokens) out of the shared source file entirely
- Re-export the source config using only fields from the tool's allowed set (command, args, env, url, oauth.client_id, etc.)
Example fix
// before
{"mcpServers":{"fs":{"command":"npx","oauth":{"client_id":"abc","client_secret":"zzz"}}}}
// after
{"mcpServers":{"fs":{"command":"npx","oauth":{"client_id":"abc"}}}} Defensive patterns
Strategy: validation
Validate before calling
const ALLOWED_OAUTH = new Set(["client_id"]);
function oauthKeysOk(server) {
const o = server.oauth;
return o == null || (typeof o === "object" && !Array.isArray(o) && Object.keys(o).every(k => ALLOWED_OAUTH.has(k)));
} Type guard
function hasOnlyClientIdOAuth(v) {
return v == null || (typeof v === "object" && !Array.isArray(v) && Object.keys(v).every(k => k === "client_id"));
} Prevention
- Keep OAuth secrets in environment variables, never in shared config files
- Before sharing a config, inspect oauth blocks for keys other than client_id
- Lint exported configs against the tool's field allow-list
When it happens
Trigger: `discover` or `discover_from_json_file` reads a source JSON whose server entry has `oauth` containing keys other than `client_id` — e.g. {"oauth":{"client_id":"x","client_secret":"y"}} or {"oauth":{"auth_url":"..."}}.
Common situations: Importing a config authored for another client that stores full OAuth client credentials (secret, redirect URI, scopes) in its MCP entry; hand-editing an oauth block with keys from a different tool's schema.
Related errors
- Codewhale-owned OAuth path escaped the credentials directory
- Codewhale-owned OAuth path has an invalid basename
- Codewhale-owned xAI OAuth DACL is not current-user-only
- Codewhale-owned xAI OAuth DACL must grant only one user
- Codewhale-owned xAI OAuth storage must have an owner-only…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/0124d8d14f9ad967.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/mcp/external_import.rs:187
"disabled",
"enabled",
"required",
"enabled_tools",
"disabled_tools",
"headers",
"env_headers",
"env_http_headers",
"bearer_token_env_var",
"scopes",
"oauth",
"oauth_resource",
];
anyhow::ensure!(
fields.keys().all(|key| ALLOWED.contains(&key.as_str())),
"Source contains unsupported MCP fields; review it at its source"
);
if let Some(oauth) = fields.get("oauth").filter(|v| !v.is_null()) {
anyhow::ensure!(
oauth
.as_object()
.is_some_and(|map| map.keys().all(|key| key == "client_id")),
"Source contains unsupported OAuth fields"
);
}
let server: McpServerConfig = serde_json::from_value(config)
.map_err(|_| anyhow::anyhow!("Invalid MCP entry; contents omitted"))?;
anyhow::ensure!(
server.command.is_some() != server.url.is_some(),
"MCP entry must have one target"
);
if let Some(command) = &server.command {
anyhow::ensure!(
!command.trim().is_empty() && !command.chars().any(char::is_control),
"Invalid MCP command"
);
}View on GitHub (pinned to 73e0f67d83)