Skip to main content

atlassian-mcp-auth

Python-native OAuth token management for the Atlassian Rovo MCP server.

Use this package when your Python app, agent, or backend needs to connect to Atlassian Rovo MCP for Jira and Confluence without using Node.js or mcp-remote.

It handles the hard OAuth parts for you:

  • Opens Atlassian browser consent
  • Registers an OAuth client dynamically
  • Uses PKCE for login
  • Stores access and refresh tokens
  • Refreshes tokens automatically
  • Returns the MCP URL and Authorization header your framework needs

This package is an auth and token provider. Your MCP client, ADK app, LangChain/LangGraph app, CrewAI tool, or HTTP transport still owns the actual MCP tool calls.

Quick Start

Install the package:

pip install atlassian-mcp-auth

Run one-time browser login:

atlassian-mcp-auth login

The CLI opens Atlassian consent in your browser, waits for the callback at http://localhost:8765/callback, then stores tokens locally in:

~/.atlassian-mcp-auth/tokens.db

Check that you are connected:

atlassian-mcp-auth status

Print a fresh access token:

atlassian-mcp-auth token

Use it from Python:

import asyncio

from atlassian_mcp_auth import AtlassianMcpAuth


async def main() -> None:
    auth = AtlassianMcpAuth()
    connection = await auth.get_connection_info()

    print(connection.mcp_url)
    print(connection.headers)


asyncio.run(main())

connection.headers looks like this:

{"Authorization": "Bearer <fresh-access-token>"}

Pass that header to your MCP Streamable HTTP client or agent framework.

How Normal Users Use It

There are four common ways to use this package.

Use case Start here
Local development or testing Use the CLI
Python app or agent code Use AtlassianMcpAuth directly
Frontend, backend, or non-Python app Run the optional HTTP service
ADK, LangChain, CrewAI, custom MCP client Use get_connection_info() as a token/header provider

1. Use From The CLI

The CLI is the fastest way to login, verify OAuth, and get a token.

# Browser login. Stores tokens in ~/.atlassian-mcp-auth/tokens.db
atlassian-mcp-auth login

# Show saved token status
atlassian-mcp-auth status

# Print a fresh MCP access token
atlassian-mcp-auth token

# Force refresh and save any rotated refresh token
atlassian-mcp-auth refresh

# Delete saved tokens
atlassian-mcp-auth clear

Use a different profile for another user, team, or project:

atlassian-mcp-auth --profile team-a login
atlassian-mcp-auth --profile team-a token

Use a custom SQLite database path:

atlassian-mcp-auth --db ./tokens.db login

Use Postgres instead of SQLite:

pip install "atlassian-mcp-auth[postgres]"

atlassian-mcp-auth \
    --database-url "postgresql://user:password@localhost:5432/atlassian_mcp" \
    login

Use a different local callback port:

atlassian-mcp-auth login --port 8766

More details: docs/CLI_GUIDE.md

2. Use From Python API

First login once using the CLI:

atlassian-mcp-auth login

Then use the saved token from your Python code:

import asyncio

from atlassian_mcp_auth import AtlassianMcpAuth


async def main() -> None:
    auth = AtlassianMcpAuth(profile="default")
    access_token = await auth.get_access_token()
    print(access_token[:20])


asyncio.run(main())

For MCP clients and frameworks, prefer get_connection_info():

import asyncio

from atlassian_mcp_auth import AtlassianMcpAuth


async def main() -> None:
    auth = AtlassianMcpAuth(profile="user-123")
    connection = await auth.get_connection_info()

    # Give these values to your MCP Streamable HTTP transport.
    mcp_url = connection.mcp_url
    headers = connection.headers

    print("MCP URL:", mcp_url)
    print("Headers:", headers)
    print("Cloud ID:", connection.cloud_id)


asyncio.run(main())

The library refreshes the access token automatically when it is near expiry.

3. Use The Optional HTTP Service

Use the service when another app, frontend, or non-Python process needs to start OAuth and fetch connection data over HTTP.

Install service dependencies:

pip install "atlassian-mcp-auth[service]"

Start the service:

atlassian-mcp-auth serve --host 127.0.0.1 --port 8765

Health check:

curl http://127.0.0.1:8765/health

Start browser login directly:

http://127.0.0.1:8765/oauth/start?profile=user-123

Optionally redirect back to your app after authentication:

http://127.0.0.1:8765/oauth/start?profile=user-123&next=http://localhost:3000/settings/integrations

localhost, 127.0.0.1, and ::1 are allowed by default for next. For a production app, allow your app host when starting the service:

atlassian-mcp-auth serve \
    --public-url https://auth.example.com \
    --allowed-next-host app.example.com

After token exchange succeeds, the service redirects to next with:

?atlassian_mcp_auth=complete&profile=user-123&cloud_id=...

Or create the authorization URL from an API call:

curl -X POST http://127.0.0.1:8765/oauth/login \
  -H 'Content-Type: application/json' \
    -d '{"profile":"user-123","next":"http://localhost:3000/settings/integrations"}'

After login, fetch connection data:

curl "http://127.0.0.1:8765/token?profile=user-123"

Example response:

{
  "access_token": "...",
  "headers": {"Authorization": "Bearer ..."},
  "mcp_url": "https://mcp.atlassian.com/v1/mcp",
  "resource_url": "https://mcp.atlassian.com/v1/mcp/authv2",
  "cloud_id": "...",
  "expires_at": 1780000000.0
}

Useful service endpoints:

GET  /health
GET  /oauth/start?profile=user-123
POST /oauth/login
GET  /oauth/callback
GET  /status?profile=user-123
GET  /token?profile=user-123
POST /refresh?profile=user-123
POST /clear

Use Postgres In Service Mode

SQLite is the default, so this works without database setup:

atlassian-mcp-auth serve --host 127.0.0.1 --port 8765

For Postgres, install the Postgres service extra and pass one database URL:

pip install "atlassian-mcp-auth[service-postgres]"

atlassian-mcp-auth \
  --database-url "postgresql://user:password@localhost:5432/atlassian_mcp" \
  serve --host 127.0.0.1 --port 8765

You can also set the URL with an environment variable:

export ATLASSIAN_MCP_DATABASE_URL="postgresql://user:password@localhost:5432/atlassian_mcp"
atlassian-mcp-auth serve --host 127.0.0.1 --port 8765

More details: docs/SERVICE_GUIDE.md

4. Use With Any MCP Client Or Agent Framework

This package does not create an ADK, LangChain, CrewAI, or raw MCP client for you. It gives those clients fresh Atlassian MCP connection data.

Core pattern:

from atlassian_mcp_auth import AtlassianMcpAuth


auth = AtlassianMcpAuth(profile="user-123")


async def get_headers() -> dict[str, str]:
    return (await auth.get_connection_info()).headers

For a raw Streamable HTTP MCP call, use the returned URL and headers:

import asyncio

import httpx

from atlassian_mcp_auth import AtlassianMcpAuth


async def main() -> None:
    auth = AtlassianMcpAuth(profile="raw-http-user")
    connection = await auth.get_connection_info()
    headers = {
        **connection.headers,
        "Content-Type": "application/json",
        "Accept": "application/json, text/event-stream",
        "MCP-Protocol-Version": "2025-06-18",
    }

    async with httpx.AsyncClient(timeout=30.0) as client:
        response = await client.post(
            connection.mcp_url,
            headers=headers,
            json={
                "jsonrpc": "2.0",
                "id": 1,
                "method": "initialize",
                "params": {
                    "protocolVersion": "2025-06-18",
                    "capabilities": {},
                    "clientInfo": {"name": "my-mcp-client", "version": "0.1.0"},
                },
            },
        )
        print(response.status_code)
        print(response.text[:500])


asyncio.run(main())

Framework examples:

More details: docs/FRAMEWORKS_GUIDE.md

Features

  • OAuth 2.1 + PKCE login for Atlassian MCP
  • Dynamic Client Registration (RFC 7591)
  • RFC 8707 resource support for Atlassian MCP access tokens
  • Rotating refresh token persistence
  • SQLite token storage by default
  • Pluggable storage for Postgres, MySQL, Redis, Vault, or app databases
  • Framework-neutral token and connection metadata API

Guides

  • CLI Guide — local OAuth login, status, refresh, token, clear
  • Service Guide — run HTTP service and use /oauth/*, /token, /status, /refresh
  • Framework Guide — ADK, LangChain/LangGraph, CrewAI, raw MCP HTTP, service-based usage

Custom Storage

SQLite and Postgres are built in. Production apps can also bring their own storage.

from atlassian_mcp_auth.storage import TokenRecord, TokenStorage


class PostgresStorage(TokenStorage):
    async def load(self, profile: str = "default") -> TokenRecord | None:
        ...

    async def save(self, record: TokenRecord, profile: str = "default") -> None:
        ...

    async def clear(self, profile: str = "default") -> None:
        ...
auth = AtlassianMcpAuth(storage=PostgresStorage(), profile="user-123")

Advanced: Browser OAuth Flow From Your App

If your app wants to own the browser redirect flow instead of using the CLI or service, call begin_authorization() and exchange_code() directly.

from atlassian_mcp_auth import AtlassianMcpAuth, AuthorizationSession


auth = AtlassianMcpAuth(profile="user-123")

# Step 1: create browser consent URL
session: AuthorizationSession = await auth.begin_authorization(
    redirect_uri="https://your-app.example.com/oauth/callback"
)

# Send session.auth_url to the browser and store session.to_dict() temporarily.

# Step 2: after Atlassian redirects back with ?code=...&state=...
record = await auth.exchange_code(code, AuthorizationSession.from_dict(saved_session))

# Stored in SQLite/custom DB:
# - client_id
# - client_secret, when Atlassian returns one
# - access_token
# - refresh_token
# - expires_at
# - scopes
# - cloud_id, when present in the access token

Troubleshooting

If atlassian-mcp-auth token says no tokens were found, run:

atlassian-mcp-auth login

If your app uses a profile, use the same profile everywhere:

atlassian-mcp-auth --profile user-123 login
auth = AtlassianMcpAuth(profile="user-123")

If the service command is missing dependencies, install the service extra:

pip install "atlassian-mcp-auth[service]"

If a callback port is already in use, choose another port:

atlassian-mcp-auth login --port 8766

Why This Exists

Atlassian Rovo exposes Jira and Confluence tools through an MCP Streamable HTTP server. Python agent apps often need a direct server-side OAuth flow, token refresh, and storage layer without tying the auth package to one framework.

This package focuses only on that reusable auth layer.

Metadata

Release files for atlassian-mcp-auth 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for atlassian-mcp-auth 0.1.0
File Size Uploaded Provenance
atlassian_mcp_auth-0.1.0.tar.gz 21.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for atlassian-mcp-auth 0.1.0
File Interpreter ABI Platform
atlassian_mcp_auth-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 42.3 kB

Release files / atlassian_mcp_auth-0.1.0.tar.gz

Download URL atlassian_mcp_auth-0.1.0.tar.gz
Size 21.9 kB
Tags Source
SHA-256 checksum
How to use checksums
110120966960ee26aa6d2c3fafd88c7bcee79115864a49c78fa7dfdb3a9c32a3
BLAKE2b-256 checksum
How to use checksums
481dcad893b02f0167b0119b35dc00c037ef9945515cc603adca35bc372e7d73
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.5

Release files / atlassian_mcp_auth-0.1.0-py3-none-any.whl

Download URL atlassian_mcp_auth-0.1.0-py3-none-any.whl
Size 20.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
61735b8f17492860564b9f17dcad85aa60f03599674d1c4940125204197eec8c
BLAKE2b-256 checksum
How to use checksums
ddd8c52d92dc8be659f1b9ae097c5e01426a859691072a01a4cfd03d092ee5a1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.5

Security for atlassian-mcp-auth 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page