Skip to content

Latest commit

 

History

History
83 lines (64 loc) · 5.35 KB

File metadata and controls

83 lines (64 loc) · 5.35 KB

CLAUDE.md - atlassian-browser-mcp

Project Overview

MCP server wrapping upstream mcp-atlassian with browser-cookie authentication via Playwright. Designed for Atlassian Server/Data Center instances behind corporate SSO where API tokens are not available.

Architecture

  • atlassian_browser_mcp_full.py — MCP entrypoint. Monkey-patches upstream JiraClient and ConfluenceClient constructors to inject browser-backed sessions. Registers atlassian_login tool. Runs the MCP server.
  • atlassian_browser_auth.py — Shared auth core: BrowserCookieSession (requests.Session subclass), interactive_login(), profile seeding, SSO redirect detection. Both the MCP server and the CLI use this.
  • atlassian_cli.py + atlassian-cli — Command-line front-end over the same auth core (Jira/Confluence get/search, login). Preferred for agents and scripting; no MCP transport involved. See AGENT_USAGE.md.
  • run-atlassian-browser-mcp.sh — MCP launcher: creates venv via uv, installs deps, runs upstream compatibility check, starts server.

⚠️ Two-process architecture: the server NEVER opens a browser

Authentication and serving are deliberately separate jobs:

  • Authentication is interactive and slow → done only by the CLI in the foreground (atlassian-cli login <jira|confluence>), where a browser can actually open. BrowserCookieSession(allow_interactive=True) (the CLI default) may call interactive_login().
  • Serving is fast, stateless HTTP → the MCP server constructs sessions with allow_interactive=False. Such a session reads the saved cookie jar and, on a cache miss or 401, raises AuthRequiredError immediately ("run atlassian-cli login …") instead of launching a browser.

Why this exists (the bug it fixes): the server used to call interactive_login() from inside its detached, async-dispatched process. That (a) blocked the tool call up to ATLASSIAN_LOGIN_TIMEOUT_SECONDS (≈5 min, often forever) waiting for a human who can't see the window, and (b) ran sync_playwright() on the asyncio event loop, which deadlocks ("Playwright Sync API inside the asyncio loop"). Net effect: MCP Atlassian calls hung forever.

Hard rules — do not regress:

  • The MCP server (_patch_*_client_init, atlassian_login tool) must NEVER call interactive_login() or otherwise drive Playwright in-process. The atlassian_login tool returns instructions only.
  • Any new server-side session must pass allow_interactive=False.
  • Login happens out-of-band via the CLI; the server reuses the saved jar.

⚠️ Authentication: ALWAYS reuse the browser profile (do not re-enter user/pw)

Re-entering corporate username/password + MFA on every run is a real pain and must be avoided. The whole point of this tool is a persistent, reusable session. Two rules make that reliable:

  1. Seed from the user's real Chrome profile. On first login, set ATLASSIAN_SEED_FROM_CHROME_PROFILE=Default (or another profile name / an absolute path). This copies the real Chrome profile once — cookies, saved logins, and any password-manager extension — into the dedicated automation profile (.atlassian-browser-profile/). Because the user's live corporate SSO cookies come along, the first login typically completes hands-free, no password and no MFA prompt. Chrome 136+ refuses to drive the live profile in place, so seeding a copy is the supported way to reuse it.
  2. NEVER delete the browser profile on an auth failure. A previous version ran shutil.rmtree(profile_dir) on a transient 401, which silently destroyed the long-lived SSO session and forced a full manual re-login every time. That self-wipe has been removed and must not come back. On re-auth, only the short-lived per-service cookie cache (.atlassian-browser-state-<svc>.json) is refreshed; the profile is preserved so re-login stays instant.

Jira and Confluence keep separate cookie jars (*-state-jira.json, *-state-confluence.json) but share one browser profile, so a single seeded SSO session covers both services. All .atlassian-browser-* artifacts hold live credentials and are git-ignored — never commit them.

Operational how-to (commands, env vars) lives in AGENT_USAGE.md; this section is the rationale and the two hard rules.

Key Design Decisions

  • Monkey-patching over forking: We patch upstream client __init__ methods at import time rather than maintaining a fork. An assert_upstream_compatibility() check validates signatures on startup.
  • Version pinning: Pinned to mcp-atlassian>=0.23.1,<1.0.0. Bump carefully — upstream signature changes will break patches.
  • No hardcoded URLs: JIRA_URL and CONFLUENCE_URL are required env vars with no defaults.
  • Configurable SSO detection: ATLASSIAN_SSO_MARKERS env var accepts comma-separated markers. Defaults cover Okta, ADFS, Azure AD, PingOne, Google SAML.

Development Guidelines

  • Keep browser auth logic in atlassian_browser_auth.py, MCP/patching logic in atlassian_browser_mcp_full.py.
  • When upstream mcp-atlassian releases a new minor version, update the pin in pyproject.toml and verify assert_upstream_compatibility() passes.
  • Never store credentials, URLs, or company-specific references in source code.

Generated by LynxPrompt CLI