├── .gitignore ├── LICENSE ├── README.md ├── examples ├── README.md ├── brainstorm-enhancements.md ├── code-review.md ├── design-critique.md ├── second-opinion.md └── writing-feedback.md ├── mcp-client-config.example.json ├── package-lock.json ├── package.json ├── src ├── api │ └── deepseek │ │ └── deepseek.ts ├── config.ts ├── index.ts ├── server.ts ├── tools │ ├── brainstorm-enhancements │ │ ├── brainstorm-enhancements.ts │ │ └── index.ts │ ├── code-review │ │ ├── code-review.ts │ │ └── index.ts │ ├── design-critique │ │ ├── design-critique.ts │ │ └── index.ts │ ├── second-opinion │ │ ├── index.ts │ │ └── second-opinion.ts │ └── writing-feedback │ │ ├── index.ts │ │ └── writing-feedback.ts ├── types │ └── index.ts └── utils │ ├── file.ts │ └── prompt.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Operating System Files 2 | .DS_Store 3 | .DS_Store? 4 | ._* 5 | .Spotlight-V100 6 | .Trashes 7 | ehthumbs.db 8 | Thumbs.db 9 | 10 | # IDE and Editor Files 11 | .idea/ 12 | .vscode/ 13 | *.swp 14 | *.swo 15 | *~ 16 | *.sublime-workspace 17 | *.sublime-project 18 | 19 | # TypeScript 20 | *.tsbuildinfo 21 | .tscache/ 22 | *.js.map 23 | *.tgz 24 | .npm 25 | .eslintcache 26 | .rollup.cache 27 | *.mjs.map 28 | *.cjs.map 29 | !*.d.ts.template 30 | yarn.lock 31 | .pnp.js 32 | .pnp.cjs 33 | .pnp.mjs 34 | .pnp.json 35 | .pnp.ts 36 | 37 | # Demo and Example Directories 38 | demo/ 39 | demos/ 40 | samples/ 41 | .sample-env 42 | sample.* 43 | !sample.template.* 44 | !examples/ # Allow examples directory for tool documentation 45 | 46 | # Node.js 47 | node_modules/ 48 | npm-debug.log* 49 | yarn-debug.log* 50 | yarn-error.log* 51 | .pnpm-debug.log* 52 | .env 53 | .env.local 54 | .env.development.local 55 | .env.test.local 56 | .env.production.local 57 | 58 | # Python 59 | __pycache__/ 60 | *.py[cod] 61 | *$py.class 62 | *.so 63 | .Python 64 | build/ 65 | develop-eggs/ 66 | dist/ 67 | downloads/ 68 | eggs/ 69 | .eggs/ 70 | lib/ 71 | lib64/ 72 | parts/ 73 | sdist/ 74 | var/ 75 | wheels/ 76 | *.egg-info/ 77 | .installed.cfg 78 | *.egg 79 | .pytest_cache/ 80 | .coverage 81 | htmlcov/ 82 | .tox/ 83 | .venv 84 | venv/ 85 | ENV/ 86 | 87 | # Java 88 | *.class 89 | *.log 90 | *.jar 91 | *.war 92 | *.nar 93 | *.ear 94 | *.zip 95 | *.tar.gz 96 | *.rar 97 | hs_err_pid* 98 | target/ 99 | .gradle/ 100 | build/ 101 | 102 | # Ruby 103 | *.gem 104 | *.rbc 105 | /.config 106 | /coverage/ 107 | /InstalledFiles 108 | /pkg/ 109 | /spec/reports/ 110 | /spec/examples.txt 111 | /test/tmp/ 112 | /test/version_tmp/ 113 | /tmp/ 114 | .byebug_history 115 | 116 | # Compiled Files 117 | *.com 118 | *.class 119 | *.dll 120 | *.exe 121 | *.o 122 | *.so 123 | 124 | # Package Files 125 | *.7z 126 | *.dmg 127 | *.gz 128 | *.iso 129 | *.rar 130 | *.tar 131 | *.zip 132 | 133 | # Logs and Databases 134 | *.log 135 | *.sql 136 | *.sqlite 137 | *.sqlite3 138 | 139 | # Build and Distribution 140 | dist/ 141 | build/ 142 | out/ 143 | 144 | # Documentation 145 | docs/_build/ 146 | doc/api/ 147 | 148 | # Dependency Directories 149 | jspm_packages/ 150 | bower_components/ 151 | 152 | # Testing 153 | coverage/ 154 | .nyc_output/ 155 | 156 | # Cache 157 | .cache/ 158 | .parcel-cache/ 159 | 160 | # Misc 161 | .DS_Store 162 | .env.local 163 | .env.development.local 164 | .env.test.local 165 | .env.production.local 166 | *.bak 167 | *.swp 168 | *.swo 169 | *~ 170 | .history/ 171 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mentor-mcp-server 2 | 3 | [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue.svg)](https://www.typescriptlang.org/) 4 | [![Model Context Protocol](https://img.shields.io/badge/MCP-1.4.1-green.svg)](https://modelcontextprotocol.io/) 5 | [![Version](https://img.shields.io/badge/Version-1.0.0-blue.svg)]() 6 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 7 | [![Status](https://img.shields.io/badge/Status-Stable-blue.svg)]() 8 | [![GitHub](https://img.shields.io/github/stars/cyanheads/mentor-mcp-server?style=social)](https://github.com/cyanheads/mentor-mcp-server) 9 | 10 | A Model Context Protocol server providing LLM Agents a second opinion via AI-powered Deepseek-Reasoning (R1) mentorship capabilities, including code review, design critique, writing feedback, and idea brainstorming through the Deepseek API. Set your LLM Agent up for success with expert second opinions and actionable insights. 11 | 12 | ## Model Context Protocol 13 | 14 | The Model Context Protocol (MCP) enables communication between: 15 | 16 | - **Clients**: Claude Desktop, IDEs, and other MCP-compatible clients 17 | - **Servers**: Tools and resources for task management and automation 18 | - **LLM Agents**: AI models that leverage the server's capabilities 19 | 20 | ## Table of Contents 21 | 22 | - [Features](#features) 23 | - [Installation](#installation) 24 | - [Configuration](#configuration) 25 | - [Tools](#tools) 26 | - [Examples](#examples) 27 | - [Development](#development) 28 | - [Project Structure](#project-structure) 29 | - [License](#license) 30 | 31 | ## Features 32 | 33 | ### Code Analysis 34 | - Comprehensive code reviews 35 | - Bug detection and prevention 36 | - Style and best practices evaluation 37 | - Performance optimization suggestions 38 | - Security vulnerability assessment 39 | 40 | ### Design & Architecture 41 | - UI/UX design critiques 42 | - Architectural diagram analysis 43 | - Design pattern recommendations 44 | - Accessibility evaluation 45 | - Consistency checks 46 | 47 | ### Content Enhancement 48 | - Writing feedback and improvement 49 | - Grammar and style analysis 50 | - Documentation review 51 | - Content clarity assessment 52 | - Structural recommendations 53 | 54 | ### Strategic Planning 55 | - Feature enhancement brainstorming 56 | - Second opinions on approaches 57 | - Innovation suggestions 58 | - Feasibility analysis 59 | - User value assessment 60 | 61 | ## Installation 62 | 63 | ```bash 64 | # Clone the repository 65 | git clone git@github.com:cyanheads/mentor-mcp-server.git 66 | cd mentor-mcp-server 67 | 68 | # Install dependencies 69 | npm install 70 | 71 | # Build the project 72 | npm run build 73 | ``` 74 | 75 | ## Configuration 76 | 77 | Add to your MCP client settings: 78 | 79 | ```json 80 | { 81 | "mcpServers": { 82 | "mentor": { 83 | "command": "node", 84 | "args": ["build/index.js"], 85 | "env": { 86 | "DEEPSEEK_API_KEY": "your_api_key", 87 | "DEEPSEEK_MODEL": "deepseek-reasoner", 88 | "DEEPSEEK_MAX_TOKENS": "8192", 89 | "DEEPSEEK_MAX_RETRIES": "3", 90 | "DEEPSEEK_TIMEOUT": "30000" 91 | } 92 | } 93 | } 94 | } 95 | ``` 96 | 97 | ### Environment Variables 98 | 99 | | Variable | Required | Default | Description | 100 | |----------|----------|---------|-------------| 101 | | DEEPSEEK_API_KEY | Yes | - | Your Deepseek API key | 102 | | DEEPSEEK_MODEL | Yes | deepseek-reasoner | Deepseek model name | 103 | | DEEPSEEK_MAX_TOKENS | No | 8192 | Maximum tokens per request | 104 | | DEEPSEEK_MAX_RETRIES | No | 3 | Number of retry attempts | 105 | | DEEPSEEK_TIMEOUT | No | 30000 | Request timeout (ms) | 106 | 107 | ## Tools 108 | 109 | ### Code Review 110 | ```xml 111 | 112 | mentor-mcp-server 113 | code_review 114 | 115 | { 116 | "file_path": "src/app.ts", 117 | "language": "typescript" 118 | } 119 | 120 | 121 | ``` 122 | 123 | ### Design Critique 124 | ```xml 125 | 126 | mentor-mcp-server 127 | design_critique 128 | 129 | { 130 | "design_document": "path/to/design.fig", 131 | "design_type": "web UI" 132 | } 133 | 134 | 135 | ``` 136 | 137 | ### Writing Feedback 138 | ```xml 139 | 140 | mentor-mcp-server 141 | writing_feedback 142 | 143 | { 144 | "text": "Documentation content...", 145 | "writing_type": "documentation" 146 | } 147 | 148 | 149 | ``` 150 | 151 | ### Feature Enhancement 152 | ```xml 153 | 154 | mentor-mcp-server 155 | brainstorm_enhancements 156 | 157 | { 158 | "concept": "User authentication system" 159 | } 160 | 161 | 162 | ``` 163 | 164 | ## Examples 165 | 166 | Detailed examples of each tool's usage and output can be found in the [examples](examples) directory: 167 | 168 | - [Second Opinion Example](examples/second-opinion.md) - Analysis of authentication system requirements 169 | - [Code Review Example](examples/code-review.md) - Detailed TypeScript code review with security and performance insights 170 | - [Design Critique Example](examples/design-critique.md) - Comprehensive UI/UX feedback for a dashboard design 171 | - [Writing Feedback Example](examples/writing-feedback.md) - Documentation improvement suggestions 172 | - [Brainstorm Enhancements Example](examples/brainstorm-enhancements.md) - Feature ideation with implementation details 173 | 174 | Each example includes the request format and sample response, demonstrating the tool's capabilities and output structure. 175 | 176 | ## Development 177 | 178 | ```bash 179 | # Build TypeScript code 180 | npm run build 181 | 182 | # Start the server 183 | npm run start 184 | 185 | # Development with watch mode 186 | npm run dev 187 | 188 | # Clean build artifacts 189 | npm run clean 190 | ``` 191 | 192 | ## Project Structure 193 | 194 | ``` 195 | src/ 196 | ├── api/ # API integration modules 197 | ├── tools/ # Tool implementations 198 | │ ├── second-opinion/ 199 | │ ├── code-review/ 200 | │ ├── design-critique/ 201 | │ ├── writing-feedback/ 202 | │ └── brainstorm-enhancements/ 203 | ├── types/ # TypeScript type definitions 204 | ├── utils/ # Utility functions 205 | ├── config.ts # Server configuration 206 | ├── index.ts # Entry point 207 | └── server.ts # Main server implementation 208 | ``` 209 | 210 | ## License 211 | 212 | Apache License 2.0. See [LICENSE](LICENSE) for more information. 213 | 214 | --- 215 | 216 |
217 | Built with the Model Context Protocol 218 |
-------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Mentor MCP Server Tool Examples 2 | 3 | This directory contains example requests and responses for each tool provided by the mentor-mcp-server. These examples demonstrate the capabilities and expected output format of each tool. 4 | 5 | ## Tools 6 | 7 | ### 1. [Second Opinion](second-opinion.md) 8 | Provides a second opinion on a user's request by analyzing it with an LLM and listing critical considerations. The example shows analysis of building a secure authentication system. 9 | 10 | ### 2. [Code Review](code-review.md) 11 | Provides a code review for a given file or code snippet, focusing on potential bugs, style issues, performance bottlenecks, and security vulnerabilities. The example shows a review of the code review tool's own implementation. 12 | 13 | ### 3. [Design Critique](design-critique.md) 14 | Offers a critique of a design document, UI/UX mockup, or architectural diagram, focusing on usability, aesthetics, consistency, accessibility, and potential design flaws. The example shows analysis of a cloud monitoring dashboard design. 15 | 16 | ### 4. [Writing Feedback](writing-feedback.md) 17 | Provides feedback on a piece of writing, such as an essay, article, or technical documentation, focusing on clarity, grammar, style, structure, and overall effectiveness. The example shows feedback on a rate limiting implementation guide. 18 | 19 | ### 5. [Brainstorm Enhancements](brainstorm-enhancements.md) 20 | Generates creative ideas for improving a given concept, product, or feature, focusing on innovation, feasibility, and user value. The example shows enhancement ideas for an AI-powered code review tool. 21 | 22 | ## Production Readiness 23 | 24 | All tools have been tested and demonstrate: 25 | - Proper input validation and error handling 26 | - Comprehensive and well-structured responses 27 | - Consistent output formatting 28 | - Practical applicability to real-world scenarios 29 | - Deep domain expertise in their respective areas 30 | 31 | The examples serve as both documentation and test cases, showing the expected behavior and quality of responses for each tool. -------------------------------------------------------------------------------- /examples/brainstorm-enhancements.md: -------------------------------------------------------------------------------- 1 | # Brainstorm Enhancements Tool Example 2 | 3 | ## Request 4 | ```json 5 | { 6 | "concept": "A code review tool that integrates with GitHub and uses AI to automatically analyze pull requests, focusing on code quality, security vulnerabilities, and performance issues. The tool currently provides inline comments on the PR and a summary report." 7 | } 8 | ``` 9 | 10 | ## Response 11 | ```markdown 12 | ### **1. Quick Wins (Immediate, Low-Effort Improvements)** 13 | --- 14 | #### **A. Contextual Inline Comment Explanations** 15 | - **Description**: Add brief explanations and code examples to AI-generated inline comments to help developers understand *why* a change is suggested (e.g., "This SQL query is vulnerable to injection; here's a parameterized example"). 16 | - **Impact**: Reduces ambiguity, accelerates fixes, and improves trust in AI feedback. 17 | - **Complexity**: Low (leverage existing LLMs like GPT-4 for concise explanations). 18 | - **Resources**: 1–2 developers, 2–3 weeks. 19 | - **Challenges**: Ensuring explanations are accurate and non-redundant. 20 | 21 | #### **B. Customizable Rulesets** 22 | - **Description**: Allow teams to toggle specific code quality rules (e.g., enforce strict TypeScript typings but ignore line-length warnings). 23 | - **Impact**: Tailors feedback to team priorities, reducing noise. 24 | - **Complexity**: Low (add UI toggles tied to existing rule configurations). 25 | - **Resources**: 1 frontend developer, 1 backend developer, 3 weeks. 26 | - **Challenges**: Managing conflicting rule combinations. 27 | 28 | #### **C. Severity-Based Issue Prioritization** 29 | - **Description**: Flag issues as Critical/High/Medium/Low (e.g., security vulnerabilities = Critical, formatting = Low) and sort them in the summary report. 30 | - **Impact**: Helps developers triage fixes efficiently. 31 | - **Complexity**: Low (predefined severity tiers for common issues). 32 | - **Resources**: 1 developer, 1–2 weeks. 33 | - **Challenges**: Subjective severity assignments may require user customization. 34 | 35 | #### **D. Dark Mode for Summary Reports** 36 | - **Description**: Add a dark theme option to the PDF/HTML summary reports. 37 | - **Impact**: Improves readability and aligns with developer preferences. 38 | - **Complexity**: Low (CSS/theme adjustments). 39 | - **Resources**: 1 frontend developer, 1 week. 40 | - **Challenges**: Minimal. 41 | 42 | --- 43 | 44 | ### **2. Strategic Enhancements (Medium-Term, Moderate Complexity)** 45 | --- 46 | #### **A. Multi-Platform CI/CD Integration** 47 | - **Description**: Expand beyond GitHub to natively support GitLab, Bitbucket, and Azure DevOps pipelines. 48 | - **Impact**: Captures broader market share and enterprise clients. 49 | - **Complexity**: Medium (API integrations, testing across platforms). 50 | - **Resources**: 2–3 developers, 2–3 months. 51 | - **Challenges**: Varying API limitations across platforms. 52 | 53 | #### **B. Real-Time Collaboration Mode** 54 | - **Description**: Enable multiple users to interact with AI feedback simultaneously (e.g., threaded discussions, vote on fixes). 55 | - **Impact**: Streamlines team collaboration and decision-making. 56 | - **Complexity**: Medium (real-time sync, conflict resolution). 57 | - **Resources**: 2 backend developers, 1 frontend developer, 3–4 months. 58 | - **Challenges**: Scaling real-time features for large PRs. 59 | 60 | #### **C. Predictive Impact Analysis** 61 | - **Description**: Use AI to predict how code changes might affect system performance or security in production (e.g., "This loop could cause latency spikes at scale"). 62 | - **Impact**: Proactively prevents regressions. 63 | - **Complexity**: High (requires training ML models on historical performance data). 64 | - **Resources**: 1 ML engineer, 2 backend developers, 4–6 months. 65 | - **Challenges**: Data collection and model accuracy. 66 | 67 | #### **D. Automated Remediation for Simple Fixes** 68 | - **Description**: Offer one-click fixes for low-complexity issues (e.g., updating deprecated dependencies, fixing syntax errors). 69 | - **Impact**: Reduces manual toil for trivial tasks. 70 | - **Complexity**: Medium (code generation + safety checks). 71 | - **Resources**: 2 developers, 3 months. 72 | - **Challenges**: Ensuring automated fixes don't introduce new bugs. 73 | 74 | #### **E. Developer Learning Hub** 75 | - **Description**: Curate a knowledge base of common issues flagged by the tool, with links to tutorials and best practices. 76 | - **Impact**: Turns code reviews into teaching moments, improving team skills. 77 | - **Complexity**: Medium (content curation + UI integration). 78 | - **Resources**: 1 technical writer, 1 developer, 2 months. 79 | - **Challenges**: Keeping content updated. 80 | 81 | --- 82 | 83 | ### **3. Transformative Ideas (Long-Term, Innovative Solutions)** 84 | --- 85 | #### **A. Self-Learning AI Model** 86 | - **Description**: Train the AI to adapt to a team's unique coding patterns over time, reducing false positives (e.g., ignoring approved legacy code conventions). 87 | - **Impact**: Personalizes feedback, boosting adoption. 88 | - **Complexity**: High (federated learning, continuous feedback loops). 89 | - **Resources**: 2–3 ML engineers, 6–12 months. 90 | - **Challenges**: Privacy concerns with training on private codebases. 91 | 92 | #### **B. Virtual Pair Programming** 93 | - **Description**: Integrate the AI into IDEs (VS Code, JetBrains) to provide real-time suggestions *while coding*, not just during PRs. 94 | - **Impact**: Shifts left code quality checks, reducing PR backlog. 95 | - **Complexity**: High (IDE plugin development + low-latency AI). 96 | - **Resources**: 3–4 developers, 9–12 months. 97 | - **Challenges**: Performance optimization for real-time analysis. 98 | 99 | #### **C. Code Health "Credit Score"** 100 | - **Description**: Generate a dynamic score for repositories based on technical debt, test coverage, and vulnerability history, with actionable insights. 101 | - **Impact**: Helps teams track and prioritize long-term code quality. 102 | - **Complexity**: High (metric aggregation + visualization). 103 | - **Resources**: 2 data engineers, 1 frontend developer, 6 months. 104 | - **Challenges**: Defining universally meaningful metrics. 105 | 106 | #### **D. Blockchain-Verified Audits** 107 | - **Description**: Store immutable audit logs of code reviews on a blockchain for compliance-heavy industries (finance, healthcare). 108 | - **Impact**: Differentiates in regulated markets. 109 | - **Complexity**: High (blockchain integration, legal compliance). 110 | - **Resources**: 2 blockchain developers, 6–8 months. 111 | - **Challenges**: Cost and scalability of blockchain storage. 112 | 113 | #### **E. Decentralized AI Models** 114 | - **Description**: Offer on-premise deployments where AI models run locally to address data privacy concerns. 115 | - **Impact**: Attracts enterprises with strict data governance policies. 116 | - **Complexity**: High (model optimization for edge devices). 117 | - **Resources**: 2 ML engineers, 2 DevOps engineers, 12 months. 118 | - **Challenges**: Maintaining model accuracy in offline environments. 119 | 120 | --- 121 | 122 | ### **4. Implementation Recommendations** 123 | --- 124 | 1. **Prioritize Quick Wins First** to build user trust and demonstrate rapid iteration (e.g., severity filters + explanations). 125 | 2. **Phase Strategic Enhancements** based on user feedback (start with multi-platform support and automated fixes). 126 | 3. **Invest in R&D for Transformative Ideas** by partnering with research institutions or leveraging open-source models. 127 | 4. **Adopt a Modular Architecture** to isolate components (e.g., AI engine, integrations) for easier scaling and updates. 128 | 5. **Leverage Cloud-Native Tools** (e.g., Kubernetes, serverless) for scalability and cost efficiency. 129 | 6. **Build a Feedback Loop** with early adopters to validate features like the learning hub or predictive analysis. 130 | 7. **Focus on Security Early** (e.g., SOC 2 compliance, encryption) to appeal to enterprise buyers. 131 | 132 | **Key Challenges to Mitigate**: 133 | - Balancing AI autonomy with user control (avoid "black box" frustration). 134 | - Ensuring low latency for real-time features. 135 | - Competing with GitHub's native tools (Copilot, CodeQL) through deeper customization. -------------------------------------------------------------------------------- /examples/code-review.md: -------------------------------------------------------------------------------- 1 | # Code Review Tool Example 2 | 3 | ## Request 4 | ```json 5 | { 6 | "code_snippet": "import type { ToolDefinition, CodeReviewArgs, ToolResponse } from '../../types/index.js';\nimport { makeDeepseekAPICall, checkRateLimit } from '../../api/deepseek/deepseek.js';\nimport { readFileContent } from '../../utils/file.js';\nimport { createPrompt, PromptTemplate, sanitizeInput } from '../../utils/prompt.js';\n\nconst SYSTEM_PROMPT = `You are an expert code reviewer...`;\n\nconst PROMPT_TEMPLATE: PromptTemplate = {\n template: `Review the following {language} code...`,\n systemPrompt: SYSTEM_PROMPT\n};\n\nexport const definition: ToolDefinition = {\n name: 'code_review',\n description: 'Provides a code review...',\n inputSchema: {\n type: 'object',\n properties: {\n file_path: { type: 'string', description: 'The full path...' },\n language: { type: 'string', description: 'The programming language...' },\n code_snippet: { type: 'string', description: 'Optional small code...' }\n },\n oneOf: [\n { required: ['file_path', 'language'] },\n { required: ['code_snippet', 'language'] }\n ]\n }\n};\n\nexport async function handler(args: unknown): Promise {\n if (!checkRateLimit()) {\n return { content: [{ type: 'text', text: 'Rate limit exceeded' }], isError: true };\n }\n\n if (!args || typeof args !== 'object') {\n return { content: [{ type: 'text', text: 'Invalid arguments' }], isError: true };\n }\n\n if (!('language' in args) || typeof args.language !== 'string') {\n return { content: [{ type: 'text', text: 'Language required' }], isError: true };\n }\n\n try {\n let codeToReview: string;\n const typedArgs = args as CodeReviewArgs;\n\n if (typedArgs.file_path) {\n try {\n codeToReview = await readFileContent(typedArgs.file_path);\n } catch (error) {\n return {\n content: [{ type: 'text', text: `Error reading file: ${error}` }],\n isError: true\n };\n }\n } else if (typedArgs.code_snippet) {\n codeToReview = typedArgs.code_snippet;\n } else {\n return {\n content: [{ type: 'text', text: 'File path or snippet required' }],\n isError: true\n };\n }\n\n const sanitizedCode = sanitizeInput(codeToReview);\n const sanitizedLanguage = sanitizeInput(typedArgs.language);\n const prompt = createPrompt(PROMPT_TEMPLATE, {\n language: sanitizedLanguage,\n code: sanitizedCode\n });\n\n const response = await makeDeepseekAPICall(prompt, SYSTEM_PROMPT);\n\n if (response.isError) {\n return {\n content: [{ type: 'text', text: `Error: ${response.errorMessage}` }],\n isError: true\n };\n }\n\n return { content: [{ type: 'text', text: response.text }] };\n } catch (error) {\n console.error('Code review error:', error);\n return {\n content: [{ type: 'text', text: `Error: ${error}` }],\n isError: true\n };\n }\n}", 7 | "language": "typescript" 8 | } 9 | ``` 10 | 11 | ## Response 12 | ```markdown 13 | 1. Critical Issues 14 | ------------------ 15 | - **Unsafe type assertion**: 16 | `const typedArgs = args as CodeReviewArgs` bypasses proper type validation. An attacker could send malformed payloads that pass initial checks but fail later. 17 | 18 | - **Incomplete input validation**: 19 | While checking for `language`, the code doesn't validate types for `file_path` or `code_snippet`. An invalid numeric `file_path` would throw later. 20 | 21 | - **Conflicting input handling**: 22 | The schema specifies `oneOf` but code prioritizes `file_path` over `code_snippet` if both are present. This contradicts the schema definition. 23 | 24 | 2. Security Concerns 25 | -------------------- 26 | - **Error message leakage**: 27 | Returning raw error messages (e.g., `Error reading file: ${error}`) could expose sensitive filesystem information. 28 | 29 | - **Potential prompt injection**: 30 | While `sanitizeInput` is used, its implementation isn't shown. Inadequate sanitization could allow LLM prompt injections via user-provided code snippets. 31 | 32 | - **Early rate limiting**: 33 | `checkRateLimit()` is called before input validation, allowing invalid requests to consume rate quota. 34 | 35 | 3. Performance Considerations 36 | ------------------------------ 37 | - **Duplicate sanitization**: 38 | Both `codeToReview` and `language` are sanitized, but this might be redundant if the API layer already handles sanitization. 39 | 40 | - **Unbounded file reading**: 41 | `readFileContent` could cause memory issues with large files. Consider adding size limits. 42 | 43 | 4. Code Style & Best Practices 44 | ------------------------------- 45 | - **Type safety violations**: 46 | - Using type assertion (`as`) instead of proper type guards 47 | - No Zod-like validation for input schema 48 | - `unknown` type in handler parameters not properly narrowed 49 | 50 | - **Error handling inconsistencies**: 51 | - Mix of error return objects and exceptions 52 | - `console.error` in production code (should use structured logging) 53 | 54 | - **Template issues**: 55 | - Hardcoded SYSTEM_PROMPT makes testing/mocking difficult 56 | - Prompt construction could be vulnerable to injection if sanitizeInput isn't robust 57 | 58 | 5. Suggested Improvements 59 | -------------------------- 60 | **Input Validation**: 61 | ```typescript 62 | // Use type guard instead of assertion 63 | function isCodeReviewArgs(args: unknown): args is CodeReviewArgs { 64 | return /* detailed property checks */; 65 | } 66 | 67 | // Validate file_path format if applicable 68 | if (typedArgs.file_path && !isValidPath(typedArgs.file_path)) { 69 | return invalidPathError; 70 | } 71 | ``` 72 | 73 | **Security Enhancements**: 74 | - Implement generic error messages: 75 | ```typescript 76 | return { 77 | content: [{ type: 'text', text: 'File read error' }], 78 | isError: true 79 | }; 80 | ``` 81 | - Add file size limits: 82 | ```typescript 83 | const MAX_FILE_SIZE = 1024 * 1024; // 1MB 84 | if (fileStats.size > MAX_FILE_SIZE) throw new Error('File too large'); 85 | ``` 86 | 87 | **Performance Improvements**: 88 | - Move rate limit check after input validation: 89 | ```typescript 90 | export async function handler(args: unknown): Promise { 91 | // Validate FIRST 92 | if (!validateArgs(args)) return invalidArgsResponse; 93 | 94 | // Then check rate limits 95 | if (!checkRateLimit()) return rateLimitResponse; 96 | ``` 97 | 98 | **TypeScript Best Practices**: 99 | 1. Use Zod for schema validation: 100 | ```typescript 101 | import { z } from 'zod'; 102 | 103 | const CodeReviewSchema = z.union([ 104 | z.object({ 105 | file_path: z.string().min(1), 106 | language: z.string().min(1) 107 | }), 108 | z.object({ 109 | code_snippet: z.string().min(1), 110 | language: z.string().min(1) 111 | }) 112 | ]); 113 | ``` 114 | 115 | 2. Implement proper error typing: 116 | ```typescript 117 | class CodeReviewError extends Error { 118 | public readonly isUserSafe: boolean; 119 | 120 | constructor(message: string, isUserSafe: boolean) { 121 | super(message); 122 | this.isUserSafe = isUserSafe; 123 | } 124 | } 125 | ``` 126 | 127 | **Architecture Suggestions**: 128 | - Separate validation, business logic, and presentation layers 129 | - Use dependency injection for file system access and API calls 130 | - Implement circuit breakers for the Deepseek API integration 131 | - Add telemetry for code review request metrics 132 | 133 | **Additional Considerations**: 134 | - Add timeout handling for file operations and API calls 135 | - Implement content scanning for malicious code patterns in snippets 136 | - Add cache control headers for API responses 137 | - Consider streaming partial responses for large reviews 138 | - Add content security policies for any HTML output -------------------------------------------------------------------------------- /examples/design-critique.md: -------------------------------------------------------------------------------- 1 | # Design Critique Tool Example 2 | 3 | ## Request 4 | ```json 5 | { 6 | "design_document": "A dashboard interface for a cloud monitoring system with the following components:\n\n- Top navigation bar with company logo, user profile, and notifications\n- Left sidebar with collapsible menu items for different monitoring categories (CPU, Memory, Network, Storage)\n- Main content area showing:\n - Overview cards with key metrics\n - Real-time graphs showing system performance\n - Alert history table\n - Resource usage breakdown\n- Footer with system status and last update timestamp\n\nThe design uses a dark theme with accent colors for critical alerts and status indicators. Graphs update every 30 seconds and alerts appear as toast notifications.", 7 | "design_type": "web UI" 8 | } 9 | ``` 10 | 11 | ## Response 12 | ```markdown 13 | ### Comprehensive Design Critique: Cloud Monitoring Dashboard 14 | 15 | #### 1. **Overall Assessment** 16 | The design presents a functional foundation for a monitoring dashboard with logical component organization. Its dark theme aligns with industry standards for operational tools, and the real-time elements address core user needs. However, the layout risks visual clutter in high-alert scenarios, and several accessibility/technical optimizations could enhance usability and scalability. 17 | 18 | --- 19 | 20 | #### 2. **Strengths** 21 | - **Intuitive Layout**: Industry-standard top nav + left sidebar structure reduces cognitive load. 22 | - **Effective Alert Hierarchy**: Accent colors (e.g., red for critical alerts) create clear visual urgency. 23 | - **Contextual Updates**: 30-second graph refresh rate balances data recency with server load. 24 | - **Multi-Channel Notifications**: Toast + alert history provides dual awareness mechanisms. 25 | - **System Transparency**: Footer timestamp builds trust in data freshness. 26 | 27 | --- 28 | 29 | #### 3. **Areas for Improvement** 30 | **Usability** 31 | - No apparent customization options for dashboard widgets 32 | - Overloaded main content area risks "dashboard fatigue" 33 | - Missing emergency controls (e.g., manual alert suppression) 34 | 35 | **Visual Design** 36 | - Insufficient spacing between overview cards 37 | - Undifferentiated graph line colors (accessibility risk) 38 | - Status indicators lack text labels (icon-only) 39 | 40 | **Technical Feasibility** 41 | - 30-second polling may strain backend at scale 42 | - No error states for failed graph updates 43 | - Toast stacking behavior undefined 44 | 45 | **Accessibility** 46 | - Contrast ratios below WCAG 2.1 AA for secondary text 47 | - No keyboard navigation for sidebar 48 | - Missing ARIA labels for dynamic content 49 | 50 | --- 51 | 52 | #### 4. **Specific Recommendations** 53 | **A. Layout & Interaction (High Impact)** 54 | 1. Add **dashboard customization**: 55 | - Drag-and-drop widget rearrangement 56 | - Collapsible/expandable sections 57 | - User-defined thresholds for alert colors 58 | 2. Implement **progressive disclosure**: 59 | - Expandable graph tooltips with raw metrics 60 | - "Show More" pagination for alert history 61 | 3. Introduce **emergency bar** at viewport top for SEV-1 alerts 62 | 63 | **B. Visual Hierarchy (Medium Impact)** 64 | 1. Apply **8px grid system** to cards/graphs for consistent spacing 65 | 2. Use **semantic color scales**: 66 | - 3 distinct hues for CPU/Memory/Network 67 | - Pattern overlays for grayscale printing 68 | 3. Add **status badges** to overview cards (e.g., "12% ▲ from avg") 69 | 70 | **C. Technical Optimization** 71 | 1. Replace polling with **WebSocket** for real-time updates 72 | 2. Implement **client-side throttling**: 73 | - Pause updates when tab/window not active 74 | - Adaptive refresh rates (15-60s) based on connectivity 75 | 3. Create **toast queue system** with: 76 | - Auto-dismiss timers (5s info / 15s critical) 77 | - Manual "pin" capability 78 | - Batch grouping for similar alerts 79 | 80 | **D. Accessibility Compliance** 81 | 1. Achieve **4.5:1 contrast ratio** for all text (tools: Stark/Colorable) 82 | 2. Add **keyboard shortcuts**: 83 | - Ctrl+1-4 for sidebar categories 84 | - Spacebar to pause auto-refresh 85 | 3. Provide **alternative data views**: 86 | - Tabular graph data export 87 | - Sonification toggle for alert patterns 88 | 89 | --- 90 | 91 | #### 5. **Implementation Considerations** 92 | **Frontend Architecture** 93 | - Use **React/Vue component library** with: 94 | - State management (Redux/Vuex) for metric data 95 | - Recharts/Visx for customizable graphs 96 | - ResizeObserver for responsive widgets 97 | 98 | **Backend Integration** 99 | - **GraphQL API** with: 100 | - Field-level metrics subscription 101 | - Query cost analysis to prevent overfetching 102 | - Cached historical data (Redis/Memcached) 103 | 104 | **Performance** 105 | - **Web Workers** for: 106 | - Client-side data aggregation 107 | - Off-main-thread graph calculations 108 | - **Compression** for time-series data (Protocol Buffers > JSON) 109 | 110 | **Maintenance** 111 | 1. **Design Token System**: 112 | - CSS Custom Properties for themes 113 | - Versioned design docs (Storybook/Figma) 114 | 2. **Monitoring**: 115 | - Perf metrics for dashboard load (LCP, INP) 116 | - User interaction heatmaps (Hotjar/LogRocket) 117 | 3. **Alert Taxonomy**: 118 | - Machine-readable schema (JSON-LD) 119 | - Automated alert lifecycle management 120 | 121 | --- 122 | 123 | ### Final Notes 124 | This design shows strong potential but requires refinement in scalability and inclusive design. Prioritize implementing the WebSocket transition and accessibility fixes in Phase 1, followed by customization features. Conduct usability testing with SRE personas to validate alert prioritization workflows. Consider adopting the OpenTelemetry standard for future-proof metric collection. -------------------------------------------------------------------------------- /examples/second-opinion.md: -------------------------------------------------------------------------------- 1 | # Second Opinion Tool Example 2 | 3 | ## Request 4 | ```json 5 | { 6 | "user_request": "Build a secure authentication system with OAuth2 and JWT tokens" 7 | } 8 | ``` 9 | 10 | ## Response 11 | ```markdown 12 | **Critical Considerations for Building a Secure OAuth2/JWT Authentication System:** 13 | 14 | - **Flow Selection Complexity:** Choosing the correct OAuth2 flow (e.g., Authorization Code + PKCE for SPAs/mobile, Client Credentials for machine-to-machine) is critical to avoid security vulnerabilities like token leakage or misuse. 15 | - **JWT Security Hardening:** Risks of unsigned/misconfigured tokens (e.g., using `none` algorithm), insecure secret storage for signing keys, and exposure of sensitive data in claims require strict validation, asymmetric signing (RS256), and payload minimization. 16 | - **Token Lifetime & Refresh Strategy:** Short-lived JWTs with secure refresh token rotation (server-side tracking, binding to client/IP) to mitigate replay attacks and long-term exposure risks. 17 | - **Revocation Challenges:** Stateless JWTs lack built-in invalidation—implement hybrid checks (e.g., short expiration, distributed deny lists, or token introspection endpoints) for compromised tokens. 18 | - **Key Management:** Secure rotation of cryptographic keys (HS256/RS256) without downtime, avoiding hardcoded secrets, and using HSMs/KMS solutions for enterprise-grade systems. 19 | - **Client-Side Storage Risks:** Mitigate XSS/CSRF vulnerabilities via HTTP-only cookies for web apps, secure mobile keystores, and avoiding local storage for tokens. 20 | - **Compliance Overheads:** GDPR, CCPA, or industry-specific regulations (HIPAA, PCI-DSS) may mandate audit logging, consent management, or encryption-at-rest for user data. 21 | - **Federated Identity Risks:** If integrating third-party IdPs (Google, Facebook), validate issuer claims, enforce email verification, and plan for IdP outage scenarios. 22 | - **Scale & Performance:** Stateless JWTs enable horizontal scaling but risk oversized tokens; monitor header size impacts on network performance and API latency. 23 | - **Observability Gaps:** Centralized logging for token issuance/errors, anomaly detection (e.g., spike in failed auth attempts), and monitoring token misuse patterns. 24 | - **Dependency Risks:** Audit third-party OAuth libraries (e.g., `passport-oauth2`, `jsonwebtoken`) for vulnerabilities and maintain update cycles to address CVEs. 25 | - **Edge Case Blast Radius:** Plan for token leakage (auto-revocation triggers), brute-force protection on auth endpoints, and OAuth2 error handling to avoid information leaks. 26 | - **Build vs. Buy Tradeoffs:** Evaluate cost/effort of self-hosted solutions (Keycloak) vs. managed services (Auth0, AWS Cognito), especially for teams lacking security expertise. 27 | 28 | **Advanced Value Adds:** 29 | - OAuth2 dynamic client registration 30 | - OpenID Connect integration for user profile data 31 | - Step-up authentication with MFA hooks 32 | - Mutual TLS for client authentication in high-risk scenarios -------------------------------------------------------------------------------- /examples/writing-feedback.md: -------------------------------------------------------------------------------- 1 | # Writing Feedback Tool Example 2 | 3 | ## Request 4 | ```json 5 | { 6 | "text": "# Rate Limiting Implementation Guide\n\nThis document describes the implementation of rate limiting in our API service. Rate limiting prevents abuse and ensures fair resource allocation.\n\nRate limits are enforced using a token bucket algorithm. Each client gets a bucket that fills at a fixed rate. When the bucket is empty, requests are rejected.\n\nTo implement rate limiting:\n1. Configure bucket size and refill rate\n2. Store bucket state in Redis\n3. Check token availability before processing requests\n4. Update bucket state after processing\n\nExample:\n```js\nconst rateLimit = {\n bucketSize: 100,\n refillRate: 10 // tokens per second\n}\n```\n\nWhen rate limit is exceeded, return 429 Too Many Requests with retry-after header.", 7 | "writing_type": "documentation" 8 | } 9 | ``` 10 | 11 | ## Response 12 | ```markdown 13 | Here's my comprehensive feedback on your Rate Limiting Implementation Guide: 14 | 15 | **1. Overall Assessment** 16 | The document provides a functional foundation but lacks depth required for production-grade implementation guidance. While core concepts are present, critical technical details and API documentation standards are underdeveloped. 17 | 18 | **2. Strengths** 19 | ✓ Clear purpose statement in opening paragraph 20 | ✓ Logical progression from concept to implementation steps 21 | ✓ Appropriate use of code fencing for example 22 | ✓ Correct identification of HTTP 429 response 23 | ✓ Concise explanation of token bucket algorithm basics 24 | 25 | **3. Areas for Improvement** 26 | • Insufficient technical details for distributed systems implementation 27 | • Missing error handling and edge case considerations 28 | • No versioning or maintenance guidance 29 | • Lack of complete API response examples 30 | • Omission of monitoring and troubleshooting recommendations 31 | 32 | **4. Specific Recommendations** 33 | 34 | **Clarity & Coherence** 35 | → Add visual diagram of token bucket mechanism 36 | → Clarify time window interpretation ("10 per second" vs sliding window) 37 | → Define "client" precisely (IP? API key? User session?) 38 | → Explain Redis storage schema and expiration policies 39 | 40 | **Grammar & Style** 41 | → Use active voice: "Each client receives" instead of "Each client gets" 42 | → Maintain parallel structure in implementation steps: 43 | - Current: "Configure... Store... Check... Update" 44 | - Improved: "Configure... Implement... Validate... Maintain" 45 | → Fix markdown escaping in code block (extra backslashes) 46 | 47 | **Structure & Organization** 48 | Add these sections: 49 | 1. Prerequisites 50 | 2. Error Handling Specifications 51 | 3. Monitoring Metrics (e.g., X-RateLimit headers) 52 | 4. Version History 53 | 5. Common Configuration Patterns 54 | 6. Troubleshooting Checklist 55 | 56 | **Content & Accuracy** 57 | Critical technical additions needed: 58 | • Distributed system coordination (Redis transactions/Lua scripting) 59 | • Burst handling and warmup strategies 60 | • Concurrent request race conditions 61 | • Redis persistence and backup considerations 62 | • Client identification methodology 63 | • Grace period implementation for near-limit cases 64 | 65 | **5. Key Action Items** 66 | 67 | **Priority Updates** 68 | 1. Add complete API response example: 69 | ```js 70 | // 429 Response Example 71 | { 72 | "error": { 73 | "code": "rate_limit_exceeded", 74 | "message": "Maximum 100 requests per minute", 75 | "retry_after": 5.2 // seconds 76 | } 77 | } 78 | Headers: 79 | X-RateLimit-Limit: 100 80 | X-RateLimit-Remaining: 0 81 | X-RateLimit-Reset: 1689876543 82 | Retry-After: 5.2 83 | ``` 84 | 85 | 2. Expand code example with Redis operations: 86 | ```js 87 | // Token consumption logic 88 | async function checkRateLimit(clientId) { 89 | const now = Date.now(); 90 | const key = `rate_limit:${clientId}`; 91 | 92 | const result = await redis.multi() 93 | .hgetall(key) 94 | .hmset(key, { 95 | tokens: Math.min( 96 | (current.tokens || bucketSize) + 97 | Math.floor((now - (current.lastRefill || now)) / 1000 * refillRate), 98 | bucketSize 99 | ), 100 | lastRefill: now 101 | }) 102 | .expire(key, 3600) 103 | .exec(); 104 | 105 | if(result.tokens < 1) throw new RateLimitError(); 106 | } 107 | ``` 108 | 109 | 3. Add troubleshooting table: 110 | 111 | | Symptom | Potential Cause | Verification Method | 112 | |-----------------------|--------------------------|---------------------------| 113 | | Consistent 429 errors | Misconfigured bucket size | Check Redis config stores | 114 | | Redis connection fails| Network ACL restrictions | Test telnet to Redis port | 115 | 116 | **Recommended Additions** 117 | • Versioning: "Rate limit configurations are versioned with API releases. Always specify limit parameters in your API contract using semantic versioning." 118 | • Monitoring: "Track these metrics: 119 | - Rejection rate by client segment 120 | - 90th percentile token consumption 121 | - Redis latency percentiles" 122 | • Maintenance: "Review rate limits quarterly using historical traffic analysis. Implement canary deployments for limit changes." 123 | 124 | **Summary** 125 | The guide effectively introduces core concepts but requires deeper technical specification and operational documentation. Focus on adding implementation details for distributed systems, comprehensive error handling examples, and maintenance procedures to make this production-ready. Maintain the current concise style while expanding technical completeness. -------------------------------------------------------------------------------- /mcp-client-config.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "mcpServers": { 3 | "mentor-mcp-server": { 4 | "command": "node", 5 | "args": [ 6 | "/path/to/mentor-mcp-server/build/index.js" 7 | ], 8 | "env": { 9 | "DEEPSEEK_API_KEY": "your_deepseek_api_key_here", 10 | "DEEPSEEK_API_BASE_URL": "https://api.deepseek.com", 11 | "DEEPSEEK_MODEL": "deepseek-reasoner", 12 | "DEEPSEEK_MAX_TOKENS": "8192", 13 | "DEEPSEEK_MAX_RETRIES": "3", 14 | "DEEPSEEK_TIMEOUT": "30000" 15 | } 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mentor-mcp-server", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "mentor-mcp-server", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@modelcontextprotocol/sdk": "^1.4.1", 13 | "@types/node": "^22.10.10", 14 | "axios": "^1.7.9", 15 | "dotenv": "^16.4.7", 16 | "openai": "^4.80.1", 17 | "typescript": "^5.7.3" 18 | } 19 | }, 20 | "node_modules/@modelcontextprotocol/sdk": { 21 | "version": "1.4.1", 22 | "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.4.1.tgz", 23 | "integrity": "sha512-wS6YC4lkUZ9QpP+/7NBTlVNiEvsnyl0xF7rRusLF+RsG0xDPc/zWR7fEEyhKnnNutGsDAZh59l/AeoWGwIb1+g==", 24 | "license": "MIT", 25 | "dependencies": { 26 | "content-type": "^1.0.5", 27 | "eventsource": "^3.0.2", 28 | "raw-body": "^3.0.0", 29 | "zod": "^3.23.8", 30 | "zod-to-json-schema": "^3.24.1" 31 | }, 32 | "engines": { 33 | "node": ">=18" 34 | } 35 | }, 36 | "node_modules/@types/node": { 37 | "version": "22.10.10", 38 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.10.tgz", 39 | "integrity": "sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==", 40 | "license": "MIT", 41 | "dependencies": { 42 | "undici-types": "~6.20.0" 43 | } 44 | }, 45 | "node_modules/@types/node-fetch": { 46 | "version": "2.6.12", 47 | "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", 48 | "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", 49 | "license": "MIT", 50 | "dependencies": { 51 | "@types/node": "*", 52 | "form-data": "^4.0.0" 53 | } 54 | }, 55 | "node_modules/abort-controller": { 56 | "version": "3.0.0", 57 | "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", 58 | "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", 59 | "license": "MIT", 60 | "dependencies": { 61 | "event-target-shim": "^5.0.0" 62 | }, 63 | "engines": { 64 | "node": ">=6.5" 65 | } 66 | }, 67 | "node_modules/agentkeepalive": { 68 | "version": "4.6.0", 69 | "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", 70 | "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", 71 | "license": "MIT", 72 | "dependencies": { 73 | "humanize-ms": "^1.2.1" 74 | }, 75 | "engines": { 76 | "node": ">= 8.0.0" 77 | } 78 | }, 79 | "node_modules/asynckit": { 80 | "version": "0.4.0", 81 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 82 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", 83 | "license": "MIT" 84 | }, 85 | "node_modules/axios": { 86 | "version": "1.7.9", 87 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", 88 | "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", 89 | "license": "MIT", 90 | "dependencies": { 91 | "follow-redirects": "^1.15.6", 92 | "form-data": "^4.0.0", 93 | "proxy-from-env": "^1.1.0" 94 | } 95 | }, 96 | "node_modules/bytes": { 97 | "version": "3.1.2", 98 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 99 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 100 | "license": "MIT", 101 | "engines": { 102 | "node": ">= 0.8" 103 | } 104 | }, 105 | "node_modules/combined-stream": { 106 | "version": "1.0.8", 107 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 108 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 109 | "license": "MIT", 110 | "dependencies": { 111 | "delayed-stream": "~1.0.0" 112 | }, 113 | "engines": { 114 | "node": ">= 0.8" 115 | } 116 | }, 117 | "node_modules/content-type": { 118 | "version": "1.0.5", 119 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 120 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", 121 | "license": "MIT", 122 | "engines": { 123 | "node": ">= 0.6" 124 | } 125 | }, 126 | "node_modules/delayed-stream": { 127 | "version": "1.0.0", 128 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 129 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 130 | "license": "MIT", 131 | "engines": { 132 | "node": ">=0.4.0" 133 | } 134 | }, 135 | "node_modules/depd": { 136 | "version": "2.0.0", 137 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 138 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 139 | "license": "MIT", 140 | "engines": { 141 | "node": ">= 0.8" 142 | } 143 | }, 144 | "node_modules/dotenv": { 145 | "version": "16.4.7", 146 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", 147 | "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", 148 | "license": "BSD-2-Clause", 149 | "engines": { 150 | "node": ">=12" 151 | }, 152 | "funding": { 153 | "url": "https://dotenvx.com" 154 | } 155 | }, 156 | "node_modules/event-target-shim": { 157 | "version": "5.0.1", 158 | "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", 159 | "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", 160 | "license": "MIT", 161 | "engines": { 162 | "node": ">=6" 163 | } 164 | }, 165 | "node_modules/eventsource": { 166 | "version": "3.0.2", 167 | "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.2.tgz", 168 | "integrity": "sha512-YolzkJNxsTL3tCJMWFxpxtG2sCjbZ4LQUBUrkdaJK0ub0p6lmJt+2+1SwhKjLc652lpH9L/79Ptez972H9tphw==", 169 | "license": "MIT", 170 | "dependencies": { 171 | "eventsource-parser": "^3.0.0" 172 | }, 173 | "engines": { 174 | "node": ">=18.0.0" 175 | } 176 | }, 177 | "node_modules/eventsource-parser": { 178 | "version": "3.0.0", 179 | "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.0.tgz", 180 | "integrity": "sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==", 181 | "license": "MIT", 182 | "engines": { 183 | "node": ">=18.0.0" 184 | } 185 | }, 186 | "node_modules/follow-redirects": { 187 | "version": "1.15.9", 188 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", 189 | "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", 190 | "funding": [ 191 | { 192 | "type": "individual", 193 | "url": "https://github.com/sponsors/RubenVerborgh" 194 | } 195 | ], 196 | "license": "MIT", 197 | "engines": { 198 | "node": ">=4.0" 199 | }, 200 | "peerDependenciesMeta": { 201 | "debug": { 202 | "optional": true 203 | } 204 | } 205 | }, 206 | "node_modules/form-data": { 207 | "version": "4.0.1", 208 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", 209 | "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", 210 | "license": "MIT", 211 | "dependencies": { 212 | "asynckit": "^0.4.0", 213 | "combined-stream": "^1.0.8", 214 | "mime-types": "^2.1.12" 215 | }, 216 | "engines": { 217 | "node": ">= 6" 218 | } 219 | }, 220 | "node_modules/form-data-encoder": { 221 | "version": "1.7.2", 222 | "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", 223 | "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", 224 | "license": "MIT" 225 | }, 226 | "node_modules/formdata-node": { 227 | "version": "4.4.1", 228 | "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", 229 | "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", 230 | "license": "MIT", 231 | "dependencies": { 232 | "node-domexception": "1.0.0", 233 | "web-streams-polyfill": "4.0.0-beta.3" 234 | }, 235 | "engines": { 236 | "node": ">= 12.20" 237 | } 238 | }, 239 | "node_modules/http-errors": { 240 | "version": "2.0.0", 241 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 242 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 243 | "license": "MIT", 244 | "dependencies": { 245 | "depd": "2.0.0", 246 | "inherits": "2.0.4", 247 | "setprototypeof": "1.2.0", 248 | "statuses": "2.0.1", 249 | "toidentifier": "1.0.1" 250 | }, 251 | "engines": { 252 | "node": ">= 0.8" 253 | } 254 | }, 255 | "node_modules/humanize-ms": { 256 | "version": "1.2.1", 257 | "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", 258 | "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", 259 | "license": "MIT", 260 | "dependencies": { 261 | "ms": "^2.0.0" 262 | } 263 | }, 264 | "node_modules/iconv-lite": { 265 | "version": "0.6.3", 266 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", 267 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", 268 | "license": "MIT", 269 | "dependencies": { 270 | "safer-buffer": ">= 2.1.2 < 3.0.0" 271 | }, 272 | "engines": { 273 | "node": ">=0.10.0" 274 | } 275 | }, 276 | "node_modules/inherits": { 277 | "version": "2.0.4", 278 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 279 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 280 | "license": "ISC" 281 | }, 282 | "node_modules/mime-db": { 283 | "version": "1.52.0", 284 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 285 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 286 | "license": "MIT", 287 | "engines": { 288 | "node": ">= 0.6" 289 | } 290 | }, 291 | "node_modules/mime-types": { 292 | "version": "2.1.35", 293 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 294 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 295 | "license": "MIT", 296 | "dependencies": { 297 | "mime-db": "1.52.0" 298 | }, 299 | "engines": { 300 | "node": ">= 0.6" 301 | } 302 | }, 303 | "node_modules/ms": { 304 | "version": "2.1.3", 305 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 306 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 307 | "license": "MIT" 308 | }, 309 | "node_modules/node-domexception": { 310 | "version": "1.0.0", 311 | "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", 312 | "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", 313 | "funding": [ 314 | { 315 | "type": "github", 316 | "url": "https://github.com/sponsors/jimmywarting" 317 | }, 318 | { 319 | "type": "github", 320 | "url": "https://paypal.me/jimmywarting" 321 | } 322 | ], 323 | "license": "MIT", 324 | "engines": { 325 | "node": ">=10.5.0" 326 | } 327 | }, 328 | "node_modules/node-fetch": { 329 | "version": "2.7.0", 330 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", 331 | "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", 332 | "license": "MIT", 333 | "dependencies": { 334 | "whatwg-url": "^5.0.0" 335 | }, 336 | "engines": { 337 | "node": "4.x || >=6.0.0" 338 | }, 339 | "peerDependencies": { 340 | "encoding": "^0.1.0" 341 | }, 342 | "peerDependenciesMeta": { 343 | "encoding": { 344 | "optional": true 345 | } 346 | } 347 | }, 348 | "node_modules/openai": { 349 | "version": "4.80.1", 350 | "resolved": "https://registry.npmjs.org/openai/-/openai-4.80.1.tgz", 351 | "integrity": "sha512-+6+bbXFwbIE88foZsBEt36bPkgZPdyFN82clAXG61gnHb2gXdZApDyRrcAHqEtpYICywpqaNo57kOm9dtnb7Cw==", 352 | "license": "Apache-2.0", 353 | "dependencies": { 354 | "@types/node": "^18.11.18", 355 | "@types/node-fetch": "^2.6.4", 356 | "abort-controller": "^3.0.0", 357 | "agentkeepalive": "^4.2.1", 358 | "form-data-encoder": "1.7.2", 359 | "formdata-node": "^4.3.2", 360 | "node-fetch": "^2.6.7" 361 | }, 362 | "bin": { 363 | "openai": "bin/cli" 364 | }, 365 | "peerDependencies": { 366 | "ws": "^8.18.0", 367 | "zod": "^3.23.8" 368 | }, 369 | "peerDependenciesMeta": { 370 | "ws": { 371 | "optional": true 372 | }, 373 | "zod": { 374 | "optional": true 375 | } 376 | } 377 | }, 378 | "node_modules/openai/node_modules/@types/node": { 379 | "version": "18.19.74", 380 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.74.tgz", 381 | "integrity": "sha512-HMwEkkifei3L605gFdV+/UwtpxP6JSzM+xFk2Ia6DNFSwSVBRh9qp5Tgf4lNFOMfPVuU0WnkcWpXZpgn5ufO4A==", 382 | "license": "MIT", 383 | "dependencies": { 384 | "undici-types": "~5.26.4" 385 | } 386 | }, 387 | "node_modules/openai/node_modules/undici-types": { 388 | "version": "5.26.5", 389 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", 390 | "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", 391 | "license": "MIT" 392 | }, 393 | "node_modules/proxy-from-env": { 394 | "version": "1.1.0", 395 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 396 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", 397 | "license": "MIT" 398 | }, 399 | "node_modules/raw-body": { 400 | "version": "3.0.0", 401 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", 402 | "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", 403 | "license": "MIT", 404 | "dependencies": { 405 | "bytes": "3.1.2", 406 | "http-errors": "2.0.0", 407 | "iconv-lite": "0.6.3", 408 | "unpipe": "1.0.0" 409 | }, 410 | "engines": { 411 | "node": ">= 0.8" 412 | } 413 | }, 414 | "node_modules/safer-buffer": { 415 | "version": "2.1.2", 416 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 417 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 418 | "license": "MIT" 419 | }, 420 | "node_modules/setprototypeof": { 421 | "version": "1.2.0", 422 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 423 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", 424 | "license": "ISC" 425 | }, 426 | "node_modules/statuses": { 427 | "version": "2.0.1", 428 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 429 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 430 | "license": "MIT", 431 | "engines": { 432 | "node": ">= 0.8" 433 | } 434 | }, 435 | "node_modules/toidentifier": { 436 | "version": "1.0.1", 437 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 438 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 439 | "license": "MIT", 440 | "engines": { 441 | "node": ">=0.6" 442 | } 443 | }, 444 | "node_modules/tr46": { 445 | "version": "0.0.3", 446 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 447 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", 448 | "license": "MIT" 449 | }, 450 | "node_modules/typescript": { 451 | "version": "5.7.3", 452 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", 453 | "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", 454 | "license": "Apache-2.0", 455 | "bin": { 456 | "tsc": "bin/tsc", 457 | "tsserver": "bin/tsserver" 458 | }, 459 | "engines": { 460 | "node": ">=14.17" 461 | } 462 | }, 463 | "node_modules/undici-types": { 464 | "version": "6.20.0", 465 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", 466 | "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", 467 | "license": "MIT" 468 | }, 469 | "node_modules/unpipe": { 470 | "version": "1.0.0", 471 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 472 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 473 | "license": "MIT", 474 | "engines": { 475 | "node": ">= 0.8" 476 | } 477 | }, 478 | "node_modules/web-streams-polyfill": { 479 | "version": "4.0.0-beta.3", 480 | "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", 481 | "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", 482 | "license": "MIT", 483 | "engines": { 484 | "node": ">= 14" 485 | } 486 | }, 487 | "node_modules/webidl-conversions": { 488 | "version": "3.0.1", 489 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 490 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", 491 | "license": "BSD-2-Clause" 492 | }, 493 | "node_modules/whatwg-url": { 494 | "version": "5.0.0", 495 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 496 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 497 | "license": "MIT", 498 | "dependencies": { 499 | "tr46": "~0.0.3", 500 | "webidl-conversions": "^3.0.0" 501 | } 502 | }, 503 | "node_modules/zod": { 504 | "version": "3.24.1", 505 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", 506 | "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", 507 | "license": "MIT", 508 | "funding": { 509 | "url": "https://github.com/sponsors/colinhacks" 510 | } 511 | }, 512 | "node_modules/zod-to-json-schema": { 513 | "version": "3.24.1", 514 | "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.1.tgz", 515 | "integrity": "sha512-3h08nf3Vw3Wl3PK+q3ow/lIil81IT2Oa7YpQyUUDsEWbXveMesdfK1xBd2RhCkynwZndAxixji/7SYJJowr62w==", 516 | "license": "ISC", 517 | "peerDependencies": { 518 | "zod": "^3.24.1" 519 | } 520 | } 521 | } 522 | } 523 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mentor-mcp-server", 3 | "version": "1.0.0", 4 | "description": "MCP server that provides insightful feedback and guidance on various types of user requests", 5 | "type": "module", 6 | "main": "build/index.js", 7 | "scripts": { 8 | "build": "tsc && chmod +x build/index.js", 9 | "start": "node build/index.js", 10 | "dev": "tsc -w", 11 | "clean": "rm -rf build", 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "keywords": ["mcp", "mentor", "feedback", "llm"], 15 | "author": "", 16 | "license": "ISC", 17 | "dependencies": { 18 | "@modelcontextprotocol/sdk": "^1.4.1", 19 | "@types/node": "^22.10.10", 20 | "axios": "^1.7.9", 21 | "dotenv": "^16.4.7", 22 | "typescript": "^5.7.3", 23 | "openai": "^4.80.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/api/deepseek/deepseek.ts: -------------------------------------------------------------------------------- 1 | import OpenAI from 'openai'; 2 | import type { LLMResponse, ChatMessage } from '../../types/index.js'; 3 | import { config } from '../../config.js'; 4 | import { sanitizeInput } from '../../utils/prompt.js'; 5 | 6 | /** 7 | * Rate limiter implementation using token bucket algorithm 8 | */ 9 | class RateLimiter { 10 | private tokens: number; 11 | private readonly maxTokens: number; 12 | private readonly refillRate: number; 13 | private lastRefill: number; 14 | 15 | constructor(maxTokens: number = 50, refillRate: number = 10) { 16 | this.tokens = maxTokens; 17 | this.maxTokens = maxTokens; 18 | this.refillRate = refillRate; // tokens per second 19 | this.lastRefill = Date.now(); 20 | } 21 | 22 | private refillTokens(): void { 23 | const now = Date.now(); 24 | const timePassed = (now - this.lastRefill) / 1000; // convert to seconds 25 | const tokensToAdd = Math.floor(timePassed * this.refillRate); 26 | 27 | this.tokens = Math.min( 28 | this.maxTokens, 29 | this.tokens + tokensToAdd 30 | ); 31 | this.lastRefill = now; 32 | } 33 | 34 | public tryConsume(): boolean { 35 | this.refillTokens(); 36 | if (this.tokens >= 1) { 37 | this.tokens -= 1; 38 | return true; 39 | } 40 | return false; 41 | } 42 | } 43 | 44 | /** 45 | * Deepseek API client class using OpenAI SDK with deepseek-reasoner model 46 | */ 47 | class DeepseekClient { 48 | private readonly client: OpenAI; 49 | private readonly rateLimiter: RateLimiter; 50 | 51 | constructor() { 52 | this.client = new OpenAI({ 53 | baseURL: config.api.baseUrl || 'https://api.deepseek.com', 54 | apiKey: config.api.apiKey, 55 | defaultQuery: { model: 'deepseek-reasoner' } 56 | }); 57 | 58 | this.rateLimiter = new RateLimiter( 59 | 50, // max 50 requests 60 | 10 // refill 10 tokens per second 61 | ); 62 | } 63 | 64 | /** 65 | * Makes a call to the Deepseek API with exponential backoff retry 66 | */ 67 | private async retryWithExponentialBackoff( 68 | operation: () => Promise, 69 | maxRetries: number = config.api.maxRetries, 70 | baseDelay: number = 1000 71 | ): Promise { 72 | let lastError: Error | null = null; 73 | 74 | for (let attempt = 0; attempt < maxRetries; attempt++) { 75 | try { 76 | return await operation(); 77 | } catch (error) { 78 | lastError = error as Error; 79 | if (error instanceof OpenAI.APIError && error.status === 429) { 80 | const delay = baseDelay * Math.pow(2, attempt); 81 | await new Promise(resolve => setTimeout(resolve, delay)); 82 | continue; 83 | } 84 | throw error; 85 | } 86 | } 87 | 88 | throw lastError || new Error('Max retries exceeded'); 89 | } 90 | 91 | /** 92 | * Makes a call to the Deepseek API using the reasoner model 93 | */ 94 | public async makeApiCall( 95 | prompt: string, 96 | systemPrompt: string = 'You are a helpful AI assistant.', 97 | previousMessages: ChatMessage[] = [] 98 | ): Promise { 99 | // Check rate limit 100 | if (!this.rateLimiter.tryConsume()) { 101 | return { 102 | text: '', 103 | isError: true, 104 | errorMessage: 'Rate limit exceeded. Please try again later.' 105 | }; 106 | } 107 | 108 | try { 109 | // Sanitize inputs 110 | const sanitizedPrompt = sanitizeInput(prompt); 111 | const sanitizedSystemPrompt = sanitizeInput(systemPrompt); 112 | 113 | // Prepare messages, filtering out any previous reasoning_content 114 | const messages = [ 115 | { role: 'system' as const, content: sanitizedSystemPrompt }, 116 | ...previousMessages.map(msg => ({ 117 | role: msg.role, 118 | content: msg.content 119 | })), 120 | { role: 'user' as const, content: sanitizedPrompt } 121 | ]; 122 | 123 | const response = await this.retryWithExponentialBackoff(async () => { 124 | const completion = await this.client.chat.completions.create({ 125 | model: 'deepseek-reasoner', 126 | messages, 127 | max_tokens: config.api.maxTokens || 4096 128 | }); 129 | 130 | return completion; 131 | }); 132 | 133 | // Extract both the reasoning and final content 134 | const reasoningContent = (response.choices[0]?.message as any)?.reasoning_content || ''; 135 | const finalContent = response.choices[0]?.message?.content || ''; 136 | 137 | return { 138 | text: finalContent, 139 | reasoning: reasoningContent, 140 | isError: false, 141 | }; 142 | } catch (error) { 143 | console.error('Deepseek API error:', error); 144 | let errorMessage = 'Unknown error occurred'; 145 | 146 | if (error instanceof OpenAI.APIError) { 147 | errorMessage = error.message; 148 | } else if (error instanceof Error) { 149 | errorMessage = error.message; 150 | } 151 | 152 | return { 153 | text: '', 154 | isError: true, 155 | errorMessage 156 | }; 157 | } 158 | } 159 | 160 | /** 161 | * Checks if a request can be made (for external rate limit checking) 162 | */ 163 | public checkRateLimit(): boolean { 164 | return this.rateLimiter.tryConsume(); 165 | } 166 | } 167 | 168 | // Export a singleton instance 169 | export const deepseekClient = new DeepseekClient(); 170 | 171 | // Export the main interface functions 172 | export const makeDeepseekAPICall = ( 173 | prompt: string, 174 | systemPrompt?: string, 175 | previousMessages: ChatMessage[] = [] 176 | ) => deepseekClient.makeApiCall(prompt, systemPrompt, previousMessages); 177 | 178 | export const checkRateLimit = () => deepseekClient.checkRateLimit(); -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | import type { ServerConfig, APIConfig } from './types/index.js'; 2 | 3 | // Get configuration from process.env which is populated by the MCP client 4 | const apiConfig: APIConfig = { 5 | apiKey: process.env.DEEPSEEK_API_KEY || '', 6 | baseUrl: process.env.DEEPSEEK_API_BASE_URL || 'https://api.deepseek.com', 7 | model: process.env.DEEPSEEK_MODEL || 'deepseek-reasoner', 8 | maxRetries: parseInt(process.env.DEEPSEEK_MAX_RETRIES || '3', 10), 9 | timeout: parseInt(process.env.DEEPSEEK_TIMEOUT || '30000', 10), 10 | maxTokens: parseInt(process.env.DEEPSEEK_MAX_TOKENS || '8192', 10), 11 | }; 12 | 13 | // Validate required configuration 14 | if (!apiConfig.apiKey) { 15 | throw new Error('DEEPSEEK_API_KEY is required'); 16 | } 17 | 18 | // Validate model name 19 | if (!apiConfig.model.startsWith('deepseek-')) { 20 | throw new Error('DEEPSEEK_MODEL must be a valid Deepseek model name (e.g., deepseek-reasoner)'); 21 | } 22 | 23 | // Validate numeric values 24 | if (apiConfig.maxTokens < 1 || apiConfig.maxTokens > 8192) { 25 | throw new Error('DEEPSEEK_MAX_TOKENS must be between 1 and 8192'); 26 | } 27 | 28 | if (apiConfig.maxRetries < 1) { 29 | throw new Error('DEEPSEEK_MAX_RETRIES must be at least 1'); 30 | } 31 | 32 | if (apiConfig.timeout < 1000) { 33 | throw new Error('DEEPSEEK_TIMEOUT must be at least 1000ms'); 34 | } 35 | 36 | export const config: ServerConfig = { 37 | serverName: 'mentor-mcp-server', 38 | serverVersion: '1.0.0', 39 | api: apiConfig, 40 | }; -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import './server.js'; -------------------------------------------------------------------------------- /src/server.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import { Server } from "@modelcontextprotocol/sdk/server/index.js"; 3 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 4 | import { 5 | ListToolsRequestSchema, 6 | CallToolRequestSchema, 7 | ErrorCode, 8 | McpError, 9 | } from "@modelcontextprotocol/sdk/types.js"; 10 | import { config } from "./config.js"; 11 | import * as secondOpinion from "./tools/second-opinion/index.js"; 12 | import * as codeReview from "./tools/code-review/index.js"; 13 | import * as designCritique from "./tools/design-critique/index.js"; 14 | import * as writingFeedback from "./tools/writing-feedback/index.js"; 15 | import * as brainstormEnhancements from "./tools/brainstorm-enhancements/index.js"; 16 | import { 17 | isCodeReviewArgs, 18 | isDesignCritiqueArgs, 19 | isWritingFeedbackArgs, 20 | isBrainstormEnhancementsArgs, 21 | toolResponseToServerResult, 22 | } from "./types/index.js"; 23 | 24 | /** 25 | * MentorServer class implements an MCP server that provides mentorship and feedback tools. 26 | * It uses the Deepseek API to generate insightful responses for various types of requests. 27 | */ 28 | class MentorServer { 29 | private server: Server; 30 | private isShuttingDown: boolean = false; 31 | 32 | constructor() { 33 | // Initialize the MCP server with basic configuration 34 | this.server = new Server( 35 | { 36 | name: config.serverName, 37 | version: config.serverVersion, 38 | }, 39 | { 40 | capabilities: { 41 | tools: {}, 42 | }, 43 | } 44 | ); 45 | 46 | this.setupRequestHandlers(); 47 | this.setupErrorHandler(); 48 | this.setupSignalHandlers(); 49 | } 50 | 51 | /** 52 | * Sets up request handlers for the MCP server 53 | */ 54 | private setupRequestHandlers(): void { 55 | // Register tool listing handler 56 | this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ 57 | tools: [ 58 | secondOpinion.definition, 59 | codeReview.definition, 60 | designCritique.definition, 61 | writingFeedback.definition, 62 | brainstormEnhancements.definition, 63 | ], 64 | })); 65 | 66 | // Register tool execution handler 67 | this.server.setRequestHandler(CallToolRequestSchema, async (request) => { 68 | // Check if server is shutting down 69 | if (this.isShuttingDown) { 70 | throw new McpError( 71 | ErrorCode.InternalError, 72 | "Server is shutting down" 73 | ); 74 | } 75 | 76 | const { name, arguments: args } = request.params; 77 | 78 | try { 79 | let response; 80 | switch (name) { 81 | case "second_opinion": { 82 | if (!args || !('user_request' in args) || typeof args.user_request !== 'string') { 83 | throw new McpError( 84 | ErrorCode.InvalidParams, 85 | "Missing required parameter: user_request" 86 | ); 87 | } 88 | response = await secondOpinion.handler({ user_request: args.user_request }); 89 | break; 90 | } 91 | 92 | case "code_review": { 93 | if (!isCodeReviewArgs(args)) { 94 | throw new McpError( 95 | ErrorCode.InvalidParams, 96 | "Invalid parameters for code review" 97 | ); 98 | } 99 | response = await codeReview.handler(args); 100 | break; 101 | } 102 | 103 | case "design_critique": { 104 | if (!isDesignCritiqueArgs(args)) { 105 | throw new McpError( 106 | ErrorCode.InvalidParams, 107 | "Invalid parameters for design critique" 108 | ); 109 | } 110 | response = await designCritique.handler(args); 111 | break; 112 | } 113 | 114 | case "writing_feedback": { 115 | if (!isWritingFeedbackArgs(args)) { 116 | throw new McpError( 117 | ErrorCode.InvalidParams, 118 | "Invalid parameters for writing feedback" 119 | ); 120 | } 121 | response = await writingFeedback.handler(args); 122 | break; 123 | } 124 | 125 | case "brainstorm_enhancements": { 126 | if (!isBrainstormEnhancementsArgs(args)) { 127 | throw new McpError( 128 | ErrorCode.InvalidParams, 129 | "Invalid parameters for brainstorm enhancements" 130 | ); 131 | } 132 | response = await brainstormEnhancements.handler(args); 133 | break; 134 | } 135 | 136 | default: 137 | throw new McpError( 138 | ErrorCode.MethodNotFound, 139 | `Tool not found: ${name}` 140 | ); 141 | } 142 | 143 | // Convert tool response to server result format 144 | return toolResponseToServerResult(response); 145 | } catch (error) { 146 | // Handle errors that aren't already McpErrors 147 | if (!(error instanceof McpError)) { 148 | console.error(`Error executing tool ${name}:`, error); 149 | throw new McpError( 150 | ErrorCode.InternalError, 151 | `Internal server error while executing tool ${name}` 152 | ); 153 | } 154 | throw error; 155 | } 156 | }); 157 | } 158 | 159 | /** 160 | * Sets up the error handler for the MCP server 161 | */ 162 | private setupErrorHandler(): void { 163 | this.server.onerror = (error) => { 164 | console.error("[MCP Error]", error); 165 | }; 166 | } 167 | 168 | /** 169 | * Sets up signal handlers for graceful shutdown 170 | */ 171 | private setupSignalHandlers(): void { 172 | const signals: NodeJS.Signals[] = ['SIGINT', 'SIGTERM']; 173 | 174 | signals.forEach(signal => { 175 | process.on(signal, async () => { 176 | await this.stop(); 177 | process.exit(0); 178 | }); 179 | }); 180 | 181 | // Handle uncaught exceptions 182 | process.on('uncaughtException', async (error) => { 183 | console.error('Uncaught exception:', error); 184 | await this.stop(); 185 | process.exit(1); 186 | }); 187 | 188 | // Handle unhandled promise rejections 189 | process.on('unhandledRejection', async (reason) => { 190 | console.error('Unhandled rejection:', reason); 191 | await this.stop(); 192 | process.exit(1); 193 | }); 194 | } 195 | 196 | /** 197 | * Starts the MCP server 198 | */ 199 | async start(): Promise { 200 | try { 201 | const transport = new StdioServerTransport(); 202 | await this.server.connect(transport); 203 | console.error("Mentor MCP server running on stdio"); 204 | } catch (error) { 205 | console.error("Failed to start server:", error); 206 | process.exit(1); 207 | } 208 | } 209 | 210 | /** 211 | * Stops the MCP server gracefully 212 | */ 213 | async stop(): Promise { 214 | if (this.isShuttingDown) { 215 | return; 216 | } 217 | 218 | this.isShuttingDown = true; 219 | console.error("Shutting down server..."); 220 | 221 | try { 222 | await this.server.close(); 223 | console.error("Server stopped"); 224 | } catch (error) { 225 | console.error("Error during shutdown:", error); 226 | process.exit(1); 227 | } 228 | } 229 | } 230 | 231 | // Create and start the server 232 | const server = new MentorServer(); 233 | server.start().catch((error) => { 234 | console.error("Server startup error:", error); 235 | process.exit(1); 236 | }); -------------------------------------------------------------------------------- /src/tools/brainstorm-enhancements/brainstorm-enhancements.ts: -------------------------------------------------------------------------------- 1 | import type { ToolDefinition, BrainstormEnhancementsArgs, ToolResponse } from '../../types/index.js'; 2 | import { makeDeepseekAPICall, checkRateLimit } from '../../api/deepseek/deepseek.js'; 3 | import { createPrompt, PromptTemplate, sanitizeInput } from '../../utils/prompt.js'; 4 | 5 | /** 6 | * System prompt for the brainstorm enhancements tool 7 | */ 8 | const SYSTEM_PROMPT = `You are an innovative product strategist and creative thinker with expertise in 9 | various domains. Your role is to generate creative and practical ideas for improving concepts, 10 | products, or features. Focus on: 11 | 12 | 1. Innovation and creativity 13 | 2. Technical feasibility 14 | 3. User value and impact 15 | 4. Market differentiation 16 | 5. Implementation complexity 17 | 6. Resource considerations 18 | 7. Competitive advantage 19 | 20 | Generate diverse, actionable ideas that balance innovation with practicality. 21 | Consider both immediate improvements and long-term possibilities. 22 | Provide context and rationale for each suggestion.`; 23 | 24 | /** 25 | * Prompt template for brainstorming enhancements 26 | */ 27 | const PROMPT_TEMPLATE: PromptTemplate = { 28 | template: `Concept to Enhance: {concept} 29 | 30 | Please brainstorm potential improvements and enhancements, considering: 31 | 32 | 1. Core Functionality 33 | - Essential features 34 | - Performance aspects 35 | - Reliability improvements 36 | - Scalability considerations 37 | 38 | 2. User Experience 39 | - Usability enhancements 40 | - Interface improvements 41 | - Accessibility features 42 | - Personalization options 43 | 44 | 3. Technical Innovation 45 | - Emerging technologies 46 | - Novel approaches 47 | - Integration possibilities 48 | - Automation opportunities 49 | 50 | 4. Market Differentiation 51 | - Competitive advantages 52 | - Unique selling points 53 | - Market trends 54 | - User demands 55 | 56 | 5. Implementation Considerations 57 | - Technical feasibility 58 | - Resource requirements 59 | - Timeline estimates 60 | - Potential challenges 61 | 62 | Format your response with clear sections for: 63 | 1. Quick Wins (immediate, low-effort improvements) 64 | 2. Strategic Enhancements (medium-term, moderate complexity) 65 | 3. Transformative Ideas (long-term, innovative solutions) 66 | 4. Implementation Recommendations 67 | 68 | For each suggestion, provide: 69 | - Clear description 70 | - Expected impact 71 | - Implementation complexity 72 | - Resource requirements 73 | - Potential challenges`, 74 | systemPrompt: SYSTEM_PROMPT 75 | }; 76 | 77 | /** 78 | * Tool definition for the brainstorm enhancements tool 79 | */ 80 | export const definition: ToolDefinition = { 81 | name: 'brainstorm_enhancements', 82 | description: 'Generates creative ideas for improving a given concept, product, or feature, focusing on innovation, feasibility, and user value.', 83 | inputSchema: { 84 | type: 'object', 85 | properties: { 86 | concept: { 87 | type: 'string', 88 | description: 'A description of the concept, product, or feature to enhance', 89 | }, 90 | }, 91 | required: ['concept'], 92 | }, 93 | }; 94 | 95 | /** 96 | * Handles the execution of the brainstorm enhancements tool 97 | * 98 | * @param args - Tool arguments containing the concept to enhance 99 | * @returns Tool response containing enhancement suggestions 100 | */ 101 | export async function handler(args: unknown): Promise { 102 | // Check rate limit first 103 | if (!checkRateLimit()) { 104 | return { 105 | content: [ 106 | { 107 | type: 'text', 108 | text: 'Rate limit exceeded. Please try again later.', 109 | }, 110 | ], 111 | isError: true, 112 | }; 113 | } 114 | 115 | // Validate arguments 116 | if (!args || typeof args !== 'object') { 117 | return { 118 | content: [ 119 | { 120 | type: 'text', 121 | text: 'Invalid arguments provided.', 122 | }, 123 | ], 124 | isError: true, 125 | }; 126 | } 127 | 128 | try { 129 | // Type guard for BrainstormEnhancementsArgs 130 | if (!('concept' in args) || typeof args.concept !== 'string') { 131 | return { 132 | content: [ 133 | { 134 | type: 'text', 135 | text: 'Concept parameter is required and must be a string.', 136 | }, 137 | ], 138 | isError: true, 139 | }; 140 | } 141 | 142 | const typedArgs = args as BrainstormEnhancementsArgs; 143 | 144 | // Sanitize input 145 | const sanitizedConcept = sanitizeInput(typedArgs.concept); 146 | 147 | // Create the complete prompt 148 | const prompt = createPrompt(PROMPT_TEMPLATE, { 149 | concept: sanitizedConcept, 150 | }); 151 | 152 | // Make the API call 153 | const response = await makeDeepseekAPICall(prompt, SYSTEM_PROMPT); 154 | 155 | if (response.isError) { 156 | return { 157 | content: [ 158 | { 159 | type: 'text', 160 | text: `Error generating enhancement ideas: ${response.errorMessage || 'Unknown error'}`, 161 | }, 162 | ], 163 | isError: true, 164 | }; 165 | } 166 | 167 | // Return the formatted response 168 | return { 169 | content: [ 170 | { 171 | type: 'text', 172 | text: response.text, 173 | }, 174 | ], 175 | }; 176 | } catch (error) { 177 | console.error('Brainstorm enhancements tool error:', error); 178 | return { 179 | content: [ 180 | { 181 | type: 'text', 182 | text: `Error processing enhancement ideas: ${error instanceof Error ? error.message : 'Unknown error'}`, 183 | }, 184 | ], 185 | isError: true, 186 | }; 187 | } 188 | } -------------------------------------------------------------------------------- /src/tools/brainstorm-enhancements/index.ts: -------------------------------------------------------------------------------- 1 | export { definition, handler } from './brainstorm-enhancements.js'; -------------------------------------------------------------------------------- /src/tools/code-review/code-review.ts: -------------------------------------------------------------------------------- 1 | import type { ToolDefinition, CodeReviewArgs, ToolResponse } from '../../types/index.js'; 2 | import { makeDeepseekAPICall, checkRateLimit } from '../../api/deepseek/deepseek.js'; 3 | import { readFileContent } from '../../utils/file.js'; 4 | import { createPrompt, PromptTemplate, sanitizeInput } from '../../utils/prompt.js'; 5 | 6 | /** 7 | * System prompt for the code review tool 8 | */ 9 | const SYSTEM_PROMPT = `You are an expert code reviewer with deep knowledge of software development best practices, 10 | security considerations, and performance optimization. Your task is to analyze code and provide detailed, 11 | actionable feedback focusing on: 12 | 13 | 1. Potential bugs and logic issues 14 | 2. Security vulnerabilities 15 | 3. Performance bottlenecks 16 | 4. Code style and maintainability 17 | 5. Best practices and patterns 18 | 6. Possible improvements 19 | 20 | Format your response as a clear, structured analysis with sections for different types of findings. 21 | Be specific and provide examples or suggestions where applicable.`; 22 | 23 | /** 24 | * Prompt template for code review 25 | */ 26 | const PROMPT_TEMPLATE: PromptTemplate = { 27 | template: `Review the following {language} code and provide comprehensive feedback: 28 | 29 | \`\`\`{language} 30 | {code} 31 | \`\`\` 32 | 33 | Please analyze the code for: 34 | - Potential bugs or logic errors 35 | - Security vulnerabilities 36 | - Performance optimization opportunities 37 | - Code style and maintainability issues 38 | - Adherence to {language} best practices 39 | - Possible improvements or alternative approaches 40 | 41 | Format your response with clear sections for: 42 | 1. Critical Issues (if any) 43 | 2. Security Concerns 44 | 3. Performance Considerations 45 | 4. Code Style & Best Practices 46 | 5. Suggested Improvements`, 47 | systemPrompt: SYSTEM_PROMPT 48 | }; 49 | 50 | /** 51 | * Tool definition for the code review tool 52 | */ 53 | export const definition: ToolDefinition = { 54 | name: 'code_review', 55 | description: 'Provides a code review for a given file or code snippet, focusing on potential bugs, style issues, performance bottlenecks, and security vulnerabilities.', 56 | inputSchema: { 57 | type: 'object', 58 | properties: { 59 | file_path: { 60 | type: 'string', 61 | description: 'The full path to the local file containing the code to review', 62 | }, 63 | language: { 64 | type: 'string', 65 | description: 'The programming language of the code', 66 | }, 67 | code_snippet: { 68 | type: 'string', 69 | description: 'Optional small code snippet for quick reviews (alternative to file_path)', 70 | }, 71 | }, 72 | oneOf: [ 73 | { required: ['file_path', 'language'] }, 74 | { required: ['code_snippet', 'language'] }, 75 | ], 76 | }, 77 | }; 78 | 79 | /** 80 | * Handles the execution of the code review tool 81 | * 82 | * @param args - Tool arguments containing either file path or code snippet, and language 83 | * @returns Tool response containing the code review feedback 84 | */ 85 | export async function handler(args: unknown): Promise { 86 | // Validate arguments 87 | if (!checkRateLimit()) { 88 | return { 89 | content: [ 90 | { 91 | type: 'text', 92 | text: 'Rate limit exceeded. Please try again later.', 93 | }, 94 | ], 95 | isError: true, 96 | }; 97 | } 98 | 99 | if (!args || typeof args !== 'object') { 100 | return { 101 | content: [ 102 | { 103 | type: 'text', 104 | text: 'Invalid arguments provided.', 105 | }, 106 | ], 107 | isError: true, 108 | }; 109 | } 110 | 111 | // Type guard for CodeReviewArgs 112 | if (!('language' in args) || typeof args.language !== 'string') { 113 | return { 114 | content: [ 115 | { 116 | type: 'text', 117 | text: 'Language parameter is required and must be a string.', 118 | }, 119 | ], 120 | isError: true, 121 | }; 122 | } 123 | 124 | try { 125 | let codeToReview: string; 126 | const typedArgs = args as CodeReviewArgs; 127 | 128 | // Get code from either file or snippet 129 | if (typedArgs.file_path) { 130 | try { 131 | codeToReview = await readFileContent(typedArgs.file_path); 132 | } catch (error) { 133 | return { 134 | content: [ 135 | { 136 | type: 'text', 137 | text: `Error reading file: ${error instanceof Error ? error.message : 'Unknown error'}`, 138 | }, 139 | ], 140 | isError: true, 141 | }; 142 | } 143 | } else if (typedArgs.code_snippet) { 144 | codeToReview = typedArgs.code_snippet; 145 | } else { 146 | return { 147 | content: [ 148 | { 149 | type: 'text', 150 | text: 'Either file_path or code_snippet must be provided.', 151 | }, 152 | ], 153 | isError: true, 154 | }; 155 | } 156 | 157 | // Sanitize inputs 158 | const sanitizedCode = sanitizeInput(codeToReview); 159 | const sanitizedLanguage = sanitizeInput(typedArgs.language); 160 | 161 | // Create the complete prompt 162 | const prompt = createPrompt(PROMPT_TEMPLATE, { 163 | language: sanitizedLanguage, 164 | code: sanitizedCode, 165 | }); 166 | 167 | // Make the API call 168 | const response = await makeDeepseekAPICall(prompt, SYSTEM_PROMPT); 169 | 170 | if (response.isError) { 171 | return { 172 | content: [ 173 | { 174 | type: 'text', 175 | text: `Error generating code review: ${response.errorMessage || 'Unknown error'}`, 176 | }, 177 | ], 178 | isError: true, 179 | }; 180 | } 181 | 182 | // Return the formatted response 183 | return { 184 | content: [ 185 | { 186 | type: 'text', 187 | text: response.text, 188 | }, 189 | ], 190 | }; 191 | } catch (error) { 192 | console.error('Code review tool error:', error); 193 | return { 194 | content: [ 195 | { 196 | type: 'text', 197 | text: `Error processing code review: ${error instanceof Error ? error.message : 'Unknown error'}`, 198 | }, 199 | ], 200 | isError: true, 201 | }; 202 | } 203 | } -------------------------------------------------------------------------------- /src/tools/code-review/index.ts: -------------------------------------------------------------------------------- 1 | export { definition, handler } from './code-review.js'; -------------------------------------------------------------------------------- /src/tools/design-critique/design-critique.ts: -------------------------------------------------------------------------------- 1 | import type { ToolDefinition, DesignCritiqueArgs, ToolResponse } from '../../types/index.js'; 2 | import { makeDeepseekAPICall, checkRateLimit } from '../../api/deepseek/deepseek.js'; 3 | import { createPrompt, PromptTemplate, sanitizeInput } from '../../utils/prompt.js'; 4 | 5 | /** 6 | * System prompt for the design critique tool 7 | */ 8 | const SYSTEM_PROMPT = `You are an expert design critic with extensive experience in UI/UX design, 9 | system architecture, and various design methodologies. Your role is to provide constructive feedback 10 | on designs, focusing on: 11 | 12 | 1. Usability and user experience 13 | 2. Visual design and aesthetics 14 | 3. Consistency and coherence 15 | 4. Accessibility considerations 16 | 5. Technical feasibility 17 | 6. Industry best practices 18 | 7. Potential improvements 19 | 20 | Provide clear, actionable feedback that helps improve the design while acknowledging its strengths. 21 | Structure your critique to cover both high-level concepts and specific details.`; 22 | 23 | /** 24 | * Prompt templates for different design types 25 | */ 26 | const DESIGN_TYPE_PROMPTS: Record = { 27 | 'web UI': `Analyze this web UI design focusing on: 28 | - Visual hierarchy and layout 29 | - Navigation and information architecture 30 | - Responsive design considerations 31 | - Color scheme and typography 32 | - Interactive elements and micro-interactions 33 | - Loading states and error handling 34 | - Cross-browser compatibility 35 | - Mobile responsiveness`, 36 | 37 | 'mobile app': `Analyze this mobile app design focusing on: 38 | - Platform-specific design guidelines (iOS/Android) 39 | - Touch interactions and gestures 40 | - Screen transitions and navigation flow 41 | - App state management 42 | - Offline functionality 43 | - Performance considerations 44 | - Device compatibility`, 45 | 46 | 'system architecture': `Analyze this system architecture design focusing on: 47 | - Scalability and performance 48 | - Reliability and fault tolerance 49 | - Security considerations 50 | - Data flow and management 51 | - Integration points 52 | - Deployment considerations 53 | - Monitoring and maintenance 54 | - Cost implications`, 55 | 56 | 'default': `Analyze this design focusing on: 57 | - Overall effectiveness and clarity 58 | - User experience and usability 59 | - Technical feasibility 60 | - Industry best practices 61 | - Potential improvements 62 | - Implementation considerations 63 | - Maintenance aspects` 64 | }; 65 | 66 | /** 67 | * Base prompt template for design critique 68 | */ 69 | const BASE_PROMPT_TEMPLATE: PromptTemplate = { 70 | template: `Design Type: {design_type} 71 | 72 | Design Document/Description: 73 | {design_document} 74 | 75 | {type_specific_prompts} 76 | 77 | Please provide a comprehensive critique covering: 78 | 1. Overall Assessment 79 | 2. Strengths 80 | 3. Areas for Improvement 81 | 4. Specific Recommendations 82 | 5. Implementation Considerations 83 | 84 | Focus on providing actionable feedback that can be used to improve the design.`, 85 | systemPrompt: SYSTEM_PROMPT 86 | }; 87 | 88 | /** 89 | * Tool definition for the design critique tool 90 | */ 91 | export const definition: ToolDefinition = { 92 | name: 'design_critique', 93 | description: 'Offers a critique of a design document, UI/UX mockup, or architectural diagram, focusing on usability, aesthetics, consistency, accessibility, and potential design flaws.', 94 | inputSchema: { 95 | type: 'object', 96 | properties: { 97 | design_document: { 98 | type: 'string', 99 | description: 'A description or URL to the design document/image', 100 | }, 101 | design_type: { 102 | type: 'string', 103 | description: "Type of design (e.g., 'web UI', 'system architecture', 'mobile app')", 104 | }, 105 | }, 106 | required: ['design_document', 'design_type'], 107 | }, 108 | }; 109 | 110 | /** 111 | * Handles the execution of the design critique tool 112 | * 113 | * @param args - Tool arguments containing design document and type 114 | * @returns Tool response containing the design critique 115 | */ 116 | export async function handler(args: unknown): Promise { 117 | // Check rate limit first 118 | if (!checkRateLimit()) { 119 | return { 120 | content: [ 121 | { 122 | type: 'text', 123 | text: 'Rate limit exceeded. Please try again later.', 124 | }, 125 | ], 126 | isError: true, 127 | }; 128 | } 129 | 130 | // Validate arguments 131 | if (!args || typeof args !== 'object') { 132 | return { 133 | content: [ 134 | { 135 | type: 'text', 136 | text: 'Invalid arguments provided.', 137 | }, 138 | ], 139 | isError: true, 140 | }; 141 | } 142 | 143 | try { 144 | // Type guard for DesignCritiqueArgs 145 | if (!('design_document' in args) || !('design_type' in args) || 146 | typeof args.design_document !== 'string' || typeof args.design_type !== 'string') { 147 | return { 148 | content: [ 149 | { 150 | type: 'text', 151 | text: 'Both design_document and design_type are required and must be strings.', 152 | }, 153 | ], 154 | isError: true, 155 | }; 156 | } 157 | 158 | const typedArgs = args as DesignCritiqueArgs; 159 | 160 | // Sanitize inputs 161 | const sanitizedDocument = sanitizeInput(typedArgs.design_document); 162 | const sanitizedType = sanitizeInput(typedArgs.design_type.toLowerCase()); 163 | 164 | // Get type-specific prompts 165 | const typePrompts = DESIGN_TYPE_PROMPTS[sanitizedType] || DESIGN_TYPE_PROMPTS.default; 166 | 167 | // Create the complete prompt 168 | const prompt = createPrompt( 169 | { 170 | ...BASE_PROMPT_TEMPLATE, 171 | template: BASE_PROMPT_TEMPLATE.template.replace( 172 | '{type_specific_prompts}', 173 | typePrompts 174 | ), 175 | }, 176 | { 177 | design_type: sanitizedType, 178 | design_document: sanitizedDocument, 179 | } 180 | ); 181 | 182 | // Make the API call 183 | const response = await makeDeepseekAPICall(prompt, SYSTEM_PROMPT); 184 | 185 | if (response.isError) { 186 | return { 187 | content: [ 188 | { 189 | type: 'text', 190 | text: `Error generating design critique: ${response.errorMessage || 'Unknown error'}`, 191 | }, 192 | ], 193 | isError: true, 194 | }; 195 | } 196 | 197 | // Return the formatted response 198 | return { 199 | content: [ 200 | { 201 | type: 'text', 202 | text: response.text, 203 | }, 204 | ], 205 | }; 206 | } catch (error) { 207 | console.error('Design critique tool error:', error); 208 | return { 209 | content: [ 210 | { 211 | type: 'text', 212 | text: `Error processing design critique: ${error instanceof Error ? error.message : 'Unknown error'}`, 213 | }, 214 | ], 215 | isError: true, 216 | }; 217 | } 218 | } -------------------------------------------------------------------------------- /src/tools/design-critique/index.ts: -------------------------------------------------------------------------------- 1 | export { definition, handler } from './design-critique.js'; -------------------------------------------------------------------------------- /src/tools/second-opinion/index.ts: -------------------------------------------------------------------------------- 1 | export { definition, handler } from './second-opinion.js'; -------------------------------------------------------------------------------- /src/tools/second-opinion/second-opinion.ts: -------------------------------------------------------------------------------- 1 | import type { ToolDefinition, SecondOpinionArgs } from '../../types/index.js'; 2 | import { makeDeepseekAPICall, checkRateLimit } from '../../api/deepseek/deepseek.js'; 3 | import { createPrompt, PromptTemplate } from '../../utils/prompt.js'; 4 | 5 | /** 6 | * System prompt for the second opinion tool 7 | */ 8 | const SYSTEM_PROMPT = `You are an expert mentor providing second opinions on user requests. 9 | Your role is to analyze requests and identify critical considerations that might be overlooked. 10 | 11 | First, reason through the request step by step: 12 | 1. Understand the core request and its implications 13 | 2. Consider the context and domain 14 | 3. Identify potential challenges and pitfalls 15 | 4. Think about prerequisites and dependencies 16 | 5. Evaluate resource requirements 17 | 6. Consider maintenance and scalability 18 | 7. Think about security and performance implications 19 | 20 | Then, provide a concise list of critical considerations based on your reasoning. 21 | Focus on modern practices, potential pitfalls, and important factors for success.`; 22 | 23 | /** 24 | * Prompt template for generating second opinions 25 | */ 26 | const PROMPT_TEMPLATE: PromptTemplate = { 27 | template: `User Request: {user_request} 28 | 29 | Please analyze this request carefully. Consider: 30 | - Core problem/concept to address 31 | - Common pitfalls or edge cases 32 | - Security/performance implications (if applicable) 33 | - Prerequisites and dependencies 34 | - Resource constraints and requirements 35 | - Advanced topics that could add value 36 | - Maintenance/scalability factors 37 | 38 | First, reason through your analysis step by step. 39 | Then, provide a clear, non-numbered list of critical considerations.`, 40 | systemPrompt: SYSTEM_PROMPT 41 | }; 42 | 43 | /** 44 | * Tool definition for the second opinion tool 45 | */ 46 | export const definition: ToolDefinition = { 47 | name: 'second_opinion', 48 | description: 'Provides a second opinion on a user\'s request by analyzing it with an LLM and listing critical considerations.', 49 | inputSchema: { 50 | type: 'object', 51 | properties: { 52 | user_request: { 53 | type: 'string', 54 | description: 'The user\'s original request (e.g., \'Explain Python to me\' or \'Build a login system\')', 55 | }, 56 | }, 57 | required: ['user_request'], 58 | }, 59 | }; 60 | 61 | /** 62 | * Handles the execution of the second opinion tool 63 | * 64 | * @param args - Tool arguments containing the user request 65 | * @returns Tool response containing the generated second opinion with reasoning 66 | */ 67 | export async function handler(args: unknown) { 68 | // Check rate limit first 69 | if (!checkRateLimit()) { 70 | return { 71 | content: [ 72 | { 73 | type: 'text', 74 | text: 'Rate limit exceeded. Please try again later.', 75 | }, 76 | ], 77 | isError: true, 78 | }; 79 | } 80 | 81 | try { 82 | // Type guard for SecondOpinionArgs 83 | if (!args || typeof args !== 'object' || !('user_request' in args) || 84 | typeof args.user_request !== 'string') { 85 | return { 86 | content: [ 87 | { 88 | type: 'text', 89 | text: 'Missing or invalid user_request parameter.', 90 | }, 91 | ], 92 | isError: true, 93 | }; 94 | } 95 | 96 | const typedArgs = args as SecondOpinionArgs; 97 | 98 | // Create the complete prompt 99 | const prompt = createPrompt(PROMPT_TEMPLATE, { 100 | user_request: typedArgs.user_request 101 | }); 102 | 103 | // Make the API call 104 | const response = await makeDeepseekAPICall(prompt, SYSTEM_PROMPT); 105 | 106 | if (response.isError) { 107 | return { 108 | content: [ 109 | { 110 | type: 'text', 111 | text: `Error generating second opinion: ${response.errorMessage || 'Unknown error'}`, 112 | }, 113 | ], 114 | isError: true, 115 | }; 116 | } 117 | 118 | // Return both the reasoning and the final response 119 | return { 120 | content: [ 121 | { 122 | type: 'text', 123 | text: response.text, 124 | }, 125 | ], 126 | // Include the Chain of Thought reasoning if available 127 | ...(response.reasoning ? { 128 | reasoning: [ 129 | { 130 | type: 'text', 131 | text: `\n${response.reasoning}\n`, 132 | }, 133 | ], 134 | } : {}), 135 | }; 136 | } catch (error) { 137 | console.error('Second opinion tool error:', error); 138 | return { 139 | content: [ 140 | { 141 | type: 'text', 142 | text: `Error processing request: ${error instanceof Error ? error.message : 'Unknown error'}`, 143 | }, 144 | ], 145 | isError: true, 146 | }; 147 | } 148 | } -------------------------------------------------------------------------------- /src/tools/writing-feedback/index.ts: -------------------------------------------------------------------------------- 1 | export { definition, handler } from './writing-feedback.js'; -------------------------------------------------------------------------------- /src/tools/writing-feedback/writing-feedback.ts: -------------------------------------------------------------------------------- 1 | import type { ToolDefinition, WritingFeedbackArgs, ToolResponse } from '../../types/index.js'; 2 | import { makeDeepseekAPICall, checkRateLimit } from '../../api/deepseek/deepseek.js'; 3 | import { createPrompt, PromptTemplate, sanitizeInput } from '../../utils/prompt.js'; 4 | 5 | /** 6 | * System prompt for the writing feedback tool 7 | */ 8 | const SYSTEM_PROMPT = `You are an expert writing coach and editor with extensive experience in various forms of writing. 9 | Your role is to provide constructive feedback on written content, focusing on: 10 | 11 | 1. Clarity and coherence 12 | 2. Grammar and syntax 13 | 3. Style and tone 14 | 4. Structure and organization 15 | 5. Technical accuracy 16 | 6. Audience appropriateness 17 | 7. Overall effectiveness 18 | 19 | Provide specific, actionable feedback that helps improve the writing while maintaining the author's voice. 20 | Your critique should be constructive and include both strengths and areas for improvement.`; 21 | 22 | /** 23 | * Writing type-specific prompts 24 | */ 25 | const WRITING_TYPE_PROMPTS: Record = { 26 | 'documentation': `Analyze this technical documentation focusing on: 27 | - Technical accuracy and completeness 28 | - Clarity and accessibility 29 | - Structure and organization 30 | - Code examples and explanations 31 | - Versioning considerations 32 | - API documentation standards 33 | - Troubleshooting guidance 34 | - Maintenance and updates`, 35 | 36 | 'essay': `Analyze this essay focusing on: 37 | - Thesis clarity and development 38 | - Argument structure and logic 39 | - Evidence and support 40 | - Transitions and flow 41 | - Introduction and conclusion 42 | - Academic style 43 | - Citations and references 44 | - Overall persuasiveness`, 45 | 46 | 'article': `Analyze this article focusing on: 47 | - Hook and engagement 48 | - Content organization 49 | - Clarity and readability 50 | - Supporting evidence 51 | - Target audience appropriateness 52 | - SEO considerations 53 | - Call to action 54 | - Overall impact`, 55 | 56 | 'blog': `Analyze this blog post focusing on: 57 | - Reader engagement 58 | - Voice and tone 59 | - Content structure 60 | - SEO optimization 61 | - Visual elements 62 | - Call to action 63 | - Social sharing potential 64 | - Reader value`, 65 | 66 | 'default': `Analyze this writing focusing on: 67 | - Clarity and coherence 68 | - Grammar and style 69 | - Structure and flow 70 | - Audience appropriateness 71 | - Content accuracy 72 | - Overall effectiveness 73 | - Specific improvements` 74 | }; 75 | 76 | /** 77 | * Base prompt template for writing feedback 78 | */ 79 | const BASE_PROMPT_TEMPLATE: PromptTemplate = { 80 | template: `Writing Type: {writing_type} 81 | 82 | Content to Review: 83 | {text} 84 | 85 | {type_specific_prompts} 86 | 87 | Please provide comprehensive feedback covering: 88 | 1. Overall Assessment 89 | 2. Strengths 90 | 3. Areas for Improvement 91 | 4. Specific Recommendations for: 92 | - Clarity and Coherence 93 | - Grammar and Style 94 | - Structure and Organization 95 | - Content and Accuracy 96 | 5. Summary of Key Action Items 97 | 98 | Focus on providing actionable feedback that will help improve the writing while maintaining its intended purpose and voice.`, 99 | systemPrompt: SYSTEM_PROMPT 100 | }; 101 | 102 | /** 103 | * Tool definition for the writing feedback tool 104 | */ 105 | export const definition: ToolDefinition = { 106 | name: 'writing_feedback', 107 | description: 'Provides feedback on a piece of writing, such as an essay, article, or technical documentation, focusing on clarity, grammar, style, structure, and overall effectiveness.', 108 | inputSchema: { 109 | type: 'object', 110 | properties: { 111 | text: { 112 | type: 'string', 113 | description: 'The text to review', 114 | }, 115 | writing_type: { 116 | type: 'string', 117 | description: "The type of writing (e.g., 'essay', 'article', 'documentation')", 118 | }, 119 | }, 120 | required: ['text', 'writing_type'], 121 | }, 122 | }; 123 | 124 | /** 125 | * Handles the execution of the writing feedback tool 126 | * 127 | * @param args - Tool arguments containing text and writing type 128 | * @returns Tool response containing the writing feedback 129 | */ 130 | export async function handler(args: unknown): Promise { 131 | // Check rate limit first 132 | if (!checkRateLimit()) { 133 | return { 134 | content: [ 135 | { 136 | type: 'text', 137 | text: 'Rate limit exceeded. Please try again later.', 138 | }, 139 | ], 140 | isError: true, 141 | }; 142 | } 143 | 144 | // Validate arguments 145 | if (!args || typeof args !== 'object') { 146 | return { 147 | content: [ 148 | { 149 | type: 'text', 150 | text: 'Invalid arguments provided.', 151 | }, 152 | ], 153 | isError: true, 154 | }; 155 | } 156 | 157 | try { 158 | // Type guard for WritingFeedbackArgs 159 | if (!('text' in args) || !('writing_type' in args) || 160 | typeof args.text !== 'string' || typeof args.writing_type !== 'string') { 161 | return { 162 | content: [ 163 | { 164 | type: 'text', 165 | text: 'Both text and writing_type are required and must be strings.', 166 | }, 167 | ], 168 | isError: true, 169 | }; 170 | } 171 | 172 | const typedArgs = args as WritingFeedbackArgs; 173 | 174 | // Sanitize inputs 175 | const sanitizedText = sanitizeInput(typedArgs.text); 176 | const sanitizedType = sanitizeInput(typedArgs.writing_type.toLowerCase()); 177 | 178 | // Get type-specific prompts 179 | const typePrompts = WRITING_TYPE_PROMPTS[sanitizedType] || WRITING_TYPE_PROMPTS.default; 180 | 181 | // Create the complete prompt 182 | const prompt = createPrompt( 183 | { 184 | ...BASE_PROMPT_TEMPLATE, 185 | template: BASE_PROMPT_TEMPLATE.template.replace( 186 | '{type_specific_prompts}', 187 | typePrompts 188 | ), 189 | }, 190 | { 191 | writing_type: sanitizedType, 192 | text: sanitizedText, 193 | } 194 | ); 195 | 196 | // Make the API call 197 | const response = await makeDeepseekAPICall(prompt, SYSTEM_PROMPT); 198 | 199 | if (response.isError) { 200 | return { 201 | content: [ 202 | { 203 | type: 'text', 204 | text: `Error generating writing feedback: ${response.errorMessage || 'Unknown error'}`, 205 | }, 206 | ], 207 | isError: true, 208 | }; 209 | } 210 | 211 | // Return the formatted response 212 | return { 213 | content: [ 214 | { 215 | type: 'text', 216 | text: response.text, 217 | }, 218 | ], 219 | }; 220 | } catch (error) { 221 | console.error('Writing feedback tool error:', error); 222 | return { 223 | content: [ 224 | { 225 | type: 'text', 226 | text: `Error processing writing feedback: ${error instanceof Error ? error.message : 'Unknown error'}`, 227 | }, 228 | ], 229 | isError: true, 230 | }; 231 | } 232 | } -------------------------------------------------------------------------------- /src/types/index.ts: -------------------------------------------------------------------------------- 1 | import type { Tool } from "@modelcontextprotocol/sdk/types.js"; 2 | 3 | export interface ToolDefinition extends Tool { 4 | name: string; 5 | description: string; 6 | inputSchema: { 7 | type: "object"; 8 | properties: Record; 9 | required?: string[]; 10 | oneOf?: Array<{ required: string[] }>; 11 | }; 12 | } 13 | 14 | export interface ToolContent { 15 | type: string; 16 | text: string; 17 | } 18 | 19 | // Response format for our internal tool handlers 20 | export interface ToolResponse { 21 | content: ToolContent[]; 22 | reasoning?: ToolContent[]; 23 | isError?: boolean; 24 | } 25 | 26 | export interface LLMResponse { 27 | text: string; 28 | reasoning?: string; 29 | isError: boolean; 30 | errorMessage?: string; 31 | } 32 | 33 | export interface FileValidationResult { 34 | isValid: boolean; 35 | error?: string; 36 | } 37 | 38 | export interface APIConfig { 39 | apiKey: string; 40 | baseUrl: string; 41 | model: string; 42 | maxRetries: number; 43 | timeout: number; 44 | maxTokens: number; 45 | } 46 | 47 | export interface ServerConfig { 48 | serverName: string; 49 | serverVersion: string; 50 | api: APIConfig; 51 | } 52 | 53 | // Tool-specific argument types 54 | export interface SecondOpinionArgs { 55 | user_request: string; 56 | } 57 | 58 | export interface CodeReviewArgs { 59 | file_path?: string; 60 | language: string; 61 | code_snippet?: string; 62 | } 63 | 64 | export interface DesignCritiqueArgs { 65 | design_document: string; 66 | design_type: string; 67 | } 68 | 69 | export interface WritingFeedbackArgs { 70 | text: string; 71 | writing_type: string; 72 | } 73 | 74 | export interface BrainstormEnhancementsArgs { 75 | concept: string; 76 | } 77 | 78 | // Type guard for tool arguments 79 | export function isValidToolArgs(args: Record | undefined, required: string[]): boolean { 80 | if (!args) return false; 81 | return required.every(key => key in args && args[key] !== undefined); 82 | } 83 | 84 | // Type guards for specific tool arguments 85 | export function isCodeReviewArgs(args: unknown): args is CodeReviewArgs { 86 | if (!args || typeof args !== 'object') return false; 87 | const a = args as Record; 88 | 89 | // Must have either file_path or code_snippet 90 | const hasFilePath = 'file_path' in a && (typeof a.file_path === 'string' || a.file_path === undefined); 91 | const hasCodeSnippet = 'code_snippet' in a && (typeof a.code_snippet === 'string' || a.code_snippet === undefined); 92 | const hasLanguage = 'language' in a && typeof a.language === 'string'; 93 | 94 | return hasLanguage && (hasFilePath || hasCodeSnippet); 95 | } 96 | 97 | export function isDesignCritiqueArgs(args: unknown): args is DesignCritiqueArgs { 98 | if (!args || typeof args !== 'object') return false; 99 | const a = args as Record; 100 | 101 | return 'design_document' in a && 'design_type' in a && 102 | typeof a.design_document === 'string' && typeof a.design_type === 'string'; 103 | } 104 | 105 | export function isWritingFeedbackArgs(args: unknown): args is WritingFeedbackArgs { 106 | if (!args || typeof args !== 'object') return false; 107 | const a = args as Record; 108 | 109 | return 'text' in a && 'writing_type' in a && 110 | typeof a.text === 'string' && typeof a.writing_type === 'string'; 111 | } 112 | 113 | export function isBrainstormEnhancementsArgs(args: unknown): args is BrainstormEnhancementsArgs { 114 | if (!args || typeof args !== 'object') return false; 115 | const a = args as Record; 116 | 117 | return 'concept' in a && typeof a.concept === 'string'; 118 | } 119 | 120 | // Message types for OpenAI/Deepseek chat 121 | export interface ChatMessage { 122 | role: 'system' | 'user' | 'assistant'; 123 | content: string; 124 | } 125 | 126 | export interface ChatHistory { 127 | messages: ChatMessage[]; 128 | } 129 | 130 | // Helper function to convert ToolResponse to ServerResult format 131 | export function toolResponseToServerResult(response: ToolResponse): Record { 132 | return { 133 | content: response.content, 134 | ...(response.reasoning ? { reasoning: response.reasoning } : {}), 135 | ...(response.isError ? { isError: response.isError } : {}) 136 | }; 137 | } -------------------------------------------------------------------------------- /src/utils/file.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import * as path from 'path'; 3 | import type { FileValidationResult } from '../types/index.js'; 4 | 5 | /** 6 | * Validates a file path to ensure it's safe to access. 7 | * Prevents directory traversal attacks and ensures the path is within allowed boundaries. 8 | * 9 | * @param filePath - The file path to validate 10 | * @returns FileValidationResult indicating if the path is valid and any error message 11 | */ 12 | export function validateFilePath(filePath: string): FileValidationResult { 13 | try { 14 | // Resolve the absolute path 15 | const resolvedPath = path.resolve(filePath); 16 | 17 | // Get the server's root directory (two levels up from utils) 18 | const serverRoot = path.resolve(__dirname, '../../'); 19 | 20 | // Check if the path is within the server root 21 | if (!resolvedPath.startsWith(serverRoot)) { 22 | return { 23 | isValid: false, 24 | error: 'Access denied: Path is outside the server root directory' 25 | }; 26 | } 27 | 28 | // Check if the file exists 29 | if (!fs.existsSync(resolvedPath)) { 30 | return { 31 | isValid: false, 32 | error: 'File not found' 33 | }; 34 | } 35 | 36 | // Check if we have read permissions 37 | try { 38 | fs.accessSync(resolvedPath, fs.constants.R_OK); 39 | } catch { 40 | return { 41 | isValid: false, 42 | error: 'Permission denied: Cannot read file' 43 | }; 44 | } 45 | 46 | return { isValid: true }; 47 | } catch (error) { 48 | return { 49 | isValid: false, 50 | error: error instanceof Error ? error.message : 'Unknown error occurred' 51 | }; 52 | } 53 | } 54 | 55 | /** 56 | * Safely reads the content of a file after validation. 57 | * 58 | * @param filePath - The path to the file to read 59 | * @returns Promise resolving to the file content 60 | * @throws Error if file validation fails or reading fails 61 | */ 62 | export async function readFileContent(filePath: string): Promise { 63 | const validation = validateFilePath(filePath); 64 | if (!validation.isValid) { 65 | throw new Error(validation.error); 66 | } 67 | 68 | try { 69 | return await fs.promises.readFile(filePath, 'utf-8'); 70 | } catch (error) { 71 | throw new Error(`Failed to read file: ${error instanceof Error ? error.message : 'Unknown error'}`); 72 | } 73 | } 74 | 75 | /** 76 | * Checks if a file exists and is accessible. 77 | * 78 | * @param filePath - The path to check 79 | * @returns boolean indicating if the file exists and is accessible 80 | */ 81 | export function fileExists(filePath: string): boolean { 82 | try { 83 | fs.accessSync(filePath, fs.constants.F_OK | fs.constants.R_OK); 84 | return true; 85 | } catch { 86 | return false; 87 | } 88 | } -------------------------------------------------------------------------------- /src/utils/prompt.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Represents a prompt template with placeholders for dynamic values. 3 | */ 4 | export interface PromptTemplate { 5 | template: string; 6 | systemPrompt?: string; 7 | } 8 | 9 | /** 10 | * Represents variables that can be used in a prompt template. 11 | */ 12 | export type PromptVariables = Record; 13 | 14 | /** 15 | * Fills a prompt template with provided variables. 16 | * 17 | * @param template - The prompt template containing placeholders 18 | * @param variables - Object containing values for the placeholders 19 | * @returns The filled prompt string 20 | * @throws Error if required variables are missing 21 | */ 22 | export function fillPromptTemplate(template: string, variables: PromptVariables): string { 23 | // Find all placeholders in the template 24 | const placeholders = template.match(/\{([^}]+)\}/g) || []; 25 | 26 | // Create a map of required variables 27 | const requiredVars = new Set( 28 | placeholders.map(p => p.slice(1, -1)) // Remove { and } 29 | ); 30 | 31 | // Check if all required variables are provided 32 | const missingVars = Array.from(requiredVars).filter(v => !(v in variables)); 33 | if (missingVars.length > 0) { 34 | throw new Error(`Missing required variables: ${missingVars.join(', ')}`); 35 | } 36 | 37 | // Replace all placeholders with their values 38 | return template.replace(/\{([^}]+)\}/g, (_, key) => { 39 | const value = variables[key]; 40 | return String(value); 41 | }); 42 | } 43 | 44 | /** 45 | * Sanitizes user input to prevent prompt injection attacks. 46 | * 47 | * @param input - The user input to sanitize 48 | * @returns Sanitized input string 49 | */ 50 | export function sanitizeInput(input: string): string { 51 | // Remove any attempt to break out of the current context 52 | return input 53 | .replace(/```/g, '\\`\\`\\`') // Escape code blocks 54 | .replace(/\{/g, '\\{') // Escape template literals 55 | .replace(/\}/g, '\\}') 56 | .trim(); 57 | } 58 | 59 | /** 60 | * Creates a complete prompt by combining system prompt, template, and variables. 61 | * 62 | * @param promptTemplate - The prompt template object 63 | * @param variables - Variables to fill in the template 64 | * @returns Complete prompt string 65 | */ 66 | export function createPrompt( 67 | promptTemplate: PromptTemplate, 68 | variables: PromptVariables 69 | ): string { 70 | const filledTemplate = fillPromptTemplate(promptTemplate.template, variables); 71 | 72 | if (promptTemplate.systemPrompt) { 73 | return `${promptTemplate.systemPrompt}\n\n${filledTemplate}`; 74 | } 75 | 76 | return filledTemplate; 77 | } 78 | 79 | /** 80 | * Validates a prompt to ensure it doesn't exceed maximum length. 81 | * 82 | * @param prompt - The prompt to validate 83 | * @param maxLength - Maximum allowed length (default: 4000) 84 | * @returns boolean indicating if the prompt is valid 85 | */ 86 | export function validatePrompt(prompt: string, maxLength: number = 4000): boolean { 87 | return prompt.length <= maxLength; 88 | } 89 | 90 | /** 91 | * Truncates a prompt to fit within maximum length while preserving meaning. 92 | * 93 | * @param prompt - The prompt to truncate 94 | * @param maxLength - Maximum allowed length 95 | * @returns Truncated prompt string 96 | */ 97 | export function truncatePrompt(prompt: string, maxLength: number = 4000): string { 98 | if (prompt.length <= maxLength) { 99 | return prompt; 100 | } 101 | 102 | // Try to truncate at a sentence boundary 103 | const truncated = prompt.slice(0, maxLength); 104 | const lastSentence = truncated.match(/.*[.!?]/); 105 | 106 | if (lastSentence) { 107 | return lastSentence[0]; 108 | } 109 | 110 | // If no sentence boundary found, truncate at last complete word 111 | const lastSpace = truncated.lastIndexOf(' '); 112 | return truncated.slice(0, lastSpace) + '...'; 113 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "outDir": "./build", 7 | "rootDir": "./src", 8 | "strict": true, 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "resolveJsonModule": true 13 | }, 14 | "include": ["src/**/*"], 15 | "exclude": ["node_modules", "build"] 16 | } 17 | --------------------------------------------------------------------------------