Skip to content

feat: Add delete button for MCP configuration#718

Merged
hatayama merged 6 commits intomainfrom
feature/hatayama/delete-mcp-button
Mar 3, 2026
Merged

feat: Add delete button for MCP configuration#718
hatayama merged 6 commits intomainfrom
feature/hatayama/delete-mcp-button

Conversation

@hatayama
Copy link
Copy Markdown
Owner

@hatayama hatayama commented Mar 3, 2026

Summary

  • Add a "Delete Configuration" button to the MCP settings UI, allowing users to remove uLoopMCP entries from config files without manual JSON/TOML editing
  • Only deletes uLoopMCP entries — other MCP server configurations are preserved
  • Supports both JSON-based editors (Cursor, Claude Code, VSCode, etc.) and TOML-based (Codex)
  • Shows a confirmation dialog before deletion to prevent accidental removal
  • Button is only visible when configuration exists, placed at the bottom of the MCP section

Changes

Core logic

  • IMcpConfigService: Added DeleteConfiguration() method
  • McpConfigRepository: Added DeleteULoopMCPEntries() for JSON config deletion
  • McpConfigService: Implemented DeleteConfiguration() delegating to repository
  • CodexTomlConfigService: Implemented DeleteConfiguration() using regex-based TOML section removal

UI

  • Added delete button to UXML (positioned below Open Settings button with spacing)
  • Added .mcp-button--delete style with red text to indicate destructive action
  • Wired up event propagation: EditorConfigSection → McpEditorWindowUI → McpEditorWindow
  • Confirmation dialog before executing deletion

Tests

  • McpConfigRepositoryDeleteTests: 5 tests covering JSON deletion (preserve other servers, handle port-suffixed keys, missing file, no-op cases)
  • CodexConfigDeleteTests: 5 tests covering TOML deletion (section at beginning/middle/end, only section, no match)

Test plan

  • Open Unity Window/uLoop, select MCP tab
  • Verify delete button appears only when configuration exists
  • Click delete button and confirm dialog appears
  • After deletion, verify uLoopMCP entry is removed and other MCP configs are preserved
  • Verify button disappears after successful deletion
  • Run EditMode tests: McpConfigRepositoryDeleteTests, CodexConfigDeleteTests

Summary by cubic

Adds a Delete Configuration button in MCP settings to remove uLoopMCP entries without editing JSON/TOML by hand. It confirms before deleting and leaves other MCP servers untouched.

  • New Features

    • Delete button in the MCP tab; shown only when configured and placed below Open Settings.
    • Safely removes uLoopMCP from JSON (including port-suffixed keys like uLoopMCP-8801) and TOML; preserves other servers.
    • Confirmation dialog and destructive styling consistent with Stop Server.
    • Added IMcpConfigService.DeleteConfiguration with JSON (McpConfigRepository) and TOML (CodexTomlConfigService) implementations; wired through EditorConfigSection → McpEditorWindowUI → McpEditorWindow.
    • Added unit tests for JSON and TOML deletion scenarios.
  • Bug Fixes

    • Tightened TOML “unchanged” test to run through the delete path, verifying content stays intact when no uLoopMCP section exists.

Written for commit 33e158c. Summary will update on new commits.

MCP Configuration Delete Feature

Overview

This PR adds a "Delete Configuration" button to the MCP settings UI, enabling users to remove uLoopMCP entries from configuration files without manual JSON/TOML editing. The feature includes a confirmation dialog before deletion and preserves other MCP server configurations. The button is visible only when a configuration exists and is removed after deletion.

Architecture & Implementation

Core Service Layer

The deletion feature follows the existing service/repository pattern:

classDiagram
    class IMcpConfigService {
        +DeleteConfiguration() void
    }

    class McpConfigService {
        +DeleteConfiguration() void
        -FindExistingULoopMCPConfigurationKey() string
    }

    class CodexTomlConfigService {
        +DeleteConfiguration() void
    }

    class McpConfigRepository {
        +DeleteULoopMCPEntries(configPath) void
    }

    IMcpConfigService <|.. McpConfigService
    IMcpConfigService <|.. CodexTomlConfigService
    McpConfigService --> McpConfigRepository
Loading
  • IMcpConfigService: interface extended with DeleteConfiguration().
  • McpConfigService: implements DeleteConfiguration() by resolving the config path via UnityMcpPathResolver.GetConfigPath(editorType) and delegating to McpConfigRepository.DeleteULoopMCPEntries(configPath).
  • McpConfigRepository: adds DeleteULoopMCPEntries(string configPath) that safely reads the JSON config, removes uLoopMCP entries (including keys suffixed by port, e.g., "uLoopMCP-") while preserving other mcpServers and unrelated JSON content, then writes back if changed. Includes input validation and size checks.
  • CodexTomlConfigService: implements DeleteConfiguration() by removing the [mcp_servers.uLoopMCP] TOML section using a compiled SectionRegex, normalizing blank lines, and writing back only if changed.

UI Layer

classDiagram
    class McpEditorWindow {
        -DeleteEditorConfiguration() void
    }

    class McpEditorWindowUI {
        +OnDeleteConfigClicked
    }

    class EditorConfigSection {
        +OnDeleteConfigClicked
        +UpdateDeleteButton(data) void
    }

    McpEditorWindow --> McpEditorWindowUI
    McpEditorWindowUI --> EditorConfigSection
    EditorConfigSection --> McpEditorWindow
Loading
  • UXML: adds a "Delete Configuration" button (name: delete-config-button) in MCP configuration content, positioned below "Open Settings File" and styled with class mcp-button--delete.
  • USS: adds .mcp-button--delete style (red text, increased top margin) and hover state.
  • EditorConfigSection: exposes a public event OnDeleteConfigClicked, initializes the delete button, toggles its visibility based on data.IsConfigured, and sets the label to include the editor type ("Delete {Editor} Configuration").
  • McpEditorWindowUI: raises OnDeleteConfigClicked when the section event fires.
  • McpEditorWindow: subscribes to OnDeleteConfigClicked and implements DeleteEditorConfiguration() which shows a confirmation dialog; on confirmation it resolves the appropriate IMcpConfigService and calls DeleteConfiguration(), then refreshes UI sections.

Event flow: EditorConfigSection -> McpEditorWindowUI -> McpEditorWindow -> confirmation dialog -> IMcpConfigService.DeleteConfiguration() -> repository/service logic -> UI refresh.

Test Coverage

JSON Configuration Tests (McpConfigRepositoryDeleteTests)

New NUnit test fixture McpConfigRepositoryDeleteTests with cases:

  • Should_DeleteOnlyULoopMCPEntries_And_PreserveOtherServers: removes uLoopMCP entries while preserving other servers.
  • Should_DeleteWindsurfPortSuffixedEntries: removes keys suffixed with port (e.g., "uLoopMCP-").
  • Should_NotThrow_WhenFileDoesNotExist: no exception on missing file.
  • Should_NotModifyFile_WhenNoULoopMCPEntries: no-op when no uLoopMCP entries.
  • Should_NotModifyFile_WhenNoMcpServersKey: no-op when mcpServers key missing.

Tests create temporary JSON files, invoke DeleteULoopMCPEntries, and assert file contents/behavior.

TOML Configuration Tests (CodexConfigDeleteTests)

New NUnit test fixture CodexConfigDeleteTests with cases:

  • Should_DeleteULoopMCPSection_WhenAtEnd
  • Should_DeleteULoopMCPSection_WhenAtBeginning
  • Should_DeleteULoopMCPSection_WhenInMiddle
  • Should_PreserveOtherSections_WhenOnlyULoopMCPExists
  • Should_ReturnUnchanged_WhenNoULoopMCPSection

Tests simulate deletion by accessing the private static SectionRegex on CodexTomlConfigService via reflection and verify correct removal/normalization behavior.

Key Behaviors

  • Deletion targets only uLoopMCP-related entries/section; other MCP server configurations and unrelated file contents remain intact.
  • Confirmation dialog prevents accidental deletion.
  • Delete button visibility is driven by configuration presence (IsConfigured) and is removed after deletion.
  • Supports JSON-based editors (via McpConfigRepository) and TOML-based Codex config (via CodexTomlConfigService).
  • File operations include safety checks (existence, size limits) and only write when content changes.

Files Changed (high level)

  • Interfaces/Services: IMcpConfigService.cs (+DeleteConfiguration), McpConfigService.cs (+DeleteConfiguration), McpConfigRepository.cs (+DeleteULoopMCPEntries), CodexTomlConfigService.cs (+DeleteConfiguration).
  • UI: McpEditorWindow.uxml (delete-config-button), McpEditorWindow.uss (.mcp-button--delete), EditorConfigSection.cs (button + OnDeleteConfigClicked), McpEditorWindowUI.cs (event), McpEditorWindow.cs (DeleteEditorConfiguration wiring).
  • Tests: Assets/Tests/Editor/McpConfigRepositoryDeleteTests.cs, Assets/Tests/Editor/CodexConfigDeleteTests.cs.

hatayama added 5 commits March 3, 2026 11:00
エディタUI上でMCP設定を作成できるが削除手段がなく、
手動でJSONファイルを編集する必要があった。
「Delete Configuration」ボタンを追加し、uLoopMCPエントリのみを
安全に削除できるようにした(他のMCPサーバー設定は保持)。

- IMcpConfigService に DeleteConfiguration() を追加
- McpConfigRepository にJSON用の削除ロジックを実装
- CodexTomlConfigService にTOML用の削除ロジックを実装
- EditorConfigSection に削除ボタンのUI・バインディングを追加
- 確認ダイアログで誤削除を防止
- JSON/TOML両方の削除処理に対するユニットテストを追加
独自の赤系カラースキームからStop Serverボタンと同じ配色に変更し、
UI全体のトーンを統一した
ボタン配置をConfigure → Open Settings → Deleteの順に変更し、
margin-top: 12pxで視覚的に分離した
独自のbackground-colorとborder-colorを削除しデフォルトスタイルを
継承させることで、他のボタンと同じ幅に揃えた
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 3, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4d6a0d6 and 33e158c.

📒 Files selected for processing (1)
  • Assets/Tests/Editor/CodexConfigDeleteTests.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • Assets/Tests/Editor/CodexConfigDeleteTests.cs

📝 Walkthrough

Walkthrough

Adds a delete-configuration feature: repository and service methods remove uLoopMCP entries from JSON/TOML configs, UI wiring and a confirmation flow to trigger deletion, and new NUnit tests covering TOML and JSON deletion scenarios.

Changes

Cohort / File(s) Summary
Tests
Assets/Tests/Editor/CodexConfigDeleteTests.cs, Assets/Tests/Editor/McpConfigRepositoryDeleteTests.cs
Two new NUnit test suites: TOML section removal tests (reflecting SectionRegex) and JSON mcpServers deletion tests (various positions, suffixes, and absent-file/key cases).
Codex TOML service
Packages/src/Editor/Config/CodexTomlConfigService.cs
Added DeleteConfiguration() which removes the [mcp_servers.uLoopMCP] TOML section using existing SectionRegex, normalizes blank lines, and writes file.
MCP repository & service
Packages/src/Editor/Config/McpConfigRepository.cs, Packages/src/Editor/Config/McpConfigService.cs
Added DeleteULoopMCPEntries(string) in repository to remove uLoopMCP JSON entries; McpConfigService.DeleteConfiguration() delegates to repository after resolving config path.
Service interface
Packages/src/Editor/Config/IMcpConfigService.cs
Added void DeleteConfiguration() to the IMcpConfigService contract.
UI: editor section + window UI
Packages/src/Editor/UI/UIToolkit/Components/EditorConfigSection.cs, Packages/src/Editor/UI/UIToolkit/McpEditorWindowUI.cs, Packages/src/Editor/UI/McpEditorWindow.cs
Added delete button event OnDeleteConfigClicked, propagated through McpEditorWindowUI to McpEditorWindow; McpEditorWindow shows confirmation and calls DeleteConfiguration(), then refreshes UI.
UI: markup & styles
Packages/src/Editor/UI/UIToolkit/McpEditorWindow.uxml, Packages/src/Editor/UI/UIToolkit/McpEditorWindow.uss
Added delete-config-button element and .mcp-button--delete styles (red button and hover state).

Sequence Diagram

sequenceDiagram
    participant User
    participant EditorConfigSection
    participant McpEditorWindow
    participant McpConfigService
    participant McpConfigRepository
    participant ConfigFile

    User->>EditorConfigSection: Click Delete Button
    EditorConfigSection->>McpEditorWindow: OnDeleteConfigClicked
    McpEditorWindow->>User: Show Confirmation Dialog
    alt User Confirms
        User-->>McpEditorWindow: Confirm
        McpEditorWindow->>McpConfigService: DeleteConfiguration()
        McpConfigService->>McpConfigRepository: DeleteULoopMCPEntries(configPath)
        McpConfigRepository->>ConfigFile: Load (JSON/TOML)
        ConfigFile-->>McpConfigRepository: Return content
        McpConfigRepository->>McpConfigRepository: Remove uLoopMCP entries/section
        McpConfigRepository->>ConfigFile: Write updated config
        McpConfigRepository-->>McpConfigService: Complete
        McpConfigService-->>McpEditorWindow: Complete
        McpEditorWindow->>EditorConfigSection: Refresh UI
    else User Cancels
        User-->>McpEditorWindow: Cancel
        McpEditorWindow->>McpEditorWindow: No action
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • PR #503: Related UI changes to EditorConfigSection and McpEditorWindowUI that touch the same event/binding surface used for delete wiring.
  • PR #292: Introduced CodexTomlConfigService and SectionRegex logic that the new TOML deletion uses via reflection/tests.
  • PR #662: Modified EditorConfigSection event bindings and McpEditorWindowUI, overlapping with this PR's event propagation and UI wiring.
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.56% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a delete button UI component for MCP configuration deletion, which is the primary user-facing feature in this changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/hatayama/delete-mcp-button

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 13 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Packages/src/Editor/Config/McpConfigRepository.cs">

<violation number="1" location="Packages/src/Editor/Config/McpConfigRepository.cs:324">
P2: Guard against null/non-object `mcpServers` before calling `JObject.FromObject`; current code can throw for valid JSON like `"mcpServers": null` and break deletion.</violation>
</file>

<file name="Assets/Tests/Editor/CodexConfigDeleteTests.cs">

<violation number="1" location="Assets/Tests/Editor/CodexConfigDeleteTests.cs:15">
P2: These tests are coupled to a private implementation detail (`SectionRegex`) and reimplement deletion logic instead of testing `DeleteConfiguration()` behavior. This can miss real regressions in the public method and makes tests brittle to internal refactors.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

return;
}

JObject existingServers = JObject.FromObject(jsonStructure[McpConstants.JSON_KEY_MCP_SERVERS]);
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Guard against null/non-object mcpServers before calling JObject.FromObject; current code can throw for valid JSON like "mcpServers": null and break deletion.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Packages/src/Editor/Config/McpConfigRepository.cs, line 324:

<comment>Guard against null/non-object `mcpServers` before calling `JObject.FromObject`; current code can throw for valid JSON like `"mcpServers": null` and break deletion.</comment>

<file context>
@@ -297,6 +297,62 @@ private Dictionary<string, object> ExtractULoopMCPServers(Dictionary<string, obj
+                return;
+            }
+
+            JObject existingServers = JObject.FromObject(jsonStructure[McpConstants.JSON_KEY_MCP_SERVERS]);
+
+            List<string> keysToRemove = new();
</file context>
Suggested change
JObject existingServers = JObject.FromObject(jsonStructure[McpConstants.JSON_KEY_MCP_SERVERS]);
if (jsonStructure[McpConstants.JSON_KEY_MCP_SERVERS] is not JObject existingServers)
{
return;
}
Fix with Cubic

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Assets/Tests/Editor/CodexConfigDeleteTests.cs`:
- Around line 109-120: The test Should_ReturnUnchanged_WhenNoULoopMCPSection
currently only checks that GetSectionRegex().IsMatch(toml) is false; update it
to also invoke the actual transformation/removal routine that uses
GetSectionRegex (the method under test that removes uLoopMCP sections) with the
toml input and assert the returned string equals the original toml variable,
ensuring no changes were made; keep the existing regex assertion but add
Assert.AreEqual(toml, result, "...") using the same toml sample and reference
the test's local symbols sectionRegex, toml, and the removal function (the
method that applies the sectionRegex) to locate where to call it.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae1a21a and 4d6a0d6.

⛔ Files ignored due to path filters (2)
  • Assets/Tests/Editor/CodexConfigDeleteTests.cs.meta is excluded by none and included by none
  • Assets/Tests/Editor/McpConfigRepositoryDeleteTests.cs.meta is excluded by none and included by none
📒 Files selected for processing (11)
  • Assets/Tests/Editor/CodexConfigDeleteTests.cs
  • Assets/Tests/Editor/McpConfigRepositoryDeleteTests.cs
  • Packages/src/Editor/Config/CodexTomlConfigService.cs
  • Packages/src/Editor/Config/IMcpConfigService.cs
  • Packages/src/Editor/Config/McpConfigRepository.cs
  • Packages/src/Editor/Config/McpConfigService.cs
  • Packages/src/Editor/UI/McpEditorWindow.cs
  • Packages/src/Editor/UI/UIToolkit/Components/EditorConfigSection.cs
  • Packages/src/Editor/UI/UIToolkit/McpEditorWindow.uss
  • Packages/src/Editor/UI/UIToolkit/McpEditorWindow.uxml
  • Packages/src/Editor/UI/UIToolkit/McpEditorWindowUI.cs

Replace regex-only assertion with actual SimulateDelete call
to ensure the transformation path preserves content intact
@hatayama hatayama merged commit 3e4c4fb into main Mar 3, 2026
12 of 13 checks passed
@hatayama hatayama deleted the feature/hatayama/delete-mcp-button branch March 3, 2026 04:58
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