Skip to content

docs: recommend PAT setup that keeps the token out of shell history #833

Closed

Description

@zereight

Problem

The quick-setup commands in the README and docs/clients/* put the GitLab personal access token straight on the command line, for example:

claude mcp add gitlab -e GITLAB_PERSONAL_ACCESS_TOKEN=glpat-xxxx -- npx -y @zereight/mcp-gitlab

That leaves the PAT in shell history (~/.bash_history, ~/.zsh_history) and can expose it to other local users through the process list. CodeRabbit raised this while reviewing #832.

Proposal

Document, and prefer in the quick-setup examples, ways of setting the token that keep it out of shell history:

  • Read the token from an environment variable that is already exported (for example -e GITLAB_PERSONAL_ACCESS_TOKEN="$GITLAB_PERSONAL_ACCESS_TOKEN"), or have the client resolve it, such as Cursor's ${env:...} or VS Code's ${input:...}.
  • Point to the client's secret or config file instead of an inline value, where the client supports it.
  • Mention a leading-space or HISTCONTROL=ignorespace approach only as a fallback.
  • Optionally evaluate a GITLAB_PERSONAL_ACCESS_TOKEN_FILE option (read the token from a file), which is a common pattern for Docker secrets. This would be a separate code change.

Scope

Mostly docs: README (all 4 languages), docs/clients/*, docs/configuration/*. The _FILE variant would be a separate, opt-in feature.

Follow-up from #832.

Activity

  1. nk-tedo-001 commented on Oct 12, 2026

    @nk-tedo-001

    +1 for the _FILE option. grafana/mcp-grafana already does this, and its behavior could serve as a template.

    They added GRAFANA_SERVICE_ACCOUNT_TOKEN_FILE in #935 (docs). I run four instances of it this way, and the client config holds no secret at all:

    "grafana-prod": {
      "command": "uvx",
      "args": ["mcp-grafana", "-t", "stdio"],
      "env": {
        "GRAFANA_URL": "https://grafana.example.com",
        "GRAFANA_SERVICE_ACCOUNT_TOKEN_FILE": "/home/me/.config/grafana/prod.token"
      }
    }

    How it works there:

    • The file is read on every request, not once at startup, so a rotated token (for example a Kubernetes Secret mounted as a volume) is picked up without a restart.
    • Surrounding whitespace, including the trailing newline, is trimmed.
    • If both the inline variable and _FILE are set, the inline value wins.
    • If the file can't be read, the server logs a warning and falls back to the next auth method instead of failing to start.

    Two suggestions for gitlab-mcp:

    1. Cover GITLAB_OAUTH_CLIENT_SECRET as well as the PAT. With GITLAB_USE_OAUTH=true the client secret has to sit in plain text in the MCP client config (~/.claude.json in my case), which is the same problem as a PAT on the command line. A general rule like "every secret variable X also accepts X_FILE" would handle both.
    2. Part of this already exists: GITLAB_OAUTH_TOKEN_PATH keeps the obtained OAuth token in a file, and there is GITLAB_OAUTH_TOKEN_SCRIPT. A _FILE option would extend the same idea to the static secrets.

    For the docs, the quick-setup example could then be:

    claude mcp add gitlab -e GITLAB_PERSONAL_ACCESS_TOKEN_FILE="$HOME/.config/gitlab/token" -- npx -y @zereight/mcp-gitlab

    That keeps the token out of shell history, the process list, and the client config.

  2. zereight commented on Oct 12, 2026

    @zereight
    OwnerAuthor

    @nk-tedo-001 Thanks for the suggestion and the Grafana #935 reference — agreed that _FILE is the cleaner long-term answer.

    Plan:

    1. Docs first: docs: keep PAT out of shell history in install examples #837 (merged) documents how to set the PAT without leaving it in shell history.
    2. Follow-up PR: add GITLAB_PERSONAL_ACCESS_TOKEN_FILE (read once at startup, whitespace trimmed; an inline token takes precedence with a warning; an unreadable file fails startup without ever logging the token). It will close this issue.

    Will link the PR here once it's up.

  3. zereight commented on Oct 12, 2026

    @zereight
    OwnerAuthor

    Follow-up PRs: #837 (docs: keep the PAT out of shell history) and #839 (GITLAB_PERSONAL_ACCESS_TOKEN_FILE, read once at startup). Re-reading the file per request is left as a follow-up.

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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions