Skip to content

Backspace recursively escapes JSON tool inputs #1856

Closed

Description

@samriddh-johari

Summary

In the Inspector v2 web UI, editing a tool argument rendered by the fallback JsonInput can recursively quote and escape the textarea value. A single Backspace that makes an array or object temporarily invalid JSON turns the draft into a quoted string; subsequent edits add more quotes and backslashes.

This was observed with @modelcontextprotocol/inspector 2.0.0 and a sum_numbers tool whose numbers argument is correctly declared as an array of numbers.

Requested labels: bug, v2 (external reporters cannot apply repository labels).

Related tracking issue: #1015.

Reproduction

Use a tool with this input schema:

{
  "type": "object",
  "properties": {
    "numbers": {
      "type": "array",
      "items": { "type": "number" }
    }
  },
  "required": ["numbers"]
}
  1. Open the tool in the web Inspector.
  2. Enter a valid array such as [1, 2].
  3. Put the cursor after the closing ].
  4. Press Backspace.
  5. Continue pressing Backspace or editing the value.

Expected: the textarea contains the exact partially edited draft, such as [1, 2.

Actual: the textarea becomes a JSON-quoted string containing escaped characters. Each subsequent controlled render can add another escaping layer.

Root cause found locally

SchemaForm parses the fallback JsonInput on every change. When a draft is temporarily invalid JSON, it stores the raw text string in lifted form state. On the next controlled render, the value path calls JSON.stringify on that raw string, adding quotes and escapes. The next edit repeats the cycle.

A focused local fix keeps invalid object/array draft strings raw when converting lifted state back to the JsonInput display value. Valid arrays and objects continue to be parsed and formatted normally.

Verification

  • Confirmed the server contract test exposes numbers as type: "array" with numeric items.
  • Added a controlled SchemaForm regression test that removes the closing bracket/brace with Backspace and asserts the textarea retains the exact draft for both arrays and objects.
  • Verified the new test fails before the fix with a quoted value and passes after the fix.
  • npm run validate: passed.
  • Node 22.23.1 web coverage: 310 test files and 4,782 tests passed.
  • SchemaForm.tsx: 100% statements, branches, functions, and lines.

Environment:

  • Inspector: 2.0.0 (latest on 2026-07-29)
  • Client: Web
  • macOS 26.4
  • Validation runtime: Node 22.23.1

Exact prompt used

We’re investigating a possible MCP Inspector new UI bug.

Context:
- User pressed Backspace inside a tool argument textarea in MCP Inspector.
- Instead of deleting text normally, the textarea filled with escaped quote/backslash characters.
- Screenshot path: `/var/folders/v_/8t3y7x_914x0_dh93n_dfqx80000gn/T/codex-clipboard-c213f6ef-0501-42ec-bf23-f42e657968f7.png`
- Tool shown: `sum_numbers`
- Field shown: `Numbers *`
- Observed textarea content resembles repeated escaped JSON/string output, e.g. `"\"\\\\\\\\...\""`.

Prior reasoning:
- Backspace normally sends either ASCII `0x08` / `\b` / `^H`, or sometimes `0x7F` / `DEL` / `^?`.
- This behavior likely points to a controlled input bug, repeated `JSON.stringify`, double escaping, schema-to-form coercion issue, or custom keyboard handling.
- It may also be caused by the MCP server exposing the wrong schema for `numbers`.

Need to verify:
1. Check the MCP server tool schema for `sum_numbers`.
   Expected schema should make `numbers` an array of numbers, not a string:
   {
     "type": "object",
     "properties": {
       "numbers": {
         "type": "array",
         "items": { "type": "number" }
       }
     },
     "required": ["numbers"]
   }

If schema is correct, reproduce against the latest MCP Inspector.
The likely OSS repo is modelcontextprotocol/inspector; verify current repo and contribution docs before making changes.
Search the Inspector UI for textarea/input handling, JSON schema forms, argument editor components, JSON.stringify, escape helpers, and onKeyDown/onChange.
Fix root cause so Backspace edits normally and textarea state is not repeatedly escaped.
Add or update a regression test if the repo has relevant test patterns.
Prepare an OSS PR with a small focused fix and reproduction notes.

Goal:
Determine whether this is an MCP Inspector UI bug, fix it if confirmed, and prepare an open-source contribution.

Activity

  1. cliffhall commented on Aug 1, 2026

    @cliffhall
    Member

    Triage: Priority = Medium

    Scored 8/16 with the priority rubric added to AGENTS.md in #1891, as part of the backlog triage in #1872. Added to project board #28 with Status Incoming — meaning filed and scored but not yet approved for work. A maintainer decides whether it moves to Todo.

    Axis Score Reasoning
    Severity / impact 3/5 A single backspace turns a valid array into a quoted string and each further edit compounds it. Same blast radius as the other editor defects.
    Urgency / staleness 4/5 Reproduces on published 2.0.0.
    Signal bonuses +1 high engagement (3 reactions) (+1)
    Total 8 Lands in the Medium band (6-8).

    Related issues. These look connected and may be worth reading together:

    Scores are a starting point, not a verdict — the rubric is meant to be overruled when it's plainly wrong, provided the reason is written down.

  2. added this to the v2.3.0 milestone on Aug 5, 2026
  3. self-assigned this
    on Aug 16, 2026
  4. added a commit that references this issue on Aug 16, 2026
  5. cliffhall commented on Aug 16, 2026

    @cliffhall
    Member

    Fixed on v2/main and pinned by #2025.

    The root cause — unparseable draft text stored back as the field's value, then re-JSON.stringify'd on the next controlled render, adding a layer of escaping per keystroke — was removed by the draft/value split in SchemaJsonField (#1928, #2007) and the nullable-union collapse (#2014), with #2020 adding the submit gate for a field holding unsendable text. #2025 adds this report's own reproduction as a regression test; verified to fail against the pre-fix commit with exactly the corruption described here.

    Ships in v2.3.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingv2Issues and PRs for v2

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions