├── .github └── workflows │ ├── ci.yml │ └── publish.yml ├── .gitignore ├── .npmignore ├── .npmrc ├── README.md ├── README.zh-CN.md ├── bin └── cli.js ├── build.js ├── images ├── image-20250507174245589.png ├── image-20250507174511910.png ├── image-20250507174840456.png ├── image-20250507175005364.png └── image-20250507175107044.png ├── package.json ├── src ├── http-util.ts ├── index.ts ├── markdown │ ├── component-workflow.md │ └── meta.md ├── tools │ ├── base-tool.ts │ ├── get-component-link.ts │ ├── get-component-workflow.ts │ ├── get-dsl.ts │ ├── get-meta.ts │ └── get-version.ts └── types.d.ts └── tsconfig.json /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | 16 | - name: Use Node.js 18.x 17 | uses: actions/setup-node@v4 18 | with: 19 | node-version: 18.x 20 | 21 | - name: Install dependencies 22 | run: npm install 23 | 24 | - name: Build 25 | run: npm run build 26 | 27 | - name: Upload build artifacts 28 | uses: actions/upload-artifact@v4 29 | with: 30 | name: build-artifacts 31 | path: dist/ 32 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish to NPM 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | release-type: 7 | description: "Release type" 8 | required: true 9 | default: "patch" 10 | type: "choice" 11 | options: 12 | - "patch" 13 | - "minor" 14 | - "major" 15 | - "beta" 16 | - "alpha" 17 | version-increment: 18 | description: "Version increment (beta and alpha)" 19 | required: false 20 | default: "0" 21 | type: "choice" 22 | options: 23 | - "0" 24 | - "1" 25 | - "2" 26 | - "3" 27 | - "4" 28 | - "5" 29 | 30 | # Add permission configuration 31 | permissions: 32 | contents: write 33 | 34 | jobs: 35 | publish: 36 | runs-on: ubuntu-latest 37 | steps: 38 | - uses: actions/checkout@v4 39 | with: 40 | ref: main 41 | 42 | - name: Set up Node.js 43 | uses: actions/setup-node@v4 44 | with: 45 | node-version: "18.x" 46 | registry-url: "https://registry.npmjs.org" 47 | 48 | - name: Install dependencies 49 | run: npm install 50 | 51 | - name: Build project 52 | run: npm run build 53 | 54 | - name: Get current version 55 | id: get-current-version 56 | run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT 57 | 58 | - name: Version update (official version) 59 | if: ${{ github.event.inputs.release-type == 'patch' || github.event.inputs.release-type == 'minor' || github.event.inputs.release-type == 'major' }} 60 | run: npm version ${{ github.event.inputs.release-type }} --no-git-tag-version 61 | 62 | - name: Version update (Beta version - first time) 63 | if: ${{ github.event.inputs.release-type == 'beta' && !contains(steps.get-current-version.outputs.version, 'beta') }} 64 | run: | 65 | npm --no-git-tag-version version prerelease --preid=beta 66 | # If a specific increment number is needed, execute additional increments 67 | if [ "${{ github.event.inputs.version-increment }}" != "0" ]; then 68 | for i in $(seq 1 ${{ github.event.inputs.version-increment }}); do 69 | npm --no-git-tag-version version prerelease --preid=beta 70 | done 71 | fi 72 | 73 | - name: Version update (Beta version - increment) 74 | if: ${{ github.event.inputs.release-type == 'beta' && contains(steps.get-current-version.outputs.version, 'beta') }} 75 | run: | 76 | # For versions with existing beta tags, directly increment the pre-release version number 77 | for i in $(seq 1 $((${{ github.event.inputs.version-increment }} + 1))); do 78 | npm --no-git-tag-version version prerelease --preid=beta 79 | done 80 | 81 | - name: Version update (Alpha version - first time) 82 | if: ${{ github.event.inputs.release-type == 'alpha' && !contains(steps.get-current-version.outputs.version, 'alpha') }} 83 | run: | 84 | npm --no-git-tag-version version prerelease --preid=alpha 85 | # If a specific increment number is needed, execute additional increments 86 | if [ "${{ github.event.inputs.version-increment }}" != "0" ]; then 87 | for i in $(seq 1 ${{ github.event.inputs.version-increment }}); do 88 | npm --no-git-tag-version version prerelease --preid=alpha 89 | done 90 | fi 91 | 92 | - name: Version update (Alpha version - increment) 93 | if: ${{ github.event.inputs.release-type == 'alpha' && contains(steps.get-current-version.outputs.version, 'alpha') }} 94 | run: | 95 | # For versions with existing alpha tags, directly increment the pre-release version number 96 | for i in $(seq 1 $((${{ github.event.inputs.version-increment }} + 1))); do 97 | npm --no-git-tag-version version prerelease --preid=alpha 98 | done 99 | 100 | - name: Publish to NPM 101 | run: npm publish 102 | env: 103 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 104 | 105 | - name: Get new version number 106 | id: get-version 107 | run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT 108 | 109 | - name: Commit version change 110 | run: | 111 | git config --local user.email "github-actions[bot]@users.noreply.github.com" 112 | git config --local user.name "github-actions[bot]" 113 | git add package.json 114 | git commit -m "chore: publish v${{ steps.get-version.outputs.version }}" 115 | git tag v${{ steps.get-version.outputs.version }} 116 | git push 117 | git push --tags 118 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | package-lock.json 3 | yarn.lock 4 | pnpm-lock.yaml 5 | 6 | dist/ 7 | build/ 8 | out/ 9 | 10 | .cursorrules 11 | 12 | logs/ 13 | *.log 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | 18 | .env 19 | .env.local 20 | .env.development.local 21 | .env.test.local 22 | .env.production.local 23 | 24 | .idea/ 25 | .vscode/ 26 | *.swp 27 | *.swo 28 | 29 | .DS_Store 30 | Thumbs.db 31 | 32 | .specstory 33 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | node_modules 3 | **/node_modules/ 4 | **/node_modules 5 | src/ 6 | .git/ 7 | .gitignore 8 | *.log 9 | .eslintrc 10 | .prettierrc 11 | tsconfig.json 12 | build.js 13 | smithery.yaml 14 | Dockerfile 15 | README.md 16 | **/.DS_Store 17 | **/.idea 18 | **/.vscode -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | node_modules=false 3 | @mastergo:registry=https://registry.npmjs.org/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MasterGo Magic MCP 2 | 3 | [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/mastergo-design/mastergo-magic-mcp) 4 | 5 | MasterGo Magic MCP is a standalone MCP (Model Context Protocol) service designed to connect MasterGo design tools with AI models. It enables AI models to directly retrieve DSL data from MasterGo design files. 6 | 7 | ## Key Features 8 | 9 | - Retrieves DSL data from MasterGo design files 10 | - Runs directly with npx 11 | - No external dependencies required, only Node.js environment needed 12 | 13 | ## Tutorial 14 | 15 | - https://mastergo.com/file/155675508499265?page_id=158:0002 16 | 17 | ## Usage 18 | 19 | ### Obtaining MG_MCP_TOKEN 20 | 21 | 1. Visit https://mastergo.com 22 | 2. Enter personal settings 23 | 3. Click the Security Settings tab 24 | 4. Find the personal access token 25 | 5. Click to generate the token 26 | 27 | ### Command Line Options 28 | 29 | ``` 30 | npx @mastergo/magic-mcp --token=YOUR_TOKEN [--url=API_URL] [--rule=RULE_NAME] [--debug] 31 | ``` 32 | 33 | #### Parameters: 34 | 35 | - `--token=YOUR_TOKEN` (required): MasterGo API token for authentication 36 | - `--url=API_URL` (optional): API base URL, defaults to http://localhost:3000 37 | - `--rule=RULE_NAME` (optional): Add design rules to apply, can be used multiple times 38 | - `--debug` (optional): Enable debug mode for detailed error information 39 | 40 | You can also use space-separated format for parameters: 41 | 42 | ``` 43 | npx @mastergo/magic-mcp --token YOUR_TOKEN --url API_URL --rule RULE_NAME --debug 44 | ``` 45 | 46 | ### LINGMA Usage 47 | 48 | Search for LINGMA in the VSCode extension marketplace and install it. 49 | 50 | image-20250507174245589 51 | 52 | After logging in, click on [MCP tools] in the chat box. 53 | 54 | image-20250507174511910 55 | 56 | Click on [MCP Square] at the top to enter the MCP marketplace, find the MasterGo design collaboration tool and install it. 57 | 58 | image-20250507174840456 59 | 60 | After installation, go back to [MCP Servers], and edit our MCP service to replace it with your own MasterGo token. 61 | 62 | image-20250507175005364 63 | 64 | Finally, switch the chat mode to agent mode in the chat interface. 65 | 66 | image-20250507175107044 67 | 68 | ### cursor Usage 69 | 70 | Cursor Mcp usage guide reference: https://docs.cursor.com/context/model-context-protocol#using-mcp-tools-in-agent 71 | 72 | ```json 73 | { 74 | "mcpServers": { 75 | "mastergo-magic-mcp": { 76 | "command": "npx", 77 | "args": [ 78 | "-y", 79 | "@mastergo/magic-mcp", 80 | "--token=", 81 | "--url=https://mastergo.com" 82 | ], 83 | "env": {} 84 | } 85 | } 86 | } 87 | ``` 88 | 89 | ### cline Usage 90 | 91 | ```json 92 | { 93 | "mcpServers": { 94 | "@master/mastergo-magic-mcp": { 95 | "command": "npx", 96 | "args": [ 97 | "-y", 98 | "@mastergo/magic-mcp", 99 | "--token=", 100 | "--url=https://mastergo.com" 101 | ], 102 | "env": {} 103 | } 104 | } 105 | } 106 | ``` 107 | 108 | ## Project Structure 109 | 110 | ### src Directory 111 | 112 | The `src` directory contains the core implementation of the MasterGo Magic MCP service: 113 | 114 | - `index.ts`: Entry point of the application that initializes the MCP server and registers all tools 115 | - `http-util.ts`: Utility for handling HTTP requests to the MasterGo API 116 | - `types.d.ts`: TypeScript type definitions for the project 117 | 118 | #### src/tools 119 | 120 | Contains implementations of MCP tools: 121 | 122 | - `base-tool.ts`: Base class for all MCP tools 123 | - `get-dsl.ts`: Tool for retrieving DSL (Domain Specific Language) data from MasterGo design files 124 | - `get-component-link.ts`: Tool for retrieving component documentation from links 125 | - `get-meta.ts`: Tool for retrieving metadata information 126 | - `get-component-workflow.ts`: Tool providing structured component development workflow for Vue and React components, generating workflow files and component specifications 127 | 128 | #### src/markdown 129 | 130 | Contains markdown files with additional documentation: 131 | 132 | - `meta.md`: Documentation about metadata structure and usage 133 | - `component-workflow.md`: Component development workflow documentation guiding structured component development process 134 | 135 | ## Local Development 136 | 137 | 1. Run `yarn` and `yarn build` to install dependencies and build the code 138 | 2. Find the absolute path of `bin/cli.js` 139 | 3. Add local MCP configuration with your token 140 | 141 | ```json 142 | "mastergo-mcp-local": { 143 | "command": "node", 144 | "args": [ 145 | "absolute/path/to/bin/cli.js", 146 | "--token=mg_xxxxxx", 147 | "--url=https://mastergo.com", 148 | "--debug" 149 | ], 150 | "env": {} 151 | }, 152 | ``` 153 | 154 | 4. Restart your editor to ensure the local MCP is enabled 155 | 156 | After successful execution, you can debug based on the local running results. You can build your own MCP service based on your modifications. 157 | 158 | We welcome your code contributions and look forward to building MasterGo's MCP service together. 159 | 160 | ## License 161 | 162 | ISC 163 | -------------------------------------------------------------------------------- /README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # MasterGo Magic MCP 2 | 3 | [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/mastergo-design/mastergo-magic-mcp) 4 | 5 | MasterGo Magic MCP 是一个独立的 MCP(Model Context Protocol)服务,旨在连接 MasterGo 设计工具与 AI 模型。它使 AI 模型能够直接从 MasterGo 设计文件中获取 DSL 数据。 6 | 7 | ## 主要特性 8 | 9 | - 从 MasterGo 设计文件中获取 DSL 数据 10 | - 可直接通过 npx 运行 11 | - 仅需 Node.js 环境,无需其他外部依赖 12 | 13 | ## 教程 14 | 15 | - https://mastergo.com/file/155675508499265?page_id=158:0002 16 | 17 | ## 使用方法 18 | 19 | ### 获取 MG_MCP_TOKEN 20 | 21 | 1. 访问 https://mastergo.com 22 | 2. 进入个人设置 23 | 3. 点击安全设置选项卡 24 | 4. 找到个人访问令牌 25 | 5. 点击生成令牌 26 | 27 | ### 命令行选项 28 | 29 | ``` 30 | npx @mastergo/magic-mcp --token=YOUR_TOKEN [--url=API_URL] [--rule=RULE_NAME] [--debug] 31 | ``` 32 | 33 | #### 参数: 34 | 35 | - `--token=YOUR_TOKEN` (必需): MasterGo API 认证令牌 36 | - `--url=API_URL` (可选): API 基础 URL,默认为 http://localhost:3000 37 | - `--rule=RULE_NAME` (可选): 添加要应用的设计规则,可多次使用 38 | - `--debug` (可选): 启用调试模式,提供详细错误信息 39 | 40 | 你也可以使用空格分隔的参数格式: 41 | 42 | ``` 43 | npx @mastergo/magic-mcp --token YOUR_TOKEN --url API_URL --rule RULE_NAME --debug 44 | ``` 45 | 46 | ### LINGMA 使用方法 47 | 48 | 在 vscode 拓展市场中搜索 LINGMA -> 然后安装该拓展 49 | 50 | image-20250507174245589 51 | 52 | 登录后 -> 在聊天框中点击 [MCP tools] 53 | 54 | image-20250507174511910 55 | 56 | 点击顶部 [MCP Sqaure] 进入mcp市场,在市场中找到 Mastergo设计协作工具并安装 57 | 58 | image-20250507174840456 59 | 60 | 安装完成后,需要回到 [MCP Servers], 并编辑我们的mcp服务,将自己的mastergo token 替换上去 61 | 62 | image-20250507175005364 63 | 64 | 最后在聊天界面中将聊天模式切换为agent模式。 65 | 66 | image-20250507175107044 67 | 68 | ### Cursor 使用方法 69 | 70 | Cursor Mcp 使用指南参考:https://docs.cursor.com/context/model-context-protocol#using-mcp-tools-in-agent 71 | 72 | ```json 73 | { 74 | "mcpServers": { 75 | "mastergo-magic-mcp": { 76 | "command": "npx", 77 | "args": [ 78 | "-y", 79 | "@mastergo/magic-mcp", 80 | "--token=", 81 | "--url=https://mastergo.com" 82 | ], 83 | "env": {} 84 | } 85 | } 86 | } 87 | ``` 88 | 89 | ### cline 使用方法 90 | 91 | ```json 92 | { 93 | "mcpServers": { 94 | "@master/mastergo-magic-mcp": { 95 | "command": "npx", 96 | "args": [ 97 | "-y", 98 | "@mastergo/magic-mcp", 99 | "--token=", 100 | "--url=https://mastergo.com" 101 | ], 102 | "env": {} 103 | } 104 | } 105 | } 106 | ``` 107 | 108 | ## 项目结构 109 | 110 | ### src 目录 111 | 112 | `src` 目录包含 MasterGo Magic MCP 服务的核心实现: 113 | 114 | - `index.ts`:应用程序入口点,初始化 MCP 服务器并注册所有工具 115 | - `http-util.ts`:处理与 MasterGo API 通信的 HTTP 请求工具 116 | - `types.d.ts`:项目的 TypeScript 类型定义 117 | 118 | #### src/tools 119 | 120 | 包含 MCP 工具的实现: 121 | 122 | - `base-tool.ts`:所有 MCP 工具的基类 123 | - `get-dsl.ts`:从 MasterGo 设计文件中获取 DSL(领域特定语言)数据的工具 124 | - `get-component-link.ts`:从链接中获取组件文档的工具 125 | - `get-meta.ts`:获取元数据信息的工具 126 | - `get-component-workflow.ts`:提供结构化的组件开发工作流工具,支持 Vue 和 React 组件开发,生成所需的工作流文件和组件规范 127 | 128 | #### src/markdown 129 | 130 | 包含附加文档的 markdown 文件: 131 | 132 | - `meta.md`:关于元数据结构和用法的文档 133 | - `component-workflow.md`:组件开发工作流程文档,指导结构化组件开发过程 134 | 135 | ## 本地开发 136 | 137 | 1. 运行 `yarn` 和 `yarn build`,安装依赖并构建代码 138 | 2. 查看 `bin/cli.js` 的绝对路径 139 | 3. 在 MCP 配置中添加本地 MCP 配置,其中 token 为您获取的 token 140 | 141 | ```json 142 | "mastergo-mcp-local": { 143 | "command": "node", 144 | "args": [ 145 | "bin/cli.js绝对路径地址", 146 | "--token=mg_xxxxxx", 147 | "--url=https://mastergo.com", 148 | "--debug" 149 | ], 150 | "env": {} 151 | }, 152 | ``` 153 | 154 | 4. 重启编辑器,确认本地 MCP 已开启 155 | 156 | 运行成功后,就可以基于本地运行的结果进行调试。您可以基于自己的修改构建自己的 MCP 服务。 157 | 158 | 欢迎您为我们提供代码贡献,并期待大家一起共建 MasterGo 的 MCP 服务。 159 | 160 | ## 许可证 161 | 162 | ISC 163 | -------------------------------------------------------------------------------- /bin/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { spawn } = require("child_process"); 4 | const path = require("path"); 5 | const fs = require("fs"); 6 | 7 | // Get arguments 8 | const args = process.argv.slice(2); 9 | let token = ""; 10 | let baseUrl = "http://localhost:3000"; 11 | let debug = false; 12 | // Array to collect rules 13 | let rules = []; 14 | 15 | // Parse arguments 16 | for (let i = 0; i < args.length; i++) { 17 | if (args[i] === "--token" && i + 1 < args.length) { 18 | token = args[i + 1]; 19 | i++; 20 | } else if (args[i] === "--url" && i + 1 < args.length) { 21 | baseUrl = args[i + 1]; 22 | i++; 23 | } else if (args[i].startsWith("--token=")) { 24 | token = args[i].split("=")[1]; 25 | } else if (args[i].startsWith("--url=")) { 26 | baseUrl = args[i].split("=")[1]; 27 | } else if (args[i] === "--debug") { 28 | debug = true; 29 | // Add support for --rule parameter 30 | } else if (args[i] === "--rule" && i + 1 < args.length) { 31 | rules.push(args[i + 1]); 32 | i++; 33 | } else if (args[i].startsWith("--rule=")) { 34 | rules.push(args[i].split("=")[1]); 35 | } 36 | } 37 | 38 | // Check required arguments 39 | if (!token && !process.env.MASTERGO_API_TOKEN) { 40 | console.error("Error: Missing MasterGo API Token"); 41 | console.error( 42 | "Usage: npx mastergo-magic-mcp --token=YOUR_TOKEN [--url=API_URL] [--rule=RULE_NAME]" 43 | ); 44 | console.error("Use --help or -h for more information"); 45 | process.exit(1); 46 | } 47 | 48 | // Set environment variables 49 | const env = { 50 | MASTERGO_API_TOKEN: token, 51 | ...process.env, 52 | API_BASE_URL: baseUrl, 53 | DEBUG: debug ? "true" : "false", 54 | // Add RULES environment variable as stringified array 55 | RULES: JSON.stringify(rules), 56 | }; 57 | 58 | // Get package path 59 | const packageDir = path.resolve(__dirname, "../dist"); 60 | const indexPath = path.join(packageDir, "index.js"); 61 | 62 | // Check if file exists 63 | if (!fs.existsSync(indexPath)) { 64 | console.error( 65 | "Error: Executable file not found. Please ensure the package is correctly installed." 66 | ); 67 | process.exit(1); 68 | } 69 | 70 | if (debug) { 71 | console.log("Debug information:"); 72 | console.log(`Package path: ${indexPath}`); 73 | console.log(`Token: ${token ? "set" : "not set"}`); 74 | console.log(`API URL: ${baseUrl}`); 75 | console.log(`Rules: ${rules.length > 0 ? rules.join(", ") : "none"}`); 76 | console.log(`Debug mode: ${debug ? "enabled" : "disabled"}`); 77 | } 78 | 79 | try { 80 | // Directly run the compiled file 81 | if (debug) { 82 | console.log("Using node to run the compiled code..."); 83 | } 84 | 85 | // Directly use node to run the file, passing environment variables 86 | const child = spawn("node", [indexPath], { 87 | env: env, 88 | stdio: "inherit", 89 | }); 90 | 91 | child.on("error", (error) => { 92 | console.error("Startup error:", error); 93 | if (debug) { 94 | console.error("Detailed error information:", error.stack); 95 | } 96 | process.exit(1); 97 | }); 98 | 99 | child.on("exit", (code) => { 100 | process.exit(code || 0); 101 | }); 102 | } catch (error) { 103 | console.error("Runtime error:", error); 104 | if (debug) { 105 | console.error("Detailed error information:", error.stack); 106 | } 107 | process.exit(1); 108 | } 109 | -------------------------------------------------------------------------------- /build.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const esbuild = require("esbuild"); 4 | const { execSync } = require("child_process"); 5 | const fs = require("fs"); 6 | const path = require("path"); 7 | 8 | // Ensure the dist directory exists 9 | if (!fs.existsSync("dist")) { 10 | fs.mkdirSync("dist"); 11 | } 12 | 13 | // Ensure the bin directory exists 14 | if (!fs.existsSync("bin")) { 15 | fs.mkdirSync("bin"); 16 | } 17 | 18 | // Recursively delete a directory 19 | function removeDir(dirPath) { 20 | if (fs.existsSync(dirPath)) { 21 | fs.readdirSync(dirPath).forEach((file) => { 22 | const curPath = path.join(dirPath, file); 23 | if (fs.lstatSync(curPath).isDirectory()) { 24 | // Recursively delete subdirectories 25 | removeDir(curPath); 26 | } else { 27 | // Delete the file 28 | fs.unlinkSync(curPath); 29 | } 30 | }); 31 | // Delete the directory itself 32 | fs.rmdirSync(dirPath); 33 | } 34 | } 35 | 36 | async function build() { 37 | try { 38 | console.log("🚀 Starting the build process..."); 39 | 40 | // Clean up old build files 41 | console.log("🧹 Cleaning up old build files..."); 42 | if (fs.existsSync("dist")) { 43 | // First delete the dist directory 44 | removeDir("dist"); 45 | // Re-create the dist directory 46 | fs.mkdirSync("dist"); 47 | } 48 | 49 | // Use esbuild to bundle all code into a single file 50 | console.log("📦 Using esbuild to bundle all code into a single file..."); 51 | await esbuild.build({ 52 | entryPoints: ["src/index.ts"], 53 | bundle: true, 54 | platform: "node", 55 | target: "node16", 56 | outfile: "dist/index.js", 57 | minify: true, 58 | sourcemap: false, 59 | format: "cjs", 60 | // Exclude only node built-in modules to ensure all third-party dependencies are bundled 61 | external: [ 62 | "path", 63 | "fs", 64 | "child_process", 65 | "http", 66 | "https", 67 | "util", 68 | "os", 69 | "stream", 70 | "zlib", 71 | "events", 72 | "buffer", 73 | "crypto", 74 | "net", 75 | "dns", 76 | "tls", 77 | "url", 78 | "querystring", 79 | "assert", 80 | ], 81 | // Ensure all modules are correctly resolved 82 | resolveExtensions: [".ts", ".js", ".json", ".node"], 83 | // Ensure all dependencies are correctly loaded 84 | loader: { 85 | ".ts": "ts", 86 | ".js": "js", 87 | ".json": "json", 88 | ".node": "file", 89 | ".md": "text", 90 | }, 91 | // Define environment variables 92 | define: { 93 | "process.env.NODE_ENV": '"production"', 94 | }, 95 | // Enable tree shaking 96 | treeShaking: true, 97 | }); 98 | 99 | // Verify if only one file is generated 100 | console.log("🔍 Verifying the build output..."); 101 | const files = fs.readdirSync("dist"); 102 | if (files.length > 1 || (files.length === 1 && files[0] !== "index.js")) { 103 | console.warn("⚠️ Warning: The build produced multiple files, not a single file"); 104 | console.warn("📁 File list:", files); 105 | } else { 106 | console.log("✅ Verification successful: All code has been bundled into a single file"); 107 | } 108 | 109 | // The file header is already in the source file, no need to add it again 110 | console.log("✅ The source file already includes the shebang, no need to add it again"); 111 | 112 | // Add executable permissions 113 | console.log("🔑 Adding executable permissions..."); 114 | fs.chmodSync("dist/index.js", "755"); 115 | fs.chmodSync("bin/cli.js", "755"); 116 | 117 | // Display file size 118 | const stats = fs.statSync("dist/index.js"); 119 | const fileSizeInKB = (stats.size / 1024).toFixed(2); 120 | console.log(`📦 Build output size: ${fileSizeInKB} KB`); 121 | 122 | console.log("✅ Build successful!"); 123 | console.log("📦 Executable file located at: dist/index.js"); 124 | console.log("📦 CLI entry located at: bin/cli.js"); 125 | 126 | console.log("🚀 You can publish the package using the following command:"); 127 | console.log(" npm publish"); 128 | console.log(""); 129 | console.log("🔧 Or you can test locally using the following command:"); 130 | console.log( 131 | " node bin/cli.js --token=YOUR_TOKEN [--url=API_URL] [--framework=FRAMEWORK]" 132 | ); 133 | } catch (error) { 134 | console.error("❌ Build failed:", error); 135 | process.exit(1); 136 | } 137 | } 138 | 139 | build(); 140 | -------------------------------------------------------------------------------- /images/image-20250507174245589.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mastergo-design/mastergo-magic-mcp/ea015ea1f3bb31ff98e6905a6381d46b5a236052/images/image-20250507174245589.png -------------------------------------------------------------------------------- /images/image-20250507174511910.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mastergo-design/mastergo-magic-mcp/ea015ea1f3bb31ff98e6905a6381d46b5a236052/images/image-20250507174511910.png -------------------------------------------------------------------------------- /images/image-20250507174840456.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mastergo-design/mastergo-magic-mcp/ea015ea1f3bb31ff98e6905a6381d46b5a236052/images/image-20250507174840456.png -------------------------------------------------------------------------------- /images/image-20250507175005364.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mastergo-design/mastergo-magic-mcp/ea015ea1f3bb31ff98e6905a6381d46b5a236052/images/image-20250507175005364.png -------------------------------------------------------------------------------- /images/image-20250507175107044.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mastergo-design/mastergo-magic-mcp/ea015ea1f3bb31ff98e6905a6381d46b5a236052/images/image-20250507175107044.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mastergo/magic-mcp", 3 | "version": "0.0.4-beta.11", 4 | "description": "MasterGo MCP standalone service", 5 | "main": "dist/index.js", 6 | "bin": { 7 | "mastergo-magic-mcp": "bin/cli.js" 8 | }, 9 | "files": [ 10 | "dist/**/*", 11 | "bin/**/*", 12 | "!**/*.map", 13 | "!**/.DS_Store", 14 | "!**/.idea", 15 | "!**/.vscode" 16 | ], 17 | "engines": { 18 | "node": ">=18" 19 | }, 20 | "scripts": { 21 | "build": "node build.js", 22 | "start": "node bin/cli.js --token=test --url=http://localhost:3000 --debug", 23 | "prepublishOnly": "npm run build" 24 | }, 25 | "keywords": [ 26 | "mastergo", 27 | "mcp", 28 | "ai" 29 | ], 30 | "author": "", 31 | "license": "ISC", 32 | "private": false, 33 | "dependencies": { 34 | "@modelcontextprotocol/sdk": "^1.6.1", 35 | "axios": "^1.6.0", 36 | "zod": "^3.22.4" 37 | }, 38 | "devDependencies": { 39 | "@types/node": "^20.8.10", 40 | "@typescript-eslint/eslint-plugin": "^6.9.1", 41 | "@typescript-eslint/parser": "^6.9.1", 42 | "esbuild": "^0.25.1", 43 | "esbuild-plugin-tsc": "^0.5.0", 44 | "eslint": "^8.52.0", 45 | "pkg": "^5.8.1", 46 | "prettier": "^3.0.3", 47 | "ts-node": "^10.9.1", 48 | "typescript": "^5.2.2" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/http-util.ts: -------------------------------------------------------------------------------- 1 | // Make a request through axios and set the request interceptor to add the token 2 | import axios, { 3 | AxiosInstance, 4 | AxiosRequestConfig, 5 | AxiosResponse, 6 | InternalAxiosRequestConfig, 7 | } from "axios"; 8 | 9 | // DSL response interface 10 | export interface DslResponse { 11 | [key: string]: any; 12 | } 13 | 14 | // Code generation response interface 15 | export interface CodeResponse { 16 | code: string; 17 | [key: string]: any; 18 | } 19 | 20 | /** 21 | * HttpUtil class - responsible for managing requests and storing tokens 22 | */ 23 | export class HttpUtil { 24 | private httpClient: AxiosInstance; 25 | 26 | constructor(baseUrl: string, token: string) { 27 | // Create axios instance 28 | this.httpClient = axios.create({ 29 | baseURL: baseUrl, 30 | timeout: 30000, // Default 30 second timeout 31 | headers: { 32 | "Content-Type": "application/json", 33 | Accept: "application/json", 34 | }, 35 | }); 36 | 37 | // Request interceptor 38 | this.httpClient.interceptors.request.use( 39 | (config: InternalAxiosRequestConfig) => { 40 | // If a token exists, add it to the request header 41 | if (token) { 42 | config.headers["X-MG-UserAccessToken"] = `${token}`; 43 | } 44 | return config; 45 | }, 46 | (error) => { 47 | return Promise.reject(error); 48 | } 49 | ); 50 | 51 | // Response interceptor 52 | this.httpClient.interceptors.response.use( 53 | (response: AxiosResponse) => { 54 | return response; 55 | }, 56 | (error) => { 57 | return Promise.reject(error); 58 | } 59 | ); 60 | } 61 | 62 | private handleDslComponentDocumentLinks(dsl: DslResponse) { 63 | const documentLinks = new Set(); 64 | 65 | const getChildrenDocumentLinks = (node: any) => { 66 | if (node?.componentInfo?.componentSetDocumentLink?.[0]) { 67 | documentLinks.add(node.componentInfo.componentSetDocumentLink[0]); 68 | } 69 | 70 | if (node.children && Array.isArray(node.children)) { 71 | for (const child of node.children) { 72 | getChildrenDocumentLinks(child); 73 | } 74 | } 75 | }; 76 | 77 | for (const node of dsl.nodes ?? []) { 78 | getChildrenDocumentLinks(node); 79 | } 80 | 81 | return Array.from(documentLinks); 82 | } 83 | 84 | public async getMeta(fileId: string, layerId: string): Promise { 85 | const response = await this.httpClient.get("/mcp/meta", { 86 | params: { fileId, layerId }, 87 | }); 88 | return response.data; 89 | } 90 | 91 | /** 92 | * Get DSL data 93 | */ 94 | public async getDsl(fileId: string, layerId: string): Promise { 95 | try { 96 | const params: any = { fileId, layerId }; 97 | 98 | const response = await this.httpClient.get("/mcp/dsl", { params }); 99 | const result = { 100 | dsl: response.data, 101 | componentDocumentLinks: this.handleDslComponentDocumentLinks( 102 | response.data 103 | ), 104 | rules: [ 105 | "token filed must be generated as a variable (colors, shadows, fonts, etc.) and the token field must be displayed in the comment", 106 | ` 107 | componentDocumentLinks is a list of frontend component documentation links used in the DSL layer, designed to help you understand how to use the components. 108 | When it exists and is not empty, you need to use mcp__getComponentLink in a for loop to get the URL content of all components in the list, understand how to use the components, and generate code using the components. 109 | For example: 110 | \`\`\`js 111 | const componentDocumentLinks = [ 112 | 'https://example.com/ant/button.mdx', 113 | 'https://example.com/ant/button.mdx' 114 | ] 115 | for (const url of componentDocumentLinks) { 116 | const componentLink = await mcp__getComponentLink(url); 117 | console.log(componentLink); 118 | } 119 | \`\`\` 120 | `, 121 | ...(JSON.parse(process.env.RULES ?? "[]") as string[]), 122 | ], 123 | }; 124 | return result; 125 | } catch (error) { 126 | throw error; 127 | } 128 | } 129 | 130 | public async getComponentStyleJson(fileId: string, layerId: string) { 131 | const response = await this.httpClient.get(`/mcp/style`, { 132 | params: { fileId, layerId }, 133 | }); 134 | return response.data; 135 | } 136 | 137 | /** 138 | * General request method 139 | */ 140 | public async request(config: AxiosRequestConfig): Promise { 141 | try { 142 | const response = await this.httpClient(config); 143 | return response.data; 144 | } catch (error) { 145 | throw error; 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 4 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 5 | import { HttpUtil } from "./http-util"; 6 | import { GetDslTool } from "./tools/get-dsl"; 7 | import { GetComponentLinkTool } from "./tools/get-component-link"; 8 | import { GetMetaTool } from "./tools/get-meta"; 9 | import { GetComponentWorkflowTool } from "./tools/get-component-workflow"; 10 | import { GetVersionTool } from "./tools/get-version"; 11 | 12 | // Logging function, only outputs when the DEBUG environment variable is true 13 | const log = (message: string) => { 14 | if (process.env.DEBUG === "true") { 15 | console.log(message); 16 | } 17 | }; 18 | 19 | // Main function 20 | function main() { 21 | // Retrieve token and baseUrl from environment variables 22 | const token = process.env.MASTERGO_API_TOKEN; 23 | const baseUrl = process.env.API_BASE_URL || "http://localhost:3000"; 24 | const debug = process.env.DEBUG === "true"; 25 | 26 | if (!token) { 27 | console.error("Error: MASTERGO_API_TOKEN environment variable not set"); 28 | process.exit(1); 29 | } 30 | 31 | log(`Starting MasterGo MCP server...`); 32 | log(`API base URL: ${baseUrl}`); 33 | 34 | // Create server instance 35 | const server = new McpServer({ 36 | name: "MasterGoMcpServer", 37 | version: "0.0.1", 38 | }); 39 | 40 | // Create HTTP utility 41 | const httpUtil = new HttpUtil(baseUrl, token); 42 | 43 | // Register tools 44 | new GetVersionTool().register(server); 45 | new GetDslTool(httpUtil).register(server); 46 | new GetComponentLinkTool(httpUtil).register(server); 47 | new GetMetaTool(httpUtil).register(server); 48 | new GetComponentWorkflowTool(httpUtil).register(server); 49 | 50 | // Connect to standard input/output 51 | server.connect(new StdioServerTransport()); 52 | 53 | // Only output server started message in debug mode 54 | if (debug) { 55 | console.log("MasterGo MCP server started and waiting for connection..."); 56 | } 57 | } 58 | 59 | // Start the program 60 | main(); 61 | -------------------------------------------------------------------------------- /src/markdown/component-workflow.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: 4 | alwaysApply: true 5 | --- 6 | 7 | # MasterGo Component System Specification v1.0 8 | 9 | ## Core Contents 10 | 11 | - Project Environment Setup 12 | - Component Interaction Design 13 | - Component Development Workflow 14 | 15 | --- 16 | 17 | ## Project Environment Setup 18 | 19 | ### Environment Check 20 | 21 | Check if project is initialized: 22 | 23 | - `package.json` 24 | - TypeScript configuration 25 | - Vite configuration 26 | - VitePress configuration (`docs/.vitepress/`) 27 | - Vue and testing dependencies 28 | 29 | ### Environment Initialization 30 | 31 | Required steps: 32 | 33 | ```bash 34 | npm init -y 35 | npm install vue@latest typescript vite@latest vitepress@latest vitest@latest @vitejs/plugin-vue@latest 36 | npm install -D @vue/test-utils jsdom @types/node 37 | ``` 38 | 39 | Required configuration files: 40 | 41 | - `tsconfig.json` 42 | - `vite.config.ts` 43 | - `docs/.vitepress/config.ts` 44 | - `vitest.config.ts` 45 | 46 | ### Project Structure 47 | 48 | ``` 49 | project-root/ 50 | ├── docs/ # Component documentation 51 | │ ├── .vitepress/ # VitePress configuration 52 | │ ├── components/ # Component docs and demos 53 | ├── src/ 54 | │ ├── components/ # Component source code 55 | │ ├── styles/ # Style files 56 | ├── __tests__/ # Component tests 57 | ``` 58 | 59 | ### Required Scripts 60 | 61 | ```json 62 | { 63 | "scripts": { 64 | "dev": "vitepress dev docs", 65 | "build": "vitepress build docs", 66 | "test": "vitest run", 67 | "test:ui": "vitest --ui" 68 | } 69 | } 70 | ``` 71 | 72 | ### Project Verification 73 | 74 | **CRITICAL STEP**: After project initialization, scripts must be run to verify configuration: 75 | 76 | 1. Run the development server: 77 | 78 | ```bash 79 | npm run dev 80 | ``` 81 | 82 | 2. Verify the test environment: 83 | 84 | ```bash 85 | npm run test 86 | ``` 87 | 88 | 3. Ensure no errors appear in the console for each script 89 | 4. Resolve any errors before proceeding to component development 90 | 5. Project is considered properly initialized only when all scripts run without errors 91 | 92 | --- 93 | 94 | ## Component Interaction Design Specification 95 | 96 | ### Core Principles 97 | 98 | - **CSS Priority**: Use CSS pseudo-classes for basic states 99 | - **State Extension**: Allow overriding default states via props 100 | - **Consistency**: Maintain consistent state management patterns 101 | - **Performance Priority**: Minimize JavaScript state management 102 | 103 | ### State Priority 104 | 105 | CSS Pseudo-classes > Props-specified States > JavaScript State Management 106 | 107 | ### Component Reuse Principles 108 | 109 | Reuse decision priority: 110 | 111 | 1. Direct Use (when functionality completely matches) 112 | 2. Component Composition (implement by combining existing components) 113 | 3. Component Extension (add new functionality based on existing components) 114 | 4. Redevelopment (only when above methods are not feasible) 115 | 116 | --- 117 | 118 | ## Component Development Workflow 119 | 120 | ### Complete Process 121 | 122 | ``` 123 | [Environment Check] → [Project Verification] → [Component Analysis] → [User Confirmation] → [Test Generation] → [Component Development] → [Validation] → [Documentation & Preview] 124 | ``` 125 | 126 | ### 1. Component Analysis 127 | 128 | **Input**: Component JSON specification 129 | **Output**: Architecture document (`.mastergo/${componentName}-arch.md`) 130 | 131 | #### Slot Analysis 132 | 133 | AI must analyze component design and infer: 134 | 135 | - Slots that may be needed 136 | - Purpose of each slot 137 | - Default content suggestions 138 | - Optional/required status 139 | 140 | #### Checklist 141 | 142 | - [ ] Property analysis 143 | - [ ] States and variants identification 144 | - [ ] Common styles extraction 145 | - [ ] Interface definition 146 | - [ ] Slot definition 147 | 148 | #### Architecture Document Verification 149 | 150 | **CRITICAL BREAK POINT**: After generating the architecture document, execution must pause. 151 | 152 | 1. Present the architecture document to the user for review 153 | 2. Ask user to verify all aspects of the document: 154 | - Component properties and types 155 | - State definitions 156 | - Slot specifications 157 | - Component structure 158 | - Image assets and their paths 159 | 3. If user identifies issues: 160 | - Collect all feedback 161 | - Make required modifications to the architecture document 162 | - Present updated document for review 163 | 4. Repeat review cycle until user explicitly approves the document 164 | 5. Only proceed to Test Generation phase after user confirmation 165 | 166 | #### Image Resource Handling 167 | 168 | **CRITICAL STEP**: After user confirmation of the architecture document, and before proceeding to Test Generation: 169 | 170 | 1. **Resource Inventory and Path Documentation**: 171 | 172 | - The architecture document must include an "Image Resources" section that clearly lists all necessary resources in a table format: 173 | 174 | ```markdown 175 | ## Image Resources 176 | 177 | ### Resource List and Paths 178 | 179 | | Icon Description | Original Path | Target Path | Icon Color Control | 180 | | ---------------- | ------------------------- | ------------------------------------------------------- | ---------------------------------------------------- | 181 | | Close Icon | `/original/path/icon.svg` | `src/components/${componentName}/images/icon-close.svg` | Dynamically controlled, defaults to match text color | 182 | | Other Icon | ... | ... | ... | 183 | ``` 184 | 185 | 2. **Copy Images**: 186 | 187 | - Copy all necessary image resources listed in the architecture document to the component-specific directory. 188 | - Use semantic filenames such as `icon-close.svg`, `icon-success.svg`, `bg-header.png`, etc., ensuring the names clearly indicate the purpose of each image. 189 | - The target path must be `src/components/${componentName}/images/`. Create this directory if it doesn't exist. 190 | - Example: 191 | ```bash 192 | mkdir -p src/components/${componentName}/images 193 | cp /original/path/close-icon.svg src/components/${componentName}/images/icon-close.svg 194 | ``` 195 | 196 | 3. **SVG Image Import and Color Specification**: 197 | 198 | - The architecture document must clearly specify the import method and color control approach for SVG icons. 199 | - SVGs must be imported using the following method to ensure dynamic color control: 200 | 201 | ```typescript 202 | import CloseIcon from "./images/icon-close.svg?raw"; // ?raw ensures it's imported as a string 203 | ``` 204 | 205 | - The architecture document must include code examples for SVG usage and color control: 206 | 207 | ````markdown 208 | ### Icon Import and Usage Method 209 | 210 | ```typescript 211 | // In ${componentName}.vue, import icons 212 | import CloseIcon from "./images/icon-close.svg?raw"; 213 | import SuccessIcon from "./images/icon-success.svg?raw"; 214 | ``` 215 | ```` 216 | 217 | Using SVGs in templates and controlling their color: 218 | 219 | ```html 220 | 223 | 224 | 233 | ``` 234 | 235 | - For each SVG icon, the architecture document must clearly specify: 236 | 1. Default color 237 | 2. Whether the color is fixed or needs to be dynamically controlled 238 | 3. Color variations in different states 239 | 240 | ### 2. Test Generation 241 | 242 | **Input**: Approved architecture document 243 | **Output**: Component unit tests 244 | 245 | #### Test Coverage 246 | 247 | - All component properties 248 | - All component states and behaviors 249 | - Edge cases 250 | - All inferred slots 251 | - State management (hover, focus, active, disabled, etc.) 252 | 253 | ### 3. Component Development 254 | 255 | **Input**: Architecture document and test cases 256 | **Output**: Functional component 257 | 258 | #### Required Files 259 | 260 | - `src/components/${componentName}/index.ts` 261 | - `src/components/${componentName}/types.ts` 262 | - `src/components/${componentName}/${componentName}.vue` 263 | 264 | #### Development Method 265 | 266 | - Test-driven development 267 | - Must follow UI interaction design specifications 268 | - Iterative implementation: Minimal code → Run tests → Refactor → Next test 269 | 270 | ### 4. Validation 271 | 272 | - All tests pass 273 | - Component visually matches design 274 | - Component is accessible 275 | - Responsive behavior is correct 276 | 277 | ### 5. Documentation & Preview 278 | 279 | **Output**: VitePress documentation and interactive previews 280 | 281 | #### Documentation Content 282 | 283 | - Component overview 284 | - API reference 285 | - Interactive examples 286 | - Complete slot documentation 287 | - Various states and use cases demonstrations 288 | 289 | #### Interactive Preview 290 | 291 | ````md 292 | ## Basic Usage 293 | 294 | :::demo 295 | 296 | ```vue 297 | 300 | ``` 301 | 302 | ::: 303 | ```` 304 | 305 | ### Checkpoints 306 | 307 | - **Environment**: Correct configuration, dependencies installed, documentation preview system working 308 | - **Structure**: Files created, exports working, interfaces defined, slot definitions 309 | - **Tests**: Coverage for all features, edge cases, slots and states 310 | - **Implementation**: Renders correctly, properties work, state management complies with specifications, styles applied correctly, slot functionality works 311 | - **Documentation**: Feature documentation complete, examples available, API reference complete, slot usage documentation complete 312 | -------------------------------------------------------------------------------- /src/markdown/meta.md: -------------------------------------------------------------------------------- 1 | The `results` returns an XML file, which contains two types of information: 2 | 3 | - **meta**: Describes the site, environment, requirements, and other context. 4 | - **action**: Corresponds to the entry page name and `targetLayerId`, which is the ID of the target page. 5 | 6 | I need you to write a task.md file in the current directory according to the following steps, and strictly follow these steps to generate the final project code. 7 | 8 | ## Steps 9 | 1. Obtain the `results` information, extract the `meta` and `action` data, and create a new `task.md` file. 10 | 2. Analyze the `meta` field, summarize the requirement description, and write it into task.md. 11 | 3. Analyze the `action` field, and write the page information into task.md. 12 | 4. Use the `targetLayerId` from the `action` field to call the `mcp__getDsl` method to get data. 13 | 5. Analyze the page data to check if there is an `interactive` field. If it exists, this field contains information about the current node's navigation to another page. You must continue to call the `mcp__getDsl` method according to the `interactive` field. 14 | 6. Repeat step 5 until all page data has been parsed and written into task.md. 15 | 7. According to the content in task.md, sequentially parse the pages listed in task.md and generate code. Complete the project construction. 16 | 17 | ## Example 18 | **Note**: Be sure to follow the order described in the example. Ensure that all page information is obtained! 19 | 20 | 21 | uppose the obtained results are: 22 | ```xml 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | ``` 31 | Write the following into task.md: 32 | 33 | 34 | 35 | 36 | ```markdown 37 | Requirement Description: This is a food delivery app, which includes login, food ordering, and address management features. It should be built using React and use Ant Design as the component library. 38 | 39 | ## Page List: 40 | Login Page (layerId: 0:1) 41 | Food Delivery Page (layerId: 0:2) 42 | 43 | ## Navigation Information 44 | 45 | 46 | ``` 47 | 48 | Use `mcp__getDsl` to parse the 0:1 page and analyze the data. 49 | 50 | The data might be: 51 | ```json 52 | { 53 | nodes: [{ 54 | id: "0:1", 55 | // ...others 56 | children: [{ 57 | id: "1:12", 58 | interactive: [ 59 | type: "navigation", 60 | targetLayerId: "0:3" 61 | ] 62 | }] 63 | }] 64 | } 65 | ``` 66 | 67 | if you find that the node data of page 0:1 contains the `interactive` field with id 0:3, write the 0:3 page and add the navigation information: 68 | ```markdown 69 | 70 | ## Page List: 71 | Login Page (layerId: 0:1) 72 | Food Delivery Page (layerId: 0:2) 73 | Login Page Navigation Page (layerId: 0:3) 74 | 75 | ## Navigation Information 76 | 0:1 => 0:3 77 | 78 | ``` 79 | Continue to parse 0:3. If the data contains the `interactive` field, continue writing. 80 | Repeat this process until the data parsed by `mcp__getDsl` no longer contains the `interactive` field. 81 | Then, use `mcp__getDsl` to parse the 0:2 page and repeat the steps for the 0:1 page. 82 | 83 | After completion, generate the project code sequentially according to the page list in task.md. 84 | -------------------------------------------------------------------------------- /src/tools/base-tool.ts: -------------------------------------------------------------------------------- 1 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 2 | import { z } from "zod"; 3 | 4 | export abstract class BaseTool { 5 | abstract name: string; 6 | abstract description: string; 7 | abstract schema: z.ZodObject; 8 | 9 | register(server: McpServer) { 10 | server.tool( 11 | this.name, 12 | this.description, 13 | this.schema.shape, 14 | this.execute.bind(this) 15 | ); 16 | } 17 | 18 | abstract execute(args: z.infer): Promise<{ 19 | content: Array<{ type: "text"; text: string }>; 20 | }>; 21 | } 22 | -------------------------------------------------------------------------------- /src/tools/get-component-link.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { BaseTool } from "./base-tool"; 3 | import { HttpUtil } from "../http-util"; 4 | 5 | const COMPONENT_LINK_TOOL_NAME = "mcp__getComponentLink"; 6 | const COMPONENT_LINK_TOOL_DESCRIPTION = `When the data returned by mcp__getDsl contains a non-empty componentDocumentLinks array, this tool is used to sequentially retrieve URLs from the componentDocumentLinks array and then obtain component documentation data. The returned document data is used for you to generate frontend code based on components.`; 7 | 8 | export class GetComponentLinkTool extends BaseTool { 9 | name = COMPONENT_LINK_TOOL_NAME; 10 | description = COMPONENT_LINK_TOOL_DESCRIPTION; 11 | private httpUtil: HttpUtil; 12 | 13 | constructor(httpUtil: HttpUtil) { 14 | super(); 15 | this.httpUtil = httpUtil; 16 | } 17 | 18 | schema = z.object({ 19 | url: z 20 | .string() 21 | .describe( 22 | "Component documentation link URL, from the componentDocumentLinks property, please ensure the URL is valid" 23 | ), 24 | }); 25 | 26 | async execute({ url }: z.infer) { 27 | try { 28 | const data = await this.httpUtil.request({ 29 | method: "GET", 30 | url, 31 | }); 32 | 33 | return { 34 | content: [ 35 | { 36 | type: "text" as const, 37 | text: `${data}`, 38 | }, 39 | ], 40 | }; 41 | } catch (error) { 42 | return { 43 | content: [ 44 | { 45 | type: "text" as const, 46 | text: JSON.stringify({ 47 | error: "Failed to get component documentation", 48 | message: error instanceof Error ? error.message : String(error), 49 | }), 50 | }, 51 | ], 52 | }; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/tools/get-component-workflow.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import fs from "fs"; 3 | import { BaseTool } from "./base-tool"; 4 | import { HttpUtil } from "../http-util"; 5 | import componentWorkflow from "../markdown/component-workflow.md"; 6 | 7 | const COMPONENT_GENERATOR_TOOL_NAME = "mcp__getComponentGenerator"; 8 | const COMPONENT_GENERATOR_TOOL_DESCRIPTION = ` 9 | Users need to actively call this tool to get the component development workflow. When Generator is mentioned, please actively call this tool. 10 | This tool provides a structured workflow for component development following best practices. 11 | You must provide an absolute rootPath of workspace to save workflow files. 12 | `; 13 | 14 | export class GetComponentWorkflowTool extends BaseTool { 15 | name = COMPONENT_GENERATOR_TOOL_NAME; 16 | description = COMPONENT_GENERATOR_TOOL_DESCRIPTION; 17 | private httpUtil: HttpUtil; 18 | 19 | constructor(httpUtil: HttpUtil) { 20 | super(); 21 | this.httpUtil = httpUtil; 22 | } 23 | 24 | schema = z.object({ 25 | rootPath: z 26 | .string() 27 | .describe( 28 | "The root path of the project, if the user does not provide, you can use the current directory as the root path" 29 | ), 30 | fileId: z 31 | .string() 32 | .describe( 33 | "MasterGo design file ID (format: file/ in MasterGo URL)" 34 | ), 35 | layerId: z 36 | .string() 37 | .describe( 38 | "Layer ID of the specific component or element to retrieve (format: ?layer_id= / file= in MasterGo URL)" 39 | ), 40 | }); 41 | 42 | async execute({ rootPath, fileId, layerId }: z.infer) { 43 | const baseDir = `${rootPath}/.mastergo/`; 44 | if (!fs.existsSync(baseDir)) { 45 | fs.mkdirSync(baseDir, { recursive: true }); 46 | } 47 | const workflowFilePath = `${baseDir}/component-workflow.md`; 48 | const jsonData = await this.httpUtil.getComponentStyleJson(fileId, layerId); 49 | const componentJsonDir = `${baseDir}/${jsonData[0].name}.json`; 50 | const walkLayer = (layer: any) => { 51 | if (layer.path && layer.path.length > 0) { 52 | layer.imageUrls = []; 53 | const id = layer.id.replaceAll("/", "&"); 54 | const imageDir = `${baseDir}/images`; 55 | if (!fs.existsSync(imageDir)) { 56 | fs.mkdirSync(imageDir, { recursive: true }); 57 | } 58 | (layer.path ?? []).forEach((svgPath: string, index: number) => { 59 | const filePath = `${imageDir}/${id}-${index}.svg`; 60 | if (!fs.existsSync(filePath)) { 61 | fs.writeFileSync( 62 | filePath, 63 | ` 64 | 65 | ` 66 | ); 67 | } 68 | layer.imageUrls.push(filePath); 69 | }); 70 | delete layer.path; 71 | } 72 | if (layer.children) { 73 | layer.children.forEach((child: any) => { 74 | walkLayer(child); 75 | }); 76 | } 77 | }; 78 | walkLayer(jsonData[0]); 79 | 80 | //文件夹可能也不存在递归创建 81 | if (!fs.existsSync(workflowFilePath)) { 82 | fs.writeFileSync(workflowFilePath, componentWorkflow); 83 | } 84 | 85 | fs.writeFileSync(componentJsonDir, JSON.stringify(jsonData[0])); 86 | 87 | try { 88 | return { 89 | content: [ 90 | { 91 | type: "text" as const, 92 | text: JSON.stringify({ 93 | files: { 94 | workflow: workflowFilePath, 95 | componentSpec: componentJsonDir, 96 | }, 97 | message: "Component development files successfully created", 98 | rules: [ 99 | `Follow the component workflow process defined in file://${workflowFilePath} for structured development. This workflow contains a lot of content, you'll need to read it in multiple sessions.`, 100 | `Implement the component according to the specifications in file://${componentJsonDir}, ensuring all properties and states are properly handled.`, 101 | ], 102 | }), 103 | }, 104 | ], 105 | }; 106 | } catch (error: any) { 107 | const errorMessage = error.response?.data ?? error?.message; 108 | return { 109 | isError: true, 110 | content: [ 111 | { 112 | type: "text" as const, 113 | text: JSON.stringify(errorMessage), 114 | }, 115 | ], 116 | }; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/tools/get-dsl.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { BaseTool } from "./base-tool"; 3 | import { HttpUtil } from "../http-util"; 4 | 5 | const DSL_TOOL_NAME = "mcp__getDsl"; 6 | const DSL_TOOL_DESCRIPTION = ` 7 | "Use this tool to retrieve the DSL (Domain Specific Language) data from MasterGo design files and the rules you must follow when generating code. 8 | This tool is useful when you need to analyze the structure of a design, understand component hierarchy, or extract design properties. 9 | You must provide a fileId and layerId to identify the specific design element. 10 | This tool returns the raw DSL data in JSON format that you can then parse and analyze. 11 | This tool also returns the rules you must follow when generating code. 12 | The DSL data can also be used to transform and generate code for different frameworks." 13 | `; 14 | 15 | export class GetDslTool extends BaseTool { 16 | name = DSL_TOOL_NAME; 17 | description = DSL_TOOL_DESCRIPTION; 18 | private httpUtil: HttpUtil; 19 | 20 | constructor(httpUtil: HttpUtil) { 21 | super(); 22 | this.httpUtil = httpUtil; 23 | } 24 | 25 | schema = z.object({ 26 | fileId: z 27 | .string() 28 | .describe( 29 | "MasterGo design file ID (format: file/ in MasterGo URL)" 30 | ), 31 | layerId: z 32 | .string() 33 | .describe( 34 | "Layer ID of the specific component or element to retrieve (format: ?layer_id= / file= in MasterGo URL)" 35 | ), 36 | }); 37 | 38 | async execute({ fileId, layerId }: z.infer) { 39 | try { 40 | const dsl = await this.httpUtil.getDsl(fileId, layerId); 41 | return { 42 | content: [ 43 | { 44 | type: "text" as const, 45 | text: JSON.stringify(dsl), 46 | }, 47 | ], 48 | }; 49 | } catch (error: any) { 50 | const errorMessage = error.response?.data ?? error?.message; 51 | return { 52 | isError: true, 53 | content: [ 54 | { 55 | type: "text" as const, 56 | text: JSON.stringify(errorMessage), 57 | }, 58 | ], 59 | }; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/tools/get-meta.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { BaseTool } from "./base-tool"; 3 | import { HttpUtil } from "../http-util"; 4 | import rules from "../markdown/meta.md"; 5 | 6 | const META_TOOL_NAME = "mcp__getMeta"; 7 | const META_TOOL_DESCRIPTION = ` 8 | Use this tool when the user intends to build a complete website or needs to obtain high-level site 9 | configuration information. You must provide a fileld and layerld to identify the specific design element. 10 | This tool returns the rules and results of the site and page. The rules is a markdown file, you must 11 | follow the rules and use the results to analyze the site and page. 12 | `; 13 | 14 | export class GetMetaTool extends BaseTool { 15 | name = META_TOOL_NAME; 16 | description = META_TOOL_DESCRIPTION; 17 | private httpUtil: HttpUtil; 18 | 19 | constructor(httpUtil: HttpUtil) { 20 | super(); 21 | this.httpUtil = httpUtil; 22 | } 23 | 24 | schema = z.object({ 25 | fileId: z 26 | .string() 27 | .describe( 28 | "MasterGo design file ID (format: file/ in MasterGo URL)" 29 | ), 30 | layerId: z 31 | .string() 32 | .describe( 33 | "Layer ID of the specific component or element to retrieve (format: ?layer_id= / file= in MasterGo URL)" 34 | ), 35 | }); 36 | 37 | async execute({ fileId, layerId }: z.infer) { 38 | try { 39 | const result = await this.httpUtil.getMeta(fileId, layerId); 40 | return { 41 | content: [ 42 | { 43 | type: "text" as const, 44 | text: JSON.stringify({ 45 | result, 46 | rules, 47 | }), 48 | }, 49 | ], 50 | }; 51 | } catch (error: any) { 52 | const errorMessage = error.response?.data ?? error?.message; 53 | return { 54 | isError: true, 55 | content: [ 56 | { 57 | type: "text" as const, 58 | text: JSON.stringify(errorMessage), 59 | }, 60 | ], 61 | }; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/tools/get-version.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { BaseTool } from "./base-tool"; 3 | import packageJson from "../../package.json"; 4 | 5 | const VERSION_TOOL_NAME = `version_${packageJson.version}`; 6 | const VERSION_TOOL_DESCRIPTION = `the current version is ${packageJson.version}`; 7 | 8 | export class GetVersionTool extends BaseTool { 9 | name = VERSION_TOOL_NAME; 10 | description = VERSION_TOOL_DESCRIPTION; 11 | 12 | constructor() { 13 | super(); 14 | } 15 | 16 | schema = z.object({}); 17 | 18 | async execute({}: z.infer) { 19 | return { 20 | content: [ 21 | { 22 | type: "text" as const, 23 | text: JSON.stringify(packageJson.version), 24 | }, 25 | ], 26 | }; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/types.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.md' { 2 | const content: string; 3 | export default content; 4 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "esModuleInterop": true, 7 | "strict": true, 8 | "outDir": "dist", 9 | "sourceMap": false, 10 | "declaration": false, 11 | "resolveJsonModule": true, 12 | "skipLibCheck": true, 13 | "forceConsistentCasingInFileNames": true 14 | }, 15 | "include": ["src/**/*"], 16 | "exclude": ["node_modules", "dist"] 17 | } 18 | --------------------------------------------------------------------------------