* Normalize a raw config entry into a strongly-typed server definition. * * Supported raw formats: * - string: stdio command * - object w/ command: stdio * - object w/ url: http/sse/auto (defaults to auto)
(entry: unknown)
| 59 | * - object w/ url: http/sse/auto (defaults to auto) |
| 60 | */ |
| 61 | private normalizeEntry(entry: unknown): MCPServerInfo { |
| 62 | if (typeof entry === "string") { |
| 63 | return { transport: "stdio", command: entry, disabled: false }; |
| 64 | } |
| 65 | |
| 66 | if (!entry || typeof entry !== "object") { |
| 67 | // Fail closed for invalid shapes. |
| 68 | return { transport: "stdio", command: "", disabled: true }; |
| 69 | } |
| 70 | |
| 71 | const obj = entry as Record<string, unknown>; |
| 72 | const disabled = typeof obj.disabled === "boolean" ? obj.disabled : false; |
| 73 | const toolAllowlist = Array.isArray(obj.toolAllowlist) |
| 74 | ? obj.toolAllowlist.filter((v): v is string => typeof v === "string") |
| 75 | : undefined; |
| 76 | |
| 77 | const transport = |
| 78 | obj.transport === "stdio" || |
| 79 | obj.transport === "http" || |
| 80 | obj.transport === "sse" || |
| 81 | obj.transport === "auto" |
| 82 | ? obj.transport |
| 83 | : undefined; |
| 84 | |
| 85 | const command = typeof obj.command === "string" ? obj.command : undefined; |
| 86 | const url = typeof obj.url === "string" ? obj.url : undefined; |
| 87 | |
| 88 | const headersRaw = obj.headers; |
| 89 | let headers: Record<string, string | { secret: string }> | undefined; |
| 90 | |
| 91 | if (headersRaw && typeof headersRaw === "object" && !Array.isArray(headersRaw)) { |
| 92 | const next: Record<string, string | { secret: string }> = {}; |
| 93 | for (const [k, v] of Object.entries(headersRaw as Record<string, unknown>)) { |
| 94 | if (typeof v === "string") { |
| 95 | next[k] = v; |
| 96 | continue; |
| 97 | } |
| 98 | if (v && typeof v === "object" && !Array.isArray(v)) { |
| 99 | const secret = (v as Record<string, unknown>).secret; |
| 100 | if (typeof secret === "string") { |
| 101 | next[k] = { secret }; |
| 102 | } |
| 103 | } |
| 104 | } |
| 105 | if (Object.keys(next).length > 0) { |
| 106 | headers = next; |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | // If it has a url, prefer HTTP-based transports (default to auto). |
| 111 | if (url) { |
| 112 | const httpTransport = transport && transport !== "stdio" ? transport : "auto"; |
| 113 | return { |
| 114 | transport: httpTransport, |
| 115 | url, |
| 116 | headers, |
| 117 | disabled, |
| 118 | toolAllowlist, |