Skip to content

Conversation

@peteski22
Copy link
Contributor

@peteski22 peteski22 commented Oct 29, 2025

Implement mcpd config plugins add command to add new plugins to a category.

Summary by CodeRabbit

  • New Features

    • Fully implemented plugin add command with flags for category, repeatable flows, required and commit-hash; clearer success and error messages.
    • Public flow utilities: validation, distinct parsing, ordered flow listing and case‑insensitive normalisation.
  • Bug Fixes

    • Improved name trimming/normalisation, validation and duplicate detection with guidance to update existing plugins.
    • More robust subcommand matching for commands that include arguments.
  • Tests

    • Expanded test coverage for add command behaviours, flow parsing/validation, ordered flow names and config persistence.

Implement 'mcpd config plugins add' command to add new plugins to a category.
@coderabbitai
Copy link

coderabbitai bot commented Oct 29, 2025

Walkthrough

Implements a fully functional plugins Add command with flags and run logic, adds canonical flow handling and validation utilities in the config package, and expands tests covering add behaviour, flow normalisation/validation and config persistence.

Changes

Cohort / File(s) Summary
Plugin add command
cmd/config/plugins/add.go, cmd/config/plugins/add_test.go
Adds AddCmd type and NewAddCmd, implements flags (--category, repeatable --flow, --required, --commit-hash), command run logic (arg validation, config load, duplicate checks, flow parsing/sorting, construct & upsert PluginEntry) and user messages; adds comprehensive tests with temp config loader helpers and assertions on persisted config and CLI output.
CLI subcommand test adjustment
cmd/config/plugins/cmd_test.go
Modifies subcommand validation to compare only the first word of each command's Use field so commands that include arguments (e.g. add <plugin-name>) are matched robustly.
Flow utilities and config changes
internal/config/plugin_config.go, internal/config/..._test.go
Introduces internal canonical flows and exposes helpers: Flows(), (Flow) IsValid(), ParseFlowsDistinct(), OrderedFlowNames(); updates PluginEntry.Validate to use new validation and allowed-values messaging; trims/normalises names on upsert and adds tests for flow parsing, deduplication and ordered names.

Possibly related PRs

Suggested reviewers

  • dpoulopoulos
  • agpituk

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.69% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "Add plugins 'add' command" accurately reflects the primary change across the changeset. The raw summary confirms this is the main objective: implementing a fully functional mcpd config plugins add command with associated command logic, tests, and supporting infrastructure. The title is concise, specific, and free from vague language or noise; it clearly conveys to a developer scanning the repository history that a new command has been added to the plugins CLI. The title aligns directly with the stated PR objective to implement this functionality.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch peteski22/cli-plugins-add

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

Copy link

@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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
internal/config/plugin_config.go (2)

248-253: Avoid hard‑coded allowed flow list in error

Build the allowed list from the canonical set to prevent drift.

Apply this diff:

-            if !flow.IsValid() {
-                validationErrors = append(
-                    validationErrors,
-                    fmt.Errorf("invalid flow '%s', must be '%s' or '%s'", flow, FlowRequest, FlowResponse),
-                )
-            }
+            if !flow.IsValid() {
+                allowed := slices.Sorted(maps.Keys(Flows()))
+                validationErrors = append(
+                    validationErrors,
+                    fmt.Errorf("invalid flow %q, must be one of %v", flow, allowed),
+                )
+            }

388-396: Normalise and persist trimmed plugin name in upsert

Currently you trim for comparison but not for persistence, which can leave leading/trailing spaces in stored names added by other paths. Trim early and reuse.

Apply this diff:

 func (p *PluginConfig) upsertPlugin(category Category, entry PluginEntry) (context.UpsertResult, error) {
-    if strings.TrimSpace(entry.Name) == "" {
+    entry.Name = strings.TrimSpace(entry.Name)
+    if entry.Name == "" {
         return context.Noop, fmt.Errorf("plugin name cannot be empty")
     }
 
     if err := entry.Validate(); err != nil {
         return context.Noop, fmt.Errorf("plugin validation failed: %w", err)
     }
@@
-    name := strings.TrimSpace(entry.Name)
+    name := entry.Name

Also applies to: 402-416

♻️ Duplicate comments (1)
cmd/config/plugins/add.go (1)

5-7: Confirm Go toolchain version for maps/slices usage

As noted elsewhere, maps/slices require Go 1.21+. Please verify go.mod.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 723be7c and f6e8702.

📒 Files selected for processing (5)
  • cmd/config/plugins/add.go (1 hunks)
  • cmd/config/plugins/add_test.go (1 hunks)
  • cmd/config/plugins/cmd_test.go (2 hunks)
  • internal/config/plugin_config.go (4 hunks)
  • internal/config/plugin_config_test.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
internal/config/plugin_config.go (1)
internal/filter/match.go (1)
  • NormalizeString (36-38)
internal/config/plugin_config_test.go (1)
internal/config/plugin_config.go (5)
  • Flows (92-94)
  • FlowRequest (40-40)
  • FlowResponse (43-43)
  • Flow (88-88)
  • ParseFlows (105-116)
cmd/config/plugins/add_test.go (5)
internal/cmd/basecmd.go (1)
  • BaseCmd (45-47)
cmd/config/plugins/add.go (1)
  • NewAddCmd (44-107)
internal/cmd/options/options.go (1)
  • WithConfigLoader (43-48)
internal/config/types.go (1)
  • Config (83-88)
internal/config/plugin_config.go (9)
  • CategoryAuthentication (17-17)
  • Flow (88-88)
  • FlowRequest (40-40)
  • Flows (92-94)
  • CategoryObservability (32-32)
  • FlowResponse (43-43)
  • PluginConfig (121-145)
  • PluginEntry (148-161)
  • CategoryRateLimiting (23-23)
cmd/config/plugins/add.go (3)
internal/cmd/basecmd.go (1)
  • BaseCmd (45-47)
internal/config/plugin_config.go (5)
  • Category (85-85)
  • OrderedCategories (525-527)
  • ParseFlows (105-116)
  • PluginEntry (148-161)
  • Flows (92-94)
internal/cmd/options/options.go (1)
  • CmdOption (10-10)
🔇 Additional comments (27)
internal/config/plugin_config.go (3)

90-95: Flows() clone is correct

Returning a clone prevents accidental mutation. LGTM.


96-101: Flow.IsValid() is straightforward

Efficient membership check against canonical set. LGTM.


6-6: Go version requirement confirmed

The go.mod specifies go 1.25.1, which exceeds the required Go 1.21+ for maps.Clone and maps.Keys usage. No action required.

internal/config/plugin_config_test.go (3)

727-746: Flows() clone behaviour verified

Good assertions on exact members and mutation isolation. LGTM.


748-791: Flow.IsValid() coverage is adequate

Covers valid, empty, unknown, and case. LGTM.


793-873: ParseFlows happy/edge paths well covered

Dedup, mixed validity, nil/empty, case and whitespace all covered. LGTM.

cmd/config/plugins/add.go (7)

16-20: Flag constants read well

Names are consistent with existing commands. LGTM.


22-41: Command state struct looks fine

Clear separation of parsed flags and wiring. LGTM.


120-129: Helpful duplicate guidance

Clear error with remediation. LGTM.


136-141: Stable flow ordering is good

Using slices.Sorted(maps.Keys(...)) gives deterministic serialisation. LGTM.


143-151: Optional fields handling is correct

Only set when flag is provided/non-empty. LGTM.


152-164: Upsert + success message

Correct save and clear user feedback. LGTM.


109-118: No changes required – guard rails are adequate

Verification confirms that BaseCmd.LoadConfig does not support nil loaders (line 191 would panic), but this is not a concern. The config.Loader is always initialised to &config.DefaultLoader{} through the options defaults mechanism (internal/cmd/options/options.go:20-25), and tests explicitly verify this invariant. No constructor changes are needed – the code is safe as written.

cmd/config/plugins/add_test.go (12)

15-27: Temp config helper is clean

Minimal valid TOML and safe perms. LGTM.


49-61: NewAddCmd wiring test is adequate

Verifies Use/Short/RunE. LGTM.


62-95: Happy path add with persistence verified

Good stdout/stderr assertions and reload check. LGTM.


96-137: All fields path covered

Validates flow order, Required pointer behaviour, and commitHash. LGTM.


139-168: Duplicate plugin guarded with actionable error

Strong UX. LGTM.


170-191: Invalid flows properly rejected

Asserts helpful error. LGTM.


193-227: Duplicate flows deduplicated

Good verification via reload. LGTM.


229-250: Empty name rejection test

Matches run-time guard. LGTM.


252-263: Invalid category surfaced at flag parse

Assertions match config.Category.Set behaviour. LGTM.


265-297: Case-insensitive flows verified

Good coverage. LGTM.


299-327: Required flag unset yields nil pointer

Covers intended tri-state. LGTM.


329-360: Required flag explicitly false set

Pointer set and value false verified. LGTM.

cmd/config/plugins/cmd_test.go (2)

4-4: Import is appropriate

strings is needed for tokenising Use. LGTM.


39-43: Subcommand detection made robust

Using first word avoids brittle matching against arg hints. LGTM.

Copy link

@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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f6e8702 and be6e7aa.

📒 Files selected for processing (4)
  • cmd/config/plugins/add.go (1 hunks)
  • cmd/config/plugins/add_test.go (1 hunks)
  • internal/config/plugin_config.go (4 hunks)
  • internal/config/plugin_config_test.go (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-24T09:54:59.315Z
Learnt from: peteski22
PR: mozilla-ai/mcpd#215
File: internal/plugin/types_test.go:83-90
Timestamp: 2025-10-24T09:54:59.315Z
Learning: In internal/plugin/types_test.go, TestOrderedCategories_ReturnsCorrectOrder uses hard-coded assertions to act as a regression check. If the category order changes in the config package, this test will catch it. This is intentional to ensure order stability.

Applied to files:

  • internal/config/plugin_config_test.go
  • cmd/config/plugins/add.go
  • cmd/config/plugins/add_test.go
🧬 Code graph analysis (4)
internal/config/plugin_config_test.go (1)
internal/config/plugin_config.go (5)
  • Flows (92-94)
  • FlowRequest (40-40)
  • FlowResponse (43-43)
  • Flow (88-88)
  • ParseFlowsDistinct (105-116)
cmd/config/plugins/add.go (3)
internal/cmd/basecmd.go (1)
  • BaseCmd (45-47)
internal/config/plugin_config.go (5)
  • Category (85-85)
  • OrderedCategories (525-527)
  • ParseFlowsDistinct (105-116)
  • PluginEntry (148-161)
  • Flows (92-94)
internal/cmd/options/options.go (1)
  • CmdOption (10-10)
internal/config/plugin_config.go (1)
internal/filter/match.go (1)
  • NormalizeString (36-38)
cmd/config/plugins/add_test.go (5)
internal/cmd/basecmd.go (1)
  • BaseCmd (45-47)
cmd/config/plugins/add.go (2)
  • NewAddCmd (44-110)
  • OrderedFlowNames (168-177)
internal/cmd/options/options.go (1)
  • WithConfigLoader (43-48)
internal/config/types.go (1)
  • Config (83-88)
internal/config/plugin_config.go (9)
  • CategoryAuthentication (17-17)
  • Flow (88-88)
  • FlowRequest (40-40)
  • Flows (92-94)
  • CategoryObservability (32-32)
  • FlowResponse (43-43)
  • PluginConfig (121-145)
  • PluginEntry (148-161)
  • CategoryRateLimiting (23-23)
🔇 Additional comments (18)
internal/config/plugin_config_test.go (3)

880-883: LGTM!

The helper function follows the established pattern and provides a clean way to create bool pointers for tests.


727-746: LGTM!

The test properly validates both the returned flow set contents and the clone behaviour, ensuring modifications to the returned map don't affect the internal canonical set.


748-791: LGTM!

The test comprehensively validates the IsValid() method across all expected scenarios, including valid flows, invalid flows, and edge cases like empty strings and incorrect casing.

internal/config/plugin_config.go (6)

6-6: LGTM!

The new imports are properly used for cloning the flows map and normalising flow strings.

Also applies to: 12-12


59-64: LGTM!

The canonical flows map is appropriately unexported and serves as the single source of truth for valid flow values. This design enables the Flows(), IsValid(), and ParseFlowsDistinct() functions to derive their behaviour from this authoritative set.


90-94: LGTM!

The function correctly returns a clone of the internal flows map, preventing external code from modifying the canonical set. The documentation clearly explains this behaviour.


96-100: LGTM!

The IsValid() method provides a clean API for validating Flow values against the canonical set.


102-116: LGTM!

The function correctly normalises input strings, validates them against the canonical flows set, and returns a distinct set. The documentation clearly states that invalid flows are silently ignored, which is appropriate for this use case.


248-248: LGTM!

The validation logic now correctly uses the IsValid() method, ensuring consistency with the canonical flows definition.

cmd/config/plugins/add.go (7)

3-14: LGTM!

The imports are appropriate for the command implementation, including standard library packages for data manipulation and internal packages for configuration management.


16-20: LGTM!

The flag constants provide a single source of truth for flag names, reducing the risk of typos and making refactoring easier.


22-41: LGTM!

The AddCmd struct is well-structured with clear field documentation. The embedding of BaseCmd provides access to common functionality like logging.


43-110: LGTM!

The command constructor is well-structured with comprehensive documentation and examples. The flag help text correctly derives the allowed flow names from the canonical source using OrderedFlowNames(), addressing previous review feedback.


112-132: LGTM!

The validation logic is robust. The check for existing plugins prevents accidental overwrites, and the error message helpfully directs users to the correct command for updates.


134-152: LGTM!

The flow parsing uses the canonical ParseFlowsDistinct function and provides a clear error message that derives allowed flow names from the canonical source. The optional fields are correctly set only when provided, ensuring nil values for unspecified options. Sorting the flows ensures consistent output.


167-177: LGTM!

The OrderedFlowNames helper correctly derives the ordered flow names from the canonical flows set, ensuring consistency across the codebase and addressing previous review feedback.

cmd/config/plugins/add_test.go (2)

15-47: LGTM!

The test helpers are well-designed. Using a real temporary file with the DefaultLoader enables comprehensive testing of the full configuration persistence flow, providing better coverage than purely in-memory mocks.


49-367: LGTM!

The test suite provides comprehensive coverage of the Add command functionality, including:

  • Successful plugin addition with minimal and complete field sets
  • Error handling for duplicates, invalid inputs, and validation failures
  • Edge cases such as case-insensitive flow parsing, deduplication, and optional field handling
  • Verification of configuration persistence by reloading after operations

The tests are well-structured, use appropriate assertions, and validate both the command output and the resulting configuration state.

@peteski22 peteski22 force-pushed the peteski22/cli-plugins-add branch from 9961b65 to 80ea3dc Compare October 30, 2025 09:26
Copy link

@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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between be6e7aa and 80ea3dc.

📒 Files selected for processing (3)
  • cmd/config/plugins/add.go (1 hunks)
  • internal/config/plugin_config.go (5 hunks)
  • internal/config/plugin_config_test.go (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-24T09:54:59.315Z
Learnt from: peteski22
PR: mozilla-ai/mcpd#215
File: internal/plugin/types_test.go:83-90
Timestamp: 2025-10-24T09:54:59.315Z
Learning: In internal/plugin/types_test.go, TestOrderedCategories_ReturnsCorrectOrder uses hard-coded assertions to act as a regression check. If the category order changes in the config package, this test will catch it. This is intentional to ensure order stability.

Applied to files:

  • cmd/config/plugins/add.go
  • internal/config/plugin_config_test.go
🧬 Code graph analysis (3)
cmd/config/plugins/add.go (3)
internal/cmd/basecmd.go (1)
  • BaseCmd (45-47)
internal/config/plugin_config.go (6)
  • Category (85-85)
  • OrderedCategories (523-525)
  • OrderedFlowNames (528-537)
  • ParseFlowsDistinct (105-116)
  • PluginEntry (148-161)
  • Flows (92-94)
internal/cmd/options/options.go (1)
  • CmdOption (10-10)
internal/config/plugin_config.go (1)
internal/filter/match.go (1)
  • NormalizeString (36-38)
internal/config/plugin_config_test.go (1)
internal/config/plugin_config.go (6)
  • Flows (92-94)
  • FlowRequest (40-40)
  • FlowResponse (43-43)
  • Flow (88-88)
  • ParseFlowsDistinct (105-116)
  • OrderedFlowNames (528-537)
🔇 Additional comments (13)
internal/config/plugin_config_test.go (5)

11-19: LGTM: Helper functions reduce duplication.

The helper functions correctly use t.Helper() and will reduce duplication throughout the test file.


737-756: LGTM: Clone behaviour correctly verified.

The test properly verifies that Flows() returns a defensive copy by modifying the returned map and checking that subsequent calls return unmodified data.


758-801: LGTM: Comprehensive validation coverage.

The test cases thoroughly cover valid and invalid flow values, including edge cases like empty strings and case sensitivity.


803-883: LGTM: Thorough flow parsing coverage.

The test comprehensively covers ParseFlowsDistinct behaviour including deduplication, normalisation, case handling, and invalid input filtering.


885-890: LGTM: Order regression check.

The hardcoded assertions act as a regression check for flow order stability, consistent with the established pattern for category order tests.

Based on learnings

internal/config/plugin_config.go (4)

6-6: LGTM: Necessary imports for new functionality.

The new imports support the flow handling APIs (maps for cloning/keys, internal/filter for normalisation).

Also applies to: 12-12


59-64: LGTM: Canonical flow set correctly defined.

The unexported flows variable serves as the single source of truth for valid flow types, with clear documentation warning against modification.


90-116: LGTM: Flow handling APIs well designed.

The three functions work together effectively:

  • Flows() provides safe access to canonical flows via defensive copy
  • IsValid() offers efficient validation
  • ParseFlowsDistinct() properly normalises, validates, and deduplicates input with clear documented behaviour

247-250: LGTM: Validation uses canonical sources.

The validation correctly uses IsValid() and derives error messages from OrderedFlowNames(), eliminating hardcoded flow names and ensuring consistency.

cmd/config/plugins/add.go (4)

16-20: LGTM: Flag constants follow best practices.

Defining flag names as constants improves maintainability and reduces the risk of typos.


22-41: LGTM: Well-documented command structure.

The struct is clearly documented with appropriate fields and usage guidance.


43-110: LGTM: Command setup follows best practices.

The function properly:

  • Handles options with error checking
  • Creates detailed help documentation with examples
  • Derives allowed categories and flows from canonical sources
  • Marks required flags appropriately
  • Configures optional flags with sensible defaults

112-168: LGTM: Run logic is robust and user-friendly.

The implementation correctly:

  • Validates input and provides clear error messages
  • Checks for existing plugins and guides users to the appropriate command
  • Parses and validates flows using the canonical APIs
  • Handles optional fields properly (only sets when provided/changed)
  • Sorts flows for deterministic ordering
  • Provides helpful success feedback

@peteski22 peteski22 force-pushed the peteski22/cli-plugins-add branch from 80ea3dc to 49a507e Compare October 30, 2025 09:49
Copy link

@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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 80ea3dc and 49a507e.

📒 Files selected for processing (3)
  • cmd/config/plugins/add.go (1 hunks)
  • internal/config/plugin_config.go (7 hunks)
  • internal/config/plugin_config_test.go (8 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-24T09:54:59.315Z
Learnt from: peteski22
PR: mozilla-ai/mcpd#215
File: internal/plugin/types_test.go:83-90
Timestamp: 2025-10-24T09:54:59.315Z
Learning: In internal/plugin/types_test.go, TestOrderedCategories_ReturnsCorrectOrder uses hard-coded assertions to act as a regression check. If the category order changes in the config package, this test will catch it. This is intentional to ensure order stability.

Applied to files:

  • cmd/config/plugins/add.go
  • internal/config/plugin_config_test.go
  • internal/config/plugin_config.go
🧬 Code graph analysis (3)
cmd/config/plugins/add.go (3)
internal/cmd/basecmd.go (1)
  • BaseCmd (45-47)
internal/config/plugin_config.go (6)
  • Category (85-85)
  • OrderedCategories (523-525)
  • OrderedFlowNames (528-537)
  • ParseFlowsDistinct (105-116)
  • PluginEntry (148-161)
  • Flows (92-94)
internal/cmd/options/options.go (1)
  • CmdOption (10-10)
internal/config/plugin_config_test.go (2)
internal/config/plugin_config.go (9)
  • PluginConfig (121-145)
  • CategoryAuthentication (17-17)
  • PluginEntry (148-161)
  • Flows (92-94)
  • Flow (88-88)
  • FlowRequest (40-40)
  • FlowResponse (43-43)
  • ParseFlowsDistinct (105-116)
  • OrderedFlowNames (528-537)
internal/context/loader.go (1)
  • Created (28-28)
internal/config/plugin_config.go (1)
internal/filter/match.go (1)
  • NormalizeString (36-38)

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants