CherryHQ/cherry-studio · warning · McpError
InvalidParams
InvalidParams
Error message
Unsupported product_info argument: ${unsupportedArgument} What it means
Thrown by the `product_info` MCP tool handler when the CallToolRequest arguments contain any property other than `source` or `section`. The tool's inputSchema declares `additionalProperties: false` (assistant.ts:138), so this is a defense-in-depth runtime re-check: the handler scans `Object.keys(args)` for any disallowed key. It exists because not every MCP client validates against the JSON Schema before dispatching, so the server enforces the contract itself.
Source
Thrown at src/main/ai/mcp/servers/assistant.ts:340
if (typeof routes !== 'object' || routes === null || Array.isArray(routes)) {
throw new McpError(ErrorCode.InternalError, 'Product manifest routes are invalid')
}
const allRoutes = (routes as Record<string, unknown>).all
if (!Array.isArray(allRoutes)) {
throw new McpError(ErrorCode.InternalError, 'Product manifest routes are invalid')
}
return allRoutes.filter(
(route): route is string =>
typeof route === 'string' &&
(route === '/settings' || route.startsWith('/settings/') || route.startsWith('/app/'))
)
}
private async productInfo(args: Record<string, unknown>) {
const unsupportedArgument = Object.keys(args).find((key) => key !== 'source' && key !== 'section')
if (unsupportedArgument) {
throw new McpError(ErrorCode.InvalidParams, `Unsupported product_info argument: ${unsupportedArgument}`)
}
if (args.source !== 'manifest') {
throw new McpError(ErrorCode.InvalidParams, `Unknown product_info source: ${String(args.source)}`)
}
const manifest = this.readProductManifest()
const packageRecord = manifest.package as Record<string, unknown>
const manifestVersion = packageRecord.version as string
const section = args.section
if (section !== undefined && (typeof section !== 'string' || section.trim().length === 0)) {
throw new McpError(ErrorCode.InvalidParams, "'section' must be a non-empty string")
}
let result: Record<string, unknown>
if (section === undefined) {
result = {
runtimeVersion: app.getVersion(),View on GitHub (pinned to 726446b54c)
Solutions
- Strip every property except `source` (required) and `section` (optional) from the arguments before calling.
- Re-fetch the tool list via ListTools and read the `product_info` inputSchema to confirm the accepted properties.
- If you genuinely need new data, extend the manifest and the tool schema in source rather than smuggling undocumented arguments.
Example fix
// before
client.callTool('product_info', { source: 'manifest', detail: true })
// after
client.callTool('product_info', { source: 'manifest' }) Defensive patterns
Strategy: validation
Validate before calling
// Before calling product_info, keep only accepted keys.
function sanitizeProductInfoArgs(args: Record<string, unknown>) {
const out: Record<string, unknown> = {}
if ('source' in args) out.source = args.source
if ('section' in args) out.section = args.section
return out
} Type guard
function isProductInfoArgs(
args: unknown
): args is { source: string; section?: string } {
if (typeof args !== 'object' || args === null) return false
const keys = Object.keys(args as Record<string, unknown>)
return keys.every((k) => k === 'source' || k === 'section')
} Try / catch
// The assistant server wraps thrown errors into an isError result (assistant.ts:274-281).
const res = await client.callTool('product_info', args)
if (res.isError) {
// res.content[0].text starts with "Error: Unsupported product_info argument:"
return sanitizeAndRetry(args)
} Prevention
- Treat the tool's inputSchema (with additionalProperties:false) as authoritative and never send extra keys.
- When dynamically building args, allow-list fields rather than passing through raw user/agent input.
When it happens
Trigger: Calling `product_info` with arguments like `{source:'manifest', detail:true}`, `{source:'manifest', version:1}`, or `{format:'json'}` — any object whose keys include something other than `source`/`section`.
Common situations: An LLM agent hallucinates an extra field (e.g. `detail`, `verbose`, `format`); a caller reuses an argument shape from a different tool; a client that does not run JSON-Schema validation before sending leaks through to the handler.
Related errors
- ErrorCode.InvalidParams
- InvalidParams
- InvalidParams
- Path traversal detected: target path must be direct child of
- Unsafe DXT entry path (zip-slip): ${name}
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/438bb75f4628a948.
Report an issue: GitHub.