Skip to content

CLI-managed MCP server setup, without required env variables for credentials #1685

Description

@tgrunnagle

Summary

Make setting up an MCP server easy from the CLI, and stop requiring an environment
variable for the credential-store key. Today both are manual and error-prone: adding
a server means hand-editing the operator settings.yaml mcp.servers[] block, and
the local OAuth credential store can only take its encryption key from a MECATL_*
env var that must be present in every shell/process that logs in or reads the credential.

Motivation

Writing the setup guide for connecting mecatui to an OAuth MCP server (the Stacklok
staging connector-gateway) surfaced two friction points:

  1. No CLI to manage servers. mecated mcp only supports login
    (cmd/mecated/command.go). Adding a server means hand-writing a ~20-line nested
    mcp.servers[] OAuth/DCR block with several non-obvious, easy-to-get-wrong fields:
    the server name must be [A-Za-z0-9_]+ (no hyphens), url must include the
    resource path (e.g. /gw/mcp), issuer must be the exact origin,
    client: {mode: dcr, dcr: {}}, plus credentials and network blocks. A typo in
    any of these fails discovery with a generic, detail-suppressed error (the specific
    cause is dropped in internal/app/mcplogin.go's loginDiagnostic).

  2. The credential-store key must come from an env var. The local OAuth credential
    store (MCPLocalCredentialProfile, internal/adapter/permconfig/schema.go) accepts
    only key_env: MECATL_*. So the operator has to generate a 32-byte key, store it,
    and export MECATL_MCP_CREDENTIAL_KEY in every shell that runs mecated mcp login
    and every process that later reads the credential (e.g. mecatui). Miss it in the
    runtime shell and the credential silently can't be decrypted → the server drops to
    "login required" with no obvious cause. This is exactly the "harder to set up in a
    durable way" concern raised in review.

Proposal

1. CLI management of MCP servers

Add mecated mcp subcommands to add/list/remove/inspect servers without hand-editing YAML:

  • mecated mcp add <name> --url <url> --auth oauth — sensible OAuth/DCR defaults;
    discover issuer/resource from the server's RFC 9728 protected-resource metadata
    where possible (the same discoverDCRMetadata path login already runs), prompting
    only for what can't be discovered, and validating up front so it can surface the
    specific failure (issuer mismatch, DCR unsupported, missing scope) instead of the
    current generic "authorization unavailable".
  • mecated mcp list / mecated mcp status — configured servers plus connection and
    credential state.
  • mecated mcp remove <name>.

These read/write the same operator settings.yaml mcp.servers[] schema, so config
stays declarative and reviewable — the CLI is a safe editor over it, not a second
source of truth. mecated mcp login <name> already exists and composes with this.

2. Don't require an env variable for the credential-store key

Give the MCP local credential store the same key-custody choice the OIDC provider
credential store already has. NativeCredentialKey
(internal/adapter/permconfig/providers.go) already supports source: keyring | environment,
defaulting to the OS keyring. MCPLocalCredentialProfile should adopt the same union so
the default is keyring custody (macOS Keychain / Secret Service / etc.) with no env
var, and key_env becomes one opt-in option (for headless/CI) rather than the only
mechanism.

Result: mecated mcp login <name> and the runtime both get the key from the keyring
automatically — nothing to export, nothing to re-export per shell, and it survives
across sessions and processes durably.

Acceptance sketch

  • mecated mcp add|list|remove manage mcp.servers[] entries in operator
    settings.yaml; round-trip preserves unknown top-level keys.
  • The MCP local credential store defaults to keyring-backed key custody; no MECATL_*
    env var is required to log in or to read the credential at runtime. key_env remains
    supported for headless deployments.
  • Docs updated to the CLI-first, no-env-var flow
    (user-docs/features/mcp-oauth-and-credentials.md, and the eng setup guide).

References

  • Current CLI surface: cmd/mecated/command.go (only mcp login).
  • Env-only key today: internal/adapter/permconfig/schema.go (MCPLocalCredentialProfile.KeyEnv).
  • Existing keyring pattern to reuse: internal/adapter/permconfig/providers.go (NativeCredentialKey, source: keyring).
  • Generic-error masking to improve alongside add: internal/app/mcplogin.go (loginDiagnostic).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    configOperator settings.yaml / YAML config surface, flags, and config UX (init, reference, enable models)enhancementNew feature or requestux

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions