Skip to content

fix(mcp): 对齐 source 字段的大小写归一化并补齐回归测试 - #3164

Merged
wgqqqqq merged 1 commit into
GCWing:mainfrom
wgqqqqq:wgq/fix-mcp-source-token-case
Sep 21, 2026
Merged

wgqqqqq merged 1 commit into
GCWing:mainfrom
wgqqqqq:wgq/fix-mcp-source-token-case

Conversation

@wgqqqqq

@wgqqqqq wgqqqqq commented Sep 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

Follow-up to #3156 (fix(mcp): 兼容驼峰式 streamableHttp 传输类型), which normalized the type / transport tokens but left source behind.

  • Route the MCP source token through the same trim + lowercase normalizer as type / transport, in both core paths: json_config::normalize_source and cursor_format::parse_source.
  • Rename the shared helper normalized_transport_token to normalized_token, since it now covers the type / transport / source vocabularies (including local / remote).
  • Add the regression coverage fix(mcp): 兼容驼峰式 streamableHttp 传输类型 #3156 was missing: mixed-case source / transport validation, parsing, and canonical-write assertions in mcp_contracts.rs, plus camelCase type and mixed-case source fixtures in the visual editor round-trip table.
  • Fold the one rustfmt-unclean line fix(mcp): 兼容驼峰式 streamableHttp 传输类型 #3156 left in mcp_contracts.rs (array_width).

Root cause: the visual editor lowercases type, transport, and source before matching (transportFromConfig in mcpConfigForm.ts), but the core validator and parser still matched source case-sensitively. So

{ "mcpServers": { "docs": { "source": "Remote", "url": "https://example.com/mcp" } } }

rendered fine in the form, then failed on save with Server 'docs' has unsupported 'source' value: 'Remote', and parse_cursor_format logged a warning and dropped the server on reload. Before #3156 the form rejected the same input (advancedRequired), so this cross-surface divergence was introduced by that change.

Type and Areas

Type: bug fix (follow-up to a merged fix)

Areas: Rust core (services-integrations MCP config), Web UI tests

Motivation / Impact

A config the visual editor accepts must survive a save round trip. After #3156 that held for type and transport but not for source: a hand-written or third-party-emitted "source": "Remote" was accepted in the UI and then rejected by the core, or silently dropped on reload. Both surfaces now share one normalization rule.

The canonical persisted tokens are unchanged (stdio / sse / streamable-http), so no stored configuration changes meaning and there is no migration. No user-facing strings changed.

Verification

  • cargo test -p openbitfun-services-integrations --no-default-features --features mcp --test mcp_contracts — passed, 49 passed / 0 failed (48 before this PR)
  • cargo test -p openbitfun-services-integrations --no-default-features --features mcp --test mcp_streamable_http_contracts — passed, 3 passed
  • vitest run src/infrastructure/config/components/mcpConfigForm.test.ts (from src/web-ui) — passed, 29 passed (27 before this PR)
  • Negative control: temporarily reverting normalize_source / parse_source to case-sensitive matching makes the new test fail with '{"source":"REMOTE","transport":"SSE",...}' must validate: Server 'case' has unsupported 'source' value: 'REMOTE', so the test pins the behavior rather than just passing.
  • pnpm run fmt:rs — applied; the three changed Rust files are rustfmt-clean.
  • CI on this PR: Build Impact, Repository Object Sizes, and Shell Deploy Scripts passed; Rust Build Check, Frontend Build, and CLI Tests were still pending when this description was written.

Reviewer Notes

  • Direction chosen: bring the core up to the visual editor (accept mixed-case source) instead of removing the form's .toLowerCase(). source is OpenBitFun's own read-side vocabulary — config_to_cursor_format writes type and never source — so widening it cannot regress a user-visible behavior, and it matches the fix(mcp): 兼容驼峰式 streamableHttp 传输类型 #3156 direction. If maintainers prefer strict source casing, the alternative is a one-line removal in mcpConfigForm.ts; I can switch on request.
  • normalized_token is pub(super) inside the private json_config module and is not re-exported from mcp::config, so the rename has no compatibility impact.
  • Intentionally unchanged: the external-client import adapters (claude-code / opencode / codex / dsh), which match their own upstream formats and are out of scope per fix(mcp): 兼容驼峰式 streamableHttp 传输类型 #3156; the CLI openbitfun mcp add --type vocabulary (local | remote, whose TUI path only emits wizard-generated canonical values, so there is no reproducible camelCase input); and McpServerMutation's McpTransport, a separate serde kebab-case wire contract used by app-server / peer.
  • Remote scenarios: none exercised. The change is token normalization inside a shared config parser that all four scenarios (remote workspace, remote control, peer device mode, detached dispatch) reach equally, and it does not touch workspace, process, transport, or dispatch plumbing.

Checklist

  • This PR is focused and does not include secrets, temporary prompts, generated scratch files, or unrelated artifacts.
  • Relevant verification is recorded above, or skipped checks are explained.
  • User-facing strings, docs, and locales are updated where applicable. (No user-visible string changes.)

Generated with OpenBitFun

The visual editor lowercases `type`, `transport`, and `source` before
matching, but the core validator and parser still matched `source`
case-sensitively. A hand-written `{"source": "Remote", "url": ...}` was
therefore rendered happily by the form and then rejected on save with
"Server 'x' has unsupported 'source' value: 'Remote'", while
`parse_cursor_format` dropped the server with a warning.

Route `source` through the same token normalizer as `type`/`transport`,
and rename the shared helper to `normalized_token` since it now also
covers the `local`/`remote` source vocabulary. Accepted spellings still
normalize to the canonical persisted values.

Also adds the regression coverage missing from the previous change:
mixed-case `transport`/`source` validation, parsing, and canonical write
assertions in mcp_contracts, plus camelCase `type` and mixed-case
`source` fixtures in the visual editor round-trip table.

Co-authored-by: OpenBitFun <318544290+bitfun-ai@users.noreply.github.com>
@wgqqqqq
wgqqqqq force-pushed the wgq/fix-mcp-source-token-case branch from a0335bd to 561bdc0 Compare September 21, 2026 02:12
@wgqqqqq
wgqqqqq merged commit 786eeb4 into GCWing:main Sep 21, 2026
13 checks passed
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.

1 participant