Summary
#4592 makes an unrepresentable native-capability tool survivable: offerableToolDescriptor (apps/desktop/src/main/runtime-host-native-capabilities.ts) skips a tool whose schema can't be expressed over the Client Capability protocol and console.warns it, instead of failing the whole registration. That's a strictly better trade than the total outage it replaces — but it swaps a loud failure for a silent one: a skipped tool simply vanishes from the offer, and the only diagnostic is a main-process console line the user never sees.
Where the user actually looks, the tool still reads as live. The Settings MCP page renders the MCP manager's snapshot directly:
apps/desktop/src/renderer/mcp-page.tsx:922-924 shows status.tools.length and lists status.tools by name.
status.tools comes from McpServerStatus (packages/core/src/mcp.ts:308), which is populated by the MCP manager and knows nothing about the Desktop offer probe.
So a server can report "connected, N tools" in Settings while the model was handed fewer than N — the dropped tool is present in the manager snapshot but absent from the capability offer. No error, no indication which tool is missing or why.
Impact
Correctness of the surface, not of execution — the model genuinely doesn't have the skipped tool, and calling it isn't possible, so there's no wrong-result risk. But a user debugging "why won't the model use tool X" gets no signal from the UI, and the count in Settings actively contradicts what's available. Common triggers are ordinary MCP output: a JSON Schema keyword outside the protocol allowlist (prefixItems from a pydantic tuple[...], contentEncoding from bytes, patternProperties, not, if/then/else, deprecated), pending allowlist widening in #4614.
Proposal
Thread the skipped-tool information back to a user-visible seam so Settings can show which tools were dropped and why:
McpServerStatus already carries error?: string and stderrTail?: string[] — a parallel field (e.g. unofferedTools / skippedTools, name + reason) is a natural place, and mcp-page.tsx already renders status.error / status.stderrTail, so the row has somewhere to put it.
- The offer probe in
runtime-host-native-capabilities.ts already knows the exact serverId/name and the decode error at skip time; the gap is purely plumbing that back to the manager/status, which currently runs on the offering side and never reaches the manager snapshot.
Notes
Filed with Claude Code.
Summary
#4592 makes an unrepresentable native-capability tool survivable:
offerableToolDescriptor(apps/desktop/src/main/runtime-host-native-capabilities.ts) skips a tool whose schema can't be expressed over the Client Capability protocol andconsole.warns it, instead of failing the whole registration. That's a strictly better trade than the total outage it replaces — but it swaps a loud failure for a silent one: a skipped tool simply vanishes from the offer, and the only diagnostic is a main-process console line the user never sees.Where the user actually looks, the tool still reads as live. The Settings MCP page renders the MCP manager's snapshot directly:
apps/desktop/src/renderer/mcp-page.tsx:922-924showsstatus.tools.lengthand listsstatus.toolsby name.status.toolscomes fromMcpServerStatus(packages/core/src/mcp.ts:308), which is populated by the MCP manager and knows nothing about the Desktop offer probe.So a server can report "connected, N tools" in Settings while the model was handed fewer than N — the dropped tool is present in the manager snapshot but absent from the capability offer. No error, no indication which tool is missing or why.
Impact
Correctness of the surface, not of execution — the model genuinely doesn't have the skipped tool, and calling it isn't possible, so there's no wrong-result risk. But a user debugging "why won't the model use tool X" gets no signal from the UI, and the count in Settings actively contradicts what's available. Common triggers are ordinary MCP output: a JSON Schema keyword outside the protocol allowlist (
prefixItemsfrom a pydantictuple[...],contentEncodingfrombytes,patternProperties,not,if/then/else,deprecated), pending allowlist widening in #4614.Proposal
Thread the skipped-tool information back to a user-visible seam so Settings can show which tools were dropped and why:
McpServerStatusalready carrieserror?: stringandstderrTail?: string[]— a parallel field (e.g.unofferedTools/skippedTools, name + reason) is a natural place, andmcp-page.tsxalready rendersstatus.error/status.stderrTail, so the row has somewhere to put it.runtime-host-native-capabilities.tsalready knows the exactserverId/nameand the decode error at skip time; the gap is purely plumbing that back to the manager/status, which currently runs on the offering side and never reaches the manager snapshot.Notes
Filed with Claude Code.