@smartbear/mcp
Version:
MCP server for interacting SmartBear Products
233 lines (232 loc) • 8.76 kB
JavaScript
import { z } from "zod";
import { MCP_SERVER_NAME, MCP_SERVER_VERSION } from "../common/info.js";
import { ToolError, } from "../common/types.js";
const ConfigurationSchema = z.object({
api_token: z.string().describe("Reflect API authentication token"),
});
// ReflectClient class implementing the Client interface
export class ReflectClient {
headers = {};
name = "Reflect";
toolPrefix = "reflect";
configPrefix = "Reflect";
config = ConfigurationSchema;
async configure(_server, config, _cache) {
this.headers = {
"X-API-KEY": `${config.api_token}`,
"Content-Type": "application/json",
"User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`,
};
return true;
}
async listReflectSuites() {
const response = await fetch("https://api.reflect.run/v1/suites", {
method: "GET",
headers: this.headers,
});
return response.json();
}
async listSuiteExecutions(suiteId) {
const response = await fetch(`https://api.reflect.run/v1/suites/${suiteId}/executions`, {
method: "GET",
headers: this.headers,
});
return response.json();
}
async getSuiteExecutionStatus(suiteId, executionId) {
const response = await fetch(`https://api.reflect.run/v1/suites/${suiteId}/executions/${executionId}`, {
method: "GET",
headers: this.headers,
});
return response.json();
}
async executeSuite(suiteId) {
const response = await fetch(`https://api.reflect.run/v1/suites/${suiteId}/executions`, {
method: "POST",
headers: this.headers,
});
return response.json();
}
async cancelSuiteExecution(suiteId, executionId) {
const response = await fetch(`https://api.reflect.run/v1/suites/${suiteId}/executions/${executionId}/cancel`, {
method: "PATCH",
headers: this.headers,
});
return response.json();
}
async listReflectTests() {
const response = await fetch("https://api.reflect.run/v1/tests", {
method: "GET",
headers: this.headers,
});
return response.json();
}
async runReflectTest(testId) {
const response = await fetch(`https://api.reflect.run/v1/tests/${testId}/executions`, {
method: "POST",
headers: this.headers,
});
return response.json();
}
async getReflectTestStatus(_testId, executionId) {
const response = await fetch(`https://api.reflect.run/v1/executions/${executionId}`, {
method: "GET",
headers: this.headers,
});
return response.json();
}
registerTools(register, _getInput) {
register({
title: "List Suites",
summary: "Retrieve a list of all reflect suites available",
parameters: [],
}, async (_args, _extra) => {
const response = await this.listReflectSuites();
return {
content: [{ type: "text", text: JSON.stringify(response) }],
};
});
register({
title: "List Suite Executions",
summary: "List all executions for a given suite",
parameters: [
{
name: "suiteId",
type: z.string(),
description: "ID of the reflect suite to list executions for",
required: true,
},
],
}, async (args, _extra) => {
if (!args.suiteId)
throw new ToolError("suiteId argument is required");
const response = await this.listSuiteExecutions(args.suiteId);
return {
content: [{ type: "text", text: JSON.stringify(response) }],
};
});
register({
title: "Get Suite Execution Status",
summary: "Get the status of a reflect suite execution",
parameters: [
{
name: "suiteId",
type: z.string(),
description: "ID of the reflect suite to get execution status for",
required: true,
},
{
name: "executionId",
type: z.string(),
description: "ID of the reflect suite execution to get status for",
required: true,
},
],
}, async (args, _extra) => {
if (!args.suiteId || !args.executionId)
throw new ToolError("Both suiteId and executionId arguments are required");
const response = await this.getSuiteExecutionStatus(args.suiteId, args.executionId);
return {
content: [{ type: "text", text: JSON.stringify(response) }],
};
});
register({
title: "Execute Suite",
summary: "Execute a reflect suite",
parameters: [
{
name: "suiteId",
type: z.string(),
description: "ID of the reflect suite to list executions for",
required: true,
},
],
}, async (args, _extra) => {
if (!args.suiteId)
throw new ToolError("suiteId argument is required");
const response = await this.executeSuite(args.suiteId);
return {
content: [{ type: "text", text: JSON.stringify(response) }],
};
});
register({
title: "Cancel Suite Execution",
summary: "Cancel a reflect suite execution",
parameters: [
{
name: "suiteId",
type: z.string(),
description: "ID of the reflect suite to cancel execution for",
required: true,
},
{
name: "executionId",
type: z.string(),
description: "ID of the reflect suite execution to cancel",
required: true,
},
],
}, async (args, _extra) => {
if (!args.suiteId || !args.executionId)
throw new ToolError("Both suiteId and executionId arguments are required");
const response = await this.cancelSuiteExecution(args.suiteId, args.executionId);
return {
content: [{ type: "text", text: JSON.stringify(response) }],
};
});
register({
title: "List Tests",
summary: "List all reflect tests",
parameters: [],
}, async (_args, _extra) => {
const response = await this.listReflectTests();
return {
content: [{ type: "text", text: JSON.stringify(response) }],
};
});
register({
title: "Run Test",
summary: "Run a reflect test",
parameters: [
{
name: "testId",
type: z.string(),
description: "ID of the reflect test to run",
required: true,
},
],
}, async (args, _extra) => {
if (!args.testId)
throw new ToolError("testId argument is required");
const response = await this.runReflectTest(args.testId);
return {
content: [{ type: "text", text: JSON.stringify(response) }],
};
});
register({
title: "Get Test Status",
summary: "Get the status of a reflect test execution",
parameters: [
{
name: "testId",
type: z.string(),
description: "ID of the reflect test to run",
required: true,
},
{
name: "executionId",
type: z.string(),
description: "ID of the reflect test execution to get status for",
required: true,
},
],
}, async (args, _extra) => {
if (!args.testId || !args.executionId)
throw new ToolError("Both testId and executionId arguments are required");
const response = await this.getReflectTestStatus(args.testId, args.executionId);
return {
content: [{ type: "text", text: JSON.stringify(response) }],
};
});
}
}