The mcp sub-API exposed on window.FrontPanelAPI for app
renderers whose effective bindings permission is "allow".
Lifecycle:
App calls register(...) for each tool it intends to expose
(must match a name in the package's mcp.json).
App calls useWorkQueue(...) once with the WorkQueue it uses
for UI device work, so MCP-driven work serializes against UI.
App calls ready() to publish the registration batch — one
tools/list_changed notification fires.
Subsequent register/unregister calls (e.g., when gateware
unlocks new capabilities) are microtask-coalesced into single
tools/list_changed notifications.
register / unregister / ready are async because the
authoritative validation lives in main (descriptor membership,
duplicate-name detection). Apps that await them learn at the
call site if the descriptor and code disagree, rather than later
at first tools/call. Apps that don't await still get console
errors via unhandled rejection — the local handler map is rolled
back on failure so the renderer's view stays consistent with main.
Error notes:
Errors thrown across IPC lose their prototype; consumers
discriminate on .name. register/unregister/ready
re-throw with that contract preserved.
The
mcpsub-API exposed onwindow.FrontPanelAPIfor app renderers whose effectivebindingspermission is"allow".Lifecycle:
register(...)for each tool it intends to expose (must match a name in the package'smcp.json).useWorkQueue(...)once with the WorkQueue it uses for UI device work, so MCP-driven work serializes against UI.ready()to publish the registration batch — onetools/list_changednotification fires.register/unregistercalls (e.g., when gateware unlocks new capabilities) are microtask-coalesced into singletools/list_changednotifications.register/unregister/readyare async because the authoritative validation lives in main (descriptor membership, duplicate-name detection). Apps thatawaitthem learn at the call site if the descriptor and code disagree, rather than later at firsttools/call. Apps that don't await still get console errors via unhandled rejection — the local handler map is rolled back on failure so the renderer's view stays consistent with main.Error notes:
.name.register/unregister/readyre-throw with that contract preserved.