tiny-engine icon indicating copy to clipboard operation
tiny-engine copied to clipboard

feat: enable generated applications to support MCP tool invocation

Open SonyLeo opened this issue 2 months ago • 1 comments

English | 简体中文

PR Checklist

Please check if your PR fulfills the following requirements:

  • [x] 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
  • [x] 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

  3. 运行出码应用、通过对话对 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
  • [x] 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.

SonyLeo avatar Oct 27 '25 08:10 SonyLeo

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)

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.

coderabbitai[bot] avatar Oct 27 '25 08:10 coderabbitai[bot]