UNPKG

@lxptools/mcpal

Version:

MCPal is a Model Context Protocol (MCP) server designed to enhance developer productivity by providing a suite of tools for common development tasks.

123 lines (99 loc) 11.8 kB
#!/usr/bin/env node import{McpServer as ae}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as le}from"@modelcontextprotocol/sdk/server/stdio.js";var d="hi_mcp_pal",f="A simple hello for developer prouductivity mcp",g={},J="Hi \u{1F44B} , I\u2019m MCPal \u2014 your local dev buddy!",h=()=>({content:[{type:"text",text:`Print this message as is in language that user used to greet you: ${J}`}]});import{z as V}from"zod";var{exec:X}=await import("child_process"),{promisify:Q}=await import("util"),y=Q(X),T="pr title and desc",P="Helps generating PR title and description based on the recent commit changes, write pr title and desc for latest commit changes",R={repopath:V.string().describe("Path to the repository for which latest commit is to be fetched and geenrate pr title and description")},w=async({repopath:t})=>{try{let{stdout:r}=await y("git remote show origin | grep 'HEAD branch' | awk '{print $NF}'",{cwd:t}),{stdout:e,stderr:o}=await y(`git show ${r.trim()}..HEAD`,{cwd:t});if(o)throw new Error(`Git error: ${o}`);return{content:[{type:"text",text:` ## AI will do following task consider below while generating TITLE Is this adding new functionality? -> feat Is this fixing existing behavior? -> fix Is this restructuring code without behavior changes? -> refactor Is this improving performance? -> perf Is this changing documentation? -> docs Is this modifying styles only? -> style Is this adding/updating tests? -> test Is this updating dependencies? -> chore Please include the scope and detailed description following conventional commit format. analyse this ${e} and then generate bitbucket PR title and description and give output in md format `}]}}catch(r){return{content:[{type:"text",text:`\u274C Failed to generate PR title and description: ${r}}`}]}}};import{z as C}from"zod";import{promisify as W}from"util";import{exec as Z}from"child_process";var v=` You are a Lead Frontend Engineer Assistant. Given the following **staged file diffs**, perform a code review by identifying: 1. **Code Quality Issues** \u2013 Look for: - Console logs or debugger statements - Dead/unreachable/duplicate code - Poor variable naming - Excessive complexity (deep nesting, long functions) - Inline styles instead of CSS modules or styled components 2. **Best Practices Violations** \u2013 Check for: - Missing dependency arrays in useEffect - Uncontrolled inputs without default values - Direct DOM manipulation (avoid unless absolutely necessary) - Inefficient re-renders or unnecessary state usage - Usage of 'any' instead of proper types in TypeScript - Violations of React or team conventions 3. **Opportunities for Improvement** \u2013 Suggest: - Better component decomposition - Improved readability or structure - Reusability through hooks/components - Stronger typing - DRY (Don't Repeat Yourself) improvements 4. **Security and Performance Concerns** \u2013 Flag: - Usage of dangerouslySetInnerHTML without sanitization - Unthrottled scroll or resize listeners - Memory leaks (e.g., missing cleanup in useEffect) - Blocking calls in the main thread Respond with: - \u2705 **Positive Notes** - \u274C **Issues Found** - \u{1F4A1} **Suggestions for Improvement** - \u{1F4CC} **Final Summary/Score** The goal is to help the developer ship clean, efficient, production-grade code. Cline Will not edit/modify any files it will just render the response.`;var ee=W(Z),x="code_review",b="Analyzes staged Git diffs to identify code quality issues, best practice violations, and suggestions for improvement during code review.on local latest commit",k={repopath:C.string().describe("Path of the git repository"),prompt:C.string().optional().describe("Custom prompt for code review, defaults to a predefined template")},S=async({repopath:t,prompt:r})=>{try{let e="";try{let{stdout:o}=await ee("git diff --cached",{cwd:t||process.cwd(),encoding:"utf8"});e=o}catch(o){return{content:[{type:"text",text:`Error getting staged files: ${o instanceof Error?o.message:"Unknown git error"}`}]}}return{content:[{type:"text",text:` ## AI Response Guidelines ${r||v} ### Staged File Diffs: \`\`\`diff ${e} \`\`\` `}]}}catch(e){return{content:[{type:"text",text:`Error fetching PR data: ${e instanceof Error?e.message:"Unknown error"} Please ensure: 1. The URL is a valid Bitbucket pull request URL 2. BITBUCKET_TOKEN environment variable is set 3. The token has access to the repository 4. The repository exists and is accessible`}]}}};import{z as N}from"zod";import{promisify as te}from"util";import{exec as oe}from"child_process";var l=te(oe),p="https://bitbucket.csod.com/rest/api/1.0",E="CP-",re="CP-",ie=["Switched to branch","Already on 'release-lxp-v2025.2.0'","FETCH_HEAD","Switched to a new branch","Create pull request for","no such ref was fetched","branch","set up to track","couldn't find remote ref","Everything up-to-date"];function B(t){let e=new URL(t).pathname.split("/");return{projectKey:e[2],repoSlug:e[4],pullRequestId:e[6]}}async function I(t){let r=`${p}/projects/${t.projectKey}/repos/${t.repoSlug}/pull-requests/${t.pullRequestId}`,{stdout:e}=await l(`curl -u "$BITBUCKET_USER:$BITBUCKET_TOKEN" "${r}"`);return JSON.parse(e)}async function D(t,r){let e=`${p}/projects/${t.projectKey}/repos/${t.repoSlug}/commits/${r}`,{stdout:o}=await l(`curl -u "$BITBUCKET_USER:$BITBUCKET_TOKEN" "${e}"`);return JSON.parse(o).message}function U(t,r){let e=`BITBUCKET_REPO_${t.toUpperCase()}_${r.toUpperCase()}_PATH`,o=process.env[e];if(!o)throw new Error(`Local repository path environment variable "${e}" not found`);return o}function _(t,r,e){let o=t.fromRef.repository,i=t.fromRef.displayId,n=t.toRef.displayId,s=t.fromRef.latestCommit;return[`Merge in ${o.project.key}/${o.slug} from ${i} to ${n}`,`commit '${s}':`,r,"",`Master PR: ${e}`].join(` `)}async function $(t,r){try{let{stdout:e,stderr:o}=await l(t,{cwd:r});if(o&&!ie.some(i=>o.includes(i)))throw new Error(`Unexpected git error: ${o}`);return e+o}catch(e){throw new Error(`Failed to execute git command "${t}": ${e.message}`)}}async function q(t,r){let e="",o=["git fetch origin",`git checkout ${r}`,`git branch -D ${t.newBranchName} || true`,`git pull origin ${r}`,`git checkout -b ${t.newBranchName}`,`git cherry-pick -m 1 ${t.originalPr.fromRef.latestCommit}`];for(let i of o)e+=await $(i,t.repoLocalPath);return e+=await $(`git push -u origin ${t.newBranchName}`,t.repoLocalPath),e}async function A(t,r,e){let i={title:re+r.originalPr.title,description:r.prDescription,fromRef:{id:`refs/heads/${r.newBranchName}`},toRef:{id:`refs/heads/${e}`}},s=`curl -u "$BITBUCKET_USER:$BITBUCKET_TOKEN" -X POST -H "Content-Type: application/json" "${`${p}/projects/${t.projectKey}/repos/${t.repoSlug}/pull-requests`}" -d '${JSON.stringify(i)}'`,{stdout:a,stderr:u}=await l(s);u&&console.error(`curl stderr during PR creation: ${u}`);let m=JSON.parse(a);if(m.errors)throw new Error(`Bitbucket API error: ${JSON.stringify(m.errors)}`);return a}var M="raise_cp",K="Create a cherry-pick pull request from an existing PR",O={pull_request_url:N.string().describe("URL of the pull request to cherry-pick"),target_branch:N.string().describe('Target branch to cherry-pick into, e.g., "release-lxp-v2025.2.0"')},L=async({pull_request_url:t,target_branch:r})=>{try{let e=B(t),o=await I(e),i=await D(e,o.fromRef.latestCommit),n={originalPr:o,commitMessage:i,newBranchName:E+o.fromRef.displayId,repoLocalPath:U(e.projectKey,e.repoSlug),prDescription:_(o,i,t)},s=await q(n,r);return s+=await A(e,n,r),{content:[{type:"text",text:`Cherry-pick process completed successfully: ${s}`}]}}catch(e){return{content:[{type:"text",text:`Cherry-pick process failed: ${e.message}`}],isError:!0}}};import{z as j}from"zod";var F=` You are a Lead Frontend Engineer Assistant. Given the following **staged file diffs**, perform a code review by identifying: 1. **Code Quality Issues** \u2013 Look for: - Console logs or debugger statements - Dead/unreachable/duplicate code - Poor variable naming - Excessive complexity (deep nesting, long functions) - Inline styles instead of CSS modules or styled components 2. **Best Practices Violations** \u2013 Check for: - Missing dependency arrays in useEffect - Uncontrolled inputs without default values - Direct DOM manipulation (avoid unless absolutely necessary) - Inefficient re-renders or unnecessary state usage - Usage of 'any' instead of proper types in TypeScript - Violations of React or team conventions 3. **Opportunities for Improvement** \u2013 Suggest: - Better component decomposition - Improved readability or structure - Reusability through hooks/components - Stronger typing - DRY (Don't Repeat Yourself) improvements 4. **Security and Performance Concerns** \u2013 Flag: - Usage of dangerouslySetInnerHTML without sanitization - Unthrottled scroll or resize listeners - Memory leaks (e.g., missing cleanup in useEffect) - Blocking calls in the main thread Respond with: - \u2705 **Positive Notes** - \u274C **Issues Found** - \u{1F4A1} **Suggestions for Improvement** - \u{1F4CC} **Final Summary/Score** The goal is to help the developer ship clean, efficient, production-grade code.`;var{exec:se}=await import("child_process"),{promisify:ne}=await import("util"),ce=ne(se),H="remote_pr_review",z="Helps with reviewing remote pull requests by fetching PR details and providing review assistance",G={pull_request_url:j.string().describe("URL of the pull request to review"),user_prompt:j.string().optional().describe("Custom prompt for the review, defaults to a predefined template")},Y=async({pull_request_url:t,user_prompt:r})=>{try{let o=new URL(t).pathname.split("/"),i=o[2],n=o[4],s=o[6],{stdout:a}=await ce(`curl -u "$BITBUCKET_USER:$BITBUCKET_TOKEN" "https://bitbucket.csod.com/rest/api/1.0/projects/${i}/repos/${n}/pull-requests/${s}/diff"`);return{content:[{type:"text",text:` ## AI Response Guidelines ${r||F} \`\`\`changes ${a} \`\`\` `}]}}catch(e){return{content:[{type:"text",text:`\u274C Failed to initialize remote PR review: ${e}`}]}}};var c=new ae({name:"mcpal",version:"1.0.0"});c.tool(d,f,g,h);c.tool(T,P,R,w);c.tool(x,b,k,S);c.tool(H,z,G,Y);c.tool(M,K,O,L);var pe=new le;c.connect(pe);