Skip to main content
Glama

MCP Atlassian

"""Configuration module for the Confluence client.""" import logging import os from dataclasses import dataclass from typing import Literal from ..utils.env import get_custom_headers, is_env_ssl_verify from ..utils.oauth import ( BYOAccessTokenOAuthConfig, OAuthConfig, get_oauth_config_from_env, ) from ..utils.urls import is_atlassian_cloud_url @dataclass class ConfluenceConfig: """Confluence API configuration. Handles authentication for Confluence Cloud and Server/Data Center: - Cloud: username/API token (basic auth) or OAuth 2.0 (3LO) - Server/DC: personal access token or basic auth """ url: str # Base URL for Confluence auth_type: Literal["basic", "pat", "oauth"] # Authentication type username: str | None = None # Email or username api_token: str | None = None # API token used as password personal_token: str | None = None # Personal access token (Server/DC) oauth_config: OAuthConfig | BYOAccessTokenOAuthConfig | None = None ssl_verify: bool = True # Whether to verify SSL certificates spaces_filter: str | None = None # List of space keys to filter searches http_proxy: str | None = None # HTTP proxy URL https_proxy: str | None = None # HTTPS proxy URL no_proxy: str | None = None # Comma-separated list of hosts to bypass proxy socks_proxy: str | None = None # SOCKS proxy URL (optional) custom_headers: dict[str, str] | None = None # Custom HTTP headers @property def is_cloud(self) -> bool: """Check if this is a cloud instance. Returns: True if this is a cloud instance (atlassian.net), False otherwise. Localhost URLs are always considered non-cloud (Server/Data Center). """ # Multi-Cloud OAuth mode: URL might be None, but we use api.atlassian.com if ( self.auth_type == "oauth" and self.oauth_config and self.oauth_config.cloud_id ): # OAuth with cloud_id uses api.atlassian.com which is always Cloud return True # For other auth types, check the URL return is_atlassian_cloud_url(self.url) if self.url else False @property def verify_ssl(self) -> bool: """Compatibility property for old code. Returns: The ssl_verify value """ return self.ssl_verify @classmethod def from_env(cls) -> "ConfluenceConfig": """Create configuration from environment variables. Returns: ConfluenceConfig with values from environment variables Raises: ValueError: If any required environment variable is missing """ url = os.getenv("CONFLUENCE_URL") if not url and not os.getenv("ATLASSIAN_OAUTH_ENABLE"): error_msg = "Missing required CONFLUENCE_URL environment variable" raise ValueError(error_msg) # Determine authentication type based on available environment variables username = os.getenv("CONFLUENCE_USERNAME") api_token = os.getenv("CONFLUENCE_API_TOKEN") personal_token = os.getenv("CONFLUENCE_PERSONAL_TOKEN") # Check for OAuth configuration oauth_config = get_oauth_config_from_env() auth_type = None # Use the shared utility function directly is_cloud = is_atlassian_cloud_url(url) if oauth_config: # OAuth is available - could be full config or minimal config for user-provided tokens auth_type = "oauth" elif is_cloud: if username and api_token: auth_type = "basic" else: error_msg = "Cloud authentication requires CONFLUENCE_USERNAME and CONFLUENCE_API_TOKEN, or OAuth configuration (set ATLASSIAN_OAUTH_ENABLE=true for user-provided tokens)" raise ValueError(error_msg) else: # Server/Data Center if personal_token: auth_type = "pat" elif username and api_token: # Allow basic auth for Server/DC too auth_type = "basic" else: error_msg = "Server/Data Center authentication requires CONFLUENCE_PERSONAL_TOKEN or CONFLUENCE_USERNAME and CONFLUENCE_API_TOKEN" raise ValueError(error_msg) # SSL verification (for Server/DC) ssl_verify = is_env_ssl_verify("CONFLUENCE_SSL_VERIFY") # Get the spaces filter if provided spaces_filter = os.getenv("CONFLUENCE_SPACES_FILTER") # Proxy settings http_proxy = os.getenv("CONFLUENCE_HTTP_PROXY", os.getenv("HTTP_PROXY")) https_proxy = os.getenv("CONFLUENCE_HTTPS_PROXY", os.getenv("HTTPS_PROXY")) no_proxy = os.getenv("CONFLUENCE_NO_PROXY", os.getenv("NO_PROXY")) socks_proxy = os.getenv("CONFLUENCE_SOCKS_PROXY", os.getenv("SOCKS_PROXY")) # Custom headers - service-specific only custom_headers = get_custom_headers("CONFLUENCE_CUSTOM_HEADERS") return cls( url=url, auth_type=auth_type, username=username, api_token=api_token, personal_token=personal_token, oauth_config=oauth_config, ssl_verify=ssl_verify, spaces_filter=spaces_filter, http_proxy=http_proxy, https_proxy=https_proxy, no_proxy=no_proxy, socks_proxy=socks_proxy, custom_headers=custom_headers, ) def is_auth_configured(self) -> bool: """Check if the current authentication configuration is complete and valid for making API calls. Returns: bool: True if authentication is fully configured, False otherwise. """ logger = logging.getLogger("mcp-atlassian.confluence.config") if self.auth_type == "oauth": # Handle different OAuth configuration types if self.oauth_config: # Full OAuth configuration (traditional mode) if isinstance(self.oauth_config, OAuthConfig): if ( self.oauth_config.client_id and self.oauth_config.client_secret and self.oauth_config.redirect_uri and self.oauth_config.scope and self.oauth_config.cloud_id ): return True # Minimal OAuth configuration (user-provided tokens mode) # This is valid if we have oauth_config but missing client credentials # In this case, we expect authentication to come from user-provided headers elif ( not self.oauth_config.client_id and not self.oauth_config.client_secret ): logger.debug( "Minimal OAuth config detected - expecting user-provided tokens via headers" ) return True # Bring Your Own Access Token mode elif isinstance(self.oauth_config, BYOAccessTokenOAuthConfig): if self.oauth_config.cloud_id and self.oauth_config.access_token: return True # Partial configuration is invalid logger.warning("Incomplete OAuth configuration detected") return False elif self.auth_type == "pat": return bool(self.personal_token) elif self.auth_type == "basic": return bool(self.username and self.api_token) logger.warning( f"Unknown or unsupported auth_type: {self.auth_type} in ConfluenceConfig" ) return False

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sooperset/mcp-atlassian'

If you have feedback or need assistance with the MCP directory API, please join our Discord server