Skip to content

Conversation

@SonyLeo
Copy link
Contributor

@SonyLeo SonyLeo commented Oct 27, 2025

English | 简体中文

PR Checklist

Please check if your PR fulfills the following requirements:

  • The commit message follows our Commit Message Guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)
  • Built its own designer, fully self-validated

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

Background and solution

What is the current behavior?

Issue Number: N/A

What is the new behavior?

自定义 MCP 出码功能

一、出码流程概览

1.1 整体流程图

用户配置 MCP ↓ Schema 解析 (parseSchemaPlugin) ↓ 插件系统初始化 (generateApp) ├─→ 加载 MCP 插件配置 └─→ 传递 context.pluginConfig.mcp ↓ MCP 插件执行 (genMcpPlugin) ├─→ 配置验证 (validateMcpConfig) ├─→ 生成基础配置文件 (base.ts) │ └─→ 使用 mcpBaseTemplate ├─→ 生成 MCP 服务器管理器 (server.ts) │ └─→ 使用 mcpServerTemplate(动态导入工具) ├─→ 配置驱动的工具生成 │ ├─→ 遍历 toolGenerators 注册表 │ ├─→ navigation: mcpNavigationToolsTemplate │ ├─→ application: generateApplicationTools │ └─→ 错误隔离(单个工具失败不影响其他) ├─→ 处理 tiny_mcp_config(递归转换) │ └─→ transformTinyMcpConfig └─→ 修改应用入口文件(使用模板片段) ├─→ App.vue: 5 个模板片段组合 │ ├─→ mcp-imports.ts │ ├─→ mcp-setup.ts │ ├─→ mcp-onMounted.ts │ ├─→ mcp-template.ts │ └─→ mcp-style.ts └─→ main.ts: 添加样式导入 ↓ 页面/区块生成 (genPagePlugin/genBlockPlugin) ├─→ 接收 context.pluginConfig.mcp.enabled ├─→ 传递 mcpEnabled 到 SFC 生成器 └─→ 钩子链处理 tiny_mcp_config └─→ handleTinyMcpConfigAttrHook ├─→ 格式转换(简单 → JSExpression) ├─→ 添加 usePageMcpServer 导入 └─→ 添加生命周期钩子(onMounted/onUnmounted) ↓ 依赖管理 (genDependenciesPlugin) ├─→ 接收 context.pluginConfig.mcp └─→ 条件性添加 MCP 依赖(仅当 enabled === true) ├─→ @opentiny/next-remoter: 0.0.2 ├─→ @opentiny/next-sdk: ^0.1.0 ├─→ @opentiny/tiny-robot: ^0.3.0-alpha.16 └─→ @opentiny/tiny-vue-mcp: ~0.0.3 ↓ 代码格式化 (formatCodePlugin) ↓ 生成最终代码 

1.2 生成的文件结构

生成的应用/ ├── src/ │ ├── base.ts # MCP 基础配置(agentRoot, sessionId) │ ├── mcp/ │ │ ├── server.ts # MCP 服务器管理器 │ │ └── tools/ │ │ ├── navigationTools.ts # 导航工具(页面跳转、前进后退) │ │ └── applicationTools.ts # 应用工具(状态管理) │ ├── App.vue # 修改后的应用入口(集成 MCP 客户端) │ ├── main.ts # 修改后的主文件(引入 MCP 样式) │ └── views/ # 页面文件(可能包含 tiny_mcp_config) └── package.json # 添加 MCP 相关依赖 

1.3 关键依赖包

{ "@opentiny/next-remoter": "0.0.2", // MCP UI 组件(聊天界面) "@opentiny/next-sdk": "^0.1.0", // MCP SDK(客户端/服务器) "@opentiny/tiny-robot": "^0.3.0-alpha.16", // AI 机器人组件 "@opentiny/tiny-vue-mcp": "~0.0.3", // TinyVue MCP 集成 "@opentiny/vue-common": "与 @opentiny/vue 版本一致" // Vue 通用工具 }

依赖添加逻辑(genDependenciesPlugin.js):

  • 只有在 mcpConfig.enabled === true 时才添加 MCP 相关依赖
  • 通过 context 传递 MCP 配置到依赖插件
  • 自动处理 TinyVue 相关依赖的版本一致性

二、出码流程解析

2.1 配置阶段

2.1.1 默认配置(genMcpPlugin.js)

const defaultOption = { enabled: false, // 默认禁用,需显式启用 agentRoot: 'https://agent.opentiny.design/api/v1/webmcp-trial/', sessionId: '78b66563-95c0-4839-8007-e8af634dd658', capabilities: { prompts: { listChanged: true }, resources: { subscribe: true, listChanged: true }, tools: { listChanged: true }, completions: {}, logging: {} }, tools: { navigation: true, // 导航工具 application: true // 应用工具 }, customTools: [] }

2.1.2 配置验证

插件会验证配置的有效性:

  • enabled 必须是布尔值
  • agentRoot 必须是有效的 URL
  • tools 中的工具类型必须是已知类型
  • customTools 必须是数组且每个工具有 name 和 implementation

2.2 插件执行阶段

2.2.1 插件生命周期(generateApp.js)

// 三个阶段的钩子 const codeGenInstance = new CodeGenerator({ plugins: { transformStart: [parseSchemaPlugin, ...], // 预处理 transform: [ genTemplatePlugin, genMcpPlugin, // ⭐ MCP 插件 genPagePlugin, genBlockPlugin, genDataSourcePlugin, genDependenciesPlugin, genGlobalState, genI18nPlugin, genRouterPlugin, genUtilsPlugin, ... ], transformEnd: [formatCodePlugin, ...] // 后处理 }, context: { pluginConfig: config?.pluginConfig || {} // 包含 mcp 配置 } })

2.2.2 MCP 插件执行流程(采用模板驱动)

run(schema) { // 1. 检查是否启用 if (!realOptions.enabled) return [] try { const files = [] const { tools } = realOptions // 2. 确定启用的工具类别 const enabledTools = Object.keys(tools).filter(tool => tools[tool]) // 3. 生成基础配置文件(使用模板) files.push({ fileType: 'ts', fileName: 'base.ts', path: './src', fileContent: mcpBaseTemplate(null, { agentRoot: realOptions.agentRoot, sessionId: realOptions.sessionId }) }) // 4. 生成 MCP 服务器管理器(使用模板) files.push({ fileType: 'ts', fileName: 'server.ts', path: './src/mcp', fileContent: mcpServerTemplate(null, { enabledTools }) }) // 5. mcp 的工具生成 Object.entries(tools).forEach(([toolName, enabled]) => { if (enabled && toolGenerators[toolName]) { const generator = toolGenerators[toolName] const toolFileName = `${toolName}Tools.ts` files.push({ fileType: 'ts', fileName: toolFileName, path: './src/mcp/tools', fileContent: generator( toolName === 'navigation' ? schema.pageSchema || [] : schema ) }) } }) // 6. 处理 tiny_mcp_config(递归转换) if (schema.pageSchema && Array.isArray(schema.pageSchema)) { schema.pageSchema.forEach(page => { if (pageHasTinyMcpConfig(page)) { transformTinyMcpConfig(page) } }) } // 7. 修改应用入口文件(使用模板片段) const existingAppVue = this.getFile('./src', 'App.vue') if (existingAppVue) { const modifiedAppVue = modifyAppVue(existingAppVue.fileContent, realOptions) this.replaceFile({ fileType: 'vue', fileName: 'App.vue', path: './src', fileContent: modifiedAppVue }) } // 8. 修改 main.ts 添加样式导入 const existingMainTs = this.getFile('./src', 'main.ts') || this.getFile('./src', 'main.js') if (existingMainTs && existingMainTs.fileName) { const modifiedMainTs = modifyMainTs(existingMainTs.fileContent) this.replaceFile({ fileType: existingMainTs.fileName.endsWith('.ts') ? 'ts' : 'js', fileName: existingMainTs.fileName, path: './src', fileContent: modifiedMainTs }) } return files } catch (error) { console.error('MCP 插件生成失败:', error) if (this.addLog) { this.addLog({ type: 'error', message: `MCP 插件生成失败: ${error.message}`, plugin: 'genMcpPlugin', stack: error.stack }) } return [] } }

三、 默认出码流程 vs MCP 出码流程对比

3.1 架构对比

维度 默认出码流程 MCP 出码流程
插件数量 11 个核心插件 12 个插件(新增 genMcpPlugin)
生成文件数 ~10-15 个 ~15-20 个(新增 MCP 相关文件)
依赖包数量 基础依赖 新增 4 个 MCP 相关包
应用入口修改 修改 App.vue 和 main.ts

3.2 代码生成流程对比

默认流程

Schema 输入 ↓ parseSchemaPlugin (解析) ↓ genTemplatePlugin (模板) ↓ genPagePlugin (页面) ↓ genBlockPlugin (区块) ↓ genRouterPlugin (路由) ↓ genDataSourcePlugin (数据源) ↓ genGlobalState (全局状态) ↓ genI18nPlugin (国际化) ↓ genUtilsPlugin (工具函数) ↓ genDependenciesPlugin (依赖) ↓ formatCodePlugin (格式化) ↓ 输出代码 

MCP 流程(新增部分)

Schema 输入 ↓ parseSchemaPlugin (解析) ↓ genTemplatePlugin (模板) ↓ genMcpPlugin ⭐ (MCP 集成) ├─ 生成 base.ts ├─ 生成 server.ts ├─ 生成 navigationTools.ts ├─ 生成 applicationTools.ts ├─ 修改 App.vue ├─ 修改 main.ts └─ 转换 tiny_mcp_config ↓ genPagePlugin (页面,传递 mcpEnabled) └─ handleTinyMcpConfigAttrHook ⭐ ↓ genBlockPlugin (区块,传递 mcpEnabled) └─ handleTinyMcpConfigAttrHook ⭐ ↓ ... (其他插件) ↓ genDependenciesPlugin (依赖) └─ 添加 MCP 依赖 ⭐ ↓ formatCodePlugin (格式化) ↓ 输出代码(包含 MCP 能力) 

四、相关界面与过程截图

4.1 基本使用流程(以 tiny-grid 组件为例

目前仅适配 tiny-grid 组件,后期会拓展更多组件...

  1. 给 tiny-grid 添加 mcp 相关配置
    step-one

  2. 开启 mcp 出码相关配置、生成代码

image
  1. 运行出码应用、通过对话对 mcp 组件进行操作
image

自定义出码 MCP 工具

如何在 MCP 插件中添加新的工具生成器。通过配置驱动的方式,添加新工具只需两步:

  1. 编写工具生成函数
  2. toolGenerators 中注册

1. 编写工具生成函数

genMcpPlugin.js 中添加生成函数:

/**  * 生成通知工具代码  * @param {Object} schema 应用程序模式  * @returns {string} 工具代码  */ function generateNotificationTools(schema) { return `import { z } from "@opentiny/next-sdk" import type { WebMcpServer } from "@opentiny/next-sdk"  export function registerNotificationTools(server: WebMcpServer) {  server.registerTool(  "send-notification",  {  title: "发送通知",  description: "向用户发送系统通知",  inputSchema: {  title: z.string().describe("通知标题"),  message: z.string().describe("通知内容"),  type: z.enum(['info', 'success', 'warning', 'error']).describe("通知类型")  }  },  async ({ title, message, type }) => {  try {  window.$notification[type]({ title, message })  return {  content: [{ type: "text", text: "通知已发送" }]  }  } catch (error) {  return {  content: [{ type: "text", text: \`发送失败:\${error}\` }]  }  }  }  ) } ` }
2. 注册到工具生成器

toolGenerators 对象中添加:

const toolGenerators = { navigation: generateNavigationTools, application: generateApplicationTools, notification: generateNotificationTools // 新增这一行 }
3. 配置启用工具

用户在配置中启用:

const mcpConfig = { enabled: true, tools: { navigation: true, application: true, notification: true // 启用通知工具 } }

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Summary by CodeRabbit

  • New Features

    • MCP toggle added to the code-generation UI with state sync and automatic re-generation.
    • Table column configuration now exposes an MCP settings section.
    • Generated projects gain optional MCP integration: runtime bootstrap, UI remoter, styles, navigation and application tools, and build-time wiring.
  • Chores

    • Many component version references updated to 3.26.0.
@github-actions github-actions bot added the enhancement New feature or request label Oct 27, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 27, 2025

Walkthrough

Adds MCP (Model Context Protocol) support across generator and UI: new genMcpPlugin, MCP templates and server tooling, generator plumbing to propagate pluginConfig.mcp, conditional dependency injection, UI toggle and caching for code generation, plus mock schema/version updates.

Changes

Cohort / File(s) Summary
Mock Data
designer-demo/public/mock/bundle.json, mockServer/src/mock/get/app-center/v1/apps/schema/1.json
Add MCP configuration block to table column schema; bulk-update many component version fields to 3.26.0 (some entries remain at other versions).
UI — File Selector
packages/toolbars/generate-code/src/FileSelector.vue
Add MCP toggle UI, enableMcp prop, update:enableMcp emit, local mcpEnabled state, watchers, openDialog sync, and styles.
UI — Main Code Generator
packages/toolbars/generate-code/src/Main.vue
Add enableMcp and appSchemaCache state; wire FileSelector MCP prop/emit; implement handleMcpToggle(enabled) to (re)generate code using cached schema and include MCP config in generation; expose handler.
Generator Core
packages/vue-generator/src/generator/generateApp.js
Import/include genMcpPlugin in default/custom plugins, merge mcp into plugins, and propagate pluginConfig (including mcp) into generation context/CodeGenerator.
SFC Hook Integration
packages/vue-generator/src/generator/vue/sfc/genSetupSFC.js
Import and insert handleTinyMcpConfigAttrHook into defaultAttributeHook sequence.
Plugin Index
packages/vue-generator/src/plugins/index.js
Re-export genMcpPlugin.
Plugin Signatures & Context
packages/vue-generator/src/plugins/genBlockPlugin.js, packages/vue-generator/src/plugins/genPagePlugin.js, packages/vue-generator/src/plugins/genDependenciesPlugin.js
Update run() signatures to accept context; extract context?.pluginConfig?.mcp/mcpEnabled and propagate into SFC/dependency generation; parseSchema accepts MCP config; deps plugin conditionally injects MCP dependencies.
MCP Plugin
packages/vue-generator/src/plugins/genMcpPlugin.js
New plugin providing defaults, validation, generation of MCP files (base, server, imports/onMounted/setup/style/template, tools), App/main modifications, handleTinyMcpConfigAttrHook, transform detection for tiny_mcp_config, and run(schema) behavior.
Dependencies Plugin
packages/vue-generator/src/plugins/genDependenciesPlugin.js
Add conditional MCP-related dependencies (@opentiny/next-remoter, next-sdk, tiny-robot, tiny-vue-mcp) and adjust dependency composition when MCP enabled.
Templates — MCP Files
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/*
Add template generators and runtime code: App.vue.mcp-imports.ts, App.vue.mcp-onMounted.ts, App.vue.mcp-setup.ts, App.vue.mcp-style.ts, App.vue.mcp-template.ts, base.ts, server.ts (McpServerManager + composable), and tools/navigationTools.ts.

Sequence Diagram(s)

sequenceDiagram participant UI as FileSelector participant Main as Main.vue participant Gen as generateApp() participant Plugins as Plugin Chain participant MCP as genMcpPlugin participant Templates as MCP Templates participant Out as Generated Files UI->>Main: emit update:enableMcp(enabled) Main->>Main: handleMcpToggle(enabled) / use appSchemaCache Main->>Gen: generateAppCode(schema, { pluginConfig: { mcp: { enabled } } }) Gen->>Plugins: run(schema, context) Plugins->>Plugins: read context.pluginConfig.mcp -> mcpEnabled Plugins->>Gen: pass mcpEnabled into SFC/deps generation alt mcpEnabled == true Gen->>MCP: genMcpPlugin.run(schema, context) MCP->>Templates: generate MCP files (base, server, templates, tools) MCP->>Out: emit MCP runtime files else Gen->>Out: skip MCP-specific files end Plugins->>Out: emit standard generated files Main->>UI: update saveFilesInfo (file list) 
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–75 minutes

Areas needing extra attention:

  • packages/vue-generator/src/plugins/genMcpPlugin.js — template injection, App/main modifications, validation and schema transforms.
  • packages/vue-generator/src/templates/.../server.ts — lifecycle, singleton/composable correctness.
  • packages/vue-generator/src/plugins/genDependenciesPlugin.js — conditional dependency logic and version choices.
  • Integration points: generateApp.js, genBlockPlugin.js, genPagePlugin.js, genSetupSFC.js for correct propagation of pluginConfig.mcp.
  • UI: packages/toolbars/generate-code/src/Main.vue — caching, toggle wiring, and error handling.

Poem

🐰 I nibbled code by lantern's gleam,

A tiny switch began to dream,
Servers hummed and routes took wing,
Schemas whispered MCP's new spring,
Hopping bytes — a joyous thing! 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "feat: enable generated applications to support MCP tool invocation" directly and accurately describes the primary objective of this changeset. The PR introduces comprehensive MCP (Model Context Protocol) plugin support throughout the code generation pipeline, including a new genMcpPlugin, configuration validation, file generation, and integration with existing plugins and components. The title is concise, specific, and uses clear language that effectively communicates the feature being added without vague terms or unnecessary detail.
Docstring Coverage ✅ Passed Docstring coverage is 81.82% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • 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

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

@SonyLeo SonyLeo marked this pull request as ready for review October 27, 2025 11:36
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

Caution

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

⚠️ Outside diff range comments (1)
packages/vue-generator/src/generator/generateApp.js (1)

24-38: Add 'mcp' to the defaultPlugins union type in index.d.ts.

The implementation in generateApp.js includes the mcp plugin, but the TypeScript type definition is missing the corresponding union member. Update packages/vue-generator/src/index.d.ts by adding | 'mcp' to the defaultPlugins union.

🧹 Nitpick comments (18)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-style.ts (1)

1-6: Consider making the font-size configurable.

The hardcoded 30px font-size for .next-sdk-trigger-btn may not be appropriate for all use cases. Consider accepting options to allow customization.

Example:

-export default () => { +export default (schema, options = {}) => { + const { triggerBtnFontSize = '30px' } = options +  return ` :deep(.next-sdk-trigger-btn) { - font-size: 30px; + font-size: ${triggerBtnFontSize}; }` }
packages/vue-generator/src/plugins/genPagePlugin.js (1)

21-21: Pass context safely; prefer nullish-coalescing for boolean config

Context handling looks good. Tiny nit: use ?? false over || false to avoid treating non-boolean falsy values (e.g., '') as false unexpectedly. Also, confirm genSFCWithDefaultPlugin consumers read config.mcpEnabled; if not, this flag won’t take effect.

Apply:

- const mcpEnabled = context?.pluginConfig?.mcp?.enabled || false + const mcpEnabled = context?.pluginConfig?.mcp?.enabled ?? false

And verify mcpEnabled is actually consumed in SFC hooks or downstream generators.

Also applies to: 26-34

packages/vue-generator/src/plugins/genDependenciesPlugin.js (3)

24-28: parseSchema now context-aware: default param for resilience

Good extension. To harden, default mcpConfig to an empty object to simplify call sites and narrow guards.

-const parseSchema = (schema, mcpConfig) => { +const parseSchema = (schema, mcpConfig = {}) => {

60-66: MCP deps injection: avoid accidental downgrades and keep ranges consistent

Injecting MCP deps only when enabled is correct. Two suggestions:

  • Don’t overwrite an existing version if one already exists (prevents downgrades).
  • Use consistent semver ranges (all pinned or all caret/tilde) unless you have a reason to mix.
- resDeps['@opentiny/next-remoter'] = '0.0.2' - resDeps['@opentiny/next-sdk'] = '^0.1.0' - resDeps['@opentiny/tiny-robot'] = '^0.3.0-alpha.16' - resDeps['@opentiny/tiny-vue-mcp'] = '~0.0.3' + resDeps['@opentiny/next-remoter'] ||= '0.0.2' + resDeps['@opentiny/next-sdk'] ||= '^0.1.0' + resDeps['@opentiny/tiny-robot'] ||= '^0.3.0-alpha.16' + resDeps['@opentiny/tiny-vue-mcp'] ||= '~0.0.3'

Also consider promoting pre-releases to explicit pins if stability is required.

Please confirm these versions are current and compatible with your target TinyVue version matrix.


84-106: Ensure file type when creating package.json; add minimal JSON formatting

When package.json doesn’t exist, you return a file object without fileType. Other paths use addFile with fileType: 'json'. For consistency and downstream processors, include fileType and optionally pretty-print for readability.

- if (!originPackageItem) { - return { - fileName, - path, - fileContent: JSON.stringify({ dependencies }) - } - } + if (!originPackageItem) { + return { + fileType: 'json', + fileName, + path, + fileContent: JSON.stringify({ dependencies }, null, 2) + } + }
packages/toolbars/generate-code/src/FileSelector.vue (2)

12-16: MCP toggle wiring looks good; minor a11y/UX tweaks

Solid prop/emit design. Consider:

  • Add an accessible label for the switch (aria-label or via id) so screen readers announce it properly.
  • Optionally expose v-model:enableMcp for symmetry with update:enableMcp.

Example:

- <span class="mcp-switch-label">启用 MCP 集成:</span> - <tiny-switch v-model="mcpEnabled" @change="handleMcpChange"></tiny-switch> + <label class="mcp-switch-label" :for="'mcp-switch'">启用 MCP 集成:</label> + <tiny-switch :id="'mcp-switch'" v-model="mcpEnabled" aria-label="启用 MCP 集成" @change="handleMcpChange" />

Also applies to: 41-54, 56-64


96-105: Selection reset on data updates may override user choice

The deep watch on props.data re-expands and re-selects all rows. If data updates while the dialog is open, it can erase the user’s selection.

  • Gate the auto-select to openDialog only, or
  • Detect first render vs subsequent updates, or
  • Preserve current selections before refresh and restore them after.

Also applies to: 138-146

packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/tools/navigationTools.ts (1)

28-33: Normalize error messages

Interpolating unknown errors can yield “[object Object]”. Prefer error instanceof Error ? error.message : String(error).

- content: [{ type: "text", text: `导航失败:${error}` }], + content: [{ type: "text", text: `导航失败:${error instanceof Error ? error.message : String(error)}` }],

Apply similarly to other handlers.

Also applies to: 49-54, 70-75, 94-99

packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-setup.ts (1)

25-50: Call order: connect client proxy before connecting servers

initMcpServer connects servers to serverTransport. Ensure onMounted logic calls createProxyTransport() and awaits it before initMcpServer(), otherwise client/server sides may race.

Example onMounted sequence:

await createProxyTransport(); await initMcpServer();

Confirm App.vue.mcp-onMounted.ts wires this order.

Also applies to: 52-63

packages/toolbars/generate-code/src/Main.vue (4)

55-58: Type the reactive state and consider shallow cache.

Add an explicit state type and prefer shallowRef/shallowReactive for large schemas to avoid deep proxy/memory overhead.

-const state = reactive({ +interface GenState { + dirHandle: any | null + generating: boolean + showDialogbox: boolean + saveFilesInfo: Array<{ fileContent: string; filePath: string; fileType?: string }> + enableMcp: boolean + appSchemaCache: unknown | null +} +const state = reactive<GenState>({ dirHandle: null, generating: false, showDialogbox: false, saveFilesInfo: [], enableMcp: false, // MCP 开关状态 - appSchemaCache: null // 缓存应用 schema,用于重新生成代码 + appSchemaCache: null // 缓存应用 schema,用于重新生成代码 })

188-201: Pass-through of MCP option is good. Consider co-locating defaults.

This correctly forwards mcp.enabled. If you later pass more MCP config, centralize defaults in one place to avoid divergence with the generator.


203-222: Deduplicate file path normalization.

The mapping logic is duplicated. Extract a helper to avoid drift and ease testing.

+const normalizeGenResult = (genResult = []) => { + return genResult.map(({ fileContent, fileName, path, fileType }) => { + const slash = path.endsWith('/') || path === '.' ? '' : '/' + let filePath = `${path}${slash}` + if (filePath.startsWith('./')) filePath = filePath.slice(2) + if (filePath.startsWith('.')) filePath = filePath.slice(1) + if (filePath.startsWith('/')) filePath = filePath.slice(1) + return { fileContent, filePath: `${filePath}${fileName}`, fileType } + }) +} -const { genResult = [] } = res || {} -const fileRes = genResult.map(({ fileContent, fileName, path, fileType }) => { ... }) +const { genResult = [] } = res || {} +const fileRes = normalizeGenResult(genResult)

Apply similarly in handleMcpToggle.

 Also applies to: 325-343 --- `298-360`: **Add a lightweight re-entry guard for toggle.** Rapid toggles could race and reorder results. Guard with a local flag. ```diff -const handleMcpToggle = async (enabled) => { +let toggling = false +const handleMcpToggle = async (enabled) => { + if (toggling) return + toggling = true state.enableMcp = enabled if (!state.appSchemaCache) { - return + toggling = false + return } try { // ... } catch (error) { // ... } finally { + toggling = false } } 
packages/vue-generator/src/plugins/genMcpPlugin.js (3)

251-261: Broaden onMounted regex to avoid duplicate blocks.

Current regex misses async/spacing variants and appends a new onMounted.

- if (existingScript.includes('onMounted(')) { - newScript = newScript.replace(/onMounted\(\(\) => \{([\s\S]*?)\}\)/, (_, content) => { + if (existingScript.includes('onMounted(')) { + newScript = newScript.replace(/onMounted\s*\(\s*(?:async\s*)?\(\)\s*=>\s*\{([\s\S]*?)\}\s*\)/, (_, content) => { return `onMounted(() => {${content}\n${mcpOnMountedCode}\n})` })

338-376: Parity with new-script path: add i18n imports/provide when missing.

modifyExistingScriptSetup doesn’t add i18n, unlike createNewScriptSetup, causing inconsistencies.

 // 添加必要的 imports newScript = addRequiredImports(newScript, existingScript) newScript = `${mcpImports}\n${newScript}` + if (!existingScript.includes("I18nInjectionKey")) { + newScript = `import { I18nInjectionKey } from 'vue-i18n'\n${newScript}` + } + if (!existingScript.match(/import\s+i18n\s+from\s+['"]\.\/i18n['"]/)) { + newScript = `import i18n from './i18n'\n${newScript}` + } // 添加 router 变量(如果不存在) if (!existingScript.includes('const router')) { newScript += `\nconst router = useRouter();` } + if (!existingScript.includes('provide(I18nInjectionKey')) { + newScript += `\nprovide(I18nInjectionKey, i18n)` + }

167-170: customTools are validated but unused.

Either implement generation for customTools or drop validation to avoid confusion.

Also applies to: 625-657

packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/server.ts (2)

48-57: Register main-server tools only once.

If init is called twice, duplicate registrations may occur. Consider guarding with a flag.

+ private initialized = false // 初始化管理器 init(router: Router, config: any) { + if (this.initialized) return this.router = router this.capabilities = config.capabilities // ... this.registerServerToolsByMode('main', this.mainServer) + this.initialized = true }

150-166: Dispose should also disconnect, not just null transports.

Call server.disconnect() if available to clean RPC state.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c27e843 and f048f9c.

📒 Files selected for processing (19)
  • designer-demo/public/mock/bundle.json (1 hunks)
  • mockServer/src/mock/get/app-center/v1/apps/schema/1.json (8 hunks)
  • packages/toolbars/generate-code/src/FileSelector.vue (4 hunks)
  • packages/toolbars/generate-code/src/Main.vue (4 hunks)
  • packages/vue-generator/src/generator/generateApp.js (5 hunks)
  • packages/vue-generator/src/generator/vue/sfc/genSetupSFC.js (2 hunks)
  • packages/vue-generator/src/plugins/genBlockPlugin.js (2 hunks)
  • packages/vue-generator/src/plugins/genDependenciesPlugin.js (3 hunks)
  • packages/vue-generator/src/plugins/genMcpPlugin.js (1 hunks)
  • packages/vue-generator/src/plugins/genPagePlugin.js (1 hunks)
  • packages/vue-generator/src/plugins/index.js (1 hunks)
  • packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-imports.ts (1 hunks)
  • packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-onMounted.ts (1 hunks)
  • packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-setup.ts (1 hunks)
  • packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-style.ts (1 hunks)
  • packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-template.ts (1 hunks)
  • packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/base.ts (1 hunks)
  • packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/server.ts (1 hunks)
  • packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/tools/navigationTools.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (10)
packages/vue-generator/src/generator/vue/sfc/genSetupSFC.js (1)
packages/vue-generator/src/plugins/genMcpPlugin.js (2)
  • handleTinyMcpConfigAttrHook (737-820)
  • handleTinyMcpConfigAttrHook (737-820)
packages/vue-generator/src/plugins/genPagePlugin.js (2)
packages/vue-generator/src/plugins/genDependenciesPlugin.js (2)
  • schema (10-10)
  • schema (25-25)
packages/vue-generator/src/generator/vue/sfc/genSetupSFC.js (3)
  • res (52-58)
  • genSFCWithDefaultPlugin (219-279)
  • genSFCWithDefaultPlugin (219-279)
packages/vue-generator/src/plugins/genBlockPlugin.js (1)
packages/vue-generator/src/generator/vue/sfc/genSetupSFC.js (3)
  • res (52-58)
  • genSFCWithDefaultPlugin (219-279)
  • genSFCWithDefaultPlugin (219-279)
packages/vue-generator/src/plugins/genMcpPlugin.js (5)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-setup.ts (1)
  • schema (1-64)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/base.ts (1)
  • schema (1-6)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/server.ts (1)
  • schema (1-214)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/tools/navigationTools.ts (1)
  • schema (1-102)
packages/vue-generator/src/generator/vue/sfc/genSetupSFC.js (3)
  • config (46-51)
  • config (220-220)
  • globalHooks (104-200)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/base.ts (1)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-setup.ts (1)
  • schema (1-64)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/server.ts (2)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-setup.ts (1)
  • schema (1-64)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/tools/navigationTools.ts (1)
  • schema (1-102)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/tools/navigationTools.ts (2)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/server.ts (1)
  • schema (1-214)
packages/vue-generator/src/plugins/genMcpPlugin.js (2)
  • routes (36-42)
  • routes (58-58)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-setup.ts (2)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/base.ts (1)
  • schema (1-6)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/server.ts (1)
  • schema (1-214)
packages/vue-generator/src/generator/generateApp.js (2)
packages/vue-generator/src/plugins/genGlobalState.js (1)
  • globalState (9-9)
packages/vue-generator/src/index.d.ts (1)
  • defaultPlugins (2-13)
packages/vue-generator/src/plugins/genDependenciesPlugin.js (1)
packages/vue-generator/src/plugins/genMcpPlugin.js (2)
  • mcpConfig (465-465)
  • mcpConfig (747-747)
🔇 Additional comments (18)
mockServer/src/mock/get/app-center/v1/apps/schema/1.json (1)

1729-1729: Mock data version consolidation looks good.

The bulk version updates to 3.26.0 for OpenTiny Vue components appear intentional for establishing a consistent test baseline. Non-OpenTiny packages and specialized components (element-plus, TinyPlus, TinySearch, TinyDropdown) correctly retain their original versions.

However, confirm that this version consolidation is deliberate for MCP feature testing and aligns with the plugin's component generation validation scope.

Also applies to: 1743-1743, 1750-1750, 1764-1764, 1771-1771, 1778-1778, 1820-1820, 1827-1827, 1841-1841, 1848-1848, 1855-1855, 1869-1869, 1876-1876, 1883-1883, 1890-1890, 1897-1897, 1904-1904, 1911-1911, 1918-1918, 1932-1932, 1939-1939, 1946-1946, 1953-1953, 1960-1960, 1967-1967, 1974-1974, 1988-1988, 1995-1995, 2002-2002, 2009-2009, 2016-2016

designer-demo/public/mock/bundle.json (1)

10973-11005: Add defaultValue to guide users; verify conditional visibility and schema validation support before implementing.

The defaultValue suggestion is sound and follows proven patterns in bundle.json. However, the conditional visibility (visibleWhen) and JSON schema validation (jsonSchema) suggestions lack evidence of support in the codebase—no matching patterns were found in schema processing or CodeConfigurator usage.

Recommended action:

  • ✓ Add defaultValue with a default MCP config skeleton
  • ⚠ Before implementing conditional visibility or JSON schema: verify with the forms/schema engine team that these features are supported

Suggested diff:

 "content": [ { "property": "tiny_mcp_config", "label": { "text": { "zh_CN": "组件MCP化配置" } }, "required": true, "readOnly": false, "disabled": false, "cols": 12, "widget": { "component": "CodeConfigurator", "props": { "language": "json" } }, + "defaultValue": { + "enabled": false, + "agentRoot": "", + "sessionId": "", + "capabilities": [], + "tools": { + "navigation": true, + "application": true, + "customTools": [] + } + }, "description": { - "zh_CN": "设置表格的基础 mcp 信息" + "zh_CN": "设置表格的基础 MCP 信息(与代码生成插件默认值保持一致)" }, "labelPosition": "top" } ]
packages/vue-generator/src/plugins/index.js (1)

13-13: LGTM!

The export follows the established pattern and correctly exposes the new MCP plugin.

packages/vue-generator/src/generator/vue/sfc/genSetupSFC.js (2)

27-27: LGTM!

The import correctly brings in the MCP config attribute handler for use in the SFC generation pipeline.


223-238: LGTM!

The hook is correctly positioned after handlePrimitiveAttributeHook and before handleExpressionAttrHook, which ensures that MCP config attributes are processed at the appropriate stage of attribute transformation.

packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-onMounted.ts (1)

1-4: LGTM!

The generated code correctly calls createProxyTransport() and initMcpServer() which are defined in the setup phase (as seen in App.vue.mcp-setup.ts).

packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-imports.ts (2)

9-9: Verify the import path for MCP server module.

Similar to the base module import, verify that "./mcp/server" is the correct relative path from where this generated code will be inserted.


8-8: The review comment is based on an incorrect assumption about the file structure.

The verification shows:

  • base.ts is generated to ./src/base.ts (not ./src/mcp/base.ts as the review assumes)
  • server.ts is generated to ./src/mcp/server.ts
  • App.vue is at ./src/App.vue

The imports are injected into App.vue's script, making the relative paths:

  • "./base" correctly refers to ./src/base.ts
  • "./mcp/server" correctly refers to ./src/mcp/server.ts

The import path is correct as-is. No changes needed.

Likely an incorrect or invalid review comment.

packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-template.ts (1)

1-3: LGTM!

The template correctly uses SESSION_ID which is imported via the MCP imports template, and binds it to the TinyRemoter component.

packages/vue-generator/src/plugins/genBlockPlugin.js (3)

21-21: LGTM!

The signature change correctly accepts the context parameter to enable MCP configuration propagation.


31-32: LGTM!

The MCP configuration is safely extracted with optional chaining and a sensible default value of false.


36-40: LGTM!

The mcpEnabled flag is correctly passed to the SFC generator, enabling MCP features to be conditionally applied during block code generation.

packages/vue-generator/src/plugins/genDependenciesPlugin.js (2)

2-2: Check alias resolution for '@/...' import

This file mixes relative imports with an alias import. Ensure the '@' alias is configured for this package’s build/test tooling; otherwise, this will fail in plain Node resolution.

Run your bundler/test config to confirm alias mapping for '@/generator/vue/sfc/parseImport'.


55-58: Nice: align @opentiny/vue-icon and @opentiny/vue-common with @opentiny/vue

Adding vue-common alongside vue-icon prevents runtime import gaps. LGTM.

packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-setup.ts (1)

6-20: Type imports and provide dependencies must exist in imports template

This snippet relies on Transport, WebMcpClient, createMessageChannelPairTransport, provide, router, and mcpServerManager being in scope. Ensure App.vue.mcp-imports.ts adds:

  • import { provide } from 'vue'
  • import { WebMcpClient, createMessageChannelPairTransport } from '@opentiny/next-sdk'
  • import type { Transport } from '@opentiny/next-sdk'
  • router and mcpServerManager definitions/imports

Please confirm these imports are present to avoid TS/rollup errors.

packages/toolbars/generate-code/src/Main.vue (1)

8-10: Prop/event wiring for MCP looks correct.

Kebab-case prop and model event align with Vue conventions. No issues.

packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/server.ts (1)

22-26: Import set looks correct for generated code.

Assuming dependencies are injected when MCP is enabled, these imports should resolve.

Please confirm genDependenciesPlugin adds @opentiny/next-sdk, @opentiny/tiny-vue-mcp, and @opentiny/vue-common only when mcp.enabled === true.

packages/vue-generator/src/plugins/genMcpPlugin.js (1)

736-820: No action required: mcpEnabled is correctly passed through config chains.

The review comment's concern about a flag mismatch is unfounded. Both caller sites (genPagePlugin and genBlockPlugin) explicitly extract context?.pluginConfig?.mcp?.enabled and pass it as mcpEnabled in the config object to genSFCWithDefaultPlugin. The config flows correctly through the chain: genSFCWithDefaultPlugingenerateSFCFilegenTemplateByHook → hook invocation with the config parameter intact. The hook receives config.mcpEnabled as intended, and the naming is consistent throughout.

Likely an incorrect or invalid review comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

♻️ Duplicate comments (4)
packages/vue-generator/src/plugins/genMcpPlugin.js (4)

12-28: Hardcoded defaults for agentRoot and sessionId are already flagged.

This issue was identified in previous review comments. The hardcoded values should be removed and required when enabled.


198-232: De-duplication logic is already correct.

The function checks for both style imports on lines 200-201 and returns early if both exist (line 204). It then inserts only missing imports. The concern raised in previous comments appears to be addressed in the current code.


513-578: Validation issues already flagged.

The validation logic has been identified in previous review comments as using truthy checks that miss invalid values and not requiring agentRoot/sessionId when enabled.


669-684: Transform timing issue already flagged.

This section performs transformTinyMcpConfig after pages are likely generated. This has been identified in previous review comments.

🧹 Nitpick comments (2)
packages/vue-generator/src/plugins/genMcpPlugin.js (2)

636-667: Tool generation failures are silently ignored for configured tools.

Lines 648-656 catch errors during tool generation and log a warning, but don't provide any indication to the user that their configured tools failed to generate. This could lead to runtime errors when the application expects tool files that don't exist.

Consider:

  1. Throwing an error if a configured tool fails (fail-fast)
  2. Or collecting failures and returning them as part of the result
  3. At minimum, make the log more visible (e.g., type: 'error' instead of 'warning')
 } catch (error) { if (this.addLog) { this.addLog({ - type: 'warning', + type: 'error', message: `${toolName} 工具生成失败: ${error.message}`, plugin: 'genMcpPlugin' }) } + // Re-throw to fail fast on tool generation errors + throw new Error(`Failed to generate ${toolName} tool: ${error.message}`) }

788-827: Large code block should use template for consistency.

Lines 805-826 embed a large multi-line code snippet directly in the hook. This is inconsistent with the template-driven approach used elsewhere in the file (e.g., mcpSetupTemplate, mcpImportsTemplate).

For consistency and maintainability, extract this to a template:

// In templates/vue-template/templateFiles/src/mcp/page-server-init.ts export default (schema, options) => { const { pageId } = options return ` // 使用统一管理的页面服务器 const { server, connect, disconnect } = usePageMcpServer('${pageId}', {  business: {  id: '${pageId}',  description: '${pageId}页面'  } }) // ... rest of code ` }

Then use it:

globalHooks.addStatement({ position: INSERT_POSITION.AFTER_METHODS, value: pageServerInitTemplate(null, { pageId }), key: 'mcpServerInit' })
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f048f9c and 4ceda53.

📒 Files selected for processing (3)
  • packages/vue-generator/src/plugins/genMcpPlugin.js (1 hunks)
  • packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/base.ts (1 hunks)
  • packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/tools/navigationTools.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/tools/navigationTools.ts
🧰 Additional context used
🧬 Code graph analysis (2)
packages/vue-generator/src/plugins/genMcpPlugin.js (8)
packages/vue-generator/src/plugins/genBlockPlugin.js (3)
  • defaultOption (4-6)
  • realOptions (9-9)
  • realOptions (11-11)
packages/vue-generator/src/plugins/genPagePlugin.js (3)
  • defaultOption (4-6)
  • realOptions (9-9)
  • realOptions (11-11)
packages/vue-generator/src/plugins/genDependenciesPlugin.js (5)
  • defaultOption (4-7)
  • schema (10-10)
  • schema (25-25)
  • realOptions (72-72)
  • realOptions (74-74)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/base.ts (1)
  • schema (1-10)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/tools/navigationTools.ts (1)
  • schema (1-102)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/server.ts (1)
  • schema (1-214)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-setup.ts (1)
  • schema (1-64)
packages/vue-generator/src/generator/vue/sfc/genSetupSFC.js (3)
  • config (46-51)
  • config (220-220)
  • globalHooks (104-200)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/base.ts (1)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-setup.ts (1)
  • schema (1-64)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: push-check
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (8)
packages/vue-generator/src/plugins/genMcpPlugin.js (8)

240-252: Fragile import manipulation; prefer parsing or robust update.
String replace assumes a specific format for import { provide } from 'vue'.

Suggested approach:

// Pseudocode using regex const vueImport = existingScript.match(/import\s*\{([^}]*)\}\s*from\s*['"]vue['"]/) if (vueImport) { const names = vueImport[1].split(',').map(s => s.trim()) if (!names.includes('onMounted')) names.push('onMounted') if (!names.includes('provide')) names.push('provide') newScript = newScript.replace(vueImport[0], `import { ${[...new Set(names)].join(', ')} } from 'vue'`) } else { newScript = `import { provide, onMounted } from "vue";\n${newScript}` }

Best: use @babel/parser/traverse to edit ImportDeclaration safely.


261-272: onMounted regex is brittle; handle async/function forms.
Covers only onMounted(() => {...}).

Apply this diff:

- if (existingScript.includes('onMounted(')) { - // 已有 onMounted,在其中添加 MCP 初始化 - newScript = newScript.replace(/onMounted\(\(\) => \{([\s\S]*?)\}\)/, (_, content) => { - return `onMounted(() => {${content}\n${mcpOnMountedCode}\n})` - }) + if (existingScript.includes('onMounted(')) { + newScript = newScript.replace( + /onMounted\(\s*(async\s*)?(?:\(\)\s*=>|function\s*\(\))\s*\{([\s\S]*?)\}\s*\)/, + (m, asyncK = '', body) => `onMounted(${asyncK}() => {${body}\n${mcpOnMountedCode}\n})` + )

Parsing with an AST would be more robust.


669-686: Confirm transform timing relative to page/SFC generation.
If genMcpPlugin.run executes after pages/blocks, transforms won’t affect SFCs. PR summary claims it runs earlier—please verify.

#!/bin/bash # Verify plugin order in generateApp.js (genMcpPlugin should run before genPagePlugin/genBlockPlugin) rg -n -C3 "genMcpPlugin\(|genPagePlugin\(|genBlockPlugin\(" packages/vue-generator/src/generator/generateApp.js # Also check defaultPlugins or pipeline assembly rg -n -C3 "defaultPlugins|plugins\s*=" packages/vue-generator/src/generator/generateApp.js

12-28: Do not ship hardcoded agentRoot/sessionId; require when enabled.
Defaults leak a static endpoint/UUID. Set empty defaults and read env; validation should enforce presence when enabled.

Apply this diff:

 const defaultOption = { enabled: false, // 默认禁用 MCP,用户需要显式启用 - agentRoot: 'https://agent.opentiny.design/api/v1/webmcp-trial/', - sessionId: '78b66563-95c0-4839-8007-e8af634dd658', + agentRoot: '', + sessionId: '', capabilities: {

Also merge env before user options:

- const realOptions = mergeOptions(defaultOption, options) + const envDefaults = { + agentRoot: process.env.MCP_AGENT_ROOT || '', + sessionId: process.env.MCP_SESSION_ID || '' + } + const realOptions = mergeOptions(defaultOption, envDefaults, options)

39-42: Preserve empty route ('') and guard non-string route values.
Current || 'home' turns '' into 'home' and .startsWith crashes on non-strings.

Apply this diff:

- const routeField = page.meta.route || page.meta.router - const routePath = routeField.startsWith('/') ? routeField.slice(1) : routeField - return routePath || 'home' + const routeField = page.meta.route || page.meta.router + if (typeof routeField !== 'string') return 'home' + const routePath = routeField.startsWith('/') ? routeField.slice(1) : routeField + return routePath ?? 'home'

67-161: Generated code uses unvalidated identifiers and unescaped keys.
Risk of malformed TS and runtime errors; property assignment should use bracket notation. Validate identifiers first.

Apply this diff (add validation and safer assignment):

 function generateApplicationTools(schema) { // 基于全局状态和数据源生成自定义工具 const globalStates = schema.globalState || [] + const isValidIdent = (s) => typeof s === 'string' && /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(s) + globalStates.forEach((state) => { + if (state.id && !isValidIdent(state.id)) { + throw new Error(`Invalid globalState id: ${state.id}`) + } + if (state.state && typeof state.state === 'object') { + Object.keys(state.state).forEach((k) => { + if (!isValidIdent(k)) { + throw new Error(`Invalid state key on ${state.id}: ${k}`) + } + }) + } + }) @@ - ${state.id}Store.${key} = value + ${state.id}Store[${JSON.stringify(key)}] = value

Consider switching to an AST builder for robustness in a follow-up.


312-321: Remove hardcoded i18n injection; it’s not guaranteed to exist.
Unconditionally importing/providing i18n will break projects without vue-i18n or ./i18n.

Apply this diff:

 const mcpScript = `<script setup lang="ts"> ${mcpImports} import { useRouter } from "vue-router"; -import { I18nInjectionKey } from 'vue-i18n' -import { provide, onMounted } from 'vue' -import i18n from './i18n' - -provide(I18nInjectionKey, i18n) +import { provide, onMounted } from 'vue' const router = useRouter();

If i18n is required, gate injection on actual file presence and dependency.


513-578: Tighten validation; require agentRoot/sessionId when enabled; null-safe object checks.
Current truthy checks miss invalid values and don’t enforce required fields when enabled.

Apply this diff:

- if (config.enabled && typeof config.enabled !== 'boolean') { + if ('enabled' in config && typeof config.enabled !== 'boolean') { errors.push('enabled 必须是布尔值') } - if (config.agentRoot && typeof config.agentRoot !== 'string') { + if ('agentRoot' in config && typeof config.agentRoot !== 'string') { errors.push('agentRoot 必须是字符串') } - if (config.sessionId && typeof config.sessionId !== 'string') { + if ('sessionId' in config && typeof config.sessionId !== 'string') { errors.push('sessionId 必须是字符串') } - if (config.agentRoot && config.agentRoot !== '') { + if (typeof config.agentRoot === 'string' && config.agentRoot !== '') { try { new URL(config.agentRoot) } catch (e) { errors.push('agentRoot 必须是有效的 URL') } } - if (config.tools && typeof config.tools !== 'object') { + if (config.tools && (typeof config.tools !== 'object' || config.tools === null || Array.isArray(config.tools))) { errors.push('tools 必须是对象') } else if (config.tools) { @@ - if (config.customTools && !Array.isArray(config.customTools)) { + if (config.customTools && !Array.isArray(config.customTools)) { errors.push('customTools 必须是数组') } + if (config.enabled === true) { + if (!config.agentRoot) errors.push('启用 MCP 时必须配置 agentRoot') + if (!config.sessionId) errors.push('启用 MCP 时必须配置 sessionId') + } - if (config.capabilities && typeof config.capabilities !== 'object') { + if (config.capabilities && (typeof config.capabilities !== 'object' || config.capabilities === null)) { errors.push('capabilities 必须是对象') }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ceda53 and 352a2e2.

📒 Files selected for processing (1)
  • packages/vue-generator/src/plugins/genMcpPlugin.js (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/vue-generator/src/plugins/genMcpPlugin.js (5)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/tools/navigationTools.ts (1)
  • schema (1-102)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-setup.ts (1)
  • schema (1-64)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/base.ts (1)
  • schema (1-10)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/server.ts (1)
  • schema (1-214)
packages/vue-generator/src/generator/vue/sfc/genSetupSFC.js (3)
  • config (46-51)
  • config (220-220)
  • globalHooks (104-200)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: push-check
🔇 Additional comments (2)
packages/vue-generator/src/plugins/genMcpPlugin.js (2)

198-232: Style import de-dupe logic LGTM.
Both robot and remoter imports are conditionally inserted; idempotent on reruns.


468-506: Escaping fix for id/description LGTM.
Using JSON.stringify prevents broken literals in generated JS_EXPRESSION.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (10)
packages/vue-generator/src/plugins/genMcpPlugin.js (10)

240-252: Fragile import manipulation remains unchanged.

Line 244's string replacement approach (newScript.replace('import { provide', 'import { provide, onMounted')) still assumes a specific import format. A previous review recommended using an AST parser or more robust regex to handle multi-line imports, comments, or aliases.


261-272: Regex for onMounted modification remains fragile.

Line 264's pattern (/onMounted\(\(\) => \{([\s\S]*?)\}\)/) was previously flagged—it doesn't handle async () => {}, function() {}, or nested braces reliably. Consider using an AST parser for robust modification.


669-712: Transform timing issue persists.

transformTinyMcpConfig is called at line 682 within genMcpPlugin.run. A previous review flagged that if MCP runs after page/block generation, these transformations won't affect SFC generation. The PR objectives state MCP runs before page generation, but verify the actual plugin ordering in generateApp.js to ensure transforms are applied at the correct phase.

#!/bin/bash # Verify plugin execution order in generateApp.js rg -n -A10 -B5 'genMcpPlugin|defaultPlugins' packages/vue-generator/src/generator/generateApp.js

12-28: Hardcoded credentials remain unaddressed.

The static agentRoot endpoint and sessionId UUID are still present in defaults. This was flagged in a previous review and remains a security and operational risk.


35-50: Empty string route handling still incorrect.

Line 41 uses || which converts an intentional empty route ('') to 'home'. A previous review recommended using ?? or explicit checks to preserve empty strings.


67-161: Code generation still lacks input validation and escaping.

state.id and key are directly interpolated into generated TypeScript code without validation or escaping. This was flagged previously and remains unresolved—if these contain quotes, backticks, or invalid identifier characters, the generated code will be malformed.


312-335: Hardcoded i18n imports will cause build errors.

Lines 316-318 unconditionally import vue-i18n and ./i18n, but no i18n file is generated. This critical issue from a previous review remains unresolved and will break builds when MCP is enabled.


513-578: Validation approach still uses truthy checks.

The validation logic (lines 518-556) was previously flagged for using truthy checks (config.enabled &&, config.agentRoot &&) instead of checking property presence. This misses invalid values like null or 0, and doesn't enforce that agentRoot and sessionId are required when enabled === true.


620-625: base.ts path is still incorrect.

Line 623 writes base.ts to './src' instead of './src/mcp'. This critical issue from a previous review breaks imports from MCP templates that expect ./src/mcp/base.


635-667: customTools generation still missing.

customTools are validated (lines 558-565) but never generated or registered. A previous review flagged this gap between validation and implementation—the loop at lines 636-667 only handles built-in tools from toolGenerators.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 352a2e2 and 613f270.

📒 Files selected for processing (1)
  • packages/vue-generator/src/plugins/genMcpPlugin.js (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/vue-generator/src/plugins/genMcpPlugin.js (5)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/tools/navigationTools.ts (1)
  • schema (1-102)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/base.ts (1)
  • schema (1-10)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/App.vue.mcp-setup.ts (1)
  • schema (1-64)
packages/vue-generator/src/templates/vue-template/templateFiles/src/mcp/server.ts (1)
  • schema (1-214)
packages/vue-generator/src/generator/vue/sfc/genSetupSFC.js (3)
  • config (46-51)
  • config (220-220)
  • globalHooks (104-200)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: push-check
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

1 participant