Skip to content

Desktop: enforce Client Capability aggregate limits so a large MCP config can't fail the whole native-capability registration #4652

Description

@liuxiaocs7

Summary

#4592 isolates per-tool schema failures so one unrepresentable tool no longer drops every Desktop capability. But the isolation validates each tool independently; the final registration bundles all surviving tools into offers and is sent as a single frame via ClientCapabilityChannel.replace(). The protocol enforces aggregate limits that per-tool validation cannot see, so a large (but entirely valid) MCP configuration still fails the whole registration and takes Browser, Computer Use, Client settings, Rive and MCP down together — the same outage shape as #4591.

Reachable outage (reproduced on this branch)

  • desktop_mcp is a single offer holding all MCP tools (apps/desktop/src/main/runtime-host-boot.ts). 65 completely valid MCP tools → the offer has 65 tools → decodeClientCapabilityReplaceInput throws Invalid Client Capability offer tools (per-offer cap CLIENT_CAPABILITY_MAX_TOOLS_PER_OFFER = 64) → the whole frame is rejected in replace() → on first registration every Desktop capability disappears.
    • Repro: offer tool counts [["desktop_browser",1],["desktop_mcp",65]] → rejected: Invalid Client Capability offer tools.
  • Total-tool cap CLIENT_CAPABILITY_MAX_TOOLS = 256 and manifest cap CLIENT_CAPABILITY_MAX_MANIFEST_BYTES = 56 KiB are likewise unguarded by per-tool probing: several mid-size schemas (each ≤ 32 KiB and individually legal) can exceed the aggregate manifest.
  • MCP discovery permits up to 1000 tools (packages/mcp/src/tool-discovery.ts), so >64 is realistic with a few servers.

Limits: packages/runtime-host/src/protocol/client-capability.ts (CLIENT_CAPABILITY_MAX_OFFERS = 32, _MAX_TOOLS_PER_OFFER = 64, _MAX_TOOLS = 256, _MAX_MANIFEST_BYTES = 56 * 1024). Assembly + isolation: apps/desktop/src/main/runtime-host-native-capabilities.ts.

Proposed

  • Split the MCP capability into multiple offers of ≤ 64 tools (desktop_mcp, desktop_mcp_2, …; offerId must match [A-Za-z0-9_-]{1,128}).
  • Deterministically trim tools that exceed the total-count / manifest-byte budget, warning about what was dropped (no silent caps).
  • Keep the core capabilities (Browser, Computer Use, Client settings, Rive) prioritized so MCP overflow can never evict them.
  • Run a final decodeClientCapabilityReplaceInput on the fully assembled manifest so provider.offers() always decodes — the registration can never fail the whole frame.

Acceptance

  • A workspace with > 64 MCP tools registers (serving up to the protocol caps) instead of failing the whole frame; the non-MCP capabilities always register.
  • Tests cover the 65-tool split and aggregate byte/count trimming.

Follow-up to #4592. Related: #4591, #4614.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions