├── .changeset ├── README.md ├── brave-plums-stick.md ├── clever-ears-shine.md ├── config.json ├── huge-carpets-tan.md ├── lemon-brooms-say.md ├── nine-mangos-judge.md ├── real-goats-drive.md ├── salty-lizards-fry.md ├── shaggy-pens-battle.md ├── sharp-clowns-call.md ├── sixty-spoons-retire.md ├── smart-doors-report.md ├── true-mugs-sort.md ├── twelve-jobs-jam.md └── whole-wings-send.md ├── .gitignore ├── .husky └── pre-commit ├── .npmrc ├── .prettierrc.js ├── .vscode └── settings.json ├── CONTRIBUTING.md ├── CONTRIBUTING.zh-CN.md ├── LICENSE ├── README.md ├── README.zh-CN.md ├── eslint.config.js ├── package.json ├── packages └── mcp-auto-install │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ ├── cli.ts │ ├── index.ts │ ├── server.ts │ ├── types.ts │ └── utils │ │ ├── response.ts │ │ └── utils.ts │ └── tsconfig.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── scripts └── publish-single.js └── tsconfig.json /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/brave-plums-stick.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@mcpmarket/mcp-auto-install': patch 3 | --- 4 | 5 | add package 6 | -------------------------------------------------------------------------------- /.changeset/clever-ears-shine.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@mcpmarket/mcp-auto-install': patch 3 | --- 4 | 5 | del parseConfig mcp tool 6 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [] 11 | } 12 | -------------------------------------------------------------------------------- /.changeset/huge-carpets-tan.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@mcpmarket/mcp-auto-install': minor 3 | --- 4 | 5 | add npx connect mcp server 6 | -------------------------------------------------------------------------------- /.changeset/lemon-brooms-say.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@mcpmarket/mcp-auto-install': patch 3 | --- 4 | 5 | add MCP_PACKAGE_SCOPES 6 | -------------------------------------------------------------------------------- /.changeset/nine-mangos-judge.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@mcpmarket/mcp-auto-install': patch 3 | --- 4 | 5 | add json config output 6 | -------------------------------------------------------------------------------- /.changeset/real-goats-drive.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@mcpmarket/mcp-auto-install': patch 3 | --- 4 | 5 | Fixed dependencies in package.json 6 | -------------------------------------------------------------------------------- /.changeset/salty-lizards-fry.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@mcpmarket/mcp-auto-install': patch 3 | --- 4 | 5 | fix package 6 | -------------------------------------------------------------------------------- /.changeset/shaggy-pens-battle.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@mcpmarket/mcp-auto-install': patch 3 | --- 4 | 5 | change package.json 6 | -------------------------------------------------------------------------------- /.changeset/sharp-clowns-call.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@mcpmarket/mcp-auto-install': patch 3 | --- 4 | 5 | add log 6 | -------------------------------------------------------------------------------- /.changeset/sixty-spoons-retire.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@mcpmarket/mcp-auto-install': patch 3 | --- 4 | 5 | add log 6 | -------------------------------------------------------------------------------- /.changeset/smart-doors-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@mcpmarket/mcp-auto-install': patch 3 | --- 4 | 5 | update @mcpmarket/mcp-auto-install 6 | -------------------------------------------------------------------------------- /.changeset/true-mugs-sort.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@mcpmarket/mcp-auto-install': patch 3 | --- 4 | 5 | change package.json 6 | -------------------------------------------------------------------------------- /.changeset/twelve-jobs-jam.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@mcpmarket/mcp-auto-install': patch 3 | --- 4 | 5 | update @mcpmarket/mcp-auto-install cli 6 | -------------------------------------------------------------------------------- /.changeset/whole-wings-send.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@mcpmarket/mcp-auto-install': patch 3 | --- 4 | 5 | update @mcpmarket/mcp-auto-install 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules/ 3 | **/node_modules/ 4 | 5 | # Build outputs 6 | dist/ 7 | **/dist/ 8 | build/ 9 | **/build/ 10 | 11 | # Logs 12 | logs/ 13 | *.log 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | 18 | # Environment variables 19 | .env 20 | .env.local 21 | .env.*.local 22 | 23 | # IDE 24 | .idea/ 25 | *.swp 26 | *.swo 27 | 28 | # OS 29 | .DS_Store 30 | Thumbs.db 31 | packages/*/tsconfig.tsbuildinfo 32 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | pnpm lint-staged 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-manager=false 2 | 3 | # 设置 scope 4 | @mcpmarket:registry=https://registry.npmjs.org/ 5 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | export default { 2 | semi: true, 3 | trailingComma: 'all', 4 | singleQuote: true, 5 | printWidth: 100, 6 | tabWidth: 2, 7 | useTabs: false, 8 | endOfLine: 'lf', 9 | arrowParens: 'avoid', 10 | bracketSpacing: true, 11 | singleAttributePerLine: false, 12 | htmlWhitespaceSensitivity: 'css', 13 | }; 14 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.defaultFormatter": "esbenp.prettier-vscode", 4 | "typescript.tsdk": "node_modules/typescript/lib", 5 | "typescript.enablePromptUseWorkspaceTsdk": true, 6 | "editor.tabSize": 2, 7 | "files.eol": "\n", 8 | "files.insertFinalNewline": true, 9 | "files.trimTrailingWhitespace": true, 10 | "[typescript]": { 11 | "editor.defaultFormatter": "esbenp.prettier-vscode" 12 | }, 13 | "[javascript]": { 14 | "editor.defaultFormatter": "esbenp.prettier-vscode" 15 | }, 16 | "[json]": { 17 | "editor.defaultFormatter": "esbenp.prettier-vscode" 18 | }, 19 | "[jsonc]": { 20 | "editor.defaultFormatter": "esbenp.prettier-vscode" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to MCP Market 2 | 3 | [English](CONTRIBUTING.md) | [中文](CONTRIBUTING.zh-CN.md) 4 | 5 | ## 🔧 Development Guide 6 | 7 | ### Project Setup 8 | 9 | 1. Clone the repository: 10 | 11 | ```bash 12 | git clone https://github.com/CherryHQ/mcpmarket.git 13 | cd mcpmarket 14 | ``` 15 | 16 | 2. Install dependencies: 17 | ```bash 18 | pnpm install 19 | ``` 20 | 21 | ### Code Style and Formatting 22 | 23 | We use ESLint and Prettier for code formatting and linting to maintain consistent code style across the project. 24 | 25 | 1. Format your code: 26 | 27 | ```bash 28 | pnpm format 29 | ``` 30 | 31 | 2. Lint your code: 32 | 33 | ```bash 34 | pnpm lint 35 | ``` 36 | 37 | 3. Check and auto-fix issues: 38 | ```bash 39 | pnpm lint:check 40 | ``` 41 | 42 | Key formatting rules: 43 | 44 | - Indent: 2 spaces 45 | - Quote style: single quotes 46 | - Max line length: 100 characters 47 | - Trailing comma: all 48 | - Semicolons: always required 49 | 50 | ### Creating a New Package 51 | 52 | 1. Create package directory: 53 | 54 | ```bash 55 | mkdir -p packages/your-package 56 | cd packages/your-package 57 | ``` 58 | 59 | 2. Initialize package: 60 | 61 | ```bash 62 | pnpm init 63 | ``` 64 | 65 | 3. Package naming conventions: 66 | 67 | - Must start with `@mcpmarket/` 68 | - Use descriptive names, e.g., `@mcpmarket/vanilla-server` 69 | - Keep it simple and clear 70 | 71 | 4. Required package.json fields: 72 | ```json 73 | { 74 | "name": "@mcpmarket/your-package", 75 | "version": "0.0.1", 76 | "publishConfig": { 77 | "access": "public" 78 | }, 79 | "files": ["dist"], 80 | "scripts": { 81 | "build": "tsc", 82 | "test": "jest", 83 | "clean": "rimraf dist" 84 | } 85 | } 86 | ``` 87 | 88 | ### Development Best Practices 89 | 90 | 1. Use TypeScript 91 | 92 | - Provide complete type definitions 93 | - Enable strict mode in tsconfig.json 94 | - Document public APIs 95 | 96 | 2. Documentation 97 | 98 | - Write clear README.md 99 | - Include usage examples 100 | - Document configuration options 101 | 102 | 3. [] Testing 103 | - Write unit tests 104 | - Include integration tests if needed 105 | - Test with different Node.js versions 106 | 107 | ## 📦 Publishing Guide 108 | 109 | ### Prerequisites 110 | 111 | 1. Login to npm: 112 | 113 | ```bash 114 | pnpm login 115 | ``` 116 | 117 | 2. Verify organization access: 118 | ```bash 119 | npm whoami --registry=https://registry.npmjs.org/ 120 | ``` 121 | 122 | ### Publishing Workflows 123 | 124 | #### Single Package 125 | 126 | ```bash 127 | # 1. Build the package 128 | pnpm build --filter @mcpmarket/your-package 129 | 130 | # 2. Publish 131 | pnpm publish:single --filter @mcpmarket/your-package 132 | ``` 133 | 134 | #### Batch Publishing 135 | 136 | ```bash 137 | # 1. Create changeset 138 | pnpm changeset 139 | # Follow prompts: 140 | # - Select packages 141 | # - Choose version type (patch/minor/major) 142 | # - Write change description 143 | 144 | # 2. Commit changeset 145 | git add . 146 | git commit -m "chore: add changeset" 147 | 148 | # 3. Update versions & generate changelog 149 | pnpm version 150 | 151 | # 4. Build all packages 152 | pnpm build 153 | 154 | # 5. Publish 155 | pnpm publish:all 156 | ``` 157 | 158 | ### Version Management 159 | 160 | - patch (0.0.x): Bug fixes 161 | - minor (0.x.0): New features (backward compatible) 162 | - major (x.0.0): Breaking changes 163 | 164 | ### Unpublishing 165 | 166 | Can unpublish within 72 hours: 167 | 168 | ```bash 169 | # Specific version 170 | npm unpublish @mcpmarket/your-package@0.0.1 --force 171 | 172 | # Entire package 173 | npm unpublish @mcpmarket/your-package --force 174 | ``` 175 | 176 | Restrictions: 177 | 178 | - Version numbers cannot be reused 179 | - Package name reserved for 24 hours 180 | - Cannot unpublish if other packages depend on it 181 | 182 | ## 🤝 Pull Request Process 183 | 184 | 1. Fork the repository 185 | 2. Create feature branch 186 | 3. Make changes 187 | 4. Add changeset: 188 | ```bash 189 | pnpm changeset 190 | ``` 191 | 5. Commit changes 192 | 6. Push to your fork 193 | 7. Create Pull Request 194 | 195 | ### PR Guidelines 196 | 197 | 1. Keep changes focused 198 | 2. Follow existing code style 199 | 3. Add tests for new features 200 | 4. Update documentation 201 | 5. Verify all tests pass 202 | 6. Include changeset for version management 203 | -------------------------------------------------------------------------------- /CONTRIBUTING.zh-CN.md: -------------------------------------------------------------------------------- 1 | # MCP Market 贡献指南 2 | 3 | [English](CONTRIBUTING.md) | [中文](CONTRIBUTING.zh-CN.md) 4 | 5 | ## 🔧 开发指南 6 | 7 | ### 项目设置 8 | 9 | 1. 克隆仓库: 10 | 11 | ```bash 12 | git clone https://github.com/CherryHQ/mcpmarket.git 13 | cd mcpmarket 14 | ``` 15 | 16 | 2. 安装依赖: 17 | ```bash 18 | pnpm install 19 | ``` 20 | 21 | ### 代码风格和格式化 22 | 23 | 我们使用 ESLint 和 Prettier 进行代码格式化和规范检查,以保持项目中的代码风格一致性。 24 | 25 | 1. 格式化代码: 26 | 27 | ```bash 28 | pnpm format 29 | ``` 30 | 31 | 2. 代码检查: 32 | 33 | ```bash 34 | pnpm lint 35 | ``` 36 | 37 | 3. 检查并自动修复问题: 38 | ```bash 39 | pnpm lint:check 40 | ``` 41 | 42 | 主要格式化规则: 43 | 44 | - 缩进:2个空格 45 | - 引号风格:单引号 46 | - 最大行长:100个字符 47 | - 尾随逗号:all 48 | - 分号:必须添加 49 | 50 | ### 创建新包 51 | 52 | 1. 创建包目录: 53 | 54 | ```bash 55 | mkdir -p packages/your-package 56 | cd packages/your-package 57 | ``` 58 | 59 | 2. 初始化包: 60 | 61 | ```bash 62 | pnpm init 63 | ``` 64 | 65 | 3. 包命名规范: 66 | 67 | - 必须以 `@mcpmarket/` 开头 68 | - 使用描述性名称,如 `@mcpmarket/vanilla-server` 69 | - 保持简单明了 70 | 71 | 4. package.json 必需字段: 72 | ```json 73 | { 74 | "name": "@mcpmarket/your-package", 75 | "version": "0.0.1", 76 | "publishConfig": { 77 | "access": "public" 78 | }, 79 | "files": ["dist"], 80 | "scripts": { 81 | "build": "tsc", 82 | "test": "jest", 83 | "clean": "rimraf dist" 84 | } 85 | } 86 | ``` 87 | 88 | ### 开发最佳实践 89 | 90 | 1. 使用 TypeScript 91 | 92 | - 提供完整的类型定义 93 | - 在 tsconfig.json 中启用严格模式 94 | - 为公共 API 编写文档 95 | 96 | 2. 文档 97 | 98 | - 编写清晰的 README.md 99 | - 包含使用示例 100 | - 记录配置选项 101 | 102 | 3. [ ] 测试 103 | - 编写单元测试 104 | - 必要时包含集成测试 105 | - 在不同 Node.js 版本下测试 106 | 107 | ## 📦 发布指南 108 | 109 | ### 前置条件 110 | 111 | 1. 登录 npm: 112 | 113 | ```bash 114 | pnpm login 115 | ``` 116 | 117 | 2. 验证组织访问权限: 118 | ```bash 119 | npm whoami --registry=https://registry.npmjs.org/ 120 | ``` 121 | 122 | ### 发布流程 123 | 124 | #### 单包发布 125 | 126 | ```bash 127 | # 1. 构建包 128 | pnpm build --filter @mcpmarket/your-package 129 | 130 | # 2. 发布 131 | pnpm publish:single --filter @mcpmarket/your-package 132 | ``` 133 | 134 | #### 批量发布 135 | 136 | ```bash 137 | # 1. 创建变更集 138 | pnpm changeset 139 | # 按照提示: 140 | # - 选择包 141 | # - 选择版本类型(patch/minor/major) 142 | # - 写入变更描述 143 | 144 | # 2. 提交变更集 145 | git add . 146 | git commit -m "chore: add changeset" 147 | 148 | # 3. 更新版本号和生成更新日志 149 | pnpm version 150 | 151 | # 4. 构建所有包 152 | pnpm build 153 | 154 | # 5. 发布 155 | pnpm publish:all 156 | ``` 157 | 158 | ### 版本管理 159 | 160 | - patch (0.0.x): 错误修复 161 | - minor (0.x.0): 新功能(向后兼容) 162 | - major (x.0.0): 破坏性更改 163 | 164 | ### 取消发布 165 | 166 | 可以在发布后 72 小时内取消发布: 167 | 168 | ```bash 169 | # 特定版本 170 | npm unpublish @mcpmarket/your-package@0.0.1 --force 171 | 172 | # 整个包 173 | npm unpublish @mcpmarket/your-package --force 174 | ``` 175 | 176 | 限制: 177 | 178 | - 版本号不能重复使用 179 | - 包名在 24 小时内被保留 180 | - 如果其他包依赖此包则不能取消发布 181 | 182 | ## 🤝 Pull Request 流程 183 | 184 | 1. Fork 仓库 185 | 2. 创建特性分支 186 | 3. 进行修改 187 | 4. 添加变更集: 188 | ```bash 189 | pnpm changeset 190 | ``` 191 | 5. 提交更改 192 | 6. 推送到你的 fork 193 | 7. 创建 Pull Request 194 | 195 | ### PR 指南 196 | 197 | 1. 保持更改聚焦 198 | 2. 遵循现有代码风格 199 | 3. 为新功能添加测试 200 | 4. 更新文档 201 | 5. 验证所有测试通过 202 | 6. 包含版本管理的变更集 203 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 亢奋猫 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MCP Market 2 | 3 | [English](README.md) | [中文](README.zh-CN.md) 4 | 5 | A collection of MCP (Model Context Protocol) servers for managing and integrating (LLM) various Large Language Model services. 6 | 7 | [![NPM Organization](https://img.shields.io/badge/npm-@mcpmarket-blue.svg)](https://www.npmjs.com/org/mcpmarket) 8 | [![pnpm](https://img.shields.io/badge/maintained%20with-pnpm-cc00ff.svg)](https://pnpm.io/) 9 | [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE) 10 | 11 | ## ✨ Features 12 | 13 | - **Rich MCP Servers**: Provides a variety of MCP servers to meet different LLM integration needs. 14 | - **Easy Installation and Configuration**: Easily install and configure servers via the npm package manager. 15 | - **TypeScript Support**: Provides complete TypeScript type definitions to improve development efficiency and code quality. 16 | - **Monorepo Architecture**: Adopts a Monorepo structure for easy code management, maintenance, and version control. 17 | - **Seamless Integration of LLM Services**: Simplifies the integration process with various LLM services. 18 | - **Standardized MCP Protocol**: Provides consistent model context definition and interaction methods. 19 | 20 | ## 📦 Available Servers 21 | 22 | All servers are published under the `@mcpmarket` scope on npm. 23 | 24 | | Server Name | Description | Installation Command | 25 | | ------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | 26 | | [@mcpmarket/auto-install](https://www.npmjs.com/package/@mcpmarket/mcp-auto-install) | A powerful MCP server with CLI that integrates into your client's MCP ecosystem. It enables you to install and manage other MCP servers through natural language conversations with LLMs. By default, it discovers MCP servers from the `@modelcontextprotocol` scope, but you can customize the sources using the `add-source` command. | `pnpm add @mcpmarket/auto-install` | 27 | 28 | ```bash 29 | # Install a specific server 30 | pnpm add @mcpmarket/[server-name] 31 | ``` 32 | 33 | ## 🚀 Quick Start 34 | 35 | 1. Choose the server you need from the [Available Servers](#-available-Servers) list. 36 | 2. Install using pnpm: 37 | 38 | ```bash 39 | pnpm add @mcpmarket/[server-name] 40 | ``` 41 | 42 | 3. Follow the instructions in the server's corresponding README file for configuration and usage. 43 | 44 | ## 📂 Project Structure 45 | 46 | ``` 47 | packages/ # Collection of MCP servers 48 | ├── server-a/ # MCP server A 49 | │ ├── src/ # Source code 50 | │ ├── README.md # Server documentation 51 | │ └── package.json # Package configuration file 52 | ├── server-b/ # MCP server B 53 | │ ├── src/ 54 | │ ├── README.md 55 | │ └── package.json 56 | └── ... # More servers 57 | ``` 58 | 59 | ## 🤝 Contributing 60 | 61 | Please see our [Contributing Guide](CONTRIBUTING.md) for details about: 62 | 63 | - Development workflow 64 | - Creating new packages 65 | - Publishing packages 66 | - Pull Request process 67 | 68 | ## 📜 License 69 | 70 | [MIT](./LICENSE) 71 | -------------------------------------------------------------------------------- /README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # MCP Market (模型上下文协议市场) 2 | 3 | [English](README.md) | [中文](README.zh-CN.md) 4 | 5 | 模型上下文协议(Model Context Protocol,MCP)服务集合,用于管理和集成各种大型语言模型 (LLM) 服务。 6 | 7 | [![NPM Organization](https://img.shields.io/badge/npm-@mcpmarket-blue.svg)](https://www.npmjs.com/org/mcpmarket) 8 | [![pnpm](https://img.shields.io/badge/maintained%20with-pnpm-cc00ff.svg)](https://pnpm.io/) 9 | [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE) 10 | 11 | ## ✨ 特性 12 | 13 | - **丰富的 MCP 服务**:提供多种 MCP 服务,满足不同的 LLM 集成需求。 14 | - **易于安装和配置**:通过 npm 包管理器轻松安装和配置服务。 15 | - **TypeScript 支持**:提供完整的 TypeScript 类型定义,提高开发效率和代码质量。 16 | - **Monorepo 架构**:采用 Monorepo 结构,便于代码管理、维护和版本控制。 17 | - **无缝集成 LLM 服务**:简化与各种 LLM 服务的集成流程。 18 | - **标准化的MCP协议**: 提供一致的模型上下文定义和交互方式. 19 | 20 | ## 📦 可用服务 21 | 22 | 所有服务均发布在 npm 的 `@mcpmarket` 域下。 23 | 24 | | 服务名称 | 描述 | 安装命令 | 25 | | ------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | 26 | | [@mcpmarket/auto-install](https://www.npmjs.com/package/@mcpmarket/mcp-auto-install) | 一个功能强大的MCP服务,带有CLI,可集成到客户端的MCP生态系统中。它使您能够通过与LLM的自然语言对话安装和管理其他MCP服务。默认情况下,它会从@modelcontextprotocol作用域中发现MCP服务,但您可以使用 `add-source` 命令自定义源。 | `pnpm add @mcpmarket/auto-install` | 27 | 28 | ```bash 29 | # 安装指定的服务 30 | pnpm add @mcpmarket/[server-name] 31 | ``` 32 | 33 | ## 🚀 快速开始 34 | 35 | 1. 从 [可用服务](#-可用服务) 列表中选择您需要的服务。 36 | 2. 使用 pnpm 安装: 37 | 38 | ```bash 39 | pnpm add @mcpmarket/[server-name] 40 | ``` 41 | 42 | 3. 按照服务对应的 README 文件中的说明进行配置和使用。 43 | 44 | ## 📂 项目结构 45 | 46 | ``` 47 | packages/ # MCP 服务集合 48 | ├── server-a/ # MCP server A 49 | │ ├── src/ # 源代码 50 | │ ├── README.md # 服务说明文档 51 | │ └── package.json # 包配置文件 52 | ├── server-b/ # MCP server B 53 | │ ├── src/ 54 | │ ├── README.md 55 | │ └── package.json 56 | └── ... # 更多服务 57 | ``` 58 | 59 | ## 🤝 贡献 60 | 61 | 请参阅我们的 [贡献指南](CONTRIBUTING.md) 了解以下详细信息: 62 | 63 | - 开发流程 64 | - 创建新包 65 | - 发布包 66 | - Pull Request 流程 67 | 68 | ## 📜 许可证 69 | 70 | [MIT](./LICENSE) 71 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import eslint from '@eslint/js'; 2 | import tseslint from '@typescript-eslint/eslint-plugin'; 3 | import tsParser from '@typescript-eslint/parser'; 4 | import importPlugin from 'eslint-plugin-import'; 5 | import prettier from 'eslint-plugin-prettier'; 6 | import globals from 'globals'; // 导入 globals 以支持环境定义 7 | 8 | export default [ 9 | { 10 | ignores: [ 11 | 'dist/**', 12 | 'packages/**/dist/**', 13 | 'node_modules/**', 14 | 'coverage/**', 15 | '.next/**', 16 | 'build/**', 17 | '*.d.ts', 18 | ], 19 | }, 20 | { 21 | files: ['**/*.{js,jsx,ts,tsx}'], 22 | languageOptions: { 23 | parser: tsParser, 24 | parserOptions: { 25 | ecmaVersion: 2022, 26 | sourceType: 'module', 27 | ecmaFeatures: { 28 | jsx: true, 29 | }, 30 | }, 31 | globals: { 32 | ...eslint.configs.recommended.globals, 33 | ...globals.node, // 添加 Node.js 环境的全局变量 34 | }, 35 | }, 36 | plugins: { 37 | '@typescript-eslint': tseslint, 38 | import: importPlugin, 39 | prettier: prettier, 40 | }, 41 | rules: { 42 | ...eslint.configs.recommended.rules, 43 | ...tseslint.configs.recommended.rules, 44 | }, 45 | settings: { 46 | 'import/resolver': { 47 | typescript: {}, 48 | node: { 49 | extensions: ['.js', '.jsx', '.ts', '.tsx'], 50 | }, 51 | }, 52 | }, 53 | }, 54 | ]; 55 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mcpmarket", 3 | "version": "1.0.0", 4 | "description": "A collection of Model Context Protocol (MCP) servers for LLM integration", 5 | "type": "module", 6 | "private": true, 7 | "workspaces": [ 8 | "packages/*", 9 | "!**/test/**" 10 | ], 11 | "engines": { 12 | "node": ">=16", 13 | "pnpm": ">=8" 14 | }, 15 | "scripts": { 16 | "preinstall": "npx only-allow pnpm", 17 | "test": "pnpm -r test", 18 | "build": "pnpm -r build", 19 | "clean": "pnpm -r clean", 20 | "list": "pnpm list --recursive", 21 | "publish:all": "pnpm publish -r changeset publish", 22 | "publish:single": "node scripts/publish-single.js", 23 | "changeset": "changeset", 24 | "version": "changeset version", 25 | "release": "pnpm build && pnpm publish:all", 26 | "format": "prettier --write .", 27 | "lint": "eslint . --ext .js,.jsx,.ts,.tsx --fix", 28 | "lint:check": "eslint . --ext .js,.jsx,.ts,.tsx", 29 | "prepare": "husky install" 30 | }, 31 | "repository": { 32 | "type": "git", 33 | "url": "git+https://github.com/CherryHQ/mcpmarket.git" 34 | }, 35 | "keywords": [ 36 | "mcp", 37 | "server" 38 | ], 39 | "author": "CherryHQ", 40 | "license": "MIT", 41 | "bugs": { 42 | "url": "https://github.com/CherryHQ/mcpmarket/issues" 43 | }, 44 | "homepage": "https://github.com/CherryHQ/mcpmarket#readme", 45 | "dependencies": { 46 | "@modelcontextprotocol/sdk": "^1.8.0" 47 | }, 48 | "devDependencies": { 49 | "@changesets/cli": "^2.28.1", 50 | "@commitlint/cli": "^19.8.0", 51 | "@commitlint/config-conventional": "^19.8.0", 52 | "@types/chai": "^5.2.1", 53 | "@types/mocha": "^10.0.10", 54 | "@types/node": "^20.17.24", 55 | "@types/sinon": "^17.0.4", 56 | "@typescript-eslint/eslint-plugin": "^8.27.0", 57 | "@typescript-eslint/parser": "^8.27.0", 58 | "chai": "^5.2.0", 59 | "cross-env": "^7.0.3", 60 | "eslint": "^9.22.0", 61 | "eslint-config-prettier": "^10.1.1", 62 | "eslint-import-resolver-typescript": "4.2.2", 63 | "eslint-plugin-import": "^2.31.0", 64 | "eslint-plugin-prettier": "^5.2.3", 65 | "husky": "^8.0.0", 66 | "lint-staged": "^15.5.0", 67 | "mocha": "^11.1.0", 68 | "prettier": "^3.5.3", 69 | "sinon": "^20.0.0", 70 | "ts-node": "^10.9.2", 71 | "typescript": "^5.8.2" 72 | }, 73 | "lint-staged": { 74 | "packages/**/*.{js,jsx,ts,tsx}": [ 75 | "eslint --fix", 76 | "prettier --write" 77 | ], 78 | "*.{json,md,yml,yaml}": [ 79 | "prettier --write" 80 | ] 81 | }, 82 | "packageManager": "pnpm@10.4.1" 83 | } 84 | -------------------------------------------------------------------------------- /packages/mcp-auto-install/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 whatprototype 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/mcp-auto-install/README.md: -------------------------------------------------------------------------------- 1 | # @mcpmarket/auto-install 2 | 3 | A powerful MCP server with CLI that integrates into your client's MCP ecosystem. It enables you to install and manage other MCP servers through natural language conversations with LLMs. By default, it discovers MCP servers from the `@modelcontextprotocol` scope, but you can customize the sources using the `add-source` command. 4 | 5 | ## ✨ Features 6 | 7 | - **Natural Language Interaction**: Install and manage MCP servers through natural language conversations with LLMs 8 | - **Automatic Server Discovery**: Automatically discovers MCP servers from the `@modelcontextprotocol` scope 9 | - **Custom Source Management**: Add and manage custom MCP server sources 10 | - **Command Configuration**: Save and manage server commands with environment variables 11 | - **Server Documentation**: Access server READMEs directly through the CLI 12 | - **Direct MCP Connection**: Quick connection to MCP services using npx 13 | - **JSON Configuration Support**: Parse and validate JSON configurations for bulk server setup 14 | - **JSON Output Format**: Support for machine-readable JSON output with `--json` flag 15 | - **Custom Registry Location**: Customize registry location via environment variable 16 | - **Service Descriptions**: Add descriptive metadata to MCP services 17 | 18 | ## 📦 Installation 19 | 20 | You can install this package in two ways: 21 | 22 | 1. **Global Installation**: 23 | 24 | ```bash 25 | pnpm add -g @mcpmarket/mcp-auto-install 26 | ``` 27 | 28 | 2. **Direct Execution with npx**: 29 | 30 | ```bash 31 | # Connect to MCP service 32 | npx -y @mcpmarket/mcp-auto-install connect 33 | 34 | # Use CLI commands 35 | npx @mcpmarket/mcp-auto-install [command] [options] 36 | ``` 37 | 38 | ## 🚀 Usage 39 | 40 | ### Starting the Server 41 | 42 | ```bash 43 | # Start the MCP Auto Install server 44 | mcp-auto-install start 45 | 46 | # Start with JSON output 47 | mcp-auto-install start --json 48 | ``` 49 | 50 | ### Connecting to MCP Service 51 | 52 | ```bash 53 | # Quick connection using npx 54 | npx -y @mcpmarket/mcp-auto-install connect 55 | 56 | # With JSON output (for programmatic use) 57 | npx -y @mcpmarket/mcp-auto-install connect --json 58 | ``` 59 | 60 | ### Managing Server Sources 61 | 62 | ```bash 63 | # Add a new server source 64 | mcp-auto-install add-source my-server -r https://github.com/username/repo -c "npx @modelcontextprotocol/server-name" -d "My MCP Server" 65 | 66 | # List registered servers 67 | mcp-auto-install list 68 | 69 | # Remove a server 70 | mcp-auto-install remove my-server 71 | ``` 72 | 73 | ### Installing Servers 74 | 75 | ```bash 76 | # Install a server 77 | mcp-auto-install install my-server 78 | ``` 79 | 80 | ### Managing Commands 81 | 82 | ```bash 83 | # Save a command for a server 84 | mcp-auto-install save-command my-server npx @modelcontextprotocol/server-name --port 3000 --env NODE_ENV=production 85 | 86 | # Save command with description 87 | mcp-auto-install save-command my-server npx @modelcontextprotocol/server-name --port 3000 --description "A server that handles file operations" 88 | 89 | # Save command with JSON output 90 | mcp-auto-install save-command my-server npx @modelcontextprotocol/server-name --port 3000 --json 91 | ``` 92 | 93 | ### Viewing Documentation 94 | 95 | ```bash 96 | # Get server README 97 | mcp-auto-install readme my-server 98 | 99 | # Get server configuration help 100 | mcp-auto-install configure-server my-server 101 | ``` 102 | 103 | ### Bulk Configuration 104 | 105 | ```bash 106 | # Parse and save JSON configuration 107 | mcp-auto-install parse-config '{ 108 | "mcpServers": { 109 | "my-server": { 110 | "command": "npx @modelcontextprotocol/server-name", 111 | "args": ["--port", "3000"], 112 | "description": "A server that handles file operations" 113 | } 114 | } 115 | }' 116 | 117 | # Parse configuration with JSON output 118 | mcp-auto-install parse-config '{"mcpServers":{...}}' --json 119 | ``` 120 | 121 | ## 🔧 Configuration 122 | 123 | The tool uses two configuration files: 124 | 125 | 1. **MCP Registry** (`mcp-registry.json`): Stores information about registered MCP server sources 126 | 127 | - Default locations: 128 | - Windows: `%APPDATA%\mcp\mcp-registry.json` 129 | - macOS/Linux: `~/.mcp/mcp-registry.json` 130 | - Can be customized with the `MCP_REGISTRY_PATH` environment variable 131 | 132 | 2. **External Configuration**: Specified by the `MCP_SETTINGS_PATH` environment variable, used for storing server command configurations 133 | 134 | ### Environment Variables 135 | 136 | - `MCP_SETTINGS_PATH`: Path to the LLM (e.g., Claude) MCP service configuration file 137 | 138 | ```bash 139 | export MCP_SETTINGS_PATH="/Users/username/Library/Application Support/Claude/claude_desktop_config.json" 140 | ``` 141 | 142 | - `MCP_REGISTRY_PATH`: Custom path to the MCP registry file (default: `~/.mcp/mcp-registry.json`) 143 | ```bash 144 | export MCP_REGISTRY_PATH="/path/to/custom/mcp-registry.json" 145 | ``` 146 | 147 | ### MCP_PACKAGE_SCOPES 148 | 149 | Specify one or more package scopes to search for MCP servers. Multiple scopes can be specified using comma separation. 150 | 151 | Default value: `@modelcontextprotocol` 152 | 153 | Examples: 154 | 155 | ```bash 156 | # Single scope 157 | MCP_PACKAGE_SCOPES=@modelcontextprotocol 158 | 159 | # Multiple scopes 160 | MCP_PACKAGE_SCOPES=@modelcontextprotocol,@other-scope 161 | 162 | # Multiple scopes with spaces 163 | MCP_PACKAGE_SCOPES=@modelcontextprotocol, @other-scope 164 | ``` 165 | 166 | ## 📝 Version History 167 | 168 | - v0.1.6: Added support for multiple package scopes via `MCP_PACKAGE_SCOPES` environment variable 169 | - v0.1.5: Fixed dependencies in package.json 170 | - v0.1.1: Added JSON configuration support and improved command management 171 | - v0.1.0: Added support for custom server sources and command configuration 172 | - v0.0.4: Added direct MCP connection support with npx 173 | - v0.0.3: Added support for npx execution and improved command management 174 | - v0.0.2: Added server source management and command configuration 175 | - v0.0.1: Initial release with basic MCP server installation functionality 176 | 177 | ## 📜 License 178 | 179 | [MIT](./LICENSE) 180 | 181 | ## 🎮 Features 182 | 183 | - 🤖 Natural language interaction with LLMs for server installation 184 | - 🔍 Automatic discovery of MCP servers from `@modelcontextprotocol` scope 185 | - 📦 Custom server source management through GitHub repositories 186 | - 📚 Server documentation and README viewing 187 | - ⚙️ Flexible command and environment configuration 188 | - 🔄 Seamless integration with your MCP ecosystem 189 | - 🔌 Quick connection to MCP services with npx 190 | - 📋 JSON-based bulk configuration support 191 | - 🧩 Machine-readable JSON output format for automation 192 | - 📝 Descriptive metadata for MCP services 193 | 194 | ## 📋 Prerequisites 195 | 196 | - Node.js >= 18.0.0 197 | - npm or pnpm package manager 198 | - An MCP-compatible client (e.g., Claude) 199 | 200 | ## 🤝 Contributing 201 | 202 | - Development workflow 203 | - Creating new packages 204 | - Publishing packages 205 | - Pull request process 206 | 207 | ## Support 208 | 209 | For support, please open an issue in the [GitHub repository](https://github.com/CherryHQ/mcpmarket/issues). 210 | -------------------------------------------------------------------------------- /packages/mcp-auto-install/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mcpmarket/mcp-auto-install", 3 | "version": "0.1.6", 4 | "description": "MCP server that helps install other MCP servers automatically", 5 | "type": "module", 6 | "main": "./dist/index.js", 7 | "bin": "./dist/index.js", 8 | "exports": { 9 | ".": "./dist/index.js" 10 | }, 11 | "publishConfig": { 12 | "access": "public" 13 | }, 14 | "files": [ 15 | "dist", 16 | "LICENSE", 17 | "README.md" 18 | ], 19 | "scripts": { 20 | "build": "tsc", 21 | "start": "node dist/index.js", 22 | "dev": "ts-node --esm src/index.ts", 23 | "test": "echo \"Error: no test specified\" && exit 1", 24 | "prepublishOnly": "npm run build" 25 | }, 26 | "keywords": [ 27 | "mcp", 28 | "modelcontextprotocol", 29 | "server", 30 | "auto-install", 31 | "ai", 32 | "llm", 33 | "claude", 34 | "automation" 35 | ], 36 | "author": "whatprototype", 37 | "license": "MIT", 38 | "dependencies": { 39 | "commander": "^11.1.0", 40 | "npx-scope-finder": "^1.3.0", 41 | "zod": "^3.22.4", 42 | "@modelcontextprotocol/sdk": "^1.8.0" 43 | }, 44 | "engines": { 45 | "node": ">=18.0.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/mcp-auto-install/src/cli.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { Command } from 'commander'; 4 | 5 | import { 6 | startServer, 7 | getRegisteredServers, 8 | handleInstallServer, 9 | handleRegisterServer, 10 | handleRemoveServer, 11 | handleGetServerReadme, 12 | handleConfigureServer, 13 | handleParseConfig, 14 | saveCommandToExternalConfig, 15 | } from './server.js'; 16 | import { checkMCPSettings } from './utils/utils.js'; 17 | /** 18 | * Command line interface for controlling MCP automatic installation servers 19 | */ 20 | export class MCPCliApp { 21 | private program: Command; 22 | 23 | constructor() { 24 | this.program = new Command(); 25 | this.setupCLI(); 26 | } 27 | 28 | private setupCLI() { 29 | this.program 30 | .name('mcp-auto-install') 31 | .description('A tool for managing MCP server sources and installing MCP servers from GitHub') 32 | .version('0.1.5'); 33 | 34 | // Add default command to start the server 35 | this.program 36 | .command('start', { isDefault: true }) 37 | .description('Start the MCP Auto Install server') 38 | .option('--json', 'Return responses in JSON format (for programmatic use)') 39 | .action(async options => { 40 | await startServer(options.json); 41 | }); 42 | 43 | // Add command to register a new server 44 | this.program 45 | .command('add-source ') 46 | .description('Add or update an MCP server source in the registry') 47 | .requiredOption('-r, --repo ', 'GitHub repository URL') 48 | .requiredOption('-c, --command ', 'Command to run the server') 49 | .requiredOption('-d, --description ', 'Description of the server') 50 | .option('-k, --keywords ', 'Comma-separated keywords', val => val.split(',')) 51 | .option( 52 | '-i, --install-commands ', 53 | 'Comma-separated custom installation commands', 54 | val => val.split(','), 55 | ) 56 | .action(async (name, options) => { 57 | const result = await handleRegisterServer({ 58 | name, 59 | repo: options.repo, 60 | command: options.command, 61 | description: options.description, 62 | keywords: options.keywords || [], 63 | installCommands: options.installCommands, 64 | }); 65 | 66 | if (result.success) { 67 | console.log(result.message); 68 | } else { 69 | console.error(result.message); 70 | } 71 | process.exit(0); 72 | }); 73 | 74 | // Add a command to install a server 75 | this.program 76 | .command('install ') 77 | .description('Install an MCP server from GitHub repository') 78 | .action(async name => { 79 | const result = await handleInstallServer({ serverName: name }); 80 | 81 | if (result.success) { 82 | console.log(result.message); 83 | } else { 84 | console.error(result.message); 85 | } 86 | process.exit(0); 87 | }); 88 | 89 | // Add command to list registered servers 90 | this.program 91 | .command('list') 92 | .description('List all registered MCP server sources') 93 | .action(async () => { 94 | const servers = await getRegisteredServers(); 95 | if (servers.length === 0) { 96 | console.log('No MCP server sources registered.'); 97 | return; 98 | } 99 | 100 | console.log('Registered MCP server sources:'); 101 | for (const server of servers) { 102 | console.log(`\n${server.name}`); 103 | console.log(` Description: ${server.description}`); 104 | console.log(` Repository: ${server.repo}`); 105 | console.log(` Command: ${server.command}`); 106 | if (server.keywords && server.keywords.length > 0) { 107 | console.log(` Keywords: ${server.keywords.join(', ')}`); 108 | } 109 | } 110 | process.exit(0); 111 | }); 112 | 113 | // Add command to get README for a server 114 | this.program 115 | .command('readme ') 116 | .description('Get the README content for an MCP server') 117 | .action(async (name: string) => { 118 | const result = await handleGetServerReadme({ serverName: name }); 119 | 120 | if (result.success) { 121 | console.log(`README for ${name}:`); 122 | console.log(); 123 | console.log(result.data || 'No README content available.'); 124 | } else { 125 | console.error(result.message || 'Failed to fetch README.'); 126 | } 127 | process.exit(0); 128 | }); 129 | 130 | // Add command to configure a server 131 | this.program 132 | .command('configure-server ') 133 | .description('Get configuration help for an MCP server') 134 | .action(async (name: string) => { 135 | const result = await handleConfigureServer({ serverName: name }); 136 | 137 | if (result.success) { 138 | console.log(`Configuration for ${name}:`); 139 | console.log(); 140 | for (const msg of result.message) { 141 | console.log(msg); 142 | } 143 | } else { 144 | console.error(result.message || 'Failed to get configuration help.'); 145 | } 146 | process.exit(0); 147 | }); 148 | 149 | // Add command to remove a server 150 | this.program 151 | .command('remove ') 152 | .description('Remove a registered MCP server') 153 | .action(async (name: string) => { 154 | const result = await handleRemoveServer({ serverName: name }); 155 | 156 | if (result.success) { 157 | console.log(result.message); 158 | } else { 159 | console.error(result.message); 160 | } 161 | process.exit(0); 162 | }); 163 | 164 | // Add command to parse JSON config 165 | this.program 166 | .command('parse-config ') 167 | .description('Parse and save JSON configuration for MCP servers') 168 | .option('--json', 'Return result as JSON without modifying config files') 169 | .action(async (config: string, options) => { 170 | const result = await handleParseConfig({ config }, options.json); 171 | 172 | if (result.success) { 173 | if (options.json) { 174 | console.log(JSON.stringify(result, null, 2)); 175 | } else { 176 | console.log(`✅ ${result.message}`); 177 | } 178 | } else { 179 | console.error(`❌ ${result.message}`); 180 | } 181 | process.exit(0); 182 | }); 183 | 184 | // Add a command to save user command to config 185 | this.program 186 | .command('save-command ') 187 | .description('Save a command for a server to external config file') 188 | .argument('[args...]', 'Command arguments') 189 | .option( 190 | '--env ', 191 | 'Environment variables (e.g., --env NODE_ENV=production)', 192 | (val, prev) => { 193 | const [key, value] = val.split('='); 194 | return { ...prev, [key]: value }; 195 | }, 196 | {}, 197 | ) 198 | .option('--json', 'Return result as JSON without modifying config files') 199 | .option('--description ', 'A description of what this MCP service does') 200 | .action( 201 | async ( 202 | serverName: string, 203 | command: string, 204 | args: string[], 205 | options: { env: Record; json?: boolean; description?: string }, 206 | ) => { 207 | console.log( 208 | `Saving command to external config file: ${serverName} ${command} ${args.join(' ')}`, 209 | ); 210 | const result = await saveCommandToExternalConfig( 211 | serverName, 212 | command, 213 | args, 214 | options.description || '', 215 | options.json, 216 | options.env, 217 | ); 218 | 219 | if (result.success) { 220 | if (options.json) { 221 | console.log(JSON.stringify(result, null, 2)); 222 | } else { 223 | console.log(`✅ ${result.message}`); 224 | } 225 | } else { 226 | console.error(`❌ ${result.message}`); 227 | } 228 | process.exit(0); 229 | }, 230 | ); 231 | 232 | // Uncomment if you want to implement the update-registry command 233 | /* 234 | this.program 235 | .command("update-registry") 236 | .description("Update the registry from a remote source") 237 | .option("-u, --url ", "URL to fetch registry from") 238 | .action(async (options: { url?: string }) => { 239 | try { 240 | // Initialize server instance 241 | this.server = new MCPAutoInstallServer(); 242 | await this.server.init(); 243 | 244 | // Implement update registry functionality 245 | console.log("Registry updated successfully"); 246 | } catch (error) { 247 | console.error("Failed to update registry:", error); 248 | } 249 | process.exit(0); 250 | }); 251 | */ 252 | 253 | this.program.parse(process.argv); 254 | } 255 | 256 | /** 257 | * Run the CLI application 258 | */ 259 | public run() { 260 | // Check environment variables 261 | checkMCPSettings(); 262 | 263 | this.program.parse(process.argv); 264 | } 265 | } 266 | 267 | // In ESM module, do not use module detection, directly delete this part of the code 268 | export default MCPCliApp; 269 | -------------------------------------------------------------------------------- /packages/mcp-auto-install/src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { MCPCliApp } from './cli.js'; 4 | import { startServer } from './server.js'; 5 | import { checkMCPSettings } from './utils/utils.js'; 6 | 7 | /** 8 | * Main entry point for the MCP Auto Install application 9 | */ 10 | async function main() { 11 | // Check if we're in direct server mode (npx -y @mcpmarket/mcp-auto-install connect) 12 | if (process.argv[2] === 'connect') { 13 | try { 14 | checkMCPSettings(true); 15 | // Check if --json flag is set 16 | const jsonOnly = process.argv.includes('--json'); 17 | await startServer(jsonOnly); 18 | } catch (error) { 19 | console.error('Failed to start server:', error); 20 | process.exit(1); 21 | } 22 | return; 23 | } 24 | 25 | // Otherwise, run in CLI mode 26 | try { 27 | const cliApp = new MCPCliApp(); 28 | cliApp.run(); 29 | } catch (error) { 30 | console.error('Failed to start the application:', error); 31 | process.exit(1); 32 | } 33 | } 34 | 35 | // Start the application 36 | main(); 37 | -------------------------------------------------------------------------------- /packages/mcp-auto-install/src/server.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { promises as fs } from 'node:fs'; 4 | import { homedir } from 'node:os'; 5 | import path from 'node:path'; 6 | import { exec as execCb } from 'node:child_process'; 7 | import { promisify } from 'node:util'; 8 | 9 | import { Server } from '@modelcontextprotocol/sdk/server/index.js'; 10 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; 11 | import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'; 12 | import { npxFinder, type NPMPackage } from 'npx-scope-finder'; 13 | import { z } from 'zod'; 14 | 15 | import type { MCPServerInfo, OperationResult } from './types.js'; 16 | import { 17 | createErrorResponse, 18 | createSuccessResponse, 19 | createServerResponse, 20 | } from './utils/response.js'; 21 | 22 | const exec = promisify(execCb); 23 | 24 | // Set path 25 | const SETTINGS_PATH = process.env.MCP_REGISTRY_PATH 26 | ? process.env.MCP_REGISTRY_PATH 27 | : path.join(homedir(), 'mcp', 'mcp-registry.json'); 28 | 29 | // Default package scopes 30 | const DEFAULT_PACKAGE_SCOPES = ['@modelcontextprotocol']; 31 | 32 | // Parse package scopes from environment variable 33 | const PACKAGE_SCOPES = process.env.MCP_PACKAGE_SCOPES 34 | ? process.env.MCP_PACKAGE_SCOPES.split(',') 35 | .map(scope => scope.trim()) 36 | .filter(Boolean) 37 | : DEFAULT_PACKAGE_SCOPES; 38 | 39 | // Server settings 40 | let serverSettings: { servers: MCPServerInfo[] } = { servers: [] }; 41 | 42 | /** 43 | * Simple Zod to JSON Schema conversion function 44 | */ 45 | function simpleZodToJsonSchema(schema: z.ZodType): Record { 46 | // For simplicity, we only handle basic types 47 | if (schema instanceof z.ZodString) { 48 | return { type: 'string' }; 49 | } 50 | 51 | if (schema instanceof z.ZodNumber) { 52 | return { type: 'number' }; 53 | } 54 | 55 | if (schema instanceof z.ZodBoolean) { 56 | return { type: 'boolean' }; 57 | } 58 | 59 | if (schema instanceof z.ZodArray) { 60 | return { 61 | type: 'array', 62 | items: simpleZodToJsonSchema(schema._def.type), 63 | }; 64 | } 65 | 66 | if (schema instanceof z.ZodObject) { 67 | const properties: Record> = {}; 68 | const required: string[] = []; 69 | 70 | for (const [key, value] of Object.entries(schema.shape)) { 71 | properties[key] = simpleZodToJsonSchema(value as z.ZodType); 72 | 73 | if (!(value instanceof z.ZodOptional)) { 74 | required.push(key); 75 | } 76 | } 77 | 78 | return { 79 | type: 'object', 80 | properties, 81 | required, 82 | }; 83 | } 84 | 85 | if (schema instanceof z.ZodOptional) { 86 | return simpleZodToJsonSchema(schema._def.innerType); 87 | } 88 | 89 | // Default return 90 | return { type: 'object' }; 91 | } 92 | 93 | /** 94 | * Preload MCP package information to local registry file 95 | */ 96 | async function preloadMCPPackages(): Promise { 97 | try { 98 | // Get all available packages from configured scopes concurrently 99 | const scopePromises = PACKAGE_SCOPES.map(scope => 100 | npxFinder(scope, { 101 | timeout: 15000, 102 | retries: 3, 103 | retryDelay: 1000, 104 | }).catch(error => { 105 | console.error(`Error fetching packages for scope ${scope}:`, error); 106 | return [] as NPMPackage[]; // Return empty array on error to continue processing 107 | }), 108 | ); 109 | 110 | const results = await Promise.allSettled(scopePromises); 111 | const allPackages = results.reduce((acc, result) => { 112 | if (result.status === 'fulfilled') { 113 | acc.push(...result.value); 114 | } 115 | return acc; 116 | }, [] as NPMPackage[]); 117 | 118 | // Filter and process package information 119 | for (const pkg of allPackages) { 120 | if (!pkg.name || pkg.name === '@modelcontextprotocol/sdk') { 121 | continue; // Skip SDK itself 122 | } 123 | 124 | try { 125 | // Extract server type (from package name) 126 | const nameParts = pkg.name.split('/'); 127 | const serverName = nameParts[nameParts.length - 1]; 128 | const serverType = serverName.replace('mcp-', ''); 129 | 130 | // Build server information 131 | const serverInfo: MCPServerInfo = { 132 | name: pkg.name, 133 | repo: pkg.links?.repository || '', 134 | command: `npx ${pkg.name}`, 135 | description: pkg.description || `MCP ${serverType} server`, 136 | keywords: [...(pkg.keywords || []), serverType, 'mcp'], 137 | }; 138 | 139 | // Get README content directly from npxFinder returned data and add to serverInfo 140 | if (pkg.original?.readme) { 141 | serverInfo.readme = pkg.original.readme; 142 | } 143 | 144 | // Check if server is already registered 145 | const existingServer = serverSettings.servers.find(s => s.name === pkg.name); 146 | if (!existingServer) { 147 | serverSettings.servers.push(serverInfo); 148 | } else { 149 | // Update existing server's readme (if available) 150 | if (serverInfo.readme && !existingServer.readme) { 151 | existingServer.readme = serverInfo.readme; 152 | } 153 | } 154 | } catch (pkgError) { 155 | console.error(`Error processing package ${pkg.name}:`, pkgError); 156 | // Silently handle package errors 157 | } 158 | } 159 | 160 | // Save updated settings 161 | await saveSettings(); 162 | } catch (error) { 163 | console.error('Error preloading MCP packages:', error); 164 | // Silently handle errors 165 | } 166 | } 167 | 168 | // Create MCP server instance 169 | 170 | /** 171 | * Initialize settings 172 | */ 173 | async function initSettings(): Promise { 174 | try { 175 | // Create settings directory 176 | const settingsDir = path.dirname(SETTINGS_PATH); 177 | await fs.mkdir(settingsDir, { recursive: true }); 178 | 179 | // Try to load existing settings 180 | try { 181 | const data = await fs.readFile(SETTINGS_PATH, 'utf-8'); 182 | serverSettings = JSON.parse(data); 183 | } catch (error) { 184 | console.error(error); 185 | // If file doesn't exist, use default settings 186 | serverSettings = { servers: [] }; 187 | // Save default settings 188 | await saveSettings(); 189 | } 190 | } catch (error) { 191 | console.error('Failed to initialize settings:', error); 192 | } 193 | } 194 | 195 | /** 196 | * Save settings 197 | */ 198 | async function saveSettings(): Promise { 199 | try { 200 | // Ensure directory exists 201 | const settingsDir = path.dirname(SETTINGS_PATH); 202 | await fs.mkdir(settingsDir, { recursive: true }); 203 | 204 | // Save settings file 205 | await fs.writeFile(SETTINGS_PATH, JSON.stringify(serverSettings, null, 2), 'utf-8'); 206 | } catch (error) { 207 | console.error('Failed to save settings:', error); 208 | throw new Error('Failed to save settings'); 209 | } 210 | } 211 | 212 | /** 213 | * Find server 214 | */ 215 | async function findServer(name: string): Promise { 216 | // Ensure settings are loaded 217 | await initSettings(); 218 | return serverSettings.servers.find(s => s.name.includes(name.toLowerCase())); 219 | } 220 | 221 | const createServer = (jsonOnly = false) => { 222 | console.error('jsonOnly', jsonOnly); 223 | const server = new Server( 224 | { 225 | name: 'mcp-auto-install', 226 | version: '0.1.5', 227 | }, 228 | { 229 | capabilities: { 230 | tools: {}, 231 | }, 232 | }, 233 | ); 234 | 235 | // Register tools list handler 236 | server.setRequestHandler(ListToolsRequestSchema, async () => { 237 | return { 238 | tools: [ 239 | { 240 | name: 'mcp_auto_install_getAvailableServers', 241 | description: 242 | 'List all available MCP servers that can be installed. Returns a list of server names and their basic information. Use this to discover what MCP servers are available before installing or configuring them.', 243 | inputSchema: simpleZodToJsonSchema( 244 | z.object({ 245 | random_string: z.string().describe('Dummy parameter for no-parameter tools'), 246 | }), 247 | ), 248 | }, 249 | { 250 | name: 'mcp_auto_install_removeServer', 251 | description: 252 | "Remove a registered MCP server from the local registry. This will unregister the server but won't uninstall it. Provide the exact server name to remove. Use getAvailableServers first to see registered servers.", 253 | inputSchema: simpleZodToJsonSchema( 254 | z.object({ 255 | serverName: z 256 | .string() 257 | .describe('The exact name of the server to remove from registry'), 258 | }), 259 | ), 260 | }, 261 | { 262 | name: 'mcp_auto_install_configureServer', 263 | description: 264 | 'Get detailed configuration help for a specific MCP server. Provides README content, configuration instructions, and suggested commands. Optionally specify a purpose or specific configuration question.', 265 | inputSchema: simpleZodToJsonSchema( 266 | z.object({ 267 | serverName: z.string().describe('The exact name of the server to configure'), 268 | }), 269 | ), 270 | }, 271 | { 272 | name: 'mcp_auto_install_saveCommand', 273 | description: 274 | 'Save an npx command configuration for an MCP server. This stores the command, arguments and environment variables in both the MCP settings and LLM configuration files. Use this to persist server-specific command configurations.', 275 | inputSchema: simpleZodToJsonSchema( 276 | z.object({ 277 | serverName: z 278 | .string() 279 | .describe('The exact name of the server to save command configuration for'), 280 | command: z 281 | .string() 282 | .describe( 283 | "The main command to execute (e.g., 'npx', 'node', 'npm', 'yarn', 'pnpm','cmd', 'powershell', 'bash', 'sh', 'zsh', 'fish', 'tcsh', 'csh', 'cmd', 'powershell', 'pwsh', 'cmd.exe', 'powershell.exe', 'cmd.ps1', 'powershell.ps1')", 284 | ), 285 | args: z 286 | .array(z.string()) 287 | .describe( 288 | "Array of command arguments (e.g., ['--port', '3000', '--config', 'config.json'])", 289 | ), 290 | env: z 291 | .record(z.string()) 292 | .describe( 293 | "Environment variables object for the command (e.g., { 'NODE_ENV': 'production', 'DEBUG': 'true' })", 294 | ) 295 | .optional(), 296 | description: z 297 | .string() 298 | .describe( 299 | 'A description of the functionality and purpose of the server to which the command configuration needs to be saved', 300 | ), 301 | }), 302 | ), 303 | }, 304 | // { 305 | // name: 'mcp_auto_install_parseJsonConfig', 306 | // description: 307 | // 'Parse and validate a JSON configuration string for MCP servers. This tool processes server configurations, validates their format, and merges them with existing configurations. Use this for bulk server configuration.', 308 | // inputSchema: simpleZodToJsonSchema( 309 | // z.object({ 310 | // config: z 311 | // .string() 312 | // .describe( 313 | // "JSON string containing server configurations in the format: { 'mcpServers': { 'serverName': { 'command': 'string', 'args': ['string'] } } }", 314 | // ), 315 | // }), 316 | // ), 317 | // }, 318 | ], 319 | }; 320 | }); 321 | 322 | // Register tool call handler 323 | server.setRequestHandler(CallToolRequestSchema, async req => { 324 | const { name, arguments: args = {} } = req.params; 325 | 326 | switch (name) { 327 | case 'mcp_auto_install_getAvailableServers': { 328 | const servers = await getRegisteredServers(); 329 | return { 330 | content: [ 331 | { 332 | type: 'text', 333 | text: `📋 Found ${servers.length} MCP servers`, 334 | }, 335 | { 336 | type: 'text', 337 | text: servers 338 | .map(s => `• ${s.name}${s.description ? `: ${s.description}` : ''}`) 339 | .join('\n'), 340 | }, 341 | ], 342 | success: true, 343 | }; 344 | } 345 | 346 | case 'mcp_auto_install_removeServer': { 347 | const result = await handleRemoveServer(args as unknown as { serverName: string }); 348 | return createServerResponse(result, false); 349 | } 350 | 351 | case 'mcp_auto_install_configureServer': { 352 | const result = await handleConfigureServer( 353 | args as unknown as { 354 | serverName: string; 355 | }, 356 | ); 357 | return createServerResponse(result, false); 358 | } 359 | 360 | case 'mcp_auto_install_saveCommand': { 361 | const result = await saveCommandToExternalConfig( 362 | args.serverName as string, 363 | args.command as string, 364 | args.args as string[], 365 | args.description as string, 366 | jsonOnly, 367 | args.env as Record, 368 | ); 369 | return createServerResponse(result, jsonOnly); 370 | } 371 | 372 | // case 'mcp_auto_install_parseJsonConfig': { 373 | // const result = await handleParseConfig(args as unknown as { config: string }, jsonOnly); 374 | // return createServerResponse(result, jsonOnly); 375 | // } 376 | 377 | default: 378 | throw new Error(`Unknown tool: ${name}`); 379 | } 380 | }); 381 | return server; 382 | }; 383 | 384 | /** 385 | * Start MCP server 386 | */ 387 | export async function startServer(jsonOnly = false): Promise { 388 | console.error('Initializing MCP server...'); 389 | await initSettings(); 390 | 391 | console.error('Loading MCP packages...'); 392 | await preloadMCPPackages(); 393 | 394 | const server = createServer(jsonOnly); 395 | 396 | console.error('Connecting to transport...'); 397 | const transport = new StdioServerTransport(); 398 | await server.connect(transport); 399 | console.error('MCP server started and ready'); 400 | } 401 | 402 | /** 403 | * Get list of registered servers 404 | */ 405 | export async function getRegisteredServers(): Promise { 406 | // Ensure settings are loaded 407 | await initSettings(); 408 | return serverSettings.servers; 409 | } 410 | 411 | /** 412 | * The following are interface functions for CLI tools 413 | */ 414 | 415 | export async function handleInstallServer(args: { serverName: string }): Promise { 416 | const { serverName } = args; 417 | const server = await findServer(serverName); 418 | 419 | if (!server) { 420 | return createErrorResponse( 421 | `❌ Server '${serverName}' not found. Use 'getAvailableServers' to see options.`, 422 | ); 423 | } 424 | 425 | try { 426 | // Install using git clone 427 | const repoName = server.repo.split('/').pop()?.replace('.git', '') || serverName; 428 | const cloneDir = path.join(homedir(), '.mcp', 'servers', repoName); 429 | 430 | // Create directory 431 | await fs.mkdir(path.join(homedir(), '.mcp', 'servers'), { 432 | recursive: true, 433 | }); 434 | 435 | // Clone repository 436 | await exec(`git clone ${server.repo} ${cloneDir}`); 437 | 438 | // Install dependencies 439 | await exec(`cd ${cloneDir} && npm install`); 440 | 441 | if (server.installCommands && server.installCommands.length > 0) { 442 | // Run custom installation commands 443 | for (const cmd of server.installCommands) { 444 | await exec(`cd ${cloneDir} && ${cmd}`); 445 | } 446 | } 447 | 448 | return createSuccessResponse(`✅ Installed '${serverName}'. Path: ${cloneDir}`, { 449 | installPath: cloneDir, 450 | serverName: server.name, 451 | description: server.description, 452 | }); 453 | } catch (error) { 454 | return createErrorResponse(`⚠️ Install failed: ${(error as Error).message}`); 455 | } 456 | } 457 | 458 | export async function handleRegisterServer(serverInfo: MCPServerInfo): Promise { 459 | // Check if server already exists 460 | const existingIndex = serverSettings.servers.findIndex(s => s.name === serverInfo.name); 461 | 462 | if (existingIndex !== -1) { 463 | // Update existing server 464 | serverSettings.servers[existingIndex] = serverInfo; 465 | } else { 466 | // Add new server 467 | serverSettings.servers.push(serverInfo); 468 | } 469 | 470 | // Save updated settings 471 | await saveSettings(); 472 | 473 | const action = existingIndex !== -1 ? 'updated' : 'registered'; 474 | return createSuccessResponse(`✅ Server '${serverInfo.name}' ${action} successfully.`); 475 | } 476 | 477 | export async function handleRemoveServer(args: { serverName: string }): Promise { 478 | const { serverName } = args; 479 | const initialLength = serverSettings.servers.length; 480 | 481 | // Remove specified server 482 | serverSettings.servers = serverSettings.servers.filter(s => s.name !== serverName); 483 | 484 | if (serverSettings.servers.length === initialLength) { 485 | return createErrorResponse(`❌ Server '${serverName}' not found.`); 486 | } 487 | 488 | // Save updated settings 489 | await saveSettings(); 490 | 491 | return createSuccessResponse(`✅ Server '${serverName}' removed.`); 492 | } 493 | 494 | export async function handleConfigureServer(args: { 495 | serverName: string; 496 | }): Promise { 497 | const { serverName } = args; 498 | const server = await findServer(serverName); 499 | 500 | if (!server) { 501 | return createErrorResponse(`❌ Server '${serverName}' not found.`); 502 | } 503 | 504 | // Get README content 505 | const readmeResult = await handleGetServerReadme({ serverName }); 506 | 507 | if (!readmeResult.message || !readmeResult.data) { 508 | return createErrorResponse( 509 | `⚠️ README not available: ${readmeResult.message?.[0] || 'Unknown error'}`, 510 | ); 511 | } 512 | 513 | const messages = [ 514 | `📝 Config guide for '${serverName}'`, 515 | server.description ? `Description: ${server.description}` : '', 516 | readmeResult.data as string, 517 | ]; 518 | 519 | return createSuccessResponse(messages); 520 | } 521 | 522 | /** 523 | * Get server README content 524 | */ 525 | export async function handleGetServerReadme(args: { 526 | serverName: string; 527 | }): Promise { 528 | const { serverName } = args; 529 | const server = await findServer(serverName); 530 | 531 | if (!server) { 532 | return createErrorResponse(`❌ Server '${serverName}' not found in the registry.`); 533 | } 534 | 535 | try { 536 | // Get README content (directly from server object) 537 | const readmeContent = server.readme || 'No README content available for this server.'; 538 | 539 | // Add prompts to guide LLM in summarizing content and guiding parameter configuration 540 | const promptedReadme = `# ${serverName} README 541 | ${server.description ? `\n> ${server.description}\n` : ''} 542 | ${readmeContent} 543 | 544 | --- 545 | 546 | 547 | Summary: What does this MCP server do? (1-2 sentences) 548 | 549 | Setup: List required/optional parameters, env vars needed. 550 | 551 | Examples: 552 | - Working npx command example 553 | - JSON config example for integration 554 | 555 | Next steps: How to get started quickly? 556 | 557 | Note any unclear/missing information. 558 | `; 559 | 560 | return createSuccessResponse('README fetch successful', promptedReadme); 561 | } catch (error) { 562 | return createErrorResponse(`⚠️ Failed to fetch README: ${(error as Error).message}`); 563 | } 564 | } 565 | 566 | /** 567 | * Handle user configuration parsing 568 | */ 569 | export async function handleParseConfig( 570 | args: { config: string }, 571 | jsonOnly = false, 572 | ): Promise { 573 | try { 574 | // Parse the JSON string sent by the user 575 | const userConfig = JSON.parse(args.config); 576 | 577 | // Ensure mcpServers field exists 578 | if (!userConfig.mcpServers) { 579 | userConfig.mcpServers = {}; 580 | } 581 | 582 | // Validate each server's configuration format 583 | for (const [serverName, serverConfig] of Object.entries(userConfig.mcpServers)) { 584 | const config = serverConfig as { command: string; args: string[] }; 585 | 586 | // Validate required fields 587 | if (!config.command || !Array.isArray(config.args)) { 588 | return createErrorResponse( 589 | `❌ Invalid config for '${serverName}'. Require 'command' and 'args' fields.`, 590 | ); 591 | } 592 | } 593 | 594 | // If jsonOnly is true, just return the parsed config without saving 595 | if (jsonOnly) { 596 | return createSuccessResponse('✅ Config parsed', userConfig); 597 | } 598 | 599 | // Save configuration to external file 600 | const externalConfigPath = process.env.MCP_SETTINGS_PATH; 601 | if (!externalConfigPath) { 602 | return createErrorResponse('❌ MCP_SETTINGS_PATH not set. Set this to save config.'); 603 | } 604 | 605 | // Read existing configuration (if any) 606 | let existingConfig: Record = {}; 607 | try { 608 | const existingData = await fs.readFile(externalConfigPath, 'utf-8'); 609 | existingConfig = JSON.parse(existingData); 610 | } catch (error) { 611 | return createErrorResponse(`⚠️ Parse error: ${(error as Error).message}`); 612 | } 613 | 614 | // Merge configurations 615 | const mergedConfig = { 616 | ...existingConfig, 617 | mcpServers: { 618 | ...((existingConfig.mcpServers as Record) || {}), 619 | ...userConfig.mcpServers, 620 | }, 621 | }; 622 | 623 | // Save merged configuration 624 | await fs.writeFile(externalConfigPath, JSON.stringify(mergedConfig, null, 2), 'utf-8'); 625 | 626 | return createSuccessResponse('✅ Config saved'); 627 | } catch (error) { 628 | return createErrorResponse(`⚠️ Parse error: ${(error as Error).message}`); 629 | } 630 | } 631 | 632 | /** 633 | * Save command to external configuration file (e.g., Claude's configuration file) 634 | * @param serverName MCP server name 635 | * @param command User input command, e.g., "npx @modelcontextprotocol/server-name --arg1 value1 --arg2 value2" 636 | * @param args Array of command arguments, e.g., ['--port', '3000', '--config', 'config.json'] 637 | * @param env Environment variables object for the command, e.g., { 'NODE_ENV': 'production', 'DEBUG': 'true' } 638 | * @param jsonOnly If true, only return the command configuration without saving to files 639 | * @param description Optional description for the command 640 | * @returns Operation result 641 | */ 642 | export async function saveCommandToExternalConfig( 643 | serverName: string, 644 | command: string, 645 | args: string[], 646 | description: string, 647 | jsonOnly = false, 648 | env?: Record, 649 | ): Promise { 650 | try { 651 | if (!command) { 652 | return createErrorResponse('❌ Command cannot be empty'); 653 | } 654 | 655 | // Check if server exists (in our MCP server registry) 656 | const server = await findServer(serverName); 657 | if (!server) { 658 | return createErrorResponse(`❌ Server '${serverName}' not found`); 659 | } 660 | 661 | // Create command configuration 662 | const commandConfig = { 663 | name: server?.name || serverName, 664 | command, 665 | args, 666 | env: env || {}, 667 | description: description || server.description || '', 668 | }; 669 | 670 | // If jsonOnly is true, just return the configuration without saving 671 | if (jsonOnly) { 672 | return createSuccessResponse('✅ Command config generated', commandConfig); 673 | } 674 | 675 | // Check environment variable - points to LLM (e.g., Claude) config file path 676 | const externalConfigPath = process.env.MCP_SETTINGS_PATH; 677 | if (!externalConfigPath) { 678 | return createErrorResponse( 679 | '❌ MCP_SETTINGS_PATH not set. Please set it to your LLM config path.', 680 | ); 681 | } 682 | 683 | try { 684 | // Read external LLM configuration file 685 | const configData = await fs.readFile(externalConfigPath, 'utf-8'); 686 | const config = JSON.parse(configData); 687 | 688 | // Ensure mcpServers field exists 689 | if (!config.mcpServers) { 690 | config.mcpServers = {}; 691 | } 692 | 693 | // Add/update server configuration to LLM config file 694 | config.mcpServers[serverName] = commandConfig; 695 | 696 | // Save configuration to LLM config file 697 | await fs.writeFile(externalConfigPath, JSON.stringify(config, null, 2), 'utf-8'); 698 | 699 | // Also update internal server configuration - save to our MCP server registry 700 | server.commandConfig = commandConfig; 701 | 702 | // Update server description if provided 703 | if (description) { 704 | server.description = description; 705 | } 706 | 707 | await saveSettings(); 708 | 709 | return createSuccessResponse(`✅ Command saved for '${serverName}'`); 710 | } catch (error) { 711 | return createErrorResponse(`⚠️ Config file error: ${(error as Error).message}`); 712 | } 713 | } catch (error) { 714 | return createErrorResponse(`⚠️ Command save error: ${(error as Error).message}`); 715 | } 716 | } 717 | -------------------------------------------------------------------------------- /packages/mcp-auto-install/src/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 描述MCP服务器的接口 3 | */ 4 | export interface MCPServerInfo { 5 | name: string; 6 | repo: string; 7 | command: string; 8 | description: string; 9 | keywords: string[]; 10 | readme?: string; 11 | installCommands?: string[]; 12 | commandConfig?: { 13 | command: string; 14 | args: string[]; 15 | env?: Record; 16 | }; 17 | } 18 | 19 | /** 20 | * MCP Auto Install Server配置选项 21 | */ 22 | export interface MCPAutoInstallOptions { 23 | llmApiKey?: string; 24 | llmApiEndpoint?: string; 25 | settingsPath?: string; 26 | } 27 | 28 | /** 29 | * 操作结果接口 30 | */ 31 | export interface OperationResult { 32 | success: boolean; 33 | message: string[]; 34 | data?: unknown; 35 | } 36 | 37 | /** 38 | * npm包信息接口 39 | */ 40 | export interface NpmPackageInfo { 41 | name: string; 42 | links?: { 43 | repository?: string; 44 | [key: string]: string | undefined; 45 | }; 46 | original?: { 47 | readme?: string; 48 | [key: string]: unknown; 49 | }; 50 | [key: string]: unknown; 51 | } 52 | -------------------------------------------------------------------------------- /packages/mcp-auto-install/src/utils/response.ts: -------------------------------------------------------------------------------- 1 | import type { OperationResult } from '../types.js'; 2 | 3 | /** 4 | * Utility function to create error response 5 | */ 6 | export function createErrorResponse(message: string): OperationResult { 7 | return { 8 | success: false, 9 | message: [message], 10 | }; 11 | } 12 | 13 | /** 14 | * Utility function to create success response 15 | */ 16 | export function createSuccessResponse(message: string | string[], data?: unknown): OperationResult { 17 | return { 18 | success: true, 19 | message: Array.isArray(message) ? message : [message], 20 | ...(data !== undefined && { data }), 21 | }; 22 | } 23 | 24 | /** 25 | * Utility function to create content items for MCP server response 26 | */ 27 | export function createContentItems(result: OperationResult): Array<{ type: string; text: string }> { 28 | const items = result.message.map(text => ({ type: 'text', text })); 29 | 30 | if (result.data) { 31 | items.push({ 32 | type: 'text', 33 | text: typeof result.data === 'string' ? result.data : JSON.stringify(result.data), 34 | }); 35 | } 36 | 37 | return items; 38 | } 39 | 40 | /** 41 | * Utility function to create MCP server response 42 | */ 43 | export function createServerResponse(result: OperationResult, jsonOnly: boolean) { 44 | const response: { 45 | content: Array<{ type: string; text: string }>; 46 | data?: unknown; 47 | success: boolean; 48 | } = { 49 | content: createContentItems(result), 50 | success: result.success, 51 | }; 52 | 53 | if (jsonOnly && result.data) { 54 | response.data = result.data; 55 | } 56 | 57 | return response; 58 | } 59 | -------------------------------------------------------------------------------- /packages/mcp-auto-install/src/utils/utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Check if MCP settings environment variable is set 3 | */ 4 | export function checkMCPSettings(silent = false): boolean { 5 | // Check if MCP_SETTINGS_PATH is set 6 | if (!process.env.MCP_SETTINGS_PATH) { 7 | if (!silent) { 8 | console.warn('\n⚠️ MCP_SETTINGS_PATH environment variable is not set'); 9 | console.warn( 10 | ' This variable is needed to save commands and configurations to your LLM client.', 11 | ); 12 | console.warn(' Set it to point to your LLM config file, for example:'); 13 | console.warn( 14 | ' export MCP_SETTINGS_PATH="/Users/username/Library/Application Support/Claude/claude_desktop_config.json"\n', 15 | ); 16 | } 17 | return false; 18 | } 19 | 20 | // Optional: Check if MCP_REGISTRY_PATH is set (will use default if not) 21 | if (process.env.MCP_REGISTRY_PATH && !silent) { 22 | console.info(`📂 Using custom registry location: ${process.env.MCP_REGISTRY_PATH}`); 23 | } else if (!silent) { 24 | console.info('📂 Using default registry location (set MCP_REGISTRY_PATH to customize)'); 25 | } 26 | 27 | if (!silent) { 28 | console.info(`✅ Using LLM config file: ${process.env.MCP_SETTINGS_PATH}`); 29 | } 30 | 31 | return true; 32 | } 33 | -------------------------------------------------------------------------------- /packages/mcp-auto-install/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "rootDir": "./src" 6 | }, 7 | "include": ["./**/*.ts"], 8 | "exclude": ["node_modules", "dist"] 9 | } 10 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | # all packages in direct subdirs of packages/ 3 | - 'packages/*' 4 | # exclude packages that are inside test directories 5 | - '!**/test/**' -------------------------------------------------------------------------------- /scripts/publish-single.js: -------------------------------------------------------------------------------- 1 | import { execSync } from 'node:child_process'; 2 | const packageName = process.argv[2]; // 获取命令行参数 3 | 4 | if (!packageName) { 5 | console.error('Please provide a package name'); 6 | process.exit(1); 7 | } 8 | 9 | const command = `pnpm changeset publish --filter ${packageName}`; 10 | execSync(command, { stdio: 'inherit' }); 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "esModuleInterop": true, 8 | "skipLibCheck": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "resolveJsonModule": true 11 | } 12 | } 13 | --------------------------------------------------------------------------------