fix(core): migrate bare v1-shaped mcp config blocks
isV1 only triggered on a fixed set of top-level keys, so a config with just $schema and a v1-shaped mcp block (servers directly under mcp, with enabled) was parsed as v2 and silently produced zero servers. Detect the v1 mcp shape (no servers wrapper, entries with a type) so these files migrate correctly.
This commit is contained in:
parent
73eb6ee473
commit
319be994b6
2 changed files with 25 additions and 1 deletions
|
|
@ -29,7 +29,19 @@ const keys = new Set([
|
|||
|
||||
export function isV1(input: unknown) {
|
||||
if (typeof input !== "object" || input === null || Array.isArray(input)) return false
|
||||
return Object.keys(input).some((key) => keys.has(key))
|
||||
const record = input as Record<string, unknown>
|
||||
if (Object.keys(record).some((key) => keys.has(key))) return true
|
||||
// `mcp` exists in both versions, so presence alone is ambiguous: v1 lists servers directly under
|
||||
// `mcp`, while v2 nests them under `mcp.servers`. Only the v1 shape (a server entry with `type`)
|
||||
// counts, so a bare `mcp`-only file still migrates instead of silently parsing to zero servers.
|
||||
const mcp = record.mcp
|
||||
return (
|
||||
typeof mcp === "object" &&
|
||||
mcp !== null &&
|
||||
!Array.isArray(mcp) &&
|
||||
!("servers" in mcp) &&
|
||||
Object.values(mcp).some((server) => typeof server === "object" && server !== null && "type" in server)
|
||||
)
|
||||
}
|
||||
|
||||
export function migrate(info: typeof ConfigV1.Info.Type) {
|
||||
|
|
|
|||
|
|
@ -76,6 +76,18 @@ describe("Config", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("detects a bare v1-shaped mcp block while leaving v2 mcp config alone", () =>
|
||||
Effect.sync(() => {
|
||||
// V1 lists servers directly under `mcp`, so a file with only `$schema` + `mcp` still migrates.
|
||||
expect(ConfigMigrateV1.isV1({ mcp: { context7: { type: "local", command: ["npx"] } } })).toBe(true)
|
||||
expect(ConfigMigrateV1.isV1({ $schema: "x", mcp: { executor: { type: "remote", url: "https://x" } } })).toBe(true)
|
||||
// V2 nests under `mcp.servers`, so it must not be misdetected and re-migrated.
|
||||
expect(ConfigMigrateV1.isV1({ mcp: { servers: { context7: { type: "local", command: ["npx"] } } } })).toBe(false)
|
||||
expect(ConfigMigrateV1.isV1({ mcp: {} })).toBe(false)
|
||||
expect(ConfigMigrateV1.isV1({ mcp: { timeout: { request: 1000 } } })).toBe(false)
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("migrates arbitrary v1 configuration into valid v2 configuration", () =>
|
||||
Effect.sync(() => {
|
||||
FastCheck.assert(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue