Conversation
The save handler read the document with `model.toJSON()` before entering its try block. That call is `JSON.parse` on the editor's text, so a typo in the user's edit threw straight past the error handling: no notification, nothing in the UI at all, only a message in the devtools console. The handler runs when the document goes clean, so the tab looked saved while the server still held the previous config. Move the save into `saveMCPConfig`, which takes the read as a thunk so it cannot end up outside the guarded path again, and returns a description instead of throwing out of a signal handler with nowhere to put it. A parse failure names itself as invalid JSON and keeps the parser's position so the user can find the typo; a server rejection passes through with its own message. The capabilities refresh that follows a successful save no longer rejects unobserved, and is not reported as a save failure, because the save did succeed. Closes plmbr#466
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Saving malformed JSON in the MCP config editor dropped the edit with no feedback anywhere in the UI. The only trace was a
SyntaxErrorin the devtools console, and because the save handler runs when the document goes clean, the editor tab looked saved while the server still held the previous config.Solution
MCPConfigEditor._onSaveread the document withthis._docWidget.context.model.toJSON()one line above itstry. That call isJSON.parse(this.sharedModel.getSource() || 'null')in@jupyterlab/docregistry, so a syntax error in the user's edit threw before the error handling was in scope. The existingcatchwas written for server-side rejections and never saw a client-side parse failure.The save now lives in
saveMCPConfig, which takes the document read as a thunk. That is the load-bearing decision: the parse cannot end up outside the guarded path again, because the function that guards it is the one that calls it. It returns a description rather than throwing, so nothing rejects out of a signal handler that has nowhere to put it.describeMCPConfigSaveErrorchooses the wording. A parse failure says the file is not valid JSON and keeps the parser's position; a server rejection passes through with its own message. The message is deliberately terse because JupyterLab truncates a notification at 140 characters, and the part that would be cut is the trailing(line 64 column 10)that locates the typo. Measured on a realistic eight-server config, the old phrasing produced 139 characters against that limit; the current one produces 127.Two smaller corrections came out of review:
String(reason)on a plain object renderedFailed to save MCP config: [object Object]at the user. That case now says the save failed for an unknown reason.Testing
tests/ts/mcp-config-save.test.ts, 10 tests. Four pinsaveMCPConfigitself: a parse failure must not reach the server or refresh capabilities, a server rejection must not refresh capabilities, a success must post the parsed config and refresh, and a failed refresh must not turn a successful save into a failure. The rest cover the wording, including that aSyntaxErrorand anErrorcarrying identical text are described differently.tryfailsreports a parse failure without reaching the server, and restoring it passes. An earlier version of this branch tested only the message formatter, and that version survived the same mutation with all tests green.jlpm tsc --noEmitclean,jlpm lint:checkclean,jlpm jest543 passed across 46 suites.Failed to save MCP config: not valid JSON. Expected ',' or '}' after property value in JSON at position 294 (line 10 column 1)(126 characters, inside the truncation limit). Restoring the brace and saving succeeds with no notification.Risks / follow-ups
The document still goes clean on a failed save, which is JupyterLab's save lifecycle rather than something this handler controls; the notification is what tells the user the config did not persist. Holding the document dirty on failure would give the tab an unsaved marker and a close confirmation, which is worth considering separately.
MCPConfigEditor.open()is also called without observing its promise, so a failure ingetMCPConfigFileorclaimMCPTempFileNameopens nothing and says nothing. Same class of problem, different trigger, left alone here to keep this change to one issue.Closes #466