routes/mcp_routes.py declares POST /api/mcp/servers with FastAPI
Form(...) params. The Save handler in static/js/settings.js was
sending application/json, so the Form parser saw no fields and
returned 422 with "Field required" for every input — clicking Save
did nothing visible.
Build a FormData object and let the browser set the multipart
Content-Type. args/env are JSON-stringified per the controller
contract (defaults "[]" / "{}"); bad JSON still falls back to
defaults, same as before.
Also check r.ok and surface non-2xx in the form-status span — the
previous code never checked status, so a 422 looked like success.
Matches the FormData pattern already used in this file (uf-mcp-toggle,
~L4036) for the toggle-enable PATCH against the same controller.
Co-authored-by: Toji <ccryptoji@gmail.com>
Hoist the HTML-escape lookup table in static/js/ui.js out of the
String.replace callback so it is allocated once instead of on every
matched character. esc() is the canonical escaper aliased across 27
modules and runs on essentially every render, so this removes a lot of
short-lived garbage on the hottest text path. Output is byte-identical
(verified across null/undefined/emoji/attribute edge cases).
Also build the <select> option lists in cookbook-hwfit.js and group.js
by accumulating a string and assigning innerHTML once, instead of
`innerHTML +=` inside a forEach (which makes the browser re-parse the
element's markup on every iteration). Final DOM is unchanged.
Pure micro-optimizations; no behavior change.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>