Skip to content

feat: mcp server picker component#125

Merged
hexqi merged 22 commits intoopentiny:developfrom
SonyLeo:component/mcp-server-picker
Jul 25, 2025
Merged

feat: mcp server picker component#125
hexqi merged 22 commits intoopentiny:developfrom
SonyLeo:component/mcp-server-picker

Conversation

@SonyLeo
Copy link
Copy Markdown
Collaborator

@SonyLeo SonyLeo commented Jun 25, 2025

  1. 组件基本实现
  2. 案例及文档编写

Summary by CodeRabbit

  • New Features

    • Introduced the McpServerPicker component for managing plugins with installed and market tabs, supporting enable/disable, add, delete, and expand actions, plus flexible popup modes (fixed and drawer).
    • Added interactive demo components demonstrating basic usage and popup configuration with modal and drawer popups.
    • Provided detailed documentation covering component usage, API, props, events, and types.
    • Added new UI components including plugin cards, plugin modals, code editor, and form editor, with centralized exports for easy integration.
  • Chores

    • Updated dependencies to include additional TinyVue components to support new UI elements.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 25, 2025

Walkthrough

This change set introduces a new McpServerPicker Vue component for managing plugins, along with comprehensive type definitions, documentation, and demo usage examples. It includes supporting UI components, integrates the new component into the main package, updates dependencies, and documents all APIs and usage scenarios. No modifications to existing logic or exported entities outside the new feature scope are made.

Changes

File(s) Change Summary
docs/.vitepress/config.mts Added sidebar entry for "McpServerPicker 插件选择器" in documentation config.
docs/demos/mcp-server-picker/basic-usage.vue
docs/demos/mcp-server-picker/popup-config.vue
Added two new Vue demo components showcasing basic usage and popup configuration of McpServerPicker.
docs/src/components/mcp-server-picker.md Added detailed documentation for the MCP Server Picker component, including props, events, and types.
packages/components/package.json Added seven new Vue UI dependencies required for the new component.
packages/components/src/index.ts Registered and exported the new McpServerPicker component and its types in the package entry point.
packages/components/src/mcp-server-picker/index.ts Added plugin-style export and install function for McpServerPicker.
packages/components/src/mcp-server-picker/index.type.ts Introduced comprehensive TypeScript type declarations for all component props, events, and related data structures.
packages/components/src/mcp-server-picker/index.vue Implemented the main McpServerPicker Vue component with plugin management UI, event handling, and popup modes.
packages/components/src/mcp-server-picker/components/PluginCard.vue Added PluginCard UI component for displaying individual plugins in installed/market modes with tool toggling and actions.
packages/components/src/mcp-server-picker/components/PluginModal.vue Added PluginModal component for adding plugins via form or code, with modal transitions and validation.
packages/components/src/mcp-server-picker/components/FormEditor.vue Added FormEditor component for editing plugin metadata, including image upload and preview.
packages/components/src/mcp-server-picker/components/CodeEditor.vue Added CodeEditor component for editing plugin JSON configuration in a textarea.
packages/components/src/mcp-server-picker/components/index.ts Centralized re-exports for PluginCard, PluginModal, CodeEditor, and FormEditor components.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant McpServerPicker
    participant PluginCard
    participant PluginModal
    participant FormEditor
    participant CodeEditor

    User->>McpServerPicker: Open plugin picker (show popup)
    McpServerPicker->>User: Display installed/market plugins

    User->>McpServerPicker: Search/filter/toggle plugin/tool
    McpServerPicker->>PluginCard: Render plugin cards
    PluginCard-->>McpServerPicker: Emit toggle/add/delete/expand events

    User->>McpServerPicker: Click "Add Plugin"
    McpServerPicker->>PluginModal: Open add plugin modal
    PluginModal->>User: Show FormEditor or CodeEditor

    User->>FormEditor: Fill form and confirm
    FormEditor-->>PluginModal: Provide form data
    PluginModal-->>McpServerPicker: Emit confirm event with data

    User->>CodeEditor: Input plugin JSON and confirm
    CodeEditor-->>PluginModal: Provide code data
    PluginModal-->>McpServerPicker: Emit confirm event with data

    McpServerPicker->>User: Update plugin list and UI
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~90 minutes

Poem

🐰
In the garden of code, a picker appears,
With plugins and tools, it brings many cheers.
Cards, modals, and forms—oh what a sight!
Add, toggle, or search, from morning till night.
With docs and demos, the story is clear—
The Server Picker’s magic is finally here!

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

docs/demos/mcp-server-picker/basic-usage.vue

Oops! Something went wrong! :(

ESLint: 9.31.0

Error: The 'jiti' library is required for loading TypeScript configuration files. Make sure to install it.
at /node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/config/config-loader.js:145:10
at async loadTypeScriptConfigFileWithJiti (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/config/config-loader.js:144:3)
at async loadConfigFile (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/config/config-loader.js:266:11)
at async ConfigLoader.calculateConfigArray (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/config/config-loader.js:589:23)
at async #calculateConfigArray (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/config/config-loader.js:743:23)
at async /node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/eslint/eslint.js:767:6
at async Promise.all (index 0)
at async ESLint.lintFiles (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/eslint/eslint.js:764:19)
at async Object.execute (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/cli.js:632:14)
at async main (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/bin/eslint.js:175:19)

packages/components/src/mcp-server-picker/components/FormEditor.vue

Oops! Something went wrong! :(

ESLint: 9.31.0

Error: The 'jiti' library is required for loading TypeScript configuration files. Make sure to install it.
at /node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/config/config-loader.js:145:10
at async loadTypeScriptConfigFileWithJiti (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/config/config-loader.js:144:3)
at async loadConfigFile (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/config/config-loader.js:266:11)
at async ConfigLoader.calculateConfigArray (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/config/config-loader.js:589:23)
at async #calculateConfigArray (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/config/config-loader.js:743:23)
at async /node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/eslint/eslint.js:767:6
at async Promise.all (index 0)
at async ESLint.lintFiles (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/eslint/eslint.js:764:19)
at async Object.execute (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/cli.js:632:14)
at async main (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/bin/eslint.js:175:19)

packages/components/src/mcp-server-picker/components/PluginModal.vue

Oops! Something went wrong! :(

ESLint: 9.31.0

Error: The 'jiti' library is required for loading TypeScript configuration files. Make sure to install it.
at /node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/config/config-loader.js:145:10
at async loadTypeScriptConfigFileWithJiti (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/config/config-loader.js:144:3)
at async loadConfigFile (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/config/config-loader.js:266:11)
at async ConfigLoader.calculateConfigArray (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/config/config-loader.js:589:23)
at async #calculateConfigArray (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/config/config-loader.js:743:23)
at async /node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/eslint/eslint.js:767:6
at async Promise.all (index 0)
at async ESLint.lintFiles (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/eslint/eslint.js:764:19)
at async Object.execute (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/lib/cli.js:632:14)
at async main (/node_modules/.pnpm/eslint@9.31.0/node_modules/eslint/bin/eslint.js:175:19)

  • 1 others

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

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

🧹 Nitpick comments (10)
packages/components/package.json (1)

29-33: Align dependency versions to avoid multiple installs

New UI dependencies are locked at ^3.21.0, while existing ones (@opentiny/vue-icon, @opentiny/vue-tooltip) are on ^3.22.0.
Mixing ranges forces the package manager to hoist the highest minor (3.22.x), but it can still duplicate sub-trees if any peer range mismatch occurs.

Prefer pinning the newly-added deps to the same ^3.22.0 range (or keep everything on ^3.21.0) to guarantee a single copy is resolved and cut bundle size.

-    "@opentiny/vue-tabs": "^3.21.0",
-    "@opentiny/vue-tab-item": "^3.21.0",
-    "@opentiny/vue-switch": "^3.21.0",
-    "@opentiny/vue-select": "^3.21.0",
-    "@opentiny/vue-option": "^3.21.0",
+    "@opentiny/vue-tabs": "^3.22.0",
+    "@opentiny/vue-tab-item": "^3.22.0",
+    "@opentiny/vue-switch": "^3.22.0",
+    "@opentiny/vue-select": "^3.22.0",
+    "@opentiny/vue-option": "^3.22.0",
docs/.vitepress/config.mts (1)

69-70: Nit: keep sidebar items alphabetically sorted

McpServerPicker now sits between SuggestionPills (S) and the end of the list, breaking the current alphabetical ordering policy used above (Bubble → Welcome).
Placing it after SuggestionPopover preserves scan-ability.

packages/components/src/mcp-server-picker/index.ts (1)

6-10: Minor: expose install via defineProperty to make it non-enumerable

Vue’s SFC compile output sometimes uses Object.assign which will copy enumerable props; keeping install non-enumerable prevents it from leaking into component props.

-const install = function <T>(app: App<T>) {
-  app.component(MCPServerPicker.name!, MCPServerPicker)
-}
-
-MCPServerPicker.install = install
+const install = function <T>(app: App<T>) {
+  app.component(McpServerPicker.name!, McpServerPicker)
+}
+Object.defineProperty(McpServerPicker, 'install', {
+  value: install,
+  writable: false,
+})
packages/components/src/index.ts (1)

18-19: Path import succeeds but consider explicit file for clarity

import McpServerPicker from './mcp-server-picker' relies on directory index.ts resolution.
An explicit ./mcp-server-picker/index.ts import is less ambiguous to tools that don’t follow Node/TS resolution rules.

packages/components/src/mcp-server-picker/components/PluginCodeDialog.vue (1)

81-95: Consider internationalization for UI text

The UI contains hardcoded Chinese text that might not be suitable for all users.

Consider using an i18n system for better internationalization support:

-<span class="plugin-code-dialog__editor-title">ai_plugin(填写json)</span>
+<span class="plugin-code-dialog__editor-title">{{ $t('plugin.code.aiPluginTitle') }}</span>

-<span class="plugin-code-dialog__editor-title">openapi(填写yaml)</span>
+<span class="plugin-code-dialog__editor-title">{{ $t('plugin.code.openapiTitle') }}</span>
packages/components/src/mcp-server-picker/components/PluginCard.vue (1)

261-266: Add tooltip for truncated descriptions

Plugin descriptions are truncated with ellipsis but users have no way to see the full text.

Add a title attribute or tooltip to show full description on hover:

 &__desc {
   font-size: 14px;
   font-weight: 400;
   line-height: 24px;
   text-align: justify;
   color: rgb(89, 89, 89);
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
+  cursor: help;
 }

And in the template:

-<div class="plugin-card__desc">{{ plugin.description }}</div>
+<div class="plugin-card__desc" :title="plugin.description">{{ plugin.description }}</div>
packages/components/src/mcp-server-picker/index.type.ts (1)

68-116: Consider breaking down the large props interface for better maintainability.

The McpServerPickerProps interface contains 26 properties, making it difficult to understand at a glance. Consider grouping related properties into sub-interfaces for better organization and reusability.

Example refactoring approach:

+export interface DataSourceProps {
+  installedPlugins?: PluginInfo[]
+  marketPlugins?: PluginInfo[]
+}
+
+export interface SearchProps {
+  searchPlaceholder?: string
+  enableSearch?: boolean
+  marketCategoryOptions?: MarketCategoryOption[]
+  marketCategoryPlaceholder?: string
+  enableMarketCategoryFilter?: boolean
+}
+
+export interface PanelControlProps {
+  defaultActiveTab?: 'installed' | 'market'
+  showInstalledTab?: boolean
+  showMarketTab?: boolean
+  visible?: boolean
+  popupConfig?: PopupConfig
+  activeCount?: number
+  installedTabTitle?: string
+  marketTabTitle?: string
+}
+
+export interface HeaderProps {
+  title?: string
+  showCustomAddButton?: boolean
+  customAddButtonText?: string
+}
+
+export interface BehaviorControlProps {
+  allowPluginToggle?: boolean
+  allowToolToggle?: boolean
+  allowPluginDelete?: boolean
+  allowPluginAdd?: boolean
+  enableParentChildSync?: boolean
+}
+
+export interface LoadingProps {
+  loading?: boolean
+  marketLoading?: boolean
+}
+
-export interface McpServerPickerProps {
-  // ... all 26 properties
-}
+export interface McpServerPickerProps extends 
+  DataSourceProps,
+  SearchProps,
+  PanelControlProps,
+  HeaderProps,
+  BehaviorControlProps,
+  LoadingProps {}
docs/src/components/mcp-server-picker.md (1)

24-29: Add blank lines around tables for proper markdown formatting.

The static analysis tool indicates that tables should be surrounded by blank lines for proper markdown formatting compliance.

Apply this pattern to all tables in the document:

 #### 数据源配置
+
 | 属性 | 类型 | 默认值 | 说明 |
 |------|------|--------|------|
 | `installedPlugins` | `PluginInfo[]` | `[]` | 已安装插件列表 |
 | `marketPlugins` | `PluginInfo[]` | `[]` | 市场插件列表 |
+
 
 #### 搜索与筛选

Also applies to: 30-38, 39-50, 52-58, 59-67, 68-73, 76-81, 82-88, 89-96, 97-101, 102-108, 109-113

packages/components/src/mcp-server-picker/index.vue (2)

388-388: Replace magic numbers with named constants or CSS variables.

Using hard-coded pixel values reduces maintainability and makes it harder to ensure consistent spacing throughout the application.

-              <div v-if="props.enableMarketCategoryFilter" style="width: 168px">
+              <div v-if="props.enableMarketCategoryFilter" class="market-category-select">
                 <TinySelect v-model="marketCategory" :placeholder="props.marketCategoryPlaceholder">

-              <div v-if="props.enableSearch" style="width: 264px; flex-shrink: 0">
+              <div v-if="props.enableSearch" class="market-search-input">
                 <TinyInput v-model="marketSearch" :placeholder="currentSearchPlaceholder">

Then define the widths in your styles section:

.market-category-select {
  width: 168px;
}

.market-search-input {
  width: 264px;
  flex-shrink: 0;
}

Also applies to: 400-400


1-615: Consider splitting this large component into smaller, focused sub-components.

At 615 lines, this component handles multiple responsibilities including dialog management, event handling, style computation, and UI rendering. This makes it harder to maintain and test.

Consider extracting:

  1. Style computation logic into a composable (e.g., usePickerStyles)
  2. Dialog management into a separate composable (e.g., usePluginDialogs)
  3. Plugin list sections into dedicated components (e.g., InstalledPluginsList, MarketPluginsList)

This would improve code organization, reusability, and testability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9cf54e9 and 05f7fdf.

⛔ Files ignored due to path filters (7)
  • packages/components/src/assets/svgs/edit.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/arrow-right.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/plugin.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/plus.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/selected.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/shell.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/unselected.svg is excluded by !**/*.svg
📒 Files selected for processing (13)
  • docs/.vitepress/config.mts (1 hunks)
  • docs/demos/mcp-server-picker/basic-usage.vue (1 hunks)
  • docs/demos/mcp-server-picker/popup-config.vue (1 hunks)
  • docs/src/components/mcp-server-picker.md (1 hunks)
  • packages/components/package.json (1 hunks)
  • packages/components/src/index.ts (4 hunks)
  • packages/components/src/mcp-server-picker/components/PluginCard.vue (1 hunks)
  • packages/components/src/mcp-server-picker/components/PluginCodeDialog.vue (1 hunks)
  • packages/components/src/mcp-server-picker/components/PluginFormDialog.vue (1 hunks)
  • packages/components/src/mcp-server-picker/components/index.ts (1 hunks)
  • packages/components/src/mcp-server-picker/index.ts (1 hunks)
  • packages/components/src/mcp-server-picker/index.type.ts (1 hunks)
  • packages/components/src/mcp-server-picker/index.vue (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/components/src/mcp-server-picker/index.ts (1)
packages/components/src/index.ts (1)
  • install (57-62)
🪛 markdownlint-cli2 (0.17.2)
docs/src/components/mcp-server-picker.md

25-25: Tables should be surrounded by blank lines
null

(MD058, blanks-around-tables)


31-31: Tables should be surrounded by blank lines
null

(MD058, blanks-around-tables)


40-40: Tables should be surrounded by blank lines
null

(MD058, blanks-around-tables)


53-53: Tables should be surrounded by blank lines
null

(MD058, blanks-around-tables)


60-60: Tables should be surrounded by blank lines
null

(MD058, blanks-around-tables)


69-69: Tables should be surrounded by blank lines
null

(MD058, blanks-around-tables)


77-77: Tables should be surrounded by blank lines
null

(MD058, blanks-around-tables)


83-83: Tables should be surrounded by blank lines
null

(MD058, blanks-around-tables)


90-90: Tables should be surrounded by blank lines
null

(MD058, blanks-around-tables)


98-98: Tables should be surrounded by blank lines
null

(MD058, blanks-around-tables)


103-103: Tables should be surrounded by blank lines
null

(MD058, blanks-around-tables)


110-110: Tables should be surrounded by blank lines
null

(MD058, blanks-around-tables)

🔇 Additional comments (6)
packages/components/src/mcp-server-picker/components/index.ts (1)

1-3: LGTM – clean barrel export

Straightforward barrel keeps import paths short.
No issues spotted.

packages/components/src/index.ts (2)

53-54: Duplicate install when both plugin array & self-install coexist

McpServerPicker already exposes its own install; pushing it into components causes the top-level installer to register it again.
While harmless, it wastes cycles and can warn in Vue 3.3 (app.component duplicate).
Either:

  1. Remove it from the components array, relying on McpServerPicker.install, or
  2. Keep it in the array and remove the local .install property.

100-102: Alias still inconsistent after renaming

Once the component name is fixed to McpServerPicker, export alias should stay as-is (TrMcpServerPicker).
Verify both export and global component name are identical (TrMcpServerPicker) to avoid confusion.

packages/components/src/mcp-server-picker/components/PluginFormDialog.vue (1)

461-461: Verify the existence of the hardcoded asset path

The edit icon uses a hardcoded relative path that might not exist in the build output.

#!/bin/bash
# Description: Check if the edit.svg file exists at the expected location

# Look for the edit.svg file
fd -t f "edit.svg" packages/components/src/

# Check if there's an assets directory structure
fd -t d "assets" packages/components/src/mcp-server-picker/
packages/components/src/mcp-server-picker/components/PluginCard.vue (1)

74-87: ```shell
#!/bin/bash

Display the first 200 lines to inspect pluginState and watcher implementation

sed -n '1,200p' packages/components/src/mcp-server-picker/components/PluginCard.vue


</details>
<details>
<summary>docs/demos/mcp-server-picker/popup-config.vue (1)</summary>

`166-188`: **Well-implemented single-instance modal pattern!**

The use of computed properties to manage modal visibility ensures only one modal is shown at a time, providing excellent user experience.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment thread packages/components/src/mcp-server-picker/index.ts Outdated
Comment thread packages/components/src/mcp-server-picker/components/PluginCodeDialog.vue Outdated
Comment thread packages/components/src/mcp-server-picker/components/PluginCodeDialog.vue Outdated
Comment thread packages/components/src/mcp-server-picker/components/PluginFormDialog.vue Outdated
Comment thread packages/components/src/mcp-server-picker/components/PluginFormDialog.vue Outdated
Comment thread docs/demos/mcp-server-picker/basic-usage.vue Outdated
Comment thread docs/demos/mcp-server-picker/basic-usage.vue
Comment thread packages/components/src/mcp-server-picker/index.type.ts
Comment thread packages/components/src/mcp-server-picker/index.vue
Copy link
Copy Markdown

@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

♻️ Duplicate comments (1)
packages/components/src/mcp-server-picker/index.vue (1)

163-177: Still violating Vue's one-way data flow principle with direct prop mutations.

The component continues to directly mutate prop objects in handleAddPlugin (line 167: plugin.added = added) and handlePluginExpand (line 174: plugin.expanded = expanded). This violates Vue's one-way data flow principle.

Remove these direct mutations and rely solely on event emission:

 const handleAddPlugin = (plugin: PluginInfo, added: boolean) => {
   if (!props.allowPluginAdd) return
 
-  // 直接更新插件对象的added状态
-  plugin.added = added
-
   emit('plugin-add', plugin, added)
 }

 const handlePluginExpand = (plugin: PluginInfo, expanded: boolean) => {
-  // 直接更新插件数据
-  plugin.expanded = expanded
-
   emit('plugin-expand', plugin, expanded)
 }

The parent component should handle these state updates and pass the updated data back through props.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 05f7fdf and 1ce7637.

📒 Files selected for processing (4)
  • packages/components/src/mcp-server-picker/components/PluginFormDialog.vue (1 hunks)
  • packages/components/src/mcp-server-picker/index.ts (1 hunks)
  • packages/components/src/mcp-server-picker/index.type.ts (1 hunks)
  • packages/components/src/mcp-server-picker/index.vue (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/components/src/mcp-server-picker/index.ts
  • packages/components/src/mcp-server-picker/components/PluginFormDialog.vue
  • packages/components/src/mcp-server-picker/index.type.ts
🔇 Additional comments (2)
packages/components/src/mcp-server-picker/index.vue (2)

1-62: Well-structured component setup with comprehensive TypeScript integration.

The imports, props definition, and initial state setup follow Vue 3 best practices with proper TypeScript support and sensible defaults.


437-603: Comprehensive and well-structured styling with proper mode support.

The LESS styles are well-organized with clear separation between popup modes, smooth animations, and appropriate deep selectors for component customization.

Comment thread packages/components/src/mcp-server-picker/index.vue Outdated
Copy link
Copy Markdown

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

♻️ Duplicate comments (1)
packages/components/src/mcp-server-picker/index.vue (1)

166-169: Fix direct prop mutation - violates Vue's one-way data flow principle.

The code directly mutates the plugin.added property, which violates Vue's one-way data flow principle and can lead to unexpected behavior.

 const handleAddPlugin = (plugin: PluginInfo, added: boolean) => {
   if (!props.allowPluginAdd) return
 
-  // 直接更新插件对象的added状态
-  plugin.added = added
-
   emit('plugin-add', plugin, added)
 }

The parent component should handle updating the plugin state and pass the updated data back through props.

🧹 Nitpick comments (3)
packages/components/src/mcp-server-picker/index.vue (3)

78-79: Consider memoization for computed properties that reference props.

These computed properties directly return props values, which may cause unnecessary re-renders. Consider whether they're needed or if direct prop access would be more appropriate.

-const installedPluginsList = computed(() => props.installedPlugins)
-const marketPluginsList = computed(() => props.marketPlugins)
+// Use props directly in template or add filtering logic if needed
+// const installedPluginsList = computed(() => 
+//   props.installedPlugins.filter(/* your filter logic */)
+// )

If these computed properties don't add transformation logic, consider using props directly in the template.


253-273: Simplify position styles function with better type safety.

The current implementation uses Record<string, string> but could be more type-safe and concise.

-const getFixedPositionStyles = (position: PopupConfig['position'] = {}) => {
-  const styles: Record<string, string> = {}
-
-  // 处理位置属性
-  Object.entries(position).forEach(([key, value]) => {
-    if (value !== undefined) {
-      styles[key] = typeof value === 'number' ? `${value}px` : value
-    }
-  })
-
-  // 如果没有设置任何位置,使用默认居中
-  if (Object.keys(styles).length === 0) {
-    return {
-      top: '50%',
-      left: '50%',
-      transform: 'translate(-50%, -50%)',
-    }
-  }
-
-  return styles
-}
+const getFixedPositionStyles = (position: PopupConfig['position'] = {}) => {
+  const hasPosition = Object.keys(position).length > 0
+  
+  if (!hasPosition) {
+    return {
+      top: '50%',
+      left: '50%',
+      transform: 'translate(-50%, -50%)',
+    }
+  }
+
+  return Object.fromEntries(
+    Object.entries(position)
+      .filter(([, value]) => value !== undefined)
+      .map(([key, value]) => [key, typeof value === 'number' ? `${value}px` : value])
+  )
+}

549-583: Consider extracting animation styles to CSS custom properties for maintainability.

The animation durations and timing functions are hardcoded. Consider using CSS custom properties for easier theming and maintenance.

+:root {
+  --mcp-picker-transition-duration: 0.3s;
+  --mcp-picker-transition-timing: ease;
+}
+
 .drawer-left,
 .drawer-right {
   &-enter-active,
   &-leave-active {
-    transition: transform 0.3s ease;
+    transition: transform var(--mcp-picker-transition-duration) var(--mcp-picker-transition-timing);
   }
 }

 .fade {
   &-enter-active,
   &-leave-active {
-    transition: opacity 0.3s ease;
+    transition: opacity var(--mcp-picker-transition-duration) var(--mcp-picker-transition-timing);
   }
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ce7637 and d70ffbf.

📒 Files selected for processing (2)
  • docs/demos/mcp-server-picker/basic-usage.vue (1 hunks)
  • packages/components/src/mcp-server-picker/index.vue (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/demos/mcp-server-picker/basic-usage.vue
🔇 Additional comments (2)
packages/components/src/mcp-server-picker/index.vue (2)

358-362: LGTM! Event-based prop communication is correctly implemented.

The component properly uses :expanded binding with @update:expanded event handler instead of v-model, which avoids direct prop mutations and maintains proper one-way data flow.


115-139: LGTM! Plugin toggle logic correctly uses event emission.

The refactored event handling properly emits events instead of directly mutating plugin properties, which maintains Vue's one-way data flow principle.

Comment thread packages/components/src/mcp-server-picker/index.vue
Comment thread packages/components/src/mcp-server-picker/index.vue
@hexqi hexqi added this to the v0.3.x milestone Jul 17, 2025
@SonyLeo SonyLeo force-pushed the component/mcp-server-picker branch from d70ffbf to 48d99e2 Compare July 22, 2025 13:11
Copy link
Copy Markdown

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

♻️ Duplicate comments (1)
packages/components/src/mcp-server-picker/index.type.ts (1)

41-184: Comprehensive type definitions with good structure.

The type system provides:

  • Clear interfaces for all component interactions
  • Proper event typing with specific parameters
  • Good separation between props and emits
  • Flexible configuration options

However, there's still the language consistency issue mentioned in previous reviews.

🧹 Nitpick comments (4)
packages/components/src/mcp-server-picker/components/PluginModal.vue (1)

52-87: Consider adding accessibility attributes for the modal.

The modal implementation is functional but missing some accessibility features that would improve screen reader support.

-  <div v-if="visible" class="plugin-editor" ref="dialogRef">
+  <div v-if="visible" class="plugin-editor" ref="dialogRef" role="dialog" aria-modal="true" aria-labelledby="modal-title">
     <div class="plugin-editor__header">
-      <h3 class="plugin-editor__title">添加插件</h3>
+      <h3 id="modal-title" class="plugin-editor__title">添加插件</h3>
       <IconClose class="plugin-editor__close" @click="handleClose" />
     </div>
packages/components/src/mcp-server-picker/components/FormEditor.vue (1)

9-9: Consider using a configurable default image URL.

The hardcoded CDN URL could become a maintenance issue if the CDN changes or becomes unavailable.

Consider making this configurable via props:

-const defaultImageUrl = 'https://res.hc-cdn.com/tinyui-design/1.1.0.20250526191525/home/images/tiny-ng.svg'
+const props = withDefaults(defineProps<FormEditorProps>(), {
+  defaultImageUrl: 'https://res.hc-cdn.com/tinyui-design/1.1.0.20250526191525/home/images/tiny-ng.svg'
+})
packages/components/src/mcp-server-picker/components/PluginCard.vue (1)

74-87: Optimize watcher performance with better dependency tracking.

The current watcher may trigger unnecessarily on unrelated changes due to deep watching the entire tools array.

Consider a more targeted approach:

-watch(
-  () => plugin.value.tools?.map((tool) => tool.enabled),
-  () => {
+watch(
+  () => plugin.value.tools?.map((tool) => tool.enabled).join(','),
+  (newEnabledStates) => {
     if (enableParentChildSync.value && mode.value === 'installed' && plugin.value.tools?.length) {
       const newPluginState = pluginState.value
       if (plugin.value.enabled !== newPluginState.checked) {
         plugin.value.enabled = newPluginState.checked
         emit('toggle-plugin', newPluginState.checked)
       }
     }
   },
-  { deep: true },
 )

This reduces the frequency of watcher executions by only watching the enabled states.

docs/src/components/mcp-server-picker.md (1)

24-72: Fix table formatting issues flagged by markdownlint.

The documentation has multiple tables that lack proper blank line spacing, which violates markdown formatting standards.

Add blank lines before and after each table as indicated by the static analysis:

 #### 数据源配置
+
 | 属性 | 类型 | 默认值 | 说明 |
 |------|------|--------|------|
 | `installedPlugins` | `PluginInfo[]` | `[]` | 已安装插件列表 |
 | `marketPlugins` | `PluginInfo[]` | `[]` | 市场插件列表 |
+

 #### 搜索与筛选
+
 | 属性 | 类型 | 默认值 | 说明 |
 |------|------|--------|------|
 | `enableSearch` | `boolean` | `true` | 是否启用搜索功能 |
 | `searchPlaceholder` | `string` | `'搜索插件'` | 搜索框占位符 |
 | `enableMarketCategoryFilter` | `boolean` | `true` | 是否启用市场分类筛选功能 |
 | `marketCategoryOptions` | `MarketCategoryOption[]` | `[]` | 市场分类选项列表 |
 | `marketCategoryPlaceholder` | `string` | `'按照分类筛选'` | 分类筛选下拉框占位符 |
+

Apply the same pattern to all remaining tables (lines 40, 53, 60, 69, 77, 83, 90, 98, 103, 110).

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d70ffbf and 48d99e2.

⛔ Files ignored due to path filters (7)
  • packages/components/src/assets/svgs/edit.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/arrow-right.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/plugin.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/plus.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/selected.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/shell.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/unselected.svg is excluded by !**/*.svg
📒 Files selected for processing (14)
  • docs/.vitepress/config.mts (1 hunks)
  • docs/demos/mcp-server-picker/basic-usage.vue (1 hunks)
  • docs/demos/mcp-server-picker/popup-config.vue (1 hunks)
  • docs/src/components/mcp-server-picker.md (1 hunks)
  • packages/components/package.json (1 hunks)
  • packages/components/src/index.ts (4 hunks)
  • packages/components/src/mcp-server-picker/components/CodeEditor.vue (1 hunks)
  • packages/components/src/mcp-server-picker/components/FormEditor.vue (1 hunks)
  • packages/components/src/mcp-server-picker/components/PluginCard.vue (1 hunks)
  • packages/components/src/mcp-server-picker/components/PluginModal.vue (1 hunks)
  • packages/components/src/mcp-server-picker/components/index.ts (1 hunks)
  • packages/components/src/mcp-server-picker/index.ts (1 hunks)
  • packages/components/src/mcp-server-picker/index.type.ts (1 hunks)
  • packages/components/src/mcp-server-picker/index.vue (1 hunks)
🧠 Learnings (4)
packages/components/src/mcp-server-picker/components/PluginModal.vue (1)

Learnt from: gene9831
PR: #59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the show computed property has a custom setter that prevents state mutations when props.trigger === 'manual'. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.

packages/components/src/mcp-server-picker/components/PluginCard.vue (1)

Learnt from: SonyLeo
PR: #119
File: packages/components/src/attachments/index.less:213-213
Timestamp: 2025-06-18T09:29:47.974Z
Learning: 在 packages/components/src/attachments/index.less 中,.tr-file-card__close 的背景色使用了硬编码的 rgb(194, 194, 194),但这个UI元素(关闭按钮)将会被直接替换为图标,所以不需要抽取为CSS变量。

packages/components/src/mcp-server-picker/index.vue (3)

Learnt from: gene9831
PR: #59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the show computed property has a custom setter that prevents state mutations when props.trigger === 'manual'. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.

Learnt from: gene9831
PR: #59
File: packages/components/src/suggestion-popover/index.vue:0-0
Timestamp: 2025-05-27T03:45:56.392Z
Learning: In Vue components using VueUse's onClickOutside, calling stopPropagation() in the onClickOutside handler can prevent subsequent click event handlers on the same element from being triggered. This means that clicking a trigger element while a popover is open can successfully close the popover without immediately reopening it, even when the onClickOutside only listens to the popover element and not the trigger element.

Learnt from: SonyLeo
PR: #119
File: packages/components/src/attachments/index.less:213-213
Timestamp: 2025-06-18T09:29:47.974Z
Learning: 在 packages/components/src/attachments/index.less 中,.tr-file-card__close 的背景色使用了硬编码的 rgb(194, 194, 194),但这个UI元素(关闭按钮)将会被直接替换为图标,所以不需要抽取为CSS变量。

packages/components/src/mcp-server-picker/components/FormEditor.vue (1)

Learnt from: gene9831
PR: #123
File: packages/components/src/bubble/message/Message.vue:22-40
Timestamp: 2025-06-25T07:04:18.791Z
Learning: In the Message component (packages/components/src/bubble/message/Message.vue), the renderer resolution is intentionally not reactive to type changes - the component is designed to work with a fixed type that doesn't change after initialization.

🪛 markdownlint-cli2 (0.17.2)
docs/src/components/mcp-server-picker.md

25-25: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


31-31: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


40-40: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


53-53: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


60-60: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


69-69: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


77-77: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


83-83: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


90-90: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


98-98: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


103-103: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


110-110: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

✅ Files skipped from review due to trivial changes (2)
  • packages/components/src/mcp-server-picker/components/CodeEditor.vue
  • packages/components/src/mcp-server-picker/index.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/components/src/index.ts
  • packages/components/package.json
  • docs/demos/mcp-server-picker/popup-config.vue
  • docs/.vitepress/config.mts
  • docs/demos/mcp-server-picker/basic-usage.vue
🧰 Additional context used
🧠 Learnings (4)
packages/components/src/mcp-server-picker/components/PluginModal.vue (1)

Learnt from: gene9831
PR: #59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the show computed property has a custom setter that prevents state mutations when props.trigger === 'manual'. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.

packages/components/src/mcp-server-picker/components/PluginCard.vue (1)

Learnt from: SonyLeo
PR: #119
File: packages/components/src/attachments/index.less:213-213
Timestamp: 2025-06-18T09:29:47.974Z
Learning: 在 packages/components/src/attachments/index.less 中,.tr-file-card__close 的背景色使用了硬编码的 rgb(194, 194, 194),但这个UI元素(关闭按钮)将会被直接替换为图标,所以不需要抽取为CSS变量。

packages/components/src/mcp-server-picker/index.vue (3)

Learnt from: gene9831
PR: #59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the show computed property has a custom setter that prevents state mutations when props.trigger === 'manual'. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.

Learnt from: gene9831
PR: #59
File: packages/components/src/suggestion-popover/index.vue:0-0
Timestamp: 2025-05-27T03:45:56.392Z
Learning: In Vue components using VueUse's onClickOutside, calling stopPropagation() in the onClickOutside handler can prevent subsequent click event handlers on the same element from being triggered. This means that clicking a trigger element while a popover is open can successfully close the popover without immediately reopening it, even when the onClickOutside only listens to the popover element and not the trigger element.

Learnt from: SonyLeo
PR: #119
File: packages/components/src/attachments/index.less:213-213
Timestamp: 2025-06-18T09:29:47.974Z
Learning: 在 packages/components/src/attachments/index.less 中,.tr-file-card__close 的背景色使用了硬编码的 rgb(194, 194, 194),但这个UI元素(关闭按钮)将会被直接替换为图标,所以不需要抽取为CSS变量。

packages/components/src/mcp-server-picker/components/FormEditor.vue (1)

Learnt from: gene9831
PR: #123
File: packages/components/src/bubble/message/Message.vue:22-40
Timestamp: 2025-06-25T07:04:18.791Z
Learning: In the Message component (packages/components/src/bubble/message/Message.vue), the renderer resolution is intentionally not reactive to type changes - the component is designed to work with a fixed type that doesn't change after initialization.

🪛 markdownlint-cli2 (0.17.2)
docs/src/components/mcp-server-picker.md

25-25: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


31-31: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


40-40: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


53-53: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


60-60: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


69-69: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


77-77: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


83-83: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


90-90: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


98-98: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


103-103: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


110-110: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

🔇 Additional comments (16)
packages/components/src/mcp-server-picker/components/index.ts (1)

1-4: LGTM! Clean barrel export pattern.

The export structure is well-organized and follows standard conventions for component libraries.

packages/components/src/mcp-server-picker/components/PluginModal.vue (2)

1-50: Well-structured modal component with proper event handling.

The component correctly implements:

  • Two-way binding with defineModel for visibility
  • Proper TypeScript typing for emits
  • Click-outside functionality for UX
  • Clean separation of form and code data handling

89-222: Well-designed styles with smooth transitions.

The CSS implementation provides:

  • Proper z-index layering for backdrop and modal
  • Smooth enter/leave transitions
  • Responsive button styling with hover states
  • Good visual hierarchy
packages/components/src/mcp-server-picker/components/FormEditor.vue (2)

73-127: Well-structured form template with proper accessibility.

The form implementation provides:

  • Proper label associations
  • Appropriate input types (text, url, textarea)
  • Good placeholder text
  • Accessible file upload with visual feedback

240-240: SVG asset path validated

The edit.svg file exists at packages/components/src/assets/svgs/edit.svg, which correctly matches the relative reference in
packages/components/src/mcp-server-picker/components/FormEditor.vue (line 240):

background-image: url('../../assets/svgs/edit.svg');

No changes required.

packages/components/src/mcp-server-picker/components/PluginCard.vue (3)

37-53: Well-implemented tri-state logic for plugin status.

The computed property correctly handles the three states:

  • All tools disabled (unchecked)
  • All tools enabled (checked)
  • Mixed state (indeterminate)

This provides good UX for managing parent-child relationships.


185-395: Comprehensive and well-organized styles.

The CSS implementation provides:

  • Smooth animations for expand/collapse
  • Proper layout with flexbox
  • Good visual hierarchy and spacing
  • Responsive design considerations
  • Consistent color scheme

102-183: Well-structured template with good slot usage.

The template provides:

  • Flexible slot system for customization
  • Proper conditional rendering based on mode
  • Clean separation of plugin and tool UI
  • Smooth transitions for expandable content
docs/src/components/mcp-server-picker.md (1)

116-204: Comprehensive and well-structured type definitions.

The TypeScript interface definitions are thorough and properly documented, covering all necessary types for plugin management, popup configuration, and data structures.

packages/components/src/mcp-server-picker/index.vue (7)

1-11: Well-structured imports and type definitions.

The imports are properly organized with external dependencies, internal components, and TypeScript types clearly separated.


12-40: Comprehensive props definition with sensible defaults.

The props are well-defined with proper TypeScript typing and reasonable default values that provide good out-of-the-box functionality.


44-87: Proper reactive state management and event emission.

The component correctly uses Vue 3's composition API with appropriate watchers for emitting events when state changes. The computed properties efficiently derive state from props.


89-149: Event handlers correctly implement one-way data flow.

The event handling functions properly emit events to the parent component rather than directly mutating props, following Vue's recommended patterns for component communication.


172-258: Robust popup positioning and animation system.

The computed properties for popup positioning and animations handle both fixed and drawer modes effectively, with proper fallbacks and transition management.


261-363: Well-structured template with proper Vue 3 patterns.

The template correctly uses Vue 3 composition API patterns, conditional rendering, and component integration. Event handling and data binding are implemented properly.


365-531: Comprehensive and well-organized component styling.

The LESS styles are properly scoped with good visual design, appropriate animations for popup transitions, and effective use of deep selectors for child component styling.

Comment thread packages/components/src/mcp-server-picker/components/FormEditor.vue
Comment thread packages/components/src/mcp-server-picker/index.vue Outdated
Copy link
Copy Markdown

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

♻️ Duplicate comments (2)
docs/demos/mcp-server-picker/basic-usage.vue (2)

165-187: Plugin removal logic still uses name-based matching.

This issue was flagged in previous reviews but remains unaddressed. The function adds plugins with unique IDs but removes them by name, which could remove the wrong plugin if multiple plugins share the same name.

Apply this fix to use proper ID-based matching:

 const handlePluginAdd = (plugin: PluginInfo, added: boolean) => {
   console.log('插件添加状态变化:', plugin, added)

   const targetPlugin = marketPlugins.value.find((p) => p.id === plugin.id)
   targetPlugin.added = added

   if (added) {
     // 如果是添加操作,创建新的插件副本并添加到已安装列表
     const newPlugin: PluginInfo = {
       ...plugin,
       id: `${plugin.id}-installed-${Date.now()}`, // 生成新的ID避免冲突
       enabled: false, // 新添加的插件默认不启用
       added: true,
+      marketPluginId: plugin.id, // Keep reference to market plugin
     }
     installedPlugins.value.push(newPlugin)
   } else {
     // 如果是取消添加操作,从已安装列表中移除
-    const index = installedPlugins.value.findIndex((p) => p.name === plugin.name)
+    const index = installedPlugins.value.findIndex((p) => p.marketPluginId === plugin.id)
     if (index > -1) {
       installedPlugins.value.splice(index, 1)
     }
   }
 }

205-217: Thumbnail file processing still missing.

The previous review flagged that the thumbnail file from form data is ignored when creating plugins. This remains unaddressed.

Process the thumbnail file to create a preview URL:

 const createPluginByForm = (data: FormData) => {
   console.log('表单方式添加插件:', data)
+  
+  // Create thumbnail URL if file exists
+  let thumbnailUrl = ''
+  if (data.thumbnail) {
+    thumbnailUrl = URL.createObjectURL(data.thumbnail)
+  }
+  
   // 可以在这里处理表单数据,例如发送到服务器
   const newPlugin: PluginInfo = {
     id: `custom-${Date.now()}`,
     name: data.name,
-    icon: '', // 如果有缩略图可以处理 data.thumbnail
+    icon: thumbnailUrl || 'https://via.placeholder.com/40', // Use thumbnail or placeholder
     description: data.description,
     enabled: false,
     tools: [],
+    // Store reference for cleanup
+    _thumbnailObjectUrl: thumbnailUrl,
   }
   installedPlugins.value.push(newPlugin)
 }
🧹 Nitpick comments (6)
docs/demos/mcp-server-picker/basic-usage.vue (1)

224-230: Add type annotation for data parameter.

The data parameter type should be explicitly typed as the union type Data for better type safety.

-const handlePluginCreate = (type: 'form' | 'code', data: Data) => {
+const handlePluginCreate = (type: 'form' | 'code', data: Data) => {
   if (type === 'form') {
-    createPluginByForm(data)
+    createPluginByForm(data as FormData)
   } else {
-    createPluginByCode(data)
+    createPluginByCode(data as string)
   }
 }
packages/components/src/mcp-server-picker/components/PluginCard.vue (2)

146-172: Optimize transition performance.

The slide transition uses max-height: 1000px which could cause performance issues and doesn't provide accurate animations. Consider using a more precise approach.

Replace the fixed max-height with dynamic calculation:

 <transition name="plugin-card-slide" v-if="expandable">
-  <div v-show="isExpanded" class="plugin-card__tools">
+  <div v-show="isExpanded" class="plugin-card__tools" ref="toolsContainer">

And update the CSS:

 .plugin-card-slide {
   &-enter-active,
   &-leave-active {
     transition: all 0.3s ease;
     overflow: hidden;
   }

   &-enter-from,
   &-leave-to {
-    max-height: 0;
+    height: 0;
     opacity: 0;
     transform: translateY(-10px);
   }

   &-enter-to,
   &-leave-from {
-    max-height: 1000px;
+    height: auto;
     opacity: 1;
     transform: translateY(0);
   }
 }

383-385: CSS custom property override may cause specificity issues.

The TinyButton style override using CSS custom properties might not work reliably across different contexts and could interfere with other components.

Use a more specific selector or move to a global stylesheet:

-.tiny-button {
+.plugin-card .tiny-button {
   --tv-Button-height-small: 16px;
 }

Or consider using a CSS module approach for better encapsulation.

docs/src/components/mcp-server-picker.md (3)

24-29: Fix markdown table formatting.

The table lacks blank lines before and after it, violating markdown standards.

 #### 数据源配置
+
 | 属性 | 类型 | 默认值 | 说明 |
 |------|------|--------|------|
 | `installedPlugins` | `PluginInfo[]` | `[]` | 已安装插件列表 |
 | `marketPlugins` | `PluginInfo[]` | `[]` | 市场插件列表 |
+

30-38: Fix markdown table formatting.

Add blank lines around the table to comply with markdown standards.

 #### 搜索与筛选
+
 | 属性 | 类型 | 默认值 | 说明 |
 |------|------|--------|------|
 | `enableSearch` | `boolean` | `true` | 是否启用搜索功能 |
 | `searchPlaceholder` | `string` | `'搜索插件'` | 搜索框占位符 |
 | `enableMarketCategoryFilter` | `boolean` | `true` | 是否启用市场分类筛选功能 |
 | `marketCategoryOptions` | `MarketCategoryOption[]` | `[]` | 市场分类选项列表 |
 | `marketCategoryPlaceholder` | `string` | `'按照分类筛选'` | 分类筛选下拉框占位符 |
+

177-191: Clarify PopupConfig type definition.

The interface definition is clear, but it would be helpful to specify which properties are required vs optional and provide examples.

 ```typescript
 interface PopupConfig {
   type: 'fixed' | 'drawer'
   // fixed模式配置
   position?: {
     top?: string | number
     left?: string | number
     right?: string | number
     bottom?: string | number
   }
   // drawer模式配置
   drawer?: {
     direction: 'left' | 'right'
   }
 }

+示例:
+
+```typescript
+// Fixed 模式
+const fixedConfig: PopupConfig = {

  • type: 'fixed',
  • position: { top: 100, right: 20 }
    +}

+// Drawer 模式
+const drawerConfig: PopupConfig = {

  • type: 'drawer',
  • drawer: { direction: 'right' }
    +}
    +```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 48d99e25ebebd458c7d770251ea44f4b502466a2 and e8173972d5d31cdeb1e351840ebd7ba4f1ccfe76.

</details>

<details>
<summary>📒 Files selected for processing (8)</summary>

* `docs/demos/mcp-server-picker/basic-usage.vue` (1 hunks)
* `docs/demos/mcp-server-picker/popup-config.vue` (1 hunks)
* `docs/src/components/mcp-server-picker.md` (1 hunks)
* `packages/components/src/mcp-server-picker/components/FormEditor.vue` (1 hunks)
* `packages/components/src/mcp-server-picker/components/PluginCard.vue` (1 hunks)
* `packages/components/src/mcp-server-picker/components/PluginModal.vue` (1 hunks)
* `packages/components/src/mcp-server-picker/index.type.ts` (1 hunks)
* `packages/components/src/mcp-server-picker/index.vue` (1 hunks)

</details>

<details>
<summary>🪛 markdownlint-cli2 (0.17.2)</summary>

<details>
<summary>docs/src/components/mcp-server-picker.md</summary>

25-25: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

31-31: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

40-40: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

53-53: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

60-60: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

68-68: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

76-76: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

82-82: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

89-89: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

97-97: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

102-102: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

</details>

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (5)</summary>

* packages/components/src/mcp-server-picker/components/PluginModal.vue
* packages/components/src/mcp-server-picker/components/FormEditor.vue
* docs/demos/mcp-server-picker/popup-config.vue
* packages/components/src/mcp-server-picker/index.vue
* packages/components/src/mcp-server-picker/index.type.ts

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 markdownlint-cli2 (0.17.2)</summary>

<details>
<summary>docs/src/components/mcp-server-picker.md</summary>

25-25: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

31-31: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

40-40: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

53-53: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

60-60: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

68-68: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

76-76: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

82-82: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

89-89: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

97-97: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

---

102-102: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (3)</summary><blockquote>

<details>
<summary>packages/components/src/mcp-server-picker/components/PluginCard.vue (3)</summary>

`1-12`: **LGTM! Clean component setup and imports.**

The component setup follows Vue 3 composition API best practices with proper TypeScript integration and well-organized imports.

---

`32-47`: **Efficient tri-state checkbox implementation.**

The computed property correctly implements tri-state logic for parent plugins based on their tools' enabled states. The logic handles all three states appropriately: unchecked (no tools enabled), checked (all tools enabled), and indeterminate (partial tools enabled).

---

`49-61`: **Handle plugin toggle efficiently.**

The plugin toggle logic correctly synchronizes all child tools when the parent plugin is toggled, and emits appropriate events. The implementation avoids unnecessary updates by checking if the tool's state actually changes.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment thread docs/demos/mcp-server-picker/basic-usage.vue Outdated
Comment thread docs/src/components/mcp-server-picker.md
Comment thread packages/components/src/mcp-server-picker/components/PluginCard.vue Outdated
Copy link
Copy Markdown

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

♻️ Duplicate comments (1)
docs/src/components/mcp-server-picker.md (1)

113-120: tools should be optional – unresolved from last review.

Previous review already flagged this; demos show plugins without a tools array.
Update the interface accordingly:

-  tools: PluginTool[]    // 工具列表
+  tools?: PluginTool[]   // 工具列表(可选)
🧹 Nitpick comments (1)
docs/src/components/mcp-server-picker.md (1)

24-28: Add blank lines before each Markdown table.

markdownlint (rule MD058) complains because every table starts immediately after the preceding heading.
Insert a single blank line before the | header row (the closing blank lines are already present).

Example fix for the first two tables (replicate for the rest):

-#### 数据源配置
-| 属性 | 类型 | 默认值 | 说明 |
+#### 数据源配置
+
+| 属性 | 类型 | 默认值 | 说明 |
@@
-#### 搜索与筛选
-| 属性 | 类型 | 默认值 | 说明 |
+#### 搜索与筛选
+
+| 属性 | 类型 | 默认值 | 说明 |

This satisfies MD058, improves readability, and keeps CI quiet.

Also applies to: 30-37, 39-49, 53-57, 59-66, 68-72, 75-80, 81-87, 88-94, 96-100, 101-104

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e817397 and 5fbfe19.

📒 Files selected for processing (4)
  • docs/demos/mcp-server-picker/basic-usage.vue (1 hunks)
  • docs/src/components/mcp-server-picker.md (1 hunks)
  • packages/components/src/mcp-server-picker/components/PluginCard.vue (1 hunks)
  • packages/components/src/mcp-server-picker/index.type.ts (1 hunks)
🪛 markdownlint-cli2 (0.17.2)
docs/src/components/mcp-server-picker.md

25-25: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


31-31: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


40-40: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


53-53: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


60-60: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


68-68: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


76-76: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


82-82: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


89-89: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


97-97: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


102-102: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/components/src/mcp-server-picker/components/PluginCard.vue
  • docs/demos/mcp-server-picker/basic-usage.vue
  • packages/components/src/mcp-server-picker/index.type.ts
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
docs/src/components/mcp-server-picker.md

25-25: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


31-31: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


40-40: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


53-53: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


60-60: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


68-68: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


76-76: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


82-82: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


89-89: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


97-97: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


102-102: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

Comment thread docs/demos/mcp-server-picker/basic-usage.vue
Comment thread docs/demos/mcp-server-picker/basic-usage.vue
Comment thread docs/src/components/mcp-server-picker.md Outdated
Comment thread docs/src/components/mcp-server-picker.md Outdated
Copy link
Copy Markdown

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

♻️ Duplicate comments (2)
packages/components/src/mcp-server-picker/index.vue (1)

269-273: Add missing accessibility attributes for interactive elements.

The custom add button and close icon still lack proper accessibility attributes for keyboard navigation and screen reader support.

Apply the accessibility improvements suggested in previous reviews:

-          <div v-if="props.showCustomAddButton" class="mcp-server-picker__header-right-item" @click="handleCustomAdd">
+          <div 
+            v-if="props.showCustomAddButton" 
+            class="mcp-server-picker__header-right-item" 
+            role="button"
+            tabindex="0"
+            :aria-label="props.customAddButtonText"
+            @click="handleCustomAdd"
+            @keydown.enter="handleCustomAdd"
+            @keydown.space.prevent="handleCustomAdd"
+          >
             <IconPlus style="font-size: 16px; cursor: pointer" />
             <span>{{ props.customAddButtonText }}</span>
           </div>
-          <IconClose class="mcp-server-picker__header-right-close" @click="handleClose" />
+          <IconClose 
+            class="mcp-server-picker__header-right-close" 
+            role="button"
+            tabindex="0"
+            aria-label="关闭"
+            @click="handleClose"
+            @keydown.enter="handleClose"
+            @keydown.space.prevent="handleClose"
+          />
docs/src/components/mcp-server-picker.md (1)

112-123: Fix TypeScript interface documentation for optional properties.

The tools and enabled properties should be marked as optional based on the component's usage patterns and past review feedback.

 interface PluginInfo {
   id: string              // 插件唯一标识
   name: string            // 插件名称
   icon: string            // 插件图标URL
   description: string     // 插件描述
-  enabled: boolean       // 是否启用
-  tools: PluginTool[]    // 工具列表
+  enabled?: boolean      // 是否启用(可选)
+  tools?: PluginTool[]   // 工具列表(可选)
   added?: boolean         // 市场插件添加状态(可选)
   category?: string       // 插件分类(可选,用于市场分类筛选)
 }
🧹 Nitpick comments (1)
docs/src/components/mcp-server-picker.md (1)

24-105: Comprehensive API documentation with minor formatting improvements needed.

The props and events documentation is thorough and well-categorized. However, markdown tables should be surrounded by blank lines for better formatting compliance.

Add blank lines before and after each table section to improve markdown formatting:

 #### 数据源配置
+
 | 属性 | 类型 | 默认值 | 说明 |
 |------|------|--------|------|
 | `installedPlugins` | `PluginInfo[]` | `[]` | 已安装插件列表 |
 | `marketPlugins` | `PluginInfo[]` | `[]` | 市场插件列表 |
+

Apply similar spacing to all table sections throughout the document.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5fbfe19 and 9aae7db.

📒 Files selected for processing (5)
  • docs/demos/mcp-server-picker/basic-usage.vue (1 hunks)
  • docs/src/components/mcp-server-picker.md (1 hunks)
  • packages/components/src/mcp-server-picker/components/FormEditor.vue (1 hunks)
  • packages/components/src/mcp-server-picker/index.type.ts (1 hunks)
  • packages/components/src/mcp-server-picker/index.vue (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/components/src/mcp-server-picker/components/FormEditor.vue
  • docs/demos/mcp-server-picker/basic-usage.vue
  • packages/components/src/mcp-server-picker/index.type.ts
🧰 Additional context used
🧠 Learnings (1)
packages/components/src/mcp-server-picker/index.vue (3)

Learnt from: gene9831
PR: #59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the show computed property has a custom setter that prevents state mutations when props.trigger === 'manual'. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.

Learnt from: gene9831
PR: #59
File: packages/components/src/suggestion-popover/index.vue:0-0
Timestamp: 2025-05-27T03:45:56.392Z
Learning: In Vue components using VueUse's onClickOutside, calling stopPropagation() in the onClickOutside handler can prevent subsequent click event handlers on the same element from being triggered. This means that clicking a trigger element while a popover is open can successfully close the popover without immediately reopening it, even when the onClickOutside only listens to the popover element and not the trigger element.

Learnt from: SonyLeo
PR: #119
File: packages/components/src/attachments/index.less:213-213
Timestamp: 2025-06-18T09:29:47.974Z
Learning: 在 packages/components/src/attachments/index.less 中,.tr-file-card__close 的背景色使用了硬编码的 rgb(194, 194, 194),但这个UI元素(关闭按钮)将会被直接替换为图标,所以不需要抽取为CSS变量。

🪛 markdownlint-cli2 (0.17.2)
docs/src/components/mcp-server-picker.md

25-25: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


31-31: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


40-40: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


53-53: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


60-60: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


68-68: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


76-76: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


82-82: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


89-89: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


97-97: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


102-102: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

🔇 Additional comments (9)
packages/components/src/mcp-server-picker/index.vue (7)

1-17: LGTM! Well-organized imports following Vue 3 best practices.

The imports are properly structured with clear separation between external libraries, local components, and TypeScript types.


18-46: Excellent TypeScript props definition with comprehensive defaults.

The use of withDefaults(defineProps<McpServerPickerProps>(), {...}) follows Vue 3 + TypeScript best practices, providing type safety while maintaining sensible default values for all configuration options.


47-73: Proper Vue 3 reactivity implementation with type-safe event handling.

The reactive state management using ref(), computed(), and watch() follows composition API best practices. The immediate execution of the activePluginCount watcher ensures proper initial state synchronization.


94-147: Excellent event handling that maintains Vue's one-way data flow.

The event handlers properly avoid direct prop mutations and use event emission for all state changes. The parent-child synchronization logic between plugins and tools is well-implemented while maintaining proper data flow patterns.


169-256: Well-architected popup configuration system with flexible styling.

The dynamic style computation effectively supports both fixed and drawer popup modes with proper fallbacks. The separation of concerns between position calculation and animation classes demonstrates good component architecture.


274-357: Clean template structure with proper component composition.

The tabbed interface is well-implemented using TinyTabs, and the PluginCard components are used consistently with appropriate event binding patterns. Loading states are handled gracefully with conditional rendering.


359-525: Comprehensive and well-organized LESS styles with proper scoping.

The styles effectively support both popup modes with appropriate animations. The use of scoped styles prevents CSS leakage, and the deep selectors for third-party components are properly implemented.

docs/src/components/mcp-server-picker.md (2)

1-19: Clear and well-structured documentation introduction.

The component description accurately reflects the MCP Server Picker's functionality, and the demo references follow the established documentation patterns.


149-191: Accurate and comprehensive TypeScript interface documentation.

The remaining interface definitions correctly reflect the component's implementation, with proper documentation of optional properties and union types.

Comment thread docs/demos/mcp-server-picker/basic-usage.vue
Comment thread packages/components/src/mcp-server-picker/components/PluginCard.vue Outdated
Copy link
Copy Markdown

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

🧹 Nitpick comments (2)
packages/components/src/mcp-server-picker/components/PluginCard.vue (2)

81-170: Well-structured template with good use of slots and transitions.

The template is well-organized with proper conditional rendering and customization slots. The delete confirmation popup addresses the previous feedback about preventing accidental operations.

Consider adding accessibility improvements:

-      <img :src="plugin.icon" class="plugin-card__icon" />
+      <img :src="plugin.icon" :alt="`${plugin.name} icon`" class="plugin-card__icon" />

And consider adding ARIA labels for interactive elements like the expand button and switches for better screen reader support.


172-382: Well-structured styles with modern CSS practices.

The LESS styles are well-organized with consistent naming conventions and good use of transitions. The component styling follows modern UI patterns with appropriate shadows, spacing, and typography.

Consider making the component more responsive:

   &__main {
-    width: 440px;
+    width: 100%;
+    max-width: 440px;

This would allow the component to adapt better to different container sizes while maintaining the intended maximum width.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 53b26f6 and 64f46e6.

📒 Files selected for processing (2)
  • packages/components/package.json (1 hunks)
  • packages/components/src/mcp-server-picker/components/PluginCard.vue (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/components/package.json
🔇 Additional comments (4)
packages/components/src/mcp-server-picker/components/PluginCard.vue (4)

1-6: LGTM! Well-structured imports.

The imports are properly organized with clear separation between external dependencies, Vue composition functions, icons, and TypeScript types.


8-13: LGTM! Proper Vue 3 TypeScript setup.

The props definition with defaults and typed emits follow Vue 3 best practices and provide good developer experience.


15-48: LGTM! Well-implemented tri-state logic.

The computed properties effectively manage the plugin's state with proper tri-state checkbox logic. The implementation correctly handles all edge cases for plugin and tool enabled states.


50-78: Event handlers look correct after infinite loop fix.

The event handlers properly manage plugin and tool state synchronization. The previous infinite loop issue appears to have been resolved, and the current implementation correctly:

  • Synchronizes all tool states when toggling the parent plugin
  • Emits appropriate events for state changes
  • Handles market mode plugin addition state

@SonyLeo SonyLeo force-pushed the component/mcp-server-picker branch from 64f46e6 to 6973896 Compare July 25, 2025 07:31
Copy link
Copy Markdown

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

♻️ Duplicate comments (4)
packages/components/src/mcp-server-picker/index.type.ts (1)

34-39: Language consistency issue persists in comments.

The Chinese comments mixed with English code identifiers create inconsistency for international development teams. This was previously flagged but the issue remains unresolved.

Also applies to: 40-54, 56-66, 68-72, 74-120

docs/src/components/mcp-server-picker.md (1)

112-123: Fix PluginInfo interface documentation consistency.

The documentation shows enabled: boolean and tools: PluginTool[] as required, but based on usage patterns and the type definitions, these should be marked as optional.

 interface PluginInfo {
   id: string              // 插件唯一标识
   name: string            // 插件名称
   icon: string            // 插件图标URL
   description: string     // 插件描述
-  enabled: boolean       // 是否启用
-  tools: PluginTool[]    // 工具列表
+  enabled?: boolean      // 是否启用(可选)
+  tools?: PluginTool[]   // 工具列表(可选)
   added?: boolean         // 市场插件添加状态(可选)
   category?: string       // 插件分类(可选,用于市场分类筛选)
 }
packages/components/src/mcp-server-picker/index.vue (2)

269-272: Add accessibility attributes for custom add button.

The custom add button lacks proper accessibility support for keyboard navigation and screen readers.

-          <div v-if="props.showCustomAddButton" class="mcp-server-picker__header-right-item" @click="handleCustomAdd">
+          <div 
+            v-if="props.showCustomAddButton" 
+            class="mcp-server-picker__header-right-item" 
+            role="button"
+            tabindex="0"
+            :aria-label="props.customAddButtonText"
+            @click="handleCustomAdd"
+            @keydown.enter="handleCustomAdd"
+            @keydown.space.prevent="handleCustomAdd"
+          >

273-273: Add accessibility attributes for close button.

The close button needs proper accessibility support.

-          <IconClose class="mcp-server-picker__header-right-close" @click="handleClose" />
+          <IconClose 
+            class="mcp-server-picker__header-right-close" 
+            role="button"
+            tabindex="0"
+            aria-label="关闭"
+            @click="handleClose"
+            @keydown.enter="handleClose"
+            @keydown.space.prevent="handleClose"
+          />
🧹 Nitpick comments (3)
packages/components/src/mcp-server-picker/index.type.ts (1)

13-17: Consider making enabled and tools properties optional in PluginInfo.

Based on the usage patterns in the documentation and implementation, both enabled and tools properties might not always be required. The enabled property could default to false and tools could be an empty array if not provided.

export interface PluginInfo {
  id: string
  name: string
  icon: string
  description: string
-  enabled: boolean
+  enabled?: boolean
-  tools: PluginTool[]
+  tools?: PluginTool[]
  added?: boolean
  category?: string
}
docs/src/components/mcp-server-picker.md (1)

25-25: Fix markdown table formatting issues.

Multiple tables lack proper blank line spacing as flagged by the markdown linter.

Add blank lines before and after each table to improve markdown compliance and readability. For example:

 #### 数据源配置
+
 | 属性 | 类型 | 默认值 | 说明 |
 |------|------|--------|------|
 | `installedPlugins` | `PluginInfo[]` | `[]` | 已安装插件列表 |
 | `marketPlugins` | `PluginInfo[]` | `[]` | 市场插件列表 |
+

Apply this pattern to all tables in the document.

Also applies to: 31-31, 40-40, 53-53, 60-60, 68-68, 76-76, 82-82, 89-89, 97-97, 102-102

packages/components/src/mcp-server-picker/index.vue (1)

161-163: Consider making visible model optional for better component flexibility.

The visible model is marked as required, but for better component reusability, it should be optional with a sensible default.

const visible = defineModel<boolean>('visible', {
-  required: true,
+  default: false,
})
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 64f46e6 and 6973896.

⛔ Files ignored due to path filters (6)
  • packages/components/src/assets/svgs/edit.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/plugin.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/plus.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/selected.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/shell.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/unselected.svg is excluded by !**/*.svg
📒 Files selected for processing (14)
  • docs/.vitepress/config.mts (1 hunks)
  • docs/demos/mcp-server-picker/basic-usage.vue (1 hunks)
  • docs/demos/mcp-server-picker/popup-config.vue (1 hunks)
  • docs/src/components/mcp-server-picker.md (1 hunks)
  • packages/components/package.json (1 hunks)
  • packages/components/src/index.ts (4 hunks)
  • packages/components/src/mcp-server-picker/components/CodeEditor.vue (1 hunks)
  • packages/components/src/mcp-server-picker/components/FormEditor.vue (1 hunks)
  • packages/components/src/mcp-server-picker/components/PluginCard.vue (1 hunks)
  • packages/components/src/mcp-server-picker/components/PluginModal.vue (1 hunks)
  • packages/components/src/mcp-server-picker/components/index.ts (1 hunks)
  • packages/components/src/mcp-server-picker/index.ts (1 hunks)
  • packages/components/src/mcp-server-picker/index.type.ts (1 hunks)
  • packages/components/src/mcp-server-picker/index.vue (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (11)
  • docs/.vitepress/config.mts
  • packages/components/src/mcp-server-picker/components/index.ts
  • packages/components/src/index.ts
  • packages/components/src/mcp-server-picker/index.ts
  • packages/components/package.json
  • packages/components/src/mcp-server-picker/components/FormEditor.vue
  • packages/components/src/mcp-server-picker/components/CodeEditor.vue
  • packages/components/src/mcp-server-picker/components/PluginModal.vue
  • packages/components/src/mcp-server-picker/components/PluginCard.vue
  • docs/demos/mcp-server-picker/basic-usage.vue
  • docs/demos/mcp-server-picker/popup-config.vue
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
docs/src/components/mcp-server-picker.md

25-25: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


31-31: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


40-40: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


53-53: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


60-60: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


68-68: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


76-76: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


82-82: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


89-89: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


97-97: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


102-102: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

🔇 Additional comments (2)
packages/components/src/mcp-server-picker/index.vue (2)

95-119: Excellent parent-child synchronization logic for plugin and tool states.

The implementation correctly handles the complex relationship between plugin and tool activation states with proper cascading behavior. The logic ensures that:

  • Disabling a parent plugin disables all child tools
  • Enabling a parent plugin activates all tools if none are currently enabled
  • The state changes are properly communicated through events

121-136: Well-implemented bidirectional synchronization for tool-to-plugin state updates.

The tool toggle handler correctly implements the reverse synchronization logic, ensuring that when tools are toggled, the parent plugin state is updated appropriately. The logic properly calculates whether the plugin should remain enabled based on the status of other tools.

Comment thread docs/src/components/mcp-server-picker.md Outdated
Comment thread packages/components/src/mcp-server-picker/index.type.ts Outdated
Copy link
Copy Markdown

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

♻️ Duplicate comments (1)
docs/src/components/mcp-server-picker.md (1)

118-119: enabled and tools should be optional as previously requested

The earlier review already pointed out that both properties are optional in real usage (see demo files). Please change:

-  enabled: boolean       // 是否启用
-  tools: PluginTool[]    // 工具列表
+  enabled?: boolean      // 是否启用(可选)
+  tools?: PluginTool[]   // 工具列表(可选)
🧹 Nitpick comments (1)
docs/src/components/mcp-server-picker.md (1)

24-30: Add blank lines around all tables to satisfy MD058

markdownlint flags every table because there’s no blank line before and after.
Example fix for the first table:

-#### 数据源配置
-| 属性 | 类型 | 默认值 | 说明 |
+#### 数据源配置
+
+| 属性 | 类型 | 默认值 | 说明 |
 |------|------|--------|------|
 ...
+

Apply the same pattern to every table section.

Also applies to: 31-37, 39-49, 52-57, 59-66, 67-72, 75-80, 81-87, 88-95, 96-100, 101-105

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6973896 and b97d40e.

📒 Files selected for processing (5)
  • docs/demos/mcp-server-picker/basic-usage.vue (1 hunks)
  • docs/src/components/mcp-server-picker.md (1 hunks)
  • packages/components/src/mcp-server-picker/components/FormEditor.vue (1 hunks)
  • packages/components/src/mcp-server-picker/components/PluginModal.vue (1 hunks)
  • packages/components/src/mcp-server-picker/index.type.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/components/src/mcp-server-picker/components/FormEditor.vue
  • packages/components/src/mcp-server-picker/components/PluginModal.vue
  • docs/demos/mcp-server-picker/basic-usage.vue
  • packages/components/src/mcp-server-picker/index.type.ts
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
docs/src/components/mcp-server-picker.md

25-25: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


31-31: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


40-40: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


53-53: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


60-60: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


68-68: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


76-76: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


82-82: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


89-89: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


97-97: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


102-102: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

@hexqi hexqi merged commit 78a30bd into opentiny:develop Jul 25, 2025
@SonyLeo SonyLeo deleted the component/mcp-server-picker branch August 4, 2025 07:54
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.

2 participants