Merge branch 'v2/main' into v2/fix/1909-salvage-malformed-list-items

This commit is contained in:
Cliff Hall 2026-08-15 23:05:31 -04:00 • committed by GitHub
commit 0f31de83af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 1782 additions and 138 deletions

View file

@ -701,6 +701,58 @@ describe("server.ts supplemental coverage", () => {
await stop(h);
}
});
// #2018 — authorizationParams must be a string record; a hand-edited file
// with anything else drops the whole `oauth` node rather than feeding
// non-string values to the authorize-URL merge.
it("drops oauth whose authorizationParams is not a string record", async () => {
const h = await start({
seedConfig: JSON.stringify({
mcpServers: {
srv: {
type: "streamable-http",
url: "https://x.test/mcp",
oauth: { authorizationParams: { kc_idp_hint: 5 } },
},
},
}),
});
try {
const res = await fetch(`${h.baseUrl}/api/servers`);
expect(res.status).toBe(200);
const body = (await res.json()) as {
mcpServers: Record<string, Record<string, unknown>>;
};
expect(body.mcpServers.srv).not.toHaveProperty("oauth");
} finally {
await stop(h);
}
});
it("keeps a well-formed authorizationParams record on read", async () => {
const h = await start({
seedConfig: JSON.stringify({
mcpServers: {
srv: {
type: "streamable-http",
url: "https://x.test/mcp",
oauth: { authorizationParams: { kc_idp_hint: "corp" } },
},
},
}),
});
try {
const res = await fetch(`${h.baseUrl}/api/servers`);
const body = (await res.json()) as {
mcpServers: Record<string, Record<string, unknown>>;
};
expect(body.mcpServers.srv?.oauth).toEqual({
authorizationParams: { kc_idp_hint: "corp" },
});
} finally {
await stop(h);
}
});
});
describe("plaintext-secret migration over a mixed config", () => {

View file

@ -449,6 +449,53 @@ describe("/api/servers routes", () => {
});
});
// #2018 — the authorization-parameter rows travel as a pair array on the
// wire and land as a record under `oauth` on disk, mirroring `headers`.
it("persists custom authorization params under oauth on POST", async () => {
const res = await fetch(`${h.baseUrl}/api/servers`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
id: "authparams",
config: { type: "streamable-http", url: "https://x.test/mcp" },
settings: {
headers: [],
metadata: [],
connectionTimeout: 0,
requestTimeout: 0,
oauthAuthorizationParams: [
{ key: "kc_idp_hint", value: "corp" },
{ key: "", value: "dropped" },
],
},
}),
});
expect(res.status).toBe(200);
const stored = readConfig(h.configPath).mcpServers.authparams;
expect(stored?.oauth).toEqual({
authorizationParams: { kc_idp_hint: "corp" },
});
});
it("rejects a malformed oauthAuthorizationParams payload", async () => {
const res = await fetch(`${h.baseUrl}/api/servers`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
id: "badauthparams",
config: { type: "streamable-http", url: "https://x.test/mcp" },
settings: {
headers: [],
metadata: [],
connectionTimeout: 0,
requestTimeout: 0,
oauthAuthorizationParams: { kc_idp_hint: "corp" },
},
}),
});
expect(res.status).toBe(400);
});
it("updates Inspector-extension fields at the top level on PUT", async () => {
writeFileSync(
h.configPath,