Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions mcp-server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { updateActionTool } from "./tools/actions/update-action.js";
import { deleteActionTool } from "./tools/actions/delete-action.js";
import { enableActionTool } from "./tools/actions/enable-action.js";
import { disableActionTool } from "./tools/actions/disable-action.js";
import { listAffectedTestsTool } from "./tools/actions/list-affected-tests.js";
import { getAffectedTestExecutionsTool } from "./tools/actions/get-affected-test-executions.js";
// Projects tools
import { getProjectsTool } from "./tools/projects/get-projects.js";
import { getProjectTool } from "./tools/projects/get-project.js";
Expand Down Expand Up @@ -98,6 +100,20 @@ server.tool(
disableActionTool.handler
);

server.tool(
"currents-list-affected-tests",
"List tests affected by actions (quarantine, skip, tag) for a project within a date range. Returns aggregated data grouped by test signature. Supports filtering by action types, action ID, status, and search. Requires projectId, date_start, and date_end. (Preview endpoint: fields and path may change.)",
listAffectedTestsTool.schema,
listAffectedTestsTool.handler
);

server.tool(
"currents-get-affected-test-executions",
"Get execution details for a specific test affected by actions within a date range. Returns individual test execution records with action info. Requires projectId, signature, date_start, and date_end. (Preview endpoint: fields and path may change.)",
getAffectedTestExecutionsTool.schema,
getAffectedTestExecutionsTool.handler
);

// Projects API tools
server.tool(
"currents-get-projects",
Expand Down
110 changes: 110 additions & 0 deletions mcp-server/src/tools/actions/get-affected-test-executions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { z } from "zod";
import { fetchApi } from "../../lib/request.js";
import { logger } from "../../lib/logger.js";

const zodSchema = z.object({
projectId: z
.string()
.describe("The project ID."),
signature: z
.string()
.describe("The test signature to fetch affected executions for."),
date_start: z
.string()
.describe("Start date in ISO 8601 format (required)."),
date_end: z
.string()
.describe("End date in ISO 8601 format (required)."),
limit: z
.number()
.int()
.min(1)
.max(50)
.optional()
.describe("Maximum number of results (1-50). Defaults to 25."),
dir: z
.enum(["asc", "desc"])
.optional()
.describe("Sort direction. Defaults to 'desc'."),
actionTypes: z
.array(z.enum(["quarantine", "skip", "tag"]))
.optional()
.describe(
"Filter by action types (can be specified multiple times)."
),
actionId: z
.string()
.optional()
.describe("Filter by a specific action ID."),
search: z
.string()
.max(100)
.optional()
.describe("Search executions by name."),
});

const handler = async ({
projectId,
signature,
date_start,
date_end,
limit = 25,
dir,
actionTypes,
actionId,
search,
}: z.infer<typeof zodSchema>) => {
const queryParams = new URLSearchParams();
queryParams.append("date_start", date_start);
queryParams.append("date_end", date_end);
queryParams.append("limit", limit.toString());

if (dir) {
queryParams.append("dir", dir);
}

if (actionTypes && actionTypes.length > 0) {
actionTypes.forEach((t) => queryParams.append("actionTypes", t));
}

if (actionId) {
queryParams.append("actionId", actionId);
}

if (search) {
queryParams.append("search", search);
}

logger.info(
`Fetching affected test executions for project ${projectId}, signature ${signature} with query params: ${queryParams.toString()}`
);

const data = await fetchApi(
`/actions/tests/${projectId}/${signature}?${queryParams.toString()}`
);

if (!data) {
return {
content: [
{
type: "text" as const,
text: "Failed to retrieve affected test executions",
},
],
};
}

return {
content: [
{
type: "text" as const,
text: JSON.stringify(data, null, 2),
},
],
};
};

export const getAffectedTestExecutionsTool = {
schema: zodSchema.shape,
handler,
};
123 changes: 123 additions & 0 deletions mcp-server/src/tools/actions/list-affected-tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { z } from "zod";
import { fetchApi } from "../../lib/request.js";
import { logger } from "../../lib/logger.js";

const zodSchema = z.object({
projectId: z
.string()
.describe("The project ID to fetch affected tests from."),
date_start: z
.string()
.describe("Start date in ISO 8601 format (required)."),
date_end: z
.string()
.describe("End date in ISO 8601 format (required)."),
page: z
.number()
.int()
.min(0)
.optional()
.describe("Page number (0-indexed). Defaults to 0."),
limit: z
.number()
.int()
.min(1)
.max(100)
.optional()
.describe("Maximum number of results (1-100). Defaults to 25."),
search: z
.string()
.max(100)
.optional()
.describe("Search affected tests by name."),
actionTypes: z
.array(z.enum(["quarantine", "skip", "tag"]))
.optional()
.describe(
"Filter by action types (can be specified multiple times)."
),
actionId: z
.string()
.optional()
.describe("Filter by a specific action ID."),
dir: z
.enum(["asc", "desc"])
.optional()
.describe("Sort direction. Defaults to 'desc'."),
status: z
.enum(["active", "expired"])
.optional()
.describe("Filter by action status: active or expired."),
});

const handler = async ({
projectId,
date_start,
date_end,
page = 0,
limit = 25,
search,
actionTypes,
actionId,
dir,
status,
}: z.infer<typeof zodSchema>) => {
const queryParams = new URLSearchParams();
queryParams.append("date_start", date_start);
queryParams.append("date_end", date_end);
queryParams.append("page", page.toString());
queryParams.append("limit", limit.toString());

if (search) {
queryParams.append("search", search);
}

if (actionTypes && actionTypes.length > 0) {
actionTypes.forEach((t) => queryParams.append("actionTypes", t));
}

if (actionId) {
queryParams.append("actionId", actionId);
}

if (dir) {
queryParams.append("dir", dir);
}

if (status) {
queryParams.append("status", status);
}

logger.info(
`Fetching affected tests for project ${projectId} with query params: ${queryParams.toString()}`
);

const data = await fetchApi(
`/actions/tests/${projectId}?${queryParams.toString()}`
);

if (!data) {
return {
content: [
{
type: "text" as const,
text: "Failed to retrieve affected tests",
},
],
};
}

return {
content: [
{
type: "text" as const,
text: JSON.stringify(data, null, 2),
},
],
};
};

export const listAffectedTestsTool = {
schema: zodSchema.shape,
handler,
};
Loading