@skyramp/mcp
Version:
Skyramp MCP (Model Context Protocol) Server - AI-powered test generation and execution
188 lines (178 loc) • 7.57 kB
JavaScript
import { z } from "zod";
import { simpleGit } from "simple-git";
import * as fs from "fs/promises";
import * as path from "path";
import { logger } from "../utils/logger.js";
import { AnalyticsService } from "../services/AnalyticsService.js";
const TOOL_NAME = "skyramp_init_testbot";
const WORKFLOW_FILENAME = "skyramp-test-bot.yml";
function generateWorkflow(targetBranches, agentType) {
const apiKeyLine = agentType === "copilot"
? " copilot_api_key: ${{ secrets.COPILOT_API_KEY }}"
: " cursor_api_key: ${{ secrets.CURSOR_API_KEY }}";
const branchesBlock = targetBranches && targetBranches.length > 0
? `\n branches:\n${targetBranches.map((b) => ` - '${b}'`).join("\n")}`
: "";
return `name: Skyramp Test Automation
on:
pull_request:${branchesBlock}
jobs:
test-maintenance:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run Skyramp Test Bot
uses: skyramp/test-bot@v1
with:
skyramp_license_file: \${{ secrets.SKYRAMP_LICENSE }}
${apiKeyLine}
`;
}
export function registerInitTestbotTool(server) {
server.registerTool(TOOL_NAME, {
description: `Initialize Skyramp Test Bot for a GitHub repository
Sets up a GitHub Actions workflow that automatically generates and maintains tests on pull requests using Skyramp Test Bot. This tool validates the repository, creates the workflow file, and provides setup instructions for required secrets.`,
inputSchema: {
repository_path: z
.string()
.describe("Absolute path to the user's GitHub repository"),
agent_type: z
.enum(["cursor", "copilot"])
.default("cursor")
.describe("Which AI agent the user uses (cursor or copilot). Defaults to cursor."),
target_branches: z
.array(z.string())
.optional()
.describe("Branches to trigger the test bot on pull requests. If not specified, the workflow triggers on all pull requests."),
},
_meta: {
keywords: [
"init",
"testbot",
"test-bot",
"github actions",
"workflow",
"setup",
"ci",
],
},
}, async (params) => {
let errorResult;
const repoPath = params.repository_path;
const agentType = params.agent_type;
const targetBranches = params.target_branches;
logger.info("Initializing Skyramp Test Bot", {
repository_path: repoPath,
agent_type: agentType,
target_branches: targetBranches,
});
try {
// Validate it's a git repo
const git = simpleGit(repoPath);
const isRepo = await git.checkIsRepo();
if (!isRepo) {
errorResult = {
content: [
{
type: "text",
text: `Error: "${repoPath}" is not a Git repository. Please run this tool from a valid Git repository.`,
},
],
isError: true,
};
return errorResult;
}
// Validate it has a GitHub remote
const remotes = await git.getRemotes(true);
const hasGitHubRemote = remotes.some((remote) => remote.refs.fetch?.includes("github.com") ||
remote.refs.push?.includes("github.com"));
if (!hasGitHubRemote) {
errorResult = {
content: [
{
type: "text",
text: `Error: No GitHub remote found in "${repoPath}". Skyramp Test Bot requires a GitHub repository. Please add a GitHub remote and try again.`,
},
],
isError: true,
};
return errorResult;
}
// Create the workflow directory if needed and write the workflow file atomically
const workflowDir = path.join(repoPath, ".github", "workflows");
await fs.mkdir(workflowDir, { recursive: true });
const workflowPath = path.join(workflowDir, WORKFLOW_FILENAME);
const workflowContent = generateWorkflow(targetBranches, agentType);
try {
await fs.writeFile(workflowPath, workflowContent, {
encoding: "utf-8",
flag: "wx",
});
}
catch (err) {
if (err.code === "EEXIST") {
return {
content: [
{
type: "text",
text: `Skyramp Test Bot workflow already exists at ".github/workflows/${WORKFLOW_FILENAME}". No changes were made. If you want to reconfigure it, delete the existing file and run this tool again.`,
},
],
};
}
throw err;
}
// Build success message with setup instructions
const secretName = agentType === "copilot" ? "COPILOT_API_KEY" : "CURSOR_API_KEY";
const agentLabel = agentType === "copilot" ? "Copilot" : "Cursor";
const successMessage = `Skyramp Test Bot workflow created successfully at ".github/workflows/${WORKFLOW_FILENAME}".
To complete the setup, configure the following GitHub Secrets in your repository (Settings > Secrets and variables > Actions):
1. **SKYRAMP_LICENSE** - The contents of your Skyramp license file (paste the full license file text)
2. **${secretName}** - Your ${agentLabel} API key
The workflow is configured to run on ${targetBranches && targetBranches.length > 0 ? `pull requests targeting: ${targetBranches.join(", ")}` : "all pull requests"}
Required repository permissions (already configured in the workflow):
- \`contents: write\` - To commit generated tests
- \`pull-requests: write\` - To post comments on PRs
Next steps:
1. Add the required secrets to your GitHub repository
2. Commit and push the new workflow file
3. Open a pull request to see Skyramp Test Bot in action`;
return {
content: [
{
type: "text",
text: successMessage,
},
],
};
}
catch (error) {
const errorMessage = `Failed to initialize Skyramp Test Bot: ${error.message}`;
logger.error(errorMessage, { error });
errorResult = {
content: [
{
type: "text",
text: errorMessage,
},
],
isError: true,
};
return errorResult;
}
finally {
const recordParams = {
repository_path: repoPath,
agent_type: agentType,
target_branches: targetBranches ? targetBranches.join(",") : "",
};
AnalyticsService.pushMCPToolEvent(TOOL_NAME, errorResult, recordParams);
}
});
}