(slug: string, input: McpConfigureAuthInput)
| 1355 | * (returns `[]`) for an unknown slug, a stdio server, or an |
| 1356 | * undecodable config. */ |
| 1357 | const configureAuth = (slug: string, input: McpConfigureAuthInput) => |
| 1358 | Effect.gen(function* () { |
| 1359 | const record = yield* ctx.core.integrations.get(slugFrom(slug)); |
| 1360 | const current = record ? parseMcpIntegrationConfig(record.config) : null; |
| 1361 | if (!current || current.transport === "stdio") { |
| 1362 | return [] as readonly McpAuthMethod[]; |
| 1363 | } |
| 1364 | |
| 1365 | // Replace mode declares the full set — backfill kind-based slugs. |
| 1366 | // Merge mode appends: `mergeAuthTemplates` replaces on slug match and |
| 1367 | // assigns fresh `custom_<id>` slugs to slug-less entries, so a custom |
| 1368 | // method never silently displaces a declared one. |
| 1369 | const merged = |
| 1370 | input.mode === "replace" |
| 1371 | ? normalizeMcpAuthMethods(input.authenticationTemplate) |
| 1372 | : mergeAuthTemplates( |
| 1373 | current.authenticationTemplate, |
| 1374 | expandMcpAuthMethodInputs( |
| 1375 | input.authenticationTemplate, |
| 1376 | ) as readonly McpAuthMethod[], |
| 1377 | ); |
| 1378 | |
| 1379 | yield* ctx.core.integrations.update(slugFrom(slug), { |
| 1380 | config: { ...current, authenticationTemplate: merged }, |
| 1381 | }); |
| 1382 | |
| 1383 | return merged; |
| 1384 | }).pipe( |
| 1385 | Effect.withSpan("mcp.plugin.configure_auth", { |
| 1386 | attributes: { "mcp.integration.slug": slug }, |
| 1387 | }), |
| 1388 | ); |
| 1389 | |
| 1390 | // Discover locally installed Codex plugins with stdio MCP servers. The |
| 1391 | // scanner touches node:fs, so it stays behind a dynamic import (the |
nothing calls this directly
no test coverage detected