Skip to content

fix(desktop): prevent React #31 when MCP config contains non-string items (#1295)#1394

Merged
esengine merged 1 commit into
esengine:mainfrom
paradoxSCH:fix/desktop-mcp-react31-1295
May 20, 2026
Merged

fix(desktop): prevent React #31 when MCP config contains non-string items (#1295)#1394
esengine merged 1 commit into
esengine:mainfrom
paradoxSCH:fix/desktop-mcp-react31-1295

Conversation

@paradoxSCH

Copy link
Copy Markdown
Contributor

Summary

Fixes #1295 — Desktop MCP tools panel crashes with React error #31 ("Objects are not valid as a React child") when config.json contains non-string items in the mcp array.

Root Cause

readConfig() does JSON.parse without runtime validation, so config.json's mcp array can contain objects even though it's typed as string[]. When summarizeMcpSpec() threw on these object inputs, its catch block returned summary: raw directly, leaking objects into JSX.

Fix (4-layer defense)

  1. summarizeMcpSpec catch block — stringifies non-string raw values using JSON.stringify(raw) ?? String(raw), so summary is always a string.
  2. emitMcpSpecs filter — filters cfg.mcp with typeof raw === "string" before mapping, preventing bad items from reaching the renderer at all.
  3. CtxTools defensive render (context-panel.tsx) — renders summary only if it's a string.
  4. PageMCP defensive render (settings.tsx) — renders name/summary only if they're strings.

Test Plan

  • Added regression test: tests/mcp-desktop-react31.test.ts
  • npm run verify passes (build + lint + typecheck + 3343 tests)

🤖 Generated with Claude Code

…string items (esengine#1295)

Root cause: readConfig() does runtime JSON.parse without validation, so
config.json's mcp array can contain objects even though typed as string[].
The summarizeMcpSpec catch block then returned summary: raw directly,
which leaked objects into JSX and triggered React error esengine#31.

Fixes (4-layer defense):
1. summarizeMcpSpec catch block now stringifies non-string raw values
   using JSON.stringify(raw) ?? String(raw), so summary is always a string.
2. emitMcpSpecs filters cfg.mcp with typeof raw === "string" before
   mapping, preventing bad items from reaching the renderer at all.
3. CtxTools (context-panel.tsx) renders summary defensively.
4. PageMCP (settings.tsx) renders name/summary defensively.

Added regression test: tests/mcp-desktop-react31.test.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@esengine esengine merged commit ba9fb3c into esengine:main May 20, 2026
4 checks passed
esengine added a commit that referenced this pull request May 20, 2026
)

readConfig() previously cast JSON.parse output to ReasonixConfig with no runtime validation. Hand-edited config.json could put objects, numbers, or null into fields typed as `string[]` (mcp, mcpDisabled, recentWorkspaces, skills.paths), corrupting downstream consumers — see #1295 / #1394 where non-string mcp items reached JSX and crashed the desktop tools panel.

- New `sanitizeStringArrayField` in `src/config.ts` drops non-string items at the boundary and warns once per field with the file path + dropped count.
- Removes the now-dead downstream defenses (#1394's filter in `emitMcpSpecs`, `typeof` ternaries in `context-panel.tsx` / `settings.tsx`, `summarizeMcpSpec`'s non-string catch). `summarizeMcpSpec` no longer needs to be exported.
- Test file renamed to `config-sanitize-string-arrays.test.ts` and rewritten against `readConfig` (where the validation actually lives).

Closes #1395
ChasLui pushed a commit to ChasLui/DeepSeek-Reasonix that referenced this pull request May 23, 2026
…string items (esengine#1394)

Fixes esengine#1295 — Desktop MCP tools panel crashes with React error esengine#31 ("Objects are not valid as a React child") when `config.json` contains non-string items in the `mcp` array.

Root cause: `readConfig()` does `JSON.parse` without runtime validation, so `cfg.mcp` can contain objects even though it's typed as `string[]`. When `summarizeMcpSpec()` threw on these object inputs, its catch block returned `summary: raw` directly, leaking objects into JSX.

Fix:
- `summarizeMcpSpec` catch block — stringify non-string `raw` before returning.
- `emitMcpSpecs` — filter `cfg.mcp` to string items before mapping.
- `CtxTools` / `PageMCP` — render `summary` / `name` only when string.
- Regression test in `tests/mcp-desktop-react31.test.ts`.

Follow-up tracked separately: tighten `readConfig` with zod schema validation so this boundary check lives in one place.
ChasLui pushed a commit to ChasLui/DeepSeek-Reasonix that referenced this pull request May 23, 2026
…engine#1396)

readConfig() previously cast JSON.parse output to ReasonixConfig with no runtime validation. Hand-edited config.json could put objects, numbers, or null into fields typed as `string[]` (mcp, mcpDisabled, recentWorkspaces, skills.paths), corrupting downstream consumers — see esengine#1295 / esengine#1394 where non-string mcp items reached JSX and crashed the desktop tools panel.

- New `sanitizeStringArrayField` in `src/config.ts` drops non-string items at the boundary and warns once per field with the file path + dropped count.
- Removes the now-dead downstream defenses (esengine#1394's filter in `emitMcpSpecs`, `typeof` ternaries in `context-panel.tsx` / `settings.tsx`, `summarizeMcpSpec`'s non-string catch). `summarizeMcpSpec` no longer needs to be exported.
- Test file renamed to `config-sanitize-string-arrays.test.ts` and rewritten against `readConfig` (where the validation actually lives).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Desktop: 配置 MCP Server 后 tools 面板报 React #31 错误

2 participants