Credentials
How external MCP server credentials are stored, resolved, and refreshed.
External MCP servers that require authentication need credentials — bearer tokens, API keys, or OAuth tokens. The credential system resolves these from multiple sources without requiring secrets to be committed to version control.
Resolution order
When the runtime needs a credential for a server, it checks these sources in order (first match wins):
- Environment variable — the
envTokenfield names a variable that holds the token - Credential file — stored at
~/.config/oxagen/credentials/<server-name>.json - Remote API — fetches the credential from the platform (requires
oxagen auth login)
Environment variables
The simplest approach for CI/CD and local development:
{
"mcpServers": {
"linear": {
"transport": "sse",
"url": "https://mcp.linear.app/sse",
"auth": "bearer",
"envToken": "LINEAR_MCP_TOKEN"
}
}
}Set the variable in your shell:
export LINEAR_MCP_TOKEN="lin_api_..."For header-based auth, use ${VAR} expansion in headers:
{
"mcpServers": {
"internal": {
"transport": "streamable-http",
"url": "https://mcp.internal.acme.com/v1",
"auth": "header",
"headers": { "X-API-Key": "${ACME_MCP_KEY}" }
}
}
}Credential files
Credential files are stored at ~/.config/oxagen/credentials/<server-name>.json with 0600 permissions (owner-read-write only). They are never committed to version control.
Structure
{
"accessToken": "ghp_abc123...",
"refreshToken": "ghr_xyz789...",
"tokenType": "Bearer",
"expiresAt": "2026-07-01T12:00:00.000Z",
"scopes": ["repo", "read:org"],
"updatedAt": "2026-06-25T10:30:00.000Z"
}| Field | Description |
|---|---|
accessToken | The bearer/access token sent in the Authorization header |
refreshToken | OAuth refresh token for automatic renewal |
tokenType | Token type (default: "Bearer") |
expiresAt | ISO timestamp when the access token expires |
scopes | OAuth scopes that were granted |
headers | For header-auth servers: the resolved header key-value pairs |
updatedAt | When this credential was last written |
Storing a credential
Write the credential file directly at ~/.config/oxagen/credentials/<server-name>.json using the structure above, with 0600 permissions:
# Write the credential file
cat > ~/.config/oxagen/credentials/linear.json <<'EOF'
{
"accessToken": "lin_api_abc123",
"tokenType": "Bearer",
"updatedAt": "2026-06-29T00:00:00.000Z"
}
EOF
chmod 600 ~/.config/oxagen/credentials/linear.jsonFor OAuth flows, tokens are stored by the platform runtime after completing the browser-based OAuth authorization flow.
OAuth flow
For servers with "auth": "oauth" (like GitHub MCP), the full OAuth 2.1 + PKCE flow is available through the web app:
- Navigate to Workspace → Settings → Integrations
- Click the server's "Connect" button
- Complete the OAuth authorization in your browser
- Tokens are stored encrypted on the platform (for the web/API runtime)
For CLI-only usage, you can paste an access token obtained from another flow directly into the credential file:
cat > ~/.config/oxagen/credentials/github.json <<'EOF'
{
"accessToken": "gho_abc123...",
"tokenType": "Bearer",
"updatedAt": "2026-06-29T00:00:00.000Z"
}
EOF
chmod 600 ~/.config/oxagen/credentials/github.jsonToken expiry and refresh
The runtime checks token expiry before connecting to a server:
- Not expired: uses the token as-is
- Expired + has refresh token: the platform's OAuth refresh watcher (runs every 30 minutes) automatically refreshes tokens. For CLI-only usage, the next connection attempt will fail and prompt re-authentication.
- Expired + no refresh token: server is skipped with a warning. Update the credential file at
~/.config/oxagen/credentials/<server-name>.jsonwith a fresh token.
Check which servers need attention:
oxagen mcp check
# ● github: healthy (42ms)
# ◐ linear: auth_required — token expired
# ● filesystem: healthySecurity considerations
- Credential files use
0600permissions (owner only) - Tokens are stored in plaintext in credential files — protect your home directory
- Never commit
.oxagen/settings.local.json(add it to.gitignore) - For team-shared secrets, use environment variables backed by a secret manager
- The
envTokenfield stores the variable name, not the value — safe to commit in.oxagen/settings.json - Platform-stored credentials (via OAuth) use AES-256-GCM encryption at rest
Credential file location
# List the credential directory
ls ~/.config/oxagen/credentials/
# View a specific credential (be careful in shared terminals)
cat ~/.config/oxagen/credentials/github.json
# Delete a credential (keeps the server config in place)
rm ~/.config/oxagen/credentials/github.json