@@ -236,6 +236,17 @@ const McpStdioServerInputSchema = Schema.Struct({
236236 * add then auto-creates the connection holding them. The UI uses `envVars`
237237 * instead and leaves the values to the connect step. */
238238 env : Schema . optional ( Schema . Record ( Schema . String , Schema . String ) ) ,
239+ /** Non-secret environment the server needs, stored on the integration and
240+ * injected verbatim at spawn.
241+ *
242+ * Separate from `env` because that channel makes every variable a
243+ * CREDENTIAL: it is declared as a `stdio_env` method and the user is asked
244+ * to type its value on a masked form. That is right for an API key and
245+ * wrong for a machine-derived path — a Codex plugin's `CODEX_HOME` is
246+ * already known to the scanner, is not a secret, and must never become a
247+ * field a person has to fill in. Nothing here is a credential, so it does
248+ * not appear in `authenticationTemplate`. */
249+ staticEnv : Schema . optional ( Schema . Record ( Schema . String , Schema . String ) ) ,
239250 cwd : Schema . optional ( Schema . String ) ,
240251 /** Protocol negotiation at connect: `auto` probes `server/discover` (spec
241252 * 2026-07-28) for modern-only servers. Defaults to the legacy `initialize`
@@ -406,18 +417,23 @@ const stdioEnvVarNames = (input: McpStdioServerInput): readonly string[] => {
406417 return [ ...names ] ;
407418} ;
408419
409- const toIntegrationConfig = ( input : McpServerInput ) : McpIntegrationConfigType => {
420+ /** Exported for tests: the credential/non-credential split is a security
421+ * boundary (a value in `env` becomes something the user is asked to type),
422+ * and asserting it through the whole add flow would not show it. */
423+ export const toIntegrationConfig = ( input : McpServerInput ) : McpIntegrationConfigType => {
410424 if ( input . transport === "stdio" ) {
411425 // The config only DECLARES the secret env vars by NAME (a `stdio_env`
412426 // method); their values are credentials and live on the connection, never
413427 // in this blob. Names come from the explicit `envVars` declaration and/or
414428 // the keys of any one-shot `env` values.
415429 const vars = stdioEnvVarNames ( input ) ;
430+ const staticEnv = input . staticEnv ;
416431 return {
417432 transport : "stdio" ,
418433 family : input . family ?. trim ( ) || undefined ,
419434 command : input . command ,
420435 args : input . args ? [ ...input . args ] : undefined ,
436+ env : staticEnv !== undefined && Object . keys ( staticEnv ) . length > 0 ? staticEnv : undefined ,
421437 cwd : input . cwd ,
422438 versionNegotiation : input . versionNegotiation ,
423439 spawnPerCall : input . spawnPerCall ,
0 commit comments