deer-flow/frontend/tests/e2e/mcp-settings.spec.ts
Aari 340bff1107
feat(mcp): manage servers from Settings (#5022)
* feat(mcp): manage servers from settings

* fix(mcp): make settings updates targeted

* fix(mcp): reject ambiguous masked array edits

* fix(mcp): honor targeted server field deletions

* fix(mcp): preserve OAuth extension secrets

* fix(mcp): validate config before persistence

* fix(mcp): preserve environment placeholders

* fix(mcp): harden targeted configuration routes

* docs: keep gateway guidance within budget

* fix(mcp): protect per-tool override secrets

* fix(mcp): keep disabled edits structurally safe
2026-09-01 23:24:49 +08:00

89 lines
2.6 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { mockLangGraphAPI } from "./utils/mock-api";
test.describe("MCP server settings", () => {
test("edits one server without dropping advanced fields or siblings", async ({
page,
}) => {
mockLangGraphAPI(page);
let servers = {
local: {
enabled: true,
description: "Local tools",
command: "uvx",
args: ["local-tools"],
},
remote: {
enabled: false,
description: "Remote tools",
type: "http",
url: "https://example.test/mcp",
headers: { "X-API-Key": "***" },
routing: { mode: "prefer" },
},
};
let submittedUpdate:
| { server_name: string; server: (typeof servers)["remote"] }
| undefined;
await page.route("**/api/mcp/config", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({ mcp_servers: servers }),
});
});
await page.route("**/api/mcp/config/server", async (route) => {
if (route.request().method() !== "PUT") {
await route.fallback();
return;
}
submittedUpdate = route
.request()
.postDataJSON() as typeof submittedUpdate;
servers = {
...servers,
[submittedUpdate!.server_name]: submittedUpdate!.server,
};
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({ mcp_servers: servers }),
});
});
await page.goto("/workspace/chats/new?settings=tools");
const settingsDialog = page.getByRole("dialog", { name: "Settings" });
await expect(settingsDialog).toBeVisible();
await settingsDialog.getByRole("button", { name: "Edit remote" }).click();
const editor = page.getByRole("dialog", { name: "Edit MCP server" });
const definitionBox = editor.getByRole("textbox");
const definition = JSON.parse(await definitionBox.inputValue()) as {
mcpServers: typeof servers;
};
definition.mcpServers.remote.description = "Updated remote tools";
await definitionBox.fill(JSON.stringify(definition));
await editor.getByRole("button", { name: "Save" }).click();
await expect(editor).toBeHidden();
await expect(
settingsDialog.getByText("Updated remote tools"),
).toBeVisible();
expect(submittedUpdate).toEqual({
server_name: "remote",
server: {
enabled: false,
description: "Updated remote tools",
type: "http",
url: "https://example.test/mcp",
headers: { "X-API-Key": "***" },
routing: { mode: "prefer" },
},
});
});
});