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
4 changes: 3 additions & 1 deletion mcp-server/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@

### Fixed

* `currents-list-affected-tests`: serialize `action_type` query params as `action_type[]` to match OpenAPI.
* `currents-list-affected-tests`: serialize `action_type` as repeated `action_type` query keys (OpenAPI `style: form`, `explode: true`).
* `currents-get-runs`: serialize `status` and `completion_state` as repeated query keys (OpenAPI `style: form`, `explode: true`); add optional `pr_id` query param per OpenAPI list runs.
* MCP tools intentionally omit deprecated-only OpenAPI query parameters (for example `tag[]` on find run).
* `currents-update-webhook`: require at least one updatable field so the HTTP request body is never empty (matches OpenAPI `requestBody.required: true`).
* `postApi`: treat HTTP 201 and empty JSON bodies like other successful POST responses.

Expand Down
6 changes: 3 additions & 3 deletions mcp-server/src/tools/actions/list-affected-tests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe("listAffectedTestsTool", () => {
vi.clearAllMocks();
});

it("serializes action_type as action_type[] per OpenAPI", async () => {
it("serializes action_type as repeated action_type per OpenAPI (form explode)", async () => {
vi.spyOn(request, "fetchApi").mockResolvedValue({ status: "OK", data: [] });

await listAffectedTestsTool.handler({
Expand All @@ -20,10 +20,10 @@ describe("listAffectedTestsTool", () => {
});

expect(request.fetchApi).toHaveBeenCalledWith(
expect.stringContaining("action_type%5B%5D=skip")
expect.stringContaining("action_type=skip")
);
expect(request.fetchApi).toHaveBeenCalledWith(
expect.stringContaining("action_type%5B%5D=tag")
expect.stringContaining("action_type=tag")
);
});
});
2 changes: 1 addition & 1 deletion mcp-server/src/tools/actions/list-affected-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const handler = async ({
}

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

if (action_id) {
Expand Down
28 changes: 28 additions & 0 deletions mcp-server/src/tools/runs/get-runs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import * as request from "../../lib/request.js";
import { getRunsTool } from "./get-runs.js";

vi.mock("../../lib/request.js");

describe("getRunsTool", () => {
beforeEach(() => {
vi.clearAllMocks();
});

it("serializes list runs query per OpenAPI (repeated status, completion_state, pr_id)", async () => {
vi.spyOn(request, "fetchApi").mockResolvedValue({ status: "OK", data: [] });

await getRunsTool.handler({
projectId: "p1",
status: ["PASSED", "FAILED"],
completion_state: ["COMPLETE"],
pr_id: "42",
});

const url = vi.mocked(request.fetchApi).mock.calls[0][0] as string;
expect(url).toContain("status=PASSED");
expect(url).toContain("status=FAILED");
expect(url).toContain("completion_state=COMPLETE");
expect(url).toContain("pr_id=42");
});
});
14 changes: 14 additions & 0 deletions mcp-server/src/tools/runs/get-runs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ const zodSchema = z.object({
.max(200)
.optional()
.describe("Search runs by ciBuildId or commit message. Case-insensitive."),
pr_id: z
.string()
.min(1)
.max(128)
.regex(/^[!-~]+$/)
.optional()
.describe(
"Filter runs by normalized pull request id (meta.pr.id). Printable ASCII only, max 128 characters."
),
authors: z
.array(z.string())
.optional()
Expand Down Expand Up @@ -73,6 +82,7 @@ const handler = async ({
tags,
tag_operator,
search,
pr_id,
authors,
status,
completion_state,
Expand Down Expand Up @@ -106,6 +116,10 @@ const handler = async ({
queryParams.append("search", search);
}

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

if (authors && authors.length > 0) {
authors.forEach((a) => queryParams.append("authors[]", a));
}
Expand Down
Loading