[object Object]

← back to Cli Printing Press

fix(cli): support OpenAPI auth metadata overrides (#561)

35fa7afe997c8f3be8461749a86e389e1583e032 · 2026-05-03 21:16:32 -0700 · Trevin Chow

Files touched

Diff

commit 35fa7afe997c8f3be8461749a86e389e1583e032
Author: Trevin Chow <trevin@trevinchow.com>
Date:   Sun May 3 21:16:32 2026 -0700

    fix(cli): support OpenAPI auth metadata overrides (#561)
---
 docs/SPEC-EXTENSIONS.md                            |  93 ++++++++++++++++-
 internal/openapi/parser.go                         | 115 ++++++++++++++++++++-
 internal/openapi/parser_test.go                    |  80 ++++++++++++++
 internal/pipeline/climanifest.go                   |   7 ++
 internal/pipeline/climanifest_test.go              |  39 ++++++-
 internal/pipeline/mcpb_manifest.go                 |  18 +++-
 internal/spec/spec.go                              |   2 +
 .../cafe-bistro/.printing-press.json               |   2 +-
 .../cafe-bistro/manifest.json                      |   8 +-
 .../printing-press-golden/.printing-press.json     |   2 +-
 .../printing-press-golden/README.md                |  12 +--
 .../printing-press-golden/SKILL.md                 |   2 +-
 .../printing-press-golden/internal/cli/auth.go     |   8 +-
 .../printing-press-golden/internal/cli/doctor.go   |   4 +-
 .../printing-press-golden/internal/cli/helpers.go  |   6 +-
 .../internal/config/config.go                      |  12 +--
 .../printing-press-golden/internal/mcp/tools.go    |   8 +-
 .../printing-press-golden/manifest.json            |   8 +-
 18 files changed, 383 insertions(+), 43 deletions(-)

diff --git a/docs/SPEC-EXTENSIONS.md b/docs/SPEC-EXTENSIONS.md
index 5fd029df..b32a0fd7 100644
--- a/docs/SPEC-EXTENSIONS.md
+++ b/docs/SPEC-EXTENSIONS.md
@@ -18,6 +18,11 @@ in the same change as any new `Extensions["x-*"]` lookup in that file.
 | `x-auth-type` | `components.securitySchemes.<name>` | `APISpec.Auth.Type` | No |
 | `x-auth-format` | `components.securitySchemes.<name>` | `APISpec.Auth.Format` | No |
 | `x-prefix` | `components.securitySchemes.<name>` | `APISpec.Auth.Format` | No |
+| `x-auth-env-vars` | `components.securitySchemes.<name>` | `APISpec.Auth.EnvVars` | No |
+| `x-auth-optional` | `components.securitySchemes.<name>` | `APISpec.Auth.Optional` | No |
+| `x-auth-key-url` | `components.securitySchemes.<name>` | `APISpec.Auth.KeyURL` | No |
+| `x-auth-title` | `components.securitySchemes.<name>` | `APISpec.Auth.Title` | No |
+| `x-auth-description` | `components.securitySchemes.<name>` | `APISpec.Auth.Description` | No |
 | `x-auth-cookie-domain` | `components.securitySchemes.<name>` | `APISpec.Auth.CookieDomain` | No |
 | `x-auth-cookies` | `components.securitySchemes.<name>` | `APISpec.Auth.Cookies` | No |
 | `x-resource-id` | path item | `Endpoint.IDField` | No |
@@ -125,8 +130,9 @@ info:
 ## Security Scheme Extensions
 
 Security scheme extensions are read from
-`components.securitySchemes.<scheme-name>`. Today they are meaningful for
-`type: apiKey` schemes that declare composed cookie auth.
+`components.securitySchemes.<scheme-name>`. They can declare composed cookie
+auth or override install/config metadata when the API spec's service identity
+differs from the product identity exposed by the printed CLI.
 
 ### `x-auth-type`
 
@@ -177,6 +183,89 @@ components:
       x-prefix: Klaviyo-API-Key
 ```
 
+### `x-auth-env-vars`
+
+Overrides the generated credential environment variable names.
+
+Parsed field: `APISpec.Auth.EnvVars`
+
+Rules:
+- Optional.
+- Must be a list of strings. A single string is also accepted for convenience.
+- Leading and trailing whitespace is trimmed from each item.
+- Empty and non-string list items are ignored.
+- When at least one non-empty item is present, the list replaces the parser's
+  generated env var names.
+
+### `x-auth-optional`
+
+Marks the credential as optional for install/config surfaces.
+
+Parsed field: `APISpec.Auth.Optional`
+
+Rules:
+- Optional.
+- Must be a boolean.
+- `true` makes MCPB `user_config.required` false even for auth types that
+  normally require credentials.
+
+### `x-auth-key-url`
+
+Declares the page where users can get a credential.
+
+Parsed field: `APISpec.Auth.KeyURL`
+
+Rules:
+- Optional.
+- Must be a string.
+- Leading and trailing whitespace is trimmed.
+- The parser does not validate the URL shape.
+
+### `x-auth-title`
+
+Overrides the title shown for the credential field in install/config surfaces.
+
+Parsed field: `APISpec.Auth.Title`
+
+Rules:
+- Optional.
+- Must be a string.
+- Leading and trailing whitespace is trimmed.
+- Used when the selected auth scheme has a single env var. Multiple env vars
+  keep env-var-name titles to avoid duplicate field labels.
+
+### `x-auth-description`
+
+Overrides the full description shown for the credential field in install/config
+surfaces.
+
+Parsed field: `APISpec.Auth.Description`
+
+Rules:
+- Optional.
+- Must be a string.
+- Leading and trailing whitespace is trimmed.
+- Used as the complete description when the selected auth scheme has a single
+  env var. When omitted, the generator builds a description from env var name,
+  display name, optionality, and `x-auth-key-url`.
+
+Example:
+
+```yaml
+components:
+  securitySchemes:
+    ApiKeyAuth:
+      type: apiKey
+      in: header
+      name: x-apikey
+      x-auth-env-vars:
+        - FLIGHTAWARE_API_KEY
+      x-auth-optional: true
+      x-auth-key-url: https://flightaware.com/commercial/aeroapi/
+      x-auth-title: FlightAware AeroAPI Key
+      x-auth-description: Optional FlightAware AeroAPI credential for enriched flight data.
+```
+
 ### `x-auth-cookie-domain`
 
 Domain used when extracting named cookies for composed auth.
diff --git a/internal/openapi/parser.go b/internal/openapi/parser.go
index f893ae51..1d7541f1 100644
--- a/internal/openapi/parser.go
+++ b/internal/openapi/parser.go
@@ -26,6 +26,14 @@ var (
 	endpointLimitExplicit   = false // true when user set --max-endpoints-per-resource
 )
 
+const (
+	extensionAuthEnvVars     = "x-auth-env-vars"
+	extensionAuthOptional    = "x-auth-optional"
+	extensionAuthKeyURL      = "x-auth-key-url"
+	extensionAuthTitle       = "x-auth-title"
+	extensionAuthDescription = "x-auth-description"
+)
+
 // SetMaxResources overrides the default resource limit. When not called,
 // the parser uses a default of 500 which accommodates all known APIs.
 func SetMaxResources(n int) {
@@ -414,7 +422,7 @@ func mapAuth(doc *openapi3.T, name string) spec.AuthConfig {
 	case "api_key":
 		// Use scheme name for more specific env var (e.g. BotToken -> DISCORD_BOT_TOKEN)
 		schemeEnvSuffix := toSnakeCase(schemeName)
-		if schemeEnvSuffix != "" && schemeEnvSuffix != "api_key" {
+		if schemeEnvSuffix != "" && !isGenericAPIKeySchemeSuffix(schemeEnvSuffix) {
 			auth.EnvVars = []string{envPrefix + "_" + strings.ToUpper(schemeEnvSuffix)}
 		} else {
 			auth.EnvVars = []string{envPrefix + "_API_KEY"}
@@ -429,9 +437,114 @@ func mapAuth(doc *openapi3.T, name string) spec.AuthConfig {
 		}
 	}
 
+	applyAuthOverrideExtensions(&auth, scheme.Extensions)
 	return auth
 }
 
+func isGenericAPIKeySchemeSuffix(suffix string) bool {
+	normalized := strings.ReplaceAll(strings.ToLower(strings.TrimSpace(suffix)), "_", "")
+	switch normalized {
+	case "", "apikey", "apikeyauth":
+		return true
+	}
+	for _, prefix := range []string{"apikeyv", "apikeyauthv"} {
+		if version, ok := strings.CutPrefix(normalized, prefix); ok {
+			if version != "" && allDigits(version) {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+func allDigits(s string) bool {
+	for _, r := range s {
+		if !unicode.IsDigit(r) {
+			return false
+		}
+	}
+	return true
+}
+
+func applyAuthOverrideExtensions(auth *spec.AuthConfig, extensions map[string]any) {
+	if auth == nil || len(extensions) == 0 {
+		return
+	}
+	if envVars := stringListExtension(extensions, extensionAuthEnvVars); len(envVars) > 0 {
+		auth.EnvVars = envVars
+	}
+	if optional, ok := boolExtension(extensions, extensionAuthOptional); ok {
+		auth.Optional = optional
+	}
+	if keyURL := stringExtension(extensions, extensionAuthKeyURL); keyURL != "" {
+		auth.KeyURL = keyURL
+	}
+	if title := stringExtension(extensions, extensionAuthTitle); title != "" {
+		auth.Title = title
+	}
+	if description := stringExtension(extensions, extensionAuthDescription); description != "" {
+		auth.Description = description
+	}
+}
+
+func stringExtension(extensions map[string]any, name string) string {
+	value, ok := extensions[name]
+	if !ok {
+		return ""
+	}
+	s, ok := value.(string)
+	if !ok {
+		return ""
+	}
+	return strings.TrimSpace(s)
+}
+
+func stringListExtension(extensions map[string]any, name string) []string {
+	value, ok := extensions[name]
+	if !ok {
+		return nil
+	}
+	switch v := value.(type) {
+	case []string:
+		var out []string
+		for _, item := range v {
+			if item = strings.TrimSpace(item); item != "" {
+				out = append(out, item)
+			}
+		}
+		return out
+	case []any:
+		var out []string
+		for _, item := range v {
+			s, ok := item.(string)
+			if !ok {
+				continue
+			}
+			if s = strings.TrimSpace(s); s != "" {
+				out = append(out, s)
+			}
+		}
+		return out
+	case string:
+		if s := strings.TrimSpace(v); s != "" {
+			return []string{s}
+		}
+	}
+	return nil
+}
+
+func boolExtension(extensions map[string]any, name string) (bool, bool) {
+	value, ok := extensions[name]
+	if !ok {
+		return false, false
+	}
+	b, ok := value.(bool)
+	if !ok {
+		return false, false
+	}
+	return b, true
+}
+
 // commonAuthQueryParams are query parameter names that commonly carry API keys.
 var commonAuthQueryParams = map[string]bool{
 	"key":          true,
diff --git a/internal/openapi/parser_test.go b/internal/openapi/parser_test.go
index dd382796..54307c92 100644
--- a/internal/openapi/parser_test.go
+++ b/internal/openapi/parser_test.go
@@ -1000,6 +1000,86 @@ paths:
 	assert.Equal(t, "POKEAPI_API_KEY", parsed.Auth.EnvVars[0])
 }
 
+func TestGenericAPIKeySchemeNamesUseAPIKeyEnvVar(t *testing.T) {
+	t.Parallel()
+
+	tests := []string{
+		"ApiKeyAuth",
+		"APIKey",
+		"ApiKeyAuth_v2",
+	}
+
+	for _, schemeName := range tests {
+		t.Run(schemeName, func(t *testing.T) {
+			t.Parallel()
+
+			yamlSpec := fmt.Appendf(nil, `openapi: "3.0.3"
+info:
+  title: FlightGoat
+  version: "1.0.0"
+servers:
+  - url: https://api.example.com
+components:
+  securitySchemes:
+    %s:
+      type: apiKey
+      in: header
+      name: x-apikey
+paths:
+  /flights:
+    get:
+      responses:
+        "200":
+          description: OK
+`, schemeName)
+			parsed, err := Parse(yamlSpec)
+			require.NoError(t, err)
+
+			assert.Equal(t, "api_key", parsed.Auth.Type)
+			assert.Equal(t, []string{"FLIGHTGOAT_API_KEY"}, parsed.Auth.EnvVars)
+		})
+	}
+}
+
+func TestOpenAPIAuthOverrideExtensions(t *testing.T) {
+	t.Parallel()
+
+	yamlSpec := []byte(`openapi: "3.0.3"
+info:
+  title: FlightGoat
+  version: "1.0.0"
+servers:
+  - url: https://api.example.com
+components:
+  securitySchemes:
+    ApiKeyAuth:
+      type: apiKey
+      in: header
+      name: x-apikey
+      x-auth-env-vars:
+        - FLIGHTAWARE_API_KEY
+      x-auth-optional: true
+      x-auth-key-url: https://flightaware.com/commercial/aeroapi/
+      x-auth-title: FlightAware AeroAPI Key
+      x-auth-description: Optional FlightAware AeroAPI credential for enriched flight data.
+paths:
+  /flights:
+    get:
+      responses:
+        "200":
+          description: OK
+`)
+	parsed, err := Parse(yamlSpec)
+	require.NoError(t, err)
+
+	assert.Equal(t, "api_key", parsed.Auth.Type)
+	assert.Equal(t, []string{"FLIGHTAWARE_API_KEY"}, parsed.Auth.EnvVars)
+	assert.True(t, parsed.Auth.Optional)
+	assert.Equal(t, "https://flightaware.com/commercial/aeroapi/", parsed.Auth.KeyURL)
+	assert.Equal(t, "FlightAware AeroAPI Key", parsed.Auth.Title)
+	assert.Equal(t, "Optional FlightAware AeroAPI credential for enriched flight data.", parsed.Auth.Description)
+}
+
 func TestInferAuthHeaderParam(t *testing.T) {
 	t.Parallel()
 
diff --git a/internal/pipeline/climanifest.go b/internal/pipeline/climanifest.go
index c9a0ddb1..f19e9edd 100644
--- a/internal/pipeline/climanifest.go
+++ b/internal/pipeline/climanifest.go
@@ -68,6 +68,11 @@ type CLIManifest struct {
 	// downstream emitters (MCPB manifest user_config descriptions, doctor
 	// hints) to point users at the right credential source.
 	AuthKeyURL string `json:"auth_key_url,omitempty"`
+	// AuthTitle and AuthDescription customize the install/config prompt for
+	// the auth credential when the spec's service identity differs from the
+	// wrapped API identity.
+	AuthTitle       string `json:"auth_title,omitempty"`
+	AuthDescription string `json:"auth_description,omitempty"`
 	// AuthOptional is true when the credential gates a subset of features
 	// (e.g., USDA nutrition backfill on recipe-goat) rather than every
 	// API call. Drives the MCPB user_config Required field so opt-in
@@ -264,6 +269,8 @@ func populateMCPMetadata(m *CLIManifest, parsed *spec.APISpec) {
 	m.AuthEnvVars = parsed.Auth.EnvVars
 	m.EndpointTemplateVars = parsed.EndpointTemplateVars
 	m.AuthKeyURL = parsed.Auth.KeyURL
+	m.AuthTitle = parsed.Auth.Title
+	m.AuthDescription = parsed.Auth.Description
 	m.AuthOptional = parsed.Auth.Optional
 	// DisplayName precedence: explicit spec field > catalog-set existing
 	// value > slug-derived fallback. Unconditional fallback would clobber a
diff --git a/internal/pipeline/climanifest_test.go b/internal/pipeline/climanifest_test.go
index bf8ff778..4b83a8df 100644
--- a/internal/pipeline/climanifest_test.go
+++ b/internal/pipeline/climanifest_test.go
@@ -721,6 +721,33 @@ func TestWriteMCPBManifest(t *testing.T) {
 		assert.Contains(t, key.Description, "https://fdc.nal.usda.gov/api-key-signup")
 	})
 
+	t.Run("auth metadata overrides user_config title and description", func(t *testing.T) {
+		dir := t.TempDir()
+		writeManifest(t, dir, CLIManifest{
+			APIName:         "flightgoat",
+			DisplayName:     "Flight GOAT",
+			MCPBinary:       "flightgoat-pp-mcp",
+			MCPReady:        "full",
+			AuthType:        "api_key",
+			AuthEnvVars:     []string{"FLIGHTAWARE_API_KEY"},
+			AuthOptional:    true,
+			AuthKeyURL:      "https://flightaware.com/commercial/aeroapi/",
+			AuthTitle:       "FlightAware AeroAPI Key",
+			AuthDescription: "Optional FlightAware AeroAPI credential for enriched flight data.",
+		})
+
+		require.NoError(t, WriteMCPBManifest(dir))
+		got := readMCPBManifest(t, dir)
+
+		assert.Equal(t, "${user_config.flightaware_api_key}", got.Server.MCPConfig.Env["FLIGHTAWARE_API_KEY"])
+		key, ok := got.UserConfig["flightaware_api_key"]
+		require.True(t, ok)
+		assert.Equal(t, "FlightAware AeroAPI Key", key.Title)
+		assert.Equal(t, "Optional FlightAware AeroAPI credential for enriched flight data.", key.Description)
+		assert.False(t, key.Required)
+		assert.True(t, key.Sensitive)
+	})
+
 	t.Run("multiple optional env vars (company-goat shape)", func(t *testing.T) {
 		dir := t.TempDir()
 		writeManifest(t, dir, CLIManifest{
@@ -1022,8 +1049,12 @@ func TestPopulateMCPMetadata(t *testing.T) {
 	populateMCPMetadata(&m, &spec.APISpec{
 		Name: "test",
 		Auth: spec.AuthConfig{
-			Type:    "cookie",
-			EnvVars: []string{"TEST_AUTH"},
+			Type:        "cookie",
+			EnvVars:     []string{"TEST_AUTH"},
+			KeyURL:      "https://auth.example.com",
+			Optional:    true,
+			Title:       "Test Auth",
+			Description: "Use this test credential.",
 		},
 		Resources: map[string]spec.Resource{
 			"items": {
@@ -1041,6 +1072,10 @@ func TestPopulateMCPMetadata(t *testing.T) {
 	assert.Equal(t, "partial", m.MCPReady)
 	assert.Equal(t, "cookie", m.AuthType)
 	assert.Equal(t, []string{"TEST_AUTH"}, m.AuthEnvVars)
+	assert.Equal(t, "https://auth.example.com", m.AuthKeyURL)
+	assert.True(t, m.AuthOptional)
+	assert.Equal(t, "Test Auth", m.AuthTitle)
+	assert.Equal(t, "Use this test credential.", m.AuthDescription)
 }
 
 // TestPopulateMCPMetadataDisplayNamePrecedence pins:
diff --git a/internal/pipeline/mcpb_manifest.go b/internal/pipeline/mcpb_manifest.go
index d28ccccc..94ebcd6e 100644
--- a/internal/pipeline/mcpb_manifest.go
+++ b/internal/pipeline/mcpb_manifest.go
@@ -312,10 +312,11 @@ func buildMCPBUserConfig(m CLIManifest) map[string]MCPBVar {
 	required := authRequiresCredential(m.AuthType) && !m.AuthOptional
 	vars := make(map[string]MCPBVar, len(m.AuthEnvVars)+len(m.EndpointTemplateVars))
 	for _, name := range m.AuthEnvVars {
+		title, description := authUserConfigText(m, name, required)
 		vars[userConfigKey(name)] = MCPBVar{
 			Type:        mcpbVarTypeString,
-			Title:       name,
-			Description: envVarDescription(m, name, required),
+			Title:       title,
+			Description: description,
 			Sensitive:   true,
 			Required:    required,
 		}
@@ -347,6 +348,19 @@ func endpointTemplateVarDescription(templateVar, envVar string) string {
 	return fmt.Sprintf("Sets %s for the endpoint template variable {%s}.", envVar, templateVar)
 }
 
+func authUserConfigText(m CLIManifest, envVar string, required bool) (string, string) {
+	title := envVar
+	if len(m.AuthEnvVars) == 1 {
+		if override := strings.TrimSpace(m.AuthTitle); override != "" {
+			title = override
+		}
+		if description := strings.TrimSpace(m.AuthDescription); description != "" {
+			return title, description
+		}
+	}
+	return title, envVarDescription(m, envVar, required)
+}
+
 func endpointTemplateDefault(m CLIManifest, templateVar string) string {
 	if strings.EqualFold(templateVar, "api_version") {
 		return m.APIVersion
diff --git a/internal/spec/spec.go b/internal/spec/spec.go
index 974368a1..7488eb4d 100644
--- a/internal/spec/spec.go
+++ b/internal/spec/spec.go
@@ -324,6 +324,8 @@ type AuthConfig struct {
 	Scheme           string   `yaml:"scheme,omitempty" json:"scheme,omitempty"`     // OpenAPI security scheme name
 	In               string   `yaml:"in,omitempty" json:"in,omitempty"`             // header, query, cookie
 	KeyURL           string   `yaml:"key_url,omitempty" json:"key_url,omitempty"`   // URL where users can register for an API key
+	Title            string   `yaml:"title,omitempty" json:"title,omitempty"`       // user-facing credential field title for install/config surfaces
+	Description      string   `yaml:"description,omitempty" json:"description,omitempty"`
 	AuthorizationURL string   `yaml:"authorization_url,omitempty" json:"authorization_url,omitempty"`
 	TokenURL         string   `yaml:"token_url,omitempty" json:"token_url,omitempty"`
 	Scopes           []string `yaml:"scopes,omitempty" json:"scopes,omitempty"`
diff --git a/testdata/golden/expected/generate-golden-api-unicode/cafe-bistro/.printing-press.json b/testdata/golden/expected/generate-golden-api-unicode/cafe-bistro/.printing-press.json
index 76a4b5d7..2d2edcf9 100644
--- a/testdata/golden/expected/generate-golden-api-unicode/cafe-bistro/.printing-press.json
+++ b/testdata/golden/expected/generate-golden-api-unicode/cafe-bistro/.printing-press.json
@@ -2,7 +2,7 @@
   "api_name": "cafe-bistro",
   "api_version": "1.0.0",
   "auth_env_vars": [
-    "CAFE_BISTRO_API_KEY_AUTH"
+    "CAFE_BISTRO_API_KEY"
   ],
   "auth_type": "api_key",
   "cli_name": "cafe-bistro-pp-cli",
diff --git a/testdata/golden/expected/generate-golden-api-unicode/cafe-bistro/manifest.json b/testdata/golden/expected/generate-golden-api-unicode/cafe-bistro/manifest.json
index 5bcaf49e..0456e5c7 100644
--- a/testdata/golden/expected/generate-golden-api-unicode/cafe-bistro/manifest.json
+++ b/testdata/golden/expected/generate-golden-api-unicode/cafe-bistro/manifest.json
@@ -21,17 +21,17 @@
       "args": [],
       "command": "${__dirname}/bin/cafe-bistro-pp-mcp",
       "env": {
-        "CAFE_BISTRO_API_KEY_AUTH": "${user_config.cafe_bistro_api_key_auth}"
+        "CAFE_BISTRO_API_KEY": "${user_config.cafe_bistro_api_key}"
       }
     },
     "type": "binary"
   },
   "user_config": {
-    "cafe_bistro_api_key_auth": {
-      "description": "Sets CAFE_BISTRO_API_KEY_AUTH for the Café Bistro MCP server.",
+    "cafe_bistro_api_key": {
+      "description": "Sets CAFE_BISTRO_API_KEY for the Café Bistro MCP server.",
       "required": true,
       "sensitive": true,
-      "title": "CAFE_BISTRO_API_KEY_AUTH",
+      "title": "CAFE_BISTRO_API_KEY",
       "type": "string"
     }
   },
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/.printing-press.json b/testdata/golden/expected/generate-golden-api/printing-press-golden/.printing-press.json
index f7381875..a892f8cd 100644
--- a/testdata/golden/expected/generate-golden-api/printing-press-golden/.printing-press.json
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/.printing-press.json
@@ -2,7 +2,7 @@
   "api_name": "printing-press-golden",
   "api_version": "2026.04",
   "auth_env_vars": [
-    "PRINTING_PRESS_GOLDEN_API_KEY_AUTH"
+    "PRINTING_PRESS_GOLDEN_API_KEY"
   ],
   "auth_type": "api_key",
   "cli_name": "printing-press-golden-pp-cli",
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/README.md b/testdata/golden/expected/generate-golden-api/printing-press-golden/README.md
index 4c5c8b59..8f3e4e8b 100644
--- a/testdata/golden/expected/generate-golden-api/printing-press-golden/README.md
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/README.md
@@ -25,7 +25,7 @@ See [Install](#install) above.
 Get your API key from your API provider's developer portal. The key typically looks like a long alphanumeric string.
 
 ```bash
-export PRINTING_PRESS_GOLDEN_API_KEY_AUTH="<paste-your-key>"
+export PRINTING_PRESS_GOLDEN_API_KEY="<paste-your-key>"
 ```
 
 You can also persist this in your config file at `~/.config/printing-press-golden-pp-cli/config.toml`.
@@ -133,7 +133,7 @@ go install github.com/mvanhorn/printing-press-library/library/other/printing-pre
 Then register it:
 
 ```bash
-claude mcp add printing-press-golden printing-press-golden-pp-mcp -e PRINTING_PRESS_GOLDEN_API_KEY_AUTH=<your-key>
+claude mcp add printing-press-golden printing-press-golden-pp-mcp -e PRINTING_PRESS_GOLDEN_API_KEY=<your-key>
 ```
 
 </details>
@@ -146,7 +146,7 @@ To install:
 
 1. Download the `.mcpb` for your platform from the [latest release](https://github.com/mvanhorn/printing-press-library/releases/tag/printing-press-golden-current).
 2. Double-click the `.mcpb` file. Claude Desktop opens and walks you through the install.
-3. Fill in `PRINTING_PRESS_GOLDEN_API_KEY_AUTH` when Claude Desktop prompts you.
+3. Fill in `PRINTING_PRESS_GOLDEN_API_KEY` when Claude Desktop prompts you.
 
 Requires Claude Desktop 1.0.0 or later. Pre-built bundles ship for macOS Apple Silicon (`darwin-arm64`) and Windows (`amd64`, `arm64`); for other platforms, use the manual config below.
 
@@ -167,7 +167,7 @@ Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_
     "printing-press-golden": {
       "command": "printing-press-golden-pp-mcp",
       "env": {
-        "PRINTING_PRESS_GOLDEN_API_KEY_AUTH": "<your-key>"
+        "PRINTING_PRESS_GOLDEN_API_KEY": "<your-key>"
       }
     }
   }
@@ -189,12 +189,12 @@ Verifies configuration, credentials, and connectivity to the API.
 Config file: `~/.config/printing-press-golden-pp-cli/config.toml`
 
 Environment variables:
-- `PRINTING_PRESS_GOLDEN_API_KEY_AUTH`
+- `PRINTING_PRESS_GOLDEN_API_KEY`
 
 ## Troubleshooting
 **Authentication errors (exit code 4)**
 - Run `printing-press-golden-pp-cli doctor` to check credentials
-- Verify the environment variable is set: `echo $PRINTING_PRESS_GOLDEN_API_KEY_AUTH`
+- Verify the environment variable is set: `echo $PRINTING_PRESS_GOLDEN_API_KEY`
 **Not found errors (exit code 3)**
 - Check the resource ID is correct
 - Run the `list` command to see available items
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/SKILL.md b/testdata/golden/expected/generate-golden-api/printing-press-golden/SKILL.md
index b667fe20..51acfdee 100644
--- a/testdata/golden/expected/generate-golden-api/printing-press-golden/SKILL.md
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/SKILL.md
@@ -45,7 +45,7 @@ printing-press-golden-pp-cli which "<capability in your own words>"
 Set your API key via environment variable:
 
 ```bash
-export PRINTING_PRESS_GOLDEN_API_KEY_AUTH="<your-key>"
+export PRINTING_PRESS_GOLDEN_API_KEY="<your-key>"
 ```
 
 Or persist it in `~/.config/printing-press-golden-pp-cli/config.toml`.
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/auth.go b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/auth.go
index 12415903..62f0a258 100644
--- a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/auth.go
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/auth.go
@@ -14,7 +14,7 @@ import (
 func newAuthCmd(flags *rootFlags) *cobra.Command {
 	cmd := &cobra.Command{
 		Use:   "auth",
-		Short: "Manage PRINTING_PRESS_GOLDEN_API_KEY_AUTH credentials",
+		Short: "Manage PRINTING_PRESS_GOLDEN_API_KEY credentials",
 	}
 
 	cmd.AddCommand(newAuthStatusCmd(flags))
@@ -41,7 +41,7 @@ func newAuthStatusCmd(flags *rootFlags) *cobra.Command {
 				fmt.Fprintln(w, red("Not authenticated"))
 				fmt.Fprintln(w, "")
 				fmt.Fprintln(w, "Set your token:")
-				fmt.Fprintln(w, "  export PRINTING_PRESS_GOLDEN_API_KEY_AUTH=\"your-token-here\"")
+				fmt.Fprintln(w, "  export PRINTING_PRESS_GOLDEN_API_KEY=\"your-token-here\"")
 				fmt.Fprintf(w, "  printing-press-golden-pp-cli auth set-token <token>\n")
 				return authErr(fmt.Errorf("no credentials configured"))
 			}
@@ -101,8 +101,8 @@ func newAuthLogoutCmd(flags *rootFlags) *cobra.Command {
 			}
 
 			// Warn if env vars still set
-			if os.Getenv("PRINTING_PRESS_GOLDEN_API_KEY_AUTH") != "" {
-				fmt.Fprintf(cmd.OutOrStdout(), "Config cleared. Note: PRINTING_PRESS_GOLDEN_API_KEY_AUTH env var is still set.\n")
+			if os.Getenv("PRINTING_PRESS_GOLDEN_API_KEY") != "" {
+				fmt.Fprintf(cmd.OutOrStdout(), "Config cleared. Note: PRINTING_PRESS_GOLDEN_API_KEY env var is still set.\n")
 				return nil
 			}
 			fmt.Fprintln(cmd.OutOrStdout(), "Logged out. Credentials cleared.")
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/doctor.go b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/doctor.go
index 30274a16..1f83b0be 100644
--- a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/doctor.go
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/doctor.go
@@ -86,7 +86,7 @@ func newDoctorCmd(flags *rootFlags) *cobra.Command {
 				header := cfg.AuthHeader()
 				if header == "" {
 					report["auth"] = "not configured"
-					report["auth_hint"] = "export PRINTING_PRESS_GOLDEN_API_KEY_AUTH=<your-key>"
+					report["auth_hint"] = "export PRINTING_PRESS_GOLDEN_API_KEY=<your-key>"
 				} else {
 					report["auth"] = "configured"
 					report["auth_source"] = cfg.AuthSource
@@ -97,7 +97,7 @@ func newDoctorCmd(flags *rootFlags) *cobra.Command {
 			authEnvChecked := 0
 			authEnvSet := 0
 			authEnvChecked++
-			if os.Getenv("PRINTING_PRESS_GOLDEN_API_KEY_AUTH") != "" {
+			if os.Getenv("PRINTING_PRESS_GOLDEN_API_KEY") != "" {
 				authEnvSet++
 			}
 			if authEnvSet == 0 {
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/helpers.go b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/helpers.go
index 8913e4f0..a5704a99 100644
--- a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/helpers.go
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/helpers.go
@@ -204,17 +204,17 @@ func classifyAPIError(err error) error {
 		return nil
 	case strings.Contains(msg, "HTTP 400") && cliutil.LooksLikeAuthError(msg):
 		return authErr(fmt.Errorf("%w\nhint: the API rejected the request — this usually means auth is missing or invalid."+
-			"\n      Set your API key: export PRINTING_PRESS_GOLDEN_API_KEY_AUTH=<your-key>"+
+			"\n      Set your API key: export PRINTING_PRESS_GOLDEN_API_KEY=<your-key>"+
 			"\n      Run 'printing-press-golden-pp-cli doctor' to check auth status."+
 			"\n      Response: "+cliutil.SanitizeErrorBody(msg), err))
 	case strings.Contains(msg, "HTTP 401"):
 		return authErr(fmt.Errorf("%w\nhint: check your API key."+
-			" Set it with: export PRINTING_PRESS_GOLDEN_API_KEY_AUTH=<your-key>"+
+			" Set it with: export PRINTING_PRESS_GOLDEN_API_KEY=<your-key>"+
 			"\n      Run 'printing-press-golden-pp-cli doctor' to check auth status.", err))
 	case strings.Contains(msg, "HTTP 403"):
 		return authErr(fmt.Errorf("%w\nhint: permission denied. Your credentials are valid but lack access to this resource."+
 			"\n      Check that your API key has the required permissions."+
-			"\n      Set it with: export PRINTING_PRESS_GOLDEN_API_KEY_AUTH=<your-key>"+
+			"\n      Set it with: export PRINTING_PRESS_GOLDEN_API_KEY=<your-key>"+
 			"\n      Run 'printing-press-golden-pp-cli doctor' to check auth status.", err))
 	case strings.Contains(msg, "HTTP 404"):
 		return notFoundErr(fmt.Errorf("%w\nhint: resource not found. Run the 'list' command to see available items", err))
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/config/config.go b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/config/config.go
index 612e5921..9ccaf699 100644
--- a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/config/config.go
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/config/config.go
@@ -23,7 +23,7 @@ type Config struct {
 	ClientID       string `toml:"client_id"`
 	ClientSecret   string `toml:"client_secret"`
 	Path           string `toml:"-"`
-	PrintingPressGoldenApiKeyAuth string `toml:"press_golden_api_key_auth"`
+	PrintingPressGoldenApiKey string `toml:"press_golden_api_key"`
 }
 
 func Load(configPath string) (*Config, error) {
@@ -51,9 +51,9 @@ func Load(configPath string) (*Config, error) {
 	}
 
 	// Env var overrides
-	if v := os.Getenv("PRINTING_PRESS_GOLDEN_API_KEY_AUTH"); v != "" {
-		cfg.PrintingPressGoldenApiKeyAuth = v
-		cfg.AuthSource = "env:PRINTING_PRESS_GOLDEN_API_KEY_AUTH"
+	if v := os.Getenv("PRINTING_PRESS_GOLDEN_API_KEY"); v != "" {
+		cfg.PrintingPressGoldenApiKey = v
+		cfg.AuthSource = "env:PRINTING_PRESS_GOLDEN_API_KEY"
 	}
 
 	// Base URL override (used by printing-press verify to point at mock/test servers)
@@ -67,11 +67,11 @@ func (c *Config) AuthHeader() string {
 	if c.AuthHeaderVal != "" {
 		return c.AuthHeaderVal
 	}
-	token := c.PrintingPressGoldenApiKeyAuth
+	token := c.PrintingPressGoldenApiKey
 	if token == "" {
 		return ""
 	}
-	if c.PrintingPressGoldenApiKeyAuth == "" {
+	if c.PrintingPressGoldenApiKey == "" {
 		return ""
 	}
 	return token
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/mcp/tools.go b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/mcp/tools.go
index 93032f94..cb9965bc 100644
--- a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/mcp/tools.go
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/mcp/tools.go
@@ -205,17 +205,17 @@ func makeAPIHandler(method, pathTemplate string, positionalParams []string) serv
 			case strings.Contains(msg, "HTTP 400") && cliutil.LooksLikeAuthError(msg):
 				return mcplib.NewToolResultError("authentication error: " + cliutil.SanitizeErrorBody(msg) +
 					"\nhint: the API rejected the request — this usually means auth is missing or invalid." +
-					"\n      Set your API key: export PRINTING_PRESS_GOLDEN_API_KEY_AUTH=<your-key>" +
+					"\n      Set your API key: export PRINTING_PRESS_GOLDEN_API_KEY=<your-key>" +
 					"\n      Run 'printing-press-golden-pp-cli doctor' to check auth status."), nil
 			case strings.Contains(msg, "HTTP 401"):
 				return mcplib.NewToolResultError("authentication failed: " + cliutil.SanitizeErrorBody(msg) +
 					"\nhint: check your API key." +
-					"\n      Set it with: export PRINTING_PRESS_GOLDEN_API_KEY_AUTH=<your-key>" +
+					"\n      Set it with: export PRINTING_PRESS_GOLDEN_API_KEY=<your-key>" +
 					"\n      Run 'printing-press-golden-pp-cli doctor' to check auth status."), nil
 			case strings.Contains(msg, "HTTP 403"):
 				return mcplib.NewToolResultError("permission denied: " + cliutil.SanitizeErrorBody(msg) +
 					"\nhint: your credentials are valid but lack access to this resource." +
-					"\n      Set it with: export PRINTING_PRESS_GOLDEN_API_KEY_AUTH=<your-key>" +
+					"\n      Set it with: export PRINTING_PRESS_GOLDEN_API_KEY=<your-key>" +
 					"\n      Run 'printing-press-golden-pp-cli doctor' to check auth status."), nil
 			case strings.Contains(msg, "HTTP 404"):
 				if method == "DELETE" {
@@ -356,7 +356,7 @@ func handleContext(_ context.Context, _ mcplib.CallToolRequest) (*mcplib.CallToo
 		"tool_surface": "MCP exposes typed endpoint tools plus a runtime mirror of user-facing CLI commands. Endpoint tools keep typed schemas; command-mirror tools shell out to the companion printing-press-golden-pp-cli binary.",
 		"auth": map[string]any{
 			"type": "api_key",
-			"env_vars": []string{"PRINTING_PRESS_GOLDEN_API_KEY_AUTH",  },
+			"env_vars": []string{"PRINTING_PRESS_GOLDEN_API_KEY",  },
 		},
 		"resources": []map[string]any{
 			{
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/manifest.json b/testdata/golden/expected/generate-golden-api/printing-press-golden/manifest.json
index aace3978..dbc7bd2e 100644
--- a/testdata/golden/expected/generate-golden-api/printing-press-golden/manifest.json
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/manifest.json
@@ -21,17 +21,17 @@
       "args": [],
       "command": "${__dirname}/bin/printing-press-golden-pp-mcp",
       "env": {
-        "PRINTING_PRESS_GOLDEN_API_KEY_AUTH": "${user_config.printing_press_golden_api_key_auth}"
+        "PRINTING_PRESS_GOLDEN_API_KEY": "${user_config.printing_press_golden_api_key}"
       }
     },
     "type": "binary"
   },
   "user_config": {
-    "printing_press_golden_api_key_auth": {
-      "description": "Sets PRINTING_PRESS_GOLDEN_API_KEY_AUTH for the Printing Press Studio MCP server.",
+    "printing_press_golden_api_key": {
+      "description": "Sets PRINTING_PRESS_GOLDEN_API_KEY for the Printing Press Studio MCP server.",
       "required": true,
       "sensitive": true,
-      "title": "PRINTING_PRESS_GOLDEN_API_KEY_AUTH",
+      "title": "PRINTING_PRESS_GOLDEN_API_KEY",
       "type": "string"
     }
   },

← b39a23d0 fix(cli): separate sampled probes from live verification (#5  ·  back to Cli Printing Press  ·  fix(cli): add client-call reimplementation directive (#562) 6242e101 →