(slug: string, input: McpConfigureAuthInput)
| 1395 | * (returns `[]`) for an unknown slug, a stdio server, or an |
| 1396 | * undecodable config. */ |
| 1397 | const configureAuth = (slug: string, input: McpConfigureAuthInput) => |
| 1398 | Effect.gen(function* () { |
| 1399 | const record = yield* ctx.core.integrations.get(slugFrom(slug)); |
| 1400 | const current = record ? parseMcpIntegrationConfig(record.config) : null; |
| 1401 | if (!current || current.transport === "stdio") { |
| 1402 | return [] as readonly McpAuthMethod[]; |
| 1403 | } |
| 1404 | |
| 1405 | // Replace mode declares the full set — backfill kind-based slugs. |
| 1406 | // Merge mode appends: `mergeAuthTemplates` replaces on slug match and |
| 1407 | // assigns fresh `custom_<id>` slugs to slug-less entries, so a custom |
| 1408 | // method never silently displaces a declared one. |
| 1409 | const merged = |
| 1410 | input.mode === "replace" |
| 1411 | ? normalizeMcpAuthMethods(input.authenticationTemplate) |
| 1412 | : mergeAuthTemplates( |
| 1413 | current.authenticationTemplate, |
| 1414 | expandMcpAuthMethodInputs( |
| 1415 | input.authenticationTemplate, |
| 1416 | ) as readonly McpAuthMethod[], |
| 1417 | ); |
| 1418 | |
| 1419 | yield* ctx.core.integrations.update(slugFrom(slug), { |
| 1420 | config: { ...current, authenticationTemplate: merged }, |
| 1421 | }); |
| 1422 | |
| 1423 | return merged; |
| 1424 | }).pipe( |
| 1425 | Effect.withSpan("mcp.plugin.configure_auth", { |
| 1426 | attributes: { "mcp.integration.slug": slug }, |
| 1427 | }), |
| 1428 | ); |
| 1429 | |
| 1430 | // Discover locally installed Codex plugins with stdio MCP servers. The |
| 1431 | // scanner touches node:fs, so it stays behind a dynamic import (the |
nothing calls this directly
no test coverage detected