You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
docs: recommend PAT setup that keeps the token out of shell history #833
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.
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:
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.
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.
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.
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.
Activity
nk-tedo-001 commentedon Oct 12, 2026
+1 for the
_FILEoption. grafana/mcp-grafana already does this, and its behavior could serve as a template.They added
GRAFANA_SERVICE_ACCOUNT_TOKEN_FILEin #935 (docs). I run four instances of it this way, and the client config holds no secret at all:How it works there:
_FILEare set, the inline value wins.Two suggestions for gitlab-mcp:
GITLAB_OAUTH_CLIENT_SECRETas well as the PAT. WithGITLAB_USE_OAUTH=truethe client secret has to sit in plain text in the MCP client config (~/.claude.jsonin my case), which is the same problem as a PAT on the command line. A general rule like "every secret variableXalso acceptsX_FILE" would handle both.GITLAB_OAUTH_TOKEN_PATHkeeps the obtained OAuth token in a file, and there isGITLAB_OAUTH_TOKEN_SCRIPT. A_FILEoption 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-gitlabThat keeps the token out of shell history, the process list, and the client config.
zereight commentedon Oct 12, 2026
@nk-tedo-001 Thanks for the suggestion and the Grafana #935 reference — agreed that
_FILEis the cleaner long-term answer.Plan:
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.
zereight commentedon Oct 12, 2026
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.docs: keep PAT out of shell history in install examples (zereight#833)
feat: add GITLAB_PERSONAL_ACCESS_TOKEN_FILE (zereight#833)