You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
failOnStartupError defaults to false and its name promises that a bad MCP entry degrades to "that server is unavailable". It does not cover a config validation failure, and the default makes that promise to every host that never sets it.
boot() sets stage = 'plugin tree failed to load' and calls mountRootInclude; any throw lands in the catch, disposes the whole context and rethrows. Validation of an entry's config happens before that entry activates, so failOnStartupError never gets a chance to apply — it governs a server that fails to start, not an entry that fails to parse.
For an embedding host the result is all-or-nothing: one malformed optional entry and the harness is gone. In the case that prompted this, an unset environment variable in one MCP server's env produced a dead harness with no listener rather than a harness missing one tool.
Being fair to the design
An all-or-nothing mount is defensible, and the code is explicit that it is transactional — the comments around the mount reason clearly about a partially mounted tree being ambiguous. The problem is narrower than "make it lenient": the flag's name and default describe behaviour the flag cannot deliver.
Three options, in the order the reporting consumer preferred them
Make the flag cover the whole entry lifecycle, validation included: a failOnStartupError: false entry that fails to parse is skipped with a loud warning and the rest of the tree mounts. This is what the name already describes.
Keep validation fatal but say so — document that the flag applies only after a valid entry begins starting, and that a config error is unconditionally fatal. Cheapest honest option; a host then guards its own input knowingly rather than by accident.
Give the host a boundary — let a config-tree layer be marked non-essential, so a host can declare which plugins are load-bearing. For the consumer here the MCP servers, a vision bridge and a skin are all optional; the client UI is not.
We took option 2 in a fork, documenting the boundary on both config interfaces rather than changing behaviour, because making validation non-fatal per entry means making the transactional mount partial and that is a design decision rather than a fix.
Option 3 is the one that actually fits the problem, and it is why this is filed here rather than carried as a patch: it is a design proposal, not something a fork should invent.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
failOnStartupErrordefaults tofalseand its name promises that a bad MCP entry degrades to "that server is unavailable". It does not cover a config validation failure, and the default makes that promise to every host that never sets it.boot()setsstage = 'plugin tree failed to load'and callsmountRootInclude; any throw lands in the catch, disposes the whole context and rethrows. Validation of an entry's config happens before that entry activates, sofailOnStartupErrornever gets a chance to apply — it governs a server that fails to start, not an entry that fails to parse.For an embedding host the result is all-or-nothing: one malformed optional entry and the harness is gone. In the case that prompted this, an unset environment variable in one MCP server's
envproduced a dead harness with no listener rather than a harness missing one tool.Being fair to the design
An all-or-nothing mount is defensible, and the code is explicit that it is transactional — the comments around the mount reason clearly about a partially mounted tree being ambiguous. The problem is narrower than "make it lenient": the flag's name and default describe behaviour the flag cannot deliver.
Three options, in the order the reporting consumer preferred them
failOnStartupError: falseentry that fails to parse is skipped with a loud warning and the rest of the tree mounts. This is what the name already describes.We took option 2 in a fork, documenting the boundary on both config interfaces rather than changing behaviour, because making validation non-fatal per entry means making the transactional mount partial and that is a design decision rather than a fix.
Option 3 is the one that actually fits the problem, and it is why this is filed here rather than carried as a patch: it is a design proposal, not something a fork should invent.
All reactions