← 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
M docs/SPEC-EXTENSIONS.mdM internal/openapi/parser.goM internal/openapi/parser_test.goM internal/pipeline/climanifest.goM internal/pipeline/climanifest_test.goM internal/pipeline/mcpb_manifest.goM internal/spec/spec.goM testdata/golden/expected/generate-golden-api-unicode/cafe-bistro/.printing-press.jsonM testdata/golden/expected/generate-golden-api-unicode/cafe-bistro/manifest.jsonM testdata/golden/expected/generate-golden-api/printing-press-golden/.printing-press.jsonM testdata/golden/expected/generate-golden-api/printing-press-golden/README.mdM testdata/golden/expected/generate-golden-api/printing-press-golden/SKILL.mdM testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/auth.goM testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/doctor.goM testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/helpers.goM testdata/golden/expected/generate-golden-api/printing-press-golden/internal/config/config.goM testdata/golden/expected/generate-golden-api/printing-press-golden/internal/mcp/tools.goM testdata/golden/expected/generate-golden-api/printing-press-golden/manifest.json
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 →