├── .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 | [](https://www.typescriptlang.org/)
4 | [](https://modelcontextprotocol.io/)
5 | []()
6 | [](https://opensource.org/licenses/Apache-2.0)
7 | []()
8 | [](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 |
--------------------------------------------------------------------------------