Switch from `toml` to `toml_edit` crate for incremental TOML editing,
preserving user-written comments, whitespace, and key ordering in
Codex config.toml.
Changes:
- Add toml_edit 0.22 dependency for preserving-style TOML editing
- Refactor sync_enabled_to_codex() to use toml_edit::DocumentMut API
- Implement smart style detection: inherit existing mcp.servers or
mcp_servers style, with fallback to sensible defaults
- Add deduplication logic to prevent both styles coexisting
- Add tests for format preservation and style inheritance
- Fix unused_mut and nonminimal_bool compiler warnings
- Apply cargo fmt to all modified files
Benefits:
- User comments and formatting are no longer lost during sync
- Respects user's preferred TOML structure (nested vs toplevel)
- Non-MCP fields in config.toml remain untouched
- Minimal surprise principle: only modifies necessary sections
Testing:
- All 47 tests passing (unit + integration)
- Clippy clean (0 warnings, 0 errors)
- Release build successful
- New tests verify comment preservation and style detection
Extract all MCP business logic from command layer into `services/mcp.rs`,
implementing snapshot isolation pattern to optimize lock granularity after
RwLock migration in Phase 5.
## Key Changes
### Service Layer (`services/mcp.rs`)
- Add `McpService` with 7 methods: `get_servers`, `upsert_server`,
`delete_server`, `set_enabled`, `sync_enabled`, `import_from_claude`,
`import_from_codex`
- Implement snapshot isolation: acquire write lock only for in-memory
modifications, clone config snapshot, release lock, then perform file I/O
with snapshot
- Use conditional cloning: only clone config when sync is actually needed
(e.g., when `enabled` flag is true or `sync_other_side` is requested)
### Command Layer (`commands/mcp.rs`)
- Reduce to thin wrappers: parse parameters and delegate to `McpService`
- Remove all `*_internal` and `*_test_hook` functions (-94 lines)
- Each command now 5-10 lines (parameter parsing + service call + error mapping)
### Core Logic Refactoring (`mcp.rs`)
- Rename `set_enabled_and_sync_for` → `set_enabled_flag_for`
- Remove file sync logic from low-level function, move sync responsibility
to service layer for better separation of concerns
### Test Adaptation (`tests/mcp_commands.rs`)
- Replace test hooks with direct `McpService` calls
- All 5 MCP integration tests pass
### Additional Fixes
- Add `Default` impl for `AppState` (clippy suggestion)
- Remove unnecessary auto-deref in `commands/provider.rs` and `lib.rs`
- Update Phase 4/5 progress in `BACKEND_REFACTOR_PLAN.md`
## Performance Impact
**Before**: Write lock held during file I/O (~10ms), blocking all readers
**After**: Write lock held only for memory ops (~100μs), file I/O lock-free
Estimated throughput improvement: ~2x in high-concurrency read scenarios
## Testing
- ✅ All tests pass: 5 MCP commands + 7 provider service tests
- ✅ Zero clippy warnings with `-D warnings`
- ✅ No behavioral changes, maintains original save semantics
Part of Phase 4 (Service Layer Abstraction) of backend refactoring roadmap.
- Extract internal functions in commands/mcp.rs and commands/provider.rs
to enable unit testing without Tauri context
- Add test hooks: set_mcp_enabled_test_hook, import_mcp_from_claude_test_hook,
import_mcp_from_codex_test_hook, import_default_config_test_hook
- Migrate error types from String to AppError for precise error matching in tests
- Extend ProviderService with delete() method to unify Codex/Claude cleanup logic
- Add comprehensive test coverage:
- tests/mcp_commands.rs: command-level tests for MCP operations
- tests/provider_service.rs: service-level tests for switch/delete operations
- Run cargo fmt to fix formatting issues (EOF newlines)
- Update BACKEND_REFACTOR_PLAN.md to mark phase 3 complete
- Add normalize_server_keys() to ensure MCP server map keys match internal id fields
- Auto-normalize on all read/write operations (get, upsert, delete, import, sync)
- Handle edge cases: empty/whitespace ids, key renaming, conflict resolution
- Auto-save config when normalization detects changes
- Apply cargo fmt for code formatting consistency
This enhancement improves data integrity by automatically fixing inconsistencies
between server entry keys and their id fields, especially after manual config edits.
- Separate MCP server metadata from connection spec for cleaner architecture
- Add comprehensive server entry fields: name, description, tags, homepage, docs
- Remove legacy format compatibility logic from extract_server_spec
- Implement data validation and filtering in get_servers_snapshot_for
- Add strict id consistency check in upsert_in_config_for
- Enhance import logic with defensive programming for corrupted data
- Simplify frontend by removing normalization logic (moved to backend)
- Improve error messages with contextual information
- Add comprehensive i18n support for new metadata fields
- Support both TOML schemas: [mcp.servers.<id>] and [mcp_servers.<id>]
- Non-destructive merge of imported servers (enabled=true only)
- Preserve existing TOML schema when syncing (prefer mcp_servers)
- Remove both mcp and mcp_servers when no enabled items
feat(ui): auto-import Codex MCP on panel init (app=codex)
chore(tauri): add import_mcp_from_codex command and register
chore(types): expose window.api.importMcpFromCodex and typings
fix(ui): remove unused variable for typecheck
- Make MCP panel app-aware; pass appType from App and call APIs with current app
- Show active app in title: “MCP Management · Claude Code/Codex”
- Add sync_enabled_to_codex: project enabled servers from SSOT to ~/.codex/config.toml as [mcp.servers.*]
- Sync on enable/disable, delete, and provider switch (post live write)
- Add Tauri command sync_enabled_mcp_to_codex and expose window.api.syncEnabledMcpToCodex()
- Fix Rust borrow scopes in switch_provider to avoid E0502
- Add TS declarations for new Codex sync API
- Backend: reject "sse" in validators; accept missing type as stdio; require url only for http (mcp.rs, claude_mcp.rs)
- Frontend: McpServer.type narrowed to "stdio" | "http" (optional) (src/types.ts)
- UI: avoid undefined in list item details (McpListItem)
- Claude-only sync after delete to update ~/.claude.json (commands.rs)
Notes:
- Ran typecheck and cargo check: both pass
- Clippy shows advisory warnings unrelated to this change
- Prettier check warns on a few files; limited scope changes kept minimal
- Add McpConfig to MultiAppConfig and persist MCP servers in ~/.cc-switch/config.json
- Add Tauri commands: get_mcp_config, upsert_mcp_server_in_config, delete_mcp_server_in_config, set_mcp_enabled, sync_enabled_mcp_to_claude, import_mcp_from_claude
- Only write enabled MCPs to ~/.claude.json (mcpServers) and strip UI-only fields (enabled/source)
- Frontend: update API wrappers and MCP panel to read/write via config.json; seed presets on first open; import from ~/.claude.json
- Fix warnings (remove unused mut, dead code)
- Verified with cargo check and pnpm typecheck