feat(mcp): JSON-paste path in Add MCP server dialog#285
Merged
Conversation
Mehmet asked for a paste-friendly alternative to filling in the form
field-by-field. The dialog now has:
- Scope moved to the top of the dialog (was the second field).
- A "Form" / "JSON" tabbed control below Scope.
- JSON mode renders a single textarea; submit parses the paste into the
existing IClaudeMCPAddInput shape and forwards to the same add path
the form uses.
The paste parser is lenient about copy-paste artefacts:
- bare `"server-key": { ... }` (the common copy-from-docs shape)
- wrapped `{ "server-key": { ... } }`
- full `{ "mcpServers": { "server-key": { ... } } }`
- stray leading or trailing comma
Multi-server payloads, empty objects, and non-object server values are
rejected with guiding error messages.
`configToInput` honors an explicit `transport` field when it matches
the rest of the config and rejects mismatches (stdio without command,
sse/http without url) rather than silently downgrading -- six-agent
review flagged the silent-downgrade as a real footgun.
Pure helpers (`parseMcpJsonEntry`, `configToInput`, `parseKVLines`)
moved to `src/components/claude-mcp-paste.ts` so the unit tests don't
need to drag in the React tree to exercise them.
The Form / JSON toggle is a proper WAI-ARIA tablist with arrow-key
navigation, roving `tabindex`, and focus management on mode change.
A `useEffect` skips the first run so the initial mount doesn't steal
focus from the Scope select.
Tests: 23 jest cases in `tests/ts/claude-mcp-paste.test.ts` covering
the parser branches, the IClaudeMCPAddInput mapping, and the explicit-
transport mismatch rejections that came out of the agent review.
Closes plmbr#278
pjdoland
added a commit
to pjdoland/notebook-intelligence
that referenced
this pull request
May 22, 2026
Promotes the [Unreleased] CHANGELOG snapshot to [5.0.0] - 2026-05-22 and expands it to cover everything merged into upstream/main after PR plmbr#287's docs refresh. Bumps package.json to 5.0.0. CHANGELOG additions cover the post-plmbr#287 surface: - Settings tabs: plugin marketplace picker (plmbr#284), plugin marketplace details + Update button (plmbr#303), per-workspace MCP disable (plmbr#286), JSON-paste path in Add MCP server (plmbr#285). - Launchers: hide-with-policy (plmbr#288), brand icons for Codex / opencode (plmbr#325, plmbr#333), per-launch directory picker (plmbr#332). - Chat sidebar and agentic UX: workspace @-mention in Claude mode (plmbr#327), reload-open-files-on-disk (plmbr#330), steered system prompt away from over-eager notebook creation (plmbr#336). - Skills: multi-manifest support (plmbr#321), tracks-upstream for user- imported skills (plmbr#322), HTTP kill switch for the reconciler (plmbr#291). - Accessibility: full sub-section covering plmbr#305-plmbr#320. - Security: shell-tool sandbox (plmbr#290), Claude UI-bridge sandbox (plmbr#323), 0o600 on encrypted token (plmbr#293), env-secret scrubbing (plmbr#295), MCP config shape validation (plmbr#299), XSS allowlist (plmbr#296), Copilot WS auth + origin (plmbr#301), GHE host detection (plmbr#292), fastmcp -> mcp SDK swap (plmbr#324). - Fixed: session listing unification (plmbr#310), session preview unwrap (plmbr#331), down-area runtime throw (plmbr#330 follow-up), WS message-handler leak (plmbr#294). - Removed: fastmcp dependency, history.jsonl session gate. Adds a Migration note covering the five behavior changes operators should review before upgrading from 4.x: fastmcp swap, path sandboxes, history.jsonl gate removal, workspace @-mention pointer shape, and the Copilot WebSocket auth/origin tightening. Two reviewer rounds (six personas each) applied: - Round 1 caught security overclaims (plmbr#293, plmbr#299, plmbr#323), the plmbr#284/plmbr#303 mis-attribution, missing migration note, 3 em dashes, and the stale `fastmcp==2.x.*` recommendation in the admin guide. - Round 2 caught the missing plmbr#301 migration bullet, missing version- matrix 5.0.x row, missing README TOC entry, and a couple of style nits (sub-heading overpromise, orphan bullet). Skipped (deferred to future PRs): - README first-run tour mention. - Admin guide HTTP kill-switch row in Failure-modes table. - Terminal drag-drop trust-model precision update after plmbr#327. - Cipher description nit in plmbr#293 (Fernet AES-128-CBC+HMAC, not AES-GCM).
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
@mbektas asked for a paste-friendly alternative to the field-by-field form when adding an MCP server. The dialog now has Scope at the top, a Form/JSON tab control below it, and a JSON textarea that parses common copy-paste shapes into the same
IClaudeMCPAddInputshape the form already emits.Solution
Dialog layout. Scope is the first field. Below it, a WAI-ARIA
tablisttoggles between Form and JSON. The Form panel is the existing inputs; the JSON panel is a single textarea with a representative placeholder.Paste parser (
src/components/claude-mcp-paste.ts). Accepts:"server-key": { ... }(the shape that lands when you copy a single entry out of a.mcp.json){ "server-key": { ... } }{ "mcpServers": { "server-key": { ... } } }Multi-server payloads, empty objects, non-object server values, and unparseable input are rejected with guiding error messages.
configToInputtranslates a parsed entry intoIClaudeMCPAddInput, inferringtransportfrom the shape, but honors an explicittransportfield when present and rejects mismatches (stdio with no command; sse/http with no url) rather than silently downgrading. Six-agent review flagged the silent-downgrade as a real footgun.Helpers moved to a sibling module (
claude-mcp-paste.ts) so the unit tests don't drag the React tree in to exercise pure data functions.A11y. The Form/JSON control uses
role="tablist"(notradiogroup, which doesn't fit a UI that swaps the rendered subtree). Arrow-Left / Arrow-Right move between tabs with rovingtabindex. AuseEffectfocuses the right input when the user actively switches modes but skips the first run so it doesn't steal focus from the Scope select on initial mount.Testing
pytest tests/ --ignore=tests/test_claude_client.py -q(709 passed).jlpm tsc --noEmit,jlpm lint:check,jlpm jestall green; new jest suiteclaude-mcp-paste.test.tsis 23 cases covering each paste shape, the empty / multi-server / non-object / array / primitive rejections, the explicit-transport-mismatch rejections (the footgun fix), andIClaudeMCPAddInputmapping (stringification of env values, http inference, sse override, unrecognized transport falls back to shape).Manual: opened the dialog locally, confirmed Scope sits at the top, tab semantics work with keyboard, paste of the issue's example JSON populates correctly.
Risks / follow-ups
//comments. A future enhancement could pre-strip JSON-with-comments via a small regex pass, but the standard error message ("Invalid JSON: ...") is informative enough for now.Closes #278