Skip to content

fix(auth): set explicit User-Agent on Jira/Confluence sessions#1326

Open
StefanWinter-ViREQ wants to merge 2 commits into
sooperset:mainfrom
StefanWinter-ViREQ:fix/default-user-agent
Open

fix(auth): set explicit User-Agent on Jira/Confluence sessions#1326
StefanWinter-ViREQ wants to merge 2 commits into
sooperset:mainfrom
StefanWinter-ViREQ:fix/default-user-agent

Conversation

@StefanWinter-ViREQ

Copy link
Copy Markdown

Summary

  • Some WAFs in front of Jira/Confluence Server/DC reject the default python-requests/X.Y User-Agent and return 403, even when the bearer token is valid. The error surfaces in mcp-atlassian as a misleading Authentication failed for Jira API (403). Token may be expired or invalid — although the same PAT works via curl.
  • JiraClient and ConfluenceClient now set User-Agent: mcp-atlassian/<version> on the session right after the underlying atlassian client is created, before _apply_custom_headers(), so user-supplied JIRA_CUSTOM_HEADERS=User-Agent=... / CONFLUENCE_CUSTOM_HEADERS=User-Agent=... still wins.
  • Adds utils/user_agent.py::get_default_user_agent() (uses importlib.metadata.version("mcp-atlassian"), falls back to 0.0.0 when not installed — same pattern as the package __version__).

Reproduction (Jira DC 9.12.4 behind a WAF)

from atlassian import Jira
jira = Jira(url="https://portal.example.com", token=PAT, cloud=False)
jira.get_issue("PROJ-1")
# requests.exceptions.HTTPError: 403 Client Error  (default UA: python-requests/2.x)

# Workaround (now built-in by this PR):
jira._session.headers["User-Agent"] = "mcp-atlassian/0.21.1"
jira.get_issue("PROJ-1")   # 200 OK

Direct curl with the same URL + Bearer token consistently returns 200. The WAF blocks only the default python-requests/X.Y UA — any identifiable UA (curl/*, Mozilla/*, mcp-atlassian/*, …) is allowed.

Test plan

  • uv run pytest tests/unit/jira/test_client.py tests/unit/confluence/test_client.py tests/unit/jira/test_custom_headers.py tests/unit/confluence/test_custom_headers.py — all green
  • pre-commit run (ruff, ruff-format, mypy) — green
  • Pre-existing failures on main (test_stdio_lifecycle, test_date::…boundary_max_valid, test_media::…[zip]) verified unrelated to this change
  • New unit tests:
    • test_jira_client_sets_default_user_agent / test_confluence_client_sets_default_user_agent — default UA is set on the session
    • test_jira_client_custom_user_agent_overrides_default / equivalent for Confluence — custom_headers still wins
  • Updated test_no_custom_headers_applied (Jira & Confluence) to expect the default UA being present

Some WAFs in front of Jira/Confluence Server/DC instances block requests
that carry the default `python-requests/X.Y` User-Agent and return 403 even
when the bearer token is valid. The error surfaces in mcp-atlassian as a
misleading "Authentication failed for Jira API (403). Token may be expired
or invalid", although the same token used via `curl` works fine.

Always set `User-Agent: mcp-atlassian/<version>` on the session in
`JiraClient` and `ConfluenceClient` after the underlying `atlassian` client
is created and before user-supplied custom headers are applied, so
`JIRA_CUSTOM_HEADERS=User-Agent=...` (or `CONFLUENCE_CUSTOM_HEADERS=...`)
can still override it.
@github-actions

Copy link
Copy Markdown

This pull request has been automatically marked as stale because it has not had recent activity for 14 days. It will be closed if no further activity occurs. Please leave a comment or remove the 'stale' label if you believe this PR is still relevant. Thank you for your contributions!

@github-actions github-actions Bot added the stale label May 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant