{"owner":"sooperset","repo":"mcp-atlassian","hasSkills":true,"totalSkillsCount":3,"totalTokensCount":3230,"categories":["root-instruction","copilot-instructions","mcp-config"],"hasMcp":true,"mcpConfig":{"mcpServers":{"mcp-atlassian":{"command":"npx","args":["-y","@modelcontextprotocol/server-mcp-atlassian"]}}},"found":["AGENTS.md",".github/copilot-instructions.md","smithery.yaml"],"skills":{"AGENTS.md":"# MCP Atlassian\n\n> **Audience**: LLM-driven engineering agents\n\n---\n\n## Repository map\n\n| Path | Purpose |\n| --- | --- |\n| `src/mcp_atlassian/` | Library source (Python ≥ 3.10) |\n| `  ├─ jira/` | Jira client + mixins (issues, search, SLA, metrics, …) |\n| `  ├─ confluence/` | Confluence client + mixins (pages, search, analytics, …) |\n| `  ├─ models/` | Pydantic v2 data models (`ApiModel` base) |\n| `  ├─ servers/` | FastMCP server instances (`jira_mcp`, `confluence_mcp`) |\n| `  ├─ preprocessing/` | Content conversion (ADF/Storage → Markdown) |\n| `  └─ utils/` | Shared utilities (auth, logging, SSL, decorators) |\n| `tests/` | Pytest suite — unit, integration, real-API validation |\n| `scripts/` | OAuth setup and testing scripts |\n\n---\n\n## Architecture\n\n- **Mixin composition**: `JiraFetcher` and `ConfluenceFetcher` are composed from the mixins listed in their `__init__.py`; client inheritance is transitive through mixins.\n- **FastMCP servers**: `servers/main.py` → lifespan → dependency injection via `get_jira_fetcher(ctx)` / `get_confluence_fetcher(ctx)`.\n- **Tool naming**: `{service}_{action}_{target}` (e.g., `jira_create_issue`, `confluence_get_page`).\n- **Config**: Environment-based `from_env()` factory on `JiraConfig` / `ConfluenceConfig` dataclasses.\n- **Auth**: Basic (Cloud + Server/DC), PAT (Server/DC), OAuth 2.0 (Cloud + Server/DC) — with multi-tenant header support.\n- **Models**: All extend `ApiModel` → `from_api_response()` + `to_simplified_dict()`.\n\n---\n\n## Dev workflow\n\n```bash\nuv sync --frozen --all-extras --dev  # install dependencies\npre-commit install                    # setup hooks\npre-commit run --all-files           # Ruff + mypy\nuv run pytest -xvs                   # full test suite\nuv run pytest tests/unit/ -xvs       # unit tests only\nuv run pytest tests/integration/     # integration tests\nuv run pytest --cov=src/mcp_atlassian --cov-report=term-missing  # coverage\n```\n\n*Tests must pass* and *lint/typing must be clean* before committing.\n\n---\n\n## Rules\n\n1. **Package management**: ONLY use `uv`, NEVER `pip`\n2. **Branching**: NEVER work on `main`, always create feature branches\n3. **Type safety**: All functions require type hints\n4. **Testing**: New features need tests, bug fixes need regression tests\n5. **Commits**: Use trailers for attribution, never mention tools/AI\n6. **Commit types**: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`, `perf`, `ci` — scopes: `jira`, `confluence`, `server`, `auth`, `docker`, `docs`\n7. **File hygiene**: Prefer editing existing files over creating new ones\n8. **Tool docs**: After changing tool signatures or registrations, run `uv run python scripts/generate_tool_docs.py` and commit the diff; CI (`Docs / check`) enforces this\n\n---\n\n## Code conventions\n\n- **Language**: Python ≥ 3.10\n- **Line length**: 88 characters maximum\n- **Imports**: Absolute imports, sorted by Ruff\n- **Naming**: `snake_case` functions, `PascalCase` classes\n- **Docstrings**: Google-style for all public APIs\n- **Error handling**: Specific exceptions only\n\n---\n\n## Gotchas\n\n- **Cloud vs Server/DC**: API endpoints, field names, and auth methods differ. Always check `is_cloud` before assuming behavior.\n- **OAuth 2.0**: Supported on both Cloud and Server/Data Center. PAT is also available for Server/DC. Basic auth (user + API token) works on both Cloud and Server/DC.\n- **Read-only mode**: `READ_ONLY_MODE=true` blocks all write tools at server level.\n- **Type checking**: pre-commit runs **mypy** (strict mode).\n- **Environment**: See `.env.example` for all configuration options (auth, proxy, SLA, filtering).\n\n---\n\n## Quick reference\n\n```bash\n# Running the server\nuv run mcp-atlassian                 # Start server\nuv run mcp-atlassian --oauth-setup   # OAuth wizard\nuv run mcp-atlassian -v              # Verbose mode\n\n# Git workflow\ngit checkout -b feature/description   # New feature\ngit checkout -b fix/issue-description # Bug fix\ngit commit --trailer \"Reported-by:<name>\"      # Attribution\ngit commit --trailer \"Github-Issue:#<number>\"  # Issue reference\n```\n",".github/copilot-instructions.md":"# MCP Atlassian - Development Guide\n\nModel Context Protocol (MCP) server for Atlassian products (Jira & Confluence). Python ≥3.10.\n\n## Build, Test, and Lint\n\n**Dependencies**:\n```bash\nuv sync --frozen --all-extras --dev  # Install all dependencies\n```\n\n**Code Quality** (required before commit):\n```bash\npre-commit run --all-files           # Run all checks: ruff, prettier, mypy\n```\n\n**Testing**:\n```bash\n# Run all tests\nuv run pytest\n\n# Run with coverage\nuv run pytest --cov=mcp_atlassian\n\n# Run single test file\nuv run pytest tests/unit/test_preprocessing.py\n\n# Run single test function\nuv run pytest tests/unit/test_preprocessing.py::test_specific_function\n```\n\n**Running the Server**:\n```bash\nuv run mcp-atlassian                 # Start MCP server\nuv run mcp-atlassian --oauth-setup   # OAuth configuration wizard\nuv run mcp-atlassian -v              # Verbose logging mode\n```\n\n## Architecture\n\n### Mixin-Based Composition\nFunctionality is organized into **focused mixins** that compose together:\n- **Jira**: `JiraFetcher` inherits from 13 feature mixins (ProjectsMixin, IssuesMixin, WorklogMixin, etc.)\n- **Confluence**: `ConfluenceFetcher` inherits from 7 feature mixins (SearchMixin, PagesMixin, SpacesMixin, etc.)\n\nEach mixin lives in its own module under `src/mcp_atlassian/jira/` or `src/mcp_atlassian/confluence/`.\n\n### Client + Fetcher Pattern\n- **Client classes** (`JiraClient`, `ConfluenceClient`): Authentication, configuration, and API session management\n- **Fetcher classes** (`JiraFetcher`, `ConfluenceFetcher`): Business operations by composing mixins; inherit from Client\n\n### Protocol-Based Dependencies\nMixins declare dependencies via Protocol interfaces instead of direct imports:\n```python\nclass IssuesMixin(AttachmentsOperationsProto, FieldsOperationsProto):\n    # Mixin knows it needs attachment and field operations\n    # Protocols define the contract without circular imports\n```\n\nThe final Fetcher class satisfies all protocols through multiple inheritance.\n\n### Data Models\n- All models extend `ApiModel` base class with `from_api_response()` for deserialization\n- Use `TimestampMixin` for timestamp handling across Jira/Confluence models\n- Models support `to_simplified_dict()` for MCP tool responses\n- Located in `src/mcp_atlassian/models/`\n\n### MCP Server Layer\nServers (`src/mcp_atlassian/servers/`) use FastMCP framework:\n- Instantiate Fetchers via dependency injection (`get_jira_fetcher()`, `get_confluence_fetcher()`)\n- Wrap fetcher methods as MCP tools using `@mcp.tool()` decorator\n- Handle error conversion and response serialization\n- Support read-only and write modes\n\n## Key Conventions\n\n### Package Management\n**Always use `uv`, never `pip`**. This is a hard requirement for dependency management.\n\n### Branching Strategy\n**Never work on `main`**. Always create feature branches:\n```bash\ngit checkout -b feature/your-feature-name   # For new features\ngit checkout -b fix/issue-description       # For bug fixes\n```\n\n### Tool Naming\nMCP tools follow the pattern: `{service}_{action}`\n- Examples: `jira_create_issue`, `confluence_get_page`, `jira_search`\n\n### Type Safety\n- All functions require type hints\n- Use modern union syntax: `str | None` (not `Optional[str]`)\n- Use `type[T]` for class types\n- Collections: `list[str]`, `dict[str, Any]`\n\n### Code Style\n- **Line length**: 88 characters maximum (enforced by ruff)\n- **Imports**: Absolute imports, sorted by ruff\n- **Naming**: `snake_case` for functions/variables, `PascalCase` for classes\n- **Docstrings**: Google-style format for all public APIs\n- **Error handling**: Use specific exceptions, avoid bare `except:`\n\n### Testing\n- New features require tests\n- Bug fixes require regression tests\n- Test files mirror source structure: `tests/unit/` and `tests/integration/`\n- Use fixtures from `tests/fixtures/` for test data\n\n### Commit Messages\nUse git trailers for attribution:\n```bash\ngit commit --trailer \"Reported-by:<name>\"          # For bug reports\ngit commit --trailer \"Github-Issue:#<number>\"      # For issue references\n```\n\n**Never mention tools or AI assistants in commit messages**.\n\n## Authentication Support\nThe codebase supports multiple authentication methods:\n- **API Tokens**: Cloud deployments (username + token)\n- **Personal Access Tokens (PAT)**: Server/Data Center deployments\n- **OAuth 2.0**: Interactive user authentication with consent flow\n\nAuth configuration lives in `src/mcp_atlassian/utils/auth.py`.\n\n## Pre-commit Hooks\nPre-commit runs:\n- **ruff-format**: Auto-format Python code\n- **ruff**: Lint with auto-fix (select rules in pyproject.toml)\n- **mypy**: Type checking (currently lenient, see TODO comments in .pre-commit-config.yaml)\n- **prettier**: Format YAML/JSON\n- **Standard checks**: trailing whitespace, file endings, YAML/TOML validity\n\nTests are **not** run by pre-commit hooks—run them manually with `uv run pytest`.\n","smithery.yaml":"# Smithery.ai configuration for mcp-atlassian\nstartCommand:\n  type: stdio # Specifies the server communicates over standard input/output\n  configSchema:\n    # JSON Schema defining the configuration options users need to provide\n    type: object\n    required:\n      - jiraUrl\n      - confluenceUrl\n      # Add other strictly required credentials based on auth needs\n    properties:\n      # Confluence Config\n      confluenceUrl:\n        type: string\n        description: \"Base URL for your Confluence instance (e.g., https://your-domain.atlassian.net/wiki or https://confluence.yourcompany.com).\"\n      confluenceUsername:\n        type: string\n        description: \"(Optional for Cloud Basic Auth) Your Confluence username or email.\"\n      confluenceApiToken:\n        type: string\n        description: \"(Optional for Cloud Basic Auth) Your Confluence API token.\"\n        format: password # Hides the value in UI inputs\n      confluencePersonalToken:\n        type: string\n        description: \"(Optional for Server/DC Token Auth) Your Confluence Personal Access Token.\"\n        format: password\n      confluenceSslVerify:\n        type: boolean\n        description: \"(Optional, Server/DC only) Verify SSL certificate for Confluence. Defaults to true.\"\n        default: true\n      confluenceSpacesFilter:\n        type: string\n        description: \"(Optional) Comma-separated list of Confluence space keys to limit searches to (e.g., 'DEV,QA').\"\n\n      # Jira Config\n      jiraUrl:\n        type: string\n        description: \"Base URL for your Jira instance (e.g., https://your-domain.atlassian.net or https://jira.yourcompany.com).\"\n      jiraUsername:\n        type: string\n        description: \"(Optional for Cloud Basic Auth or Server/DC Basic Auth) Your Jira username or email.\"\n      jiraApiToken:\n        type: string\n        description: \"(Optional for Cloud Basic Auth or Server/DC Basic Auth) Your Jira API token.\"\n        format: password\n      jiraPersonalToken:\n        type: string\n        description: \"(Optional for Server/DC Token Auth) Your Jira Personal Access Token.\"\n        format: password\n      jiraSslVerify:\n        type: boolean\n        description: \"(Optional, Server/DC only) Verify SSL certificate for Jira. Defaults to true.\"\n        default: true\n      jiraProjectsFilter:\n        type: string\n        description: \"(Optional) Comma-separated list of Jira project keys to limit searches to (e.g., 'PROJ1,PROJ2').\"\n\n      # General Config\n      readOnlyMode:\n        type: boolean\n        description: \"(Optional) Run in read-only mode (prevents create/update/delete). Defaults to false.\"\n        default: false\n\n    additionalProperties: false # Disallow properties not defined above\n\n  commandFunction:\n    # A JavaScript function that produces the CLI command and environment variables\n    # needed to start the MCP server, based on the user's configuration.\n    |-\n    (config) => {\n      // The command matches the ENTRYPOINT in the Dockerfile\n      const command = 'mcp-atlassian';\n      const args = []; // No arguments needed as config is via ENV\n\n      // Map the config schema properties to the environment variables\n      const env = {\n        // Confluence ENV VARS\n        CONFLUENCE_URL: config.confluenceUrl,\n        CONFLUENCE_USERNAME: config.confluenceUsername,\n        CONFLUENCE_API_TOKEN: config.confluenceApiToken,\n        CONFLUENCE_PERSONAL_TOKEN: config.confluencePersonalToken,\n        CONFLUENCE_SSL_VERIFY: config.confluenceSslVerify !== undefined ? String(config.confluenceSslVerify) : 'true',\n        CONFLUENCE_SPACES_FILTER: config.confluenceSpacesFilter,\n\n        // Jira ENV VARS\n        JIRA_URL: config.jiraUrl,\n        JIRA_USERNAME: config.jiraUsername,\n        JIRA_API_TOKEN: config.jiraApiToken,\n        JIRA_PERSONAL_TOKEN: config.jiraPersonalToken,\n        JIRA_SSL_VERIFY: config.jiraSslVerify !== undefined ? String(config.jiraSslVerify) : 'true',\n        JIRA_PROJECTS_FILTER: config.jiraProjectsFilter,\n\n        // General ENV VARS\n        READ_ONLY_MODE: config.readOnlyMode !== undefined ? String(config.readOnlyMode) : 'false',\n      };\n\n      // Filter out undefined/null env variables\n      const filteredEnv = Object.entries(env)\n        .filter(([key, value]) => value !== undefined && value !== null)\n        .reduce((obj, [key, value]) => {\n          obj[key] = value;\n          return obj;\n        }, {});\n\n      return {\n        command: command,\n        args: args,\n        env: filteredEnv\n      };\n    }\n"},"files":{"AGENTS.md":"# MCP Atlassian\n\n> **Audience**: LLM-driven engineering agents\n\n---\n\n## Repository map\n\n| Path | Purpose |\n| --- | --- |\n| `src/mcp_atlassian/` | Library source (Python ≥ 3.10) |\n| `  ├─ jira/` | Jira client + mixins (issues, search, SLA, metrics, …) |\n| `  ├─ confluence/` | Confluence client + mixins (pages, search, analytics, …) |\n| `  ├─ models/` | Pydantic v2 data models (`ApiModel` base) |\n| `  ├─ servers/` | FastMCP server instances (`jira_mcp`, `confluence_mcp`) |\n| `  ├─ preprocessing/` | Content conversion (ADF/Storage → Markdown) |\n| `  └─ utils/` | Shared utilities (auth, logging, SSL, decorators) |\n| `tests/` | Pytest suite — unit, integration, real-API validation |\n| `scripts/` | OAuth setup and testing scripts |\n\n---\n\n## Architecture\n\n- **Mixin composition**: `JiraFetcher` and `ConfluenceFetcher` are composed from the mixins listed in their `__init__.py`; client inheritance is transitive through mixins.\n- **FastMCP servers**: `servers/main.py` → lifespan → dependency injection via `get_jira_fetcher(ctx)` / `get_confluence_fetcher(ctx)`.\n- **Tool naming**: `{service}_{action}_{target}` (e.g., `jira_create_issue`, `confluence_get_page`).\n- **Config**: Environment-based `from_env()` factory on `JiraConfig` / `ConfluenceConfig` dataclasses.\n- **Auth**: Basic (Cloud + Server/DC), PAT (Server/DC), OAuth 2.0 (Cloud + Server/DC) — with multi-tenant header support.\n- **Models**: All extend `ApiModel` → `from_api_response()` + `to_simplified_dict()`.\n\n---\n\n## Dev workflow\n\n```bash\nuv sync --frozen --all-extras --dev  # install dependencies\npre-commit install                    # setup hooks\npre-commit run --all-files           # Ruff + mypy\nuv run pytest -xvs                   # full test suite\nuv run pytest tests/unit/ -xvs       # unit tests only\nuv run pytest tests/integration/     # integration tests\nuv run pytest --cov=src/mcp_atlassian --cov-report=term-missing  # coverage\n```\n\n*Tests must pass* and *lint/typing must be clean* before committing.\n\n---\n\n## Rules\n\n1. **Package management**: ONLY use `uv`, NEVER `pip`\n2. **Branching**: NEVER work on `main`, always create feature branches\n3. **Type safety**: All functions require type hints\n4. **Testing**: New features need tests, bug fixes need regression tests\n5. **Commits**: Use trailers for attribution, never mention tools/AI\n6. **Commit types**: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`, `perf`, `ci` — scopes: `jira`, `confluence`, `server`, `auth`, `docker`, `docs`\n7. **File hygiene**: Prefer editing existing files over creating new ones\n8. **Tool docs**: After changing tool signatures or registrations, run `uv run python scripts/generate_tool_docs.py` and commit the diff; CI (`Docs / check`) enforces this\n\n---\n\n## Code conventions\n\n- **Language**: Python ≥ 3.10\n- **Line length**: 88 characters maximum\n- **Imports**: Absolute imports, sorted by Ruff\n- **Naming**: `snake_case` functions, `PascalCase` classes\n- **Docstrings**: Google-style for all public APIs\n- **Error handling**: Specific exceptions only\n\n---\n\n## Gotchas\n\n- **Cloud vs Server/DC**: API endpoints, field names, and auth methods differ. Always check `is_cloud` before assuming behavior.\n- **OAuth 2.0**: Supported on both Cloud and Server/Data Center. PAT is also available for Server/DC. Basic auth (user + API token) works on both Cloud and Server/DC.\n- **Read-only mode**: `READ_ONLY_MODE=true` blocks all write tools at server level.\n- **Type checking**: pre-commit runs **mypy** (strict mode).\n- **Environment**: See `.env.example` for all configuration options (auth, proxy, SLA, filtering).\n\n---\n\n## Quick reference\n\n```bash\n# Running the server\nuv run mcp-atlassian                 # Start server\nuv run mcp-atlassian --oauth-setup   # OAuth wizard\nuv run mcp-atlassian -v              # Verbose mode\n\n# Git workflow\ngit checkout -b feature/description   # New feature\ngit checkout -b fix/issue-description # Bug fix\ngit commit --trailer \"Reported-by:<name>\"      # Attribution\ngit commit --trailer \"Github-Issue:#<number>\"  # Issue reference\n```\n",".github/copilot-instructions.md":"# MCP Atlassian - Development Guide\n\nModel Context Protocol (MCP) server for Atlassian products (Jira & Confluence). Python ≥3.10.\n\n## Build, Test, and Lint\n\n**Dependencies**:\n```bash\nuv sync --frozen --all-extras --dev  # Install all dependencies\n```\n\n**Code Quality** (required before commit):\n```bash\npre-commit run --all-files           # Run all checks: ruff, prettier, mypy\n```\n\n**Testing**:\n```bash\n# Run all tests\nuv run pytest\n\n# Run with coverage\nuv run pytest --cov=mcp_atlassian\n\n# Run single test file\nuv run pytest tests/unit/test_preprocessing.py\n\n# Run single test function\nuv run pytest tests/unit/test_preprocessing.py::test_specific_function\n```\n\n**Running the Server**:\n```bash\nuv run mcp-atlassian                 # Start MCP server\nuv run mcp-atlassian --oauth-setup   # OAuth configuration wizard\nuv run mcp-atlassian -v              # Verbose logging mode\n```\n\n## Architecture\n\n### Mixin-Based Composition\nFunctionality is organized into **focused mixins** that compose together:\n- **Jira**: `JiraFetcher` inherits from 13 feature mixins (ProjectsMixin, IssuesMixin, WorklogMixin, etc.)\n- **Confluence**: `ConfluenceFetcher` inherits from 7 feature mixins (SearchMixin, PagesMixin, SpacesMixin, etc.)\n\nEach mixin lives in its own module under `src/mcp_atlassian/jira/` or `src/mcp_atlassian/confluence/`.\n\n### Client + Fetcher Pattern\n- **Client classes** (`JiraClient`, `ConfluenceClient`): Authentication, configuration, and API session management\n- **Fetcher classes** (`JiraFetcher`, `ConfluenceFetcher`): Business operations by composing mixins; inherit from Client\n\n### Protocol-Based Dependencies\nMixins declare dependencies via Protocol interfaces instead of direct imports:\n```python\nclass IssuesMixin(AttachmentsOperationsProto, FieldsOperationsProto):\n    # Mixin knows it needs attachment and field operations\n    # Protocols define the contract without circular imports\n```\n\nThe final Fetcher class satisfies all protocols through multiple inheritance.\n\n### Data Models\n- All models extend `ApiModel` base class with `from_api_response()` for deserialization\n- Use `TimestampMixin` for timestamp handling across Jira/Confluence models\n- Models support `to_simplified_dict()` for MCP tool responses\n- Located in `src/mcp_atlassian/models/`\n\n### MCP Server Layer\nServers (`src/mcp_atlassian/servers/`) use FastMCP framework:\n- Instantiate Fetchers via dependency injection (`get_jira_fetcher()`, `get_confluence_fetcher()`)\n- Wrap fetcher methods as MCP tools using `@mcp.tool()` decorator\n- Handle error conversion and response serialization\n- Support read-only and write modes\n\n## Key Conventions\n\n### Package Management\n**Always use `uv`, never `pip`**. This is a hard requirement for dependency management.\n\n### Branching Strategy\n**Never work on `main`**. Always create feature branches:\n```bash\ngit checkout -b feature/your-feature-name   # For new features\ngit checkout -b fix/issue-description       # For bug fixes\n```\n\n### Tool Naming\nMCP tools follow the pattern: `{service}_{action}`\n- Examples: `jira_create_issue`, `confluence_get_page`, `jira_search`\n\n### Type Safety\n- All functions require type hints\n- Use modern union syntax: `str | None` (not `Optional[str]`)\n- Use `type[T]` for class types\n- Collections: `list[str]`, `dict[str, Any]`\n\n### Code Style\n- **Line length**: 88 characters maximum (enforced by ruff)\n- **Imports**: Absolute imports, sorted by ruff\n- **Naming**: `snake_case` for functions/variables, `PascalCase` for classes\n- **Docstrings**: Google-style format for all public APIs\n- **Error handling**: Use specific exceptions, avoid bare `except:`\n\n### Testing\n- New features require tests\n- Bug fixes require regression tests\n- Test files mirror source structure: `tests/unit/` and `tests/integration/`\n- Use fixtures from `tests/fixtures/` for test data\n\n### Commit Messages\nUse git trailers for attribution:\n```bash\ngit commit --trailer \"Reported-by:<name>\"          # For bug reports\ngit commit --trailer \"Github-Issue:#<number>\"      # For issue references\n```\n\n**Never mention tools or AI assistants in commit messages**.\n\n## Authentication Support\nThe codebase supports multiple authentication methods:\n- **API Tokens**: Cloud deployments (username + token)\n- **Personal Access Tokens (PAT)**: Server/Data Center deployments\n- **OAuth 2.0**: Interactive user authentication with consent flow\n\nAuth configuration lives in `src/mcp_atlassian/utils/auth.py`.\n\n## Pre-commit Hooks\nPre-commit runs:\n- **ruff-format**: Auto-format Python code\n- **ruff**: Lint with auto-fix (select rules in pyproject.toml)\n- **mypy**: Type checking (currently lenient, see TODO comments in .pre-commit-config.yaml)\n- **prettier**: Format YAML/JSON\n- **Standard checks**: trailing whitespace, file endings, YAML/TOML validity\n\nTests are **not** run by pre-commit hooks—run them manually with `uv run pytest`.\n","smithery.yaml":"# Smithery.ai configuration for mcp-atlassian\nstartCommand:\n  type: stdio # Specifies the server communicates over standard input/output\n  configSchema:\n    # JSON Schema defining the configuration options users need to provide\n    type: object\n    required:\n      - jiraUrl\n      - confluenceUrl\n      # Add other strictly required credentials based on auth needs\n    properties:\n      # Confluence Config\n      confluenceUrl:\n        type: string\n        description: \"Base URL for your Confluence instance (e.g., https://your-domain.atlassian.net/wiki or https://confluence.yourcompany.com).\"\n      confluenceUsername:\n        type: string\n        description: \"(Optional for Cloud Basic Auth) Your Confluence username or email.\"\n      confluenceApiToken:\n        type: string\n        description: \"(Optional for Cloud Basic Auth) Your Confluence API token.\"\n        format: password # Hides the value in UI inputs\n      confluencePersonalToken:\n        type: string\n        description: \"(Optional for Server/DC Token Auth) Your Confluence Personal Access Token.\"\n        format: password\n      confluenceSslVerify:\n        type: boolean\n        description: \"(Optional, Server/DC only) Verify SSL certificate for Confluence. Defaults to true.\"\n        default: true\n      confluenceSpacesFilter:\n        type: string\n        description: \"(Optional) Comma-separated list of Confluence space keys to limit searches to (e.g., 'DEV,QA').\"\n\n      # Jira Config\n      jiraUrl:\n        type: string\n        description: \"Base URL for your Jira instance (e.g., https://your-domain.atlassian.net or https://jira.yourcompany.com).\"\n      jiraUsername:\n        type: string\n        description: \"(Optional for Cloud Basic Auth or Server/DC Basic Auth) Your Jira username or email.\"\n      jiraApiToken:\n        type: string\n        description: \"(Optional for Cloud Basic Auth or Server/DC Basic Auth) Your Jira API token.\"\n        format: password\n      jiraPersonalToken:\n        type: string\n        description: \"(Optional for Server/DC Token Auth) Your Jira Personal Access Token.\"\n        format: password\n      jiraSslVerify:\n        type: boolean\n        description: \"(Optional, Server/DC only) Verify SSL certificate for Jira. Defaults to true.\"\n        default: true\n      jiraProjectsFilter:\n        type: string\n        description: \"(Optional) Comma-separated list of Jira project keys to limit searches to (e.g., 'PROJ1,PROJ2').\"\n\n      # General Config\n      readOnlyMode:\n        type: boolean\n        description: \"(Optional) Run in read-only mode (prevents create/update/delete). Defaults to false.\"\n        default: false\n\n    additionalProperties: false # Disallow properties not defined above\n\n  commandFunction:\n    # A JavaScript function that produces the CLI command and environment variables\n    # needed to start the MCP server, based on the user's configuration.\n    |-\n    (config) => {\n      // The command matches the ENTRYPOINT in the Dockerfile\n      const command = 'mcp-atlassian';\n      const args = []; // No arguments needed as config is via ENV\n\n      // Map the config schema properties to the environment variables\n      const env = {\n        // Confluence ENV VARS\n        CONFLUENCE_URL: config.confluenceUrl,\n        CONFLUENCE_USERNAME: config.confluenceUsername,\n        CONFLUENCE_API_TOKEN: config.confluenceApiToken,\n        CONFLUENCE_PERSONAL_TOKEN: config.confluencePersonalToken,\n        CONFLUENCE_SSL_VERIFY: config.confluenceSslVerify !== undefined ? String(config.confluenceSslVerify) : 'true',\n        CONFLUENCE_SPACES_FILTER: config.confluenceSpacesFilter,\n\n        // Jira ENV VARS\n        JIRA_URL: config.jiraUrl,\n        JIRA_USERNAME: config.jiraUsername,\n        JIRA_API_TOKEN: config.jiraApiToken,\n        JIRA_PERSONAL_TOKEN: config.jiraPersonalToken,\n        JIRA_SSL_VERIFY: config.jiraSslVerify !== undefined ? String(config.jiraSslVerify) : 'true',\n        JIRA_PROJECTS_FILTER: config.jiraProjectsFilter,\n\n        // General ENV VARS\n        READ_ONLY_MODE: config.readOnlyMode !== undefined ? String(config.readOnlyMode) : 'false',\n      };\n\n      // Filter out undefined/null env variables\n      const filteredEnv = Object.entries(env)\n        .filter(([key, value]) => value !== undefined && value !== null)\n        .reduce((obj, [key, value]) => {\n          obj[key] = value;\n          return obj;\n        }, {});\n\n      return {\n        command: command,\n        args: args,\n        env: filteredEnv\n      };\n    }\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/sooperset/mcp-atlassian/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# MCP Atlassian\n\n> **Audience**: LLM-driven engineering agents\n\n---\n\n## Repository map\n\n| Path | Purpose |\n| --- | --- |\n| `src/mcp_atlassian/` | Library source (Python ≥ 3.10) |\n| `  ├─ jira/` | Jira client + mixins (issues, search, SLA, metrics, …) |\n| `  ├─ confluence/` | Confluence client + mixins (pages, search, analytics, …) |\n| `  ├─ models/` | Pydantic v2 data models (`ApiModel` base) |\n| `  ├─ servers/` | FastMCP server instances (`jira_mcp`, `confluence_mcp`) |\n| `  ├─ preprocessing/` | Content conversion (ADF/Storage → Markdown) |\n| `  └─ utils/` | Shared utilities (auth, logging, SSL, decorators) |\n| `tests/` | Pytest suite — unit, integration, real-API validation |\n| `scripts/` | OAuth setup and testing scripts |\n\n---\n\n## Architecture\n\n- **Mixin composition**: `JiraFetcher` and `ConfluenceFetcher` are composed from the mixins listed in their `__init__.py`; client inheritance is transitive through mixins.\n- **FastMCP servers**: `servers/main.py` → lifespan → dependency injection via `get_jira_fetcher(ctx)` / `get_confluence_fetcher(ctx)`.\n- **Tool naming**: `{service}_{action}_{target}` (e.g., `jira_create_issue`, `confluence_get_page`).\n- **Config**: Environment-based `from_env()` factory on `JiraConfig` / `ConfluenceConfig` dataclasses.\n- **Auth**: Basic (Cloud + Server/DC), PAT (Server/DC), OAuth 2.0 (Cloud + Server/DC) — with multi-tenant header support.\n- **Models**: All extend `ApiModel` → `from_api_response()` + `to_simplified_dict()`.\n\n---\n\n## Dev workflow\n\n```bash\nuv sync --frozen --all-extras --dev  # install dependencies\npre-commit install                    # setup hooks\npre-commit run --all-files           # Ruff + mypy\nuv run pytest -xvs                   # full test suite\nuv run pytest tests/unit/ -xvs       # unit tests only\nuv run pytest tests/integration/     # integration tests\nuv run pytest --cov=src/mcp_atlassian --cov-report=term-missing  # coverage\n```\n\n*Tests must pass* and *lint/typing must be clean* before committing.\n\n---\n\n## Rules\n\n1. **Package management**: ONLY use `uv`, NEVER `pip`\n2. **Branching**: NEVER work on `main`, always create feature branches\n3. **Type safety**: All functions require type hints\n4. **Testing**: New features need tests, bug fixes need regression tests\n5. **Commits**: Use trailers for attribution, never mention tools/AI\n6. **Commit types**: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`, `perf`, `ci` — scopes: `jira`, `confluence`, `server`, `auth`, `docker`, `docs`\n7. **File hygiene**: Prefer editing existing files over creating new ones\n8. **Tool docs**: After changing tool signatures or registrations, run `uv run python scripts/generate_tool_docs.py` and commit the diff; CI (`Docs / check`) enforces this\n\n---\n\n## Code conventions\n\n- **Language**: Python ≥ 3.10\n- **Line length**: 88 characters maximum\n- **Imports**: Absolute imports, sorted by Ruff\n- **Naming**: `snake_case` functions, `PascalCase` classes\n- **Docstrings**: Google-style for all public APIs\n- **Error handling**: Specific exceptions only\n\n---\n\n## Gotchas\n\n- **Cloud vs Server/DC**: API endpoints, field names, and auth methods differ. Always check `is_cloud` before assuming behavior.\n- **OAuth 2.0**: Supported on both Cloud and Server/Data Center. PAT is also available for Server/DC. Basic auth (user + API token) works on both Cloud and Server/DC.\n- **Read-only mode**: `READ_ONLY_MODE=true` blocks all write tools at server level.\n- **Type checking**: pre-commit runs **mypy** (strict mode).\n- **Environment**: See `.env.example` for all configuration options (auth, proxy, SLA, filtering).\n\n---\n\n## Quick reference\n\n```bash\n# Running the server\nuv run mcp-atlassian                 # Start server\nuv run mcp-atlassian --oauth-setup   # OAuth wizard\nuv run mcp-atlassian -v              # Verbose mode\n\n# Git workflow\ngit checkout -b feature/description   # New feature\ngit checkout -b fix/issue-description # Bug fix\ngit commit --trailer \"Reported-by:<name>\"      # Attribution\ngit commit --trailer \"Github-Issue:#<number>\"  # Issue reference\n```\n","isInternal":false,"tokens":1066,"sizeBytes":4089},{"name":"copilot-instructions.md","path":".github/copilot-instructions.md","rawUrl":"https://raw.githubusercontent.com/sooperset/mcp-atlassian/HEAD/.github/copilot-instructions.md","title":"GitHub Copilot Instructions","category":"copilot-instructions","format":"markdown","content":"# MCP Atlassian - Development Guide\n\nModel Context Protocol (MCP) server for Atlassian products (Jira & Confluence). Python ≥3.10.\n\n## Build, Test, and Lint\n\n**Dependencies**:\n```bash\nuv sync --frozen --all-extras --dev  # Install all dependencies\n```\n\n**Code Quality** (required before commit):\n```bash\npre-commit run --all-files           # Run all checks: ruff, prettier, mypy\n```\n\n**Testing**:\n```bash\n# Run all tests\nuv run pytest\n\n# Run with coverage\nuv run pytest --cov=mcp_atlassian\n\n# Run single test file\nuv run pytest tests/unit/test_preprocessing.py\n\n# Run single test function\nuv run pytest tests/unit/test_preprocessing.py::test_specific_function\n```\n\n**Running the Server**:\n```bash\nuv run mcp-atlassian                 # Start MCP server\nuv run mcp-atlassian --oauth-setup   # OAuth configuration wizard\nuv run mcp-atlassian -v              # Verbose logging mode\n```\n\n## Architecture\n\n### Mixin-Based Composition\nFunctionality is organized into **focused mixins** that compose together:\n- **Jira**: `JiraFetcher` inherits from 13 feature mixins (ProjectsMixin, IssuesMixin, WorklogMixin, etc.)\n- **Confluence**: `ConfluenceFetcher` inherits from 7 feature mixins (SearchMixin, PagesMixin, SpacesMixin, etc.)\n\nEach mixin lives in its own module under `src/mcp_atlassian/jira/` or `src/mcp_atlassian/confluence/`.\n\n### Client + Fetcher Pattern\n- **Client classes** (`JiraClient`, `ConfluenceClient`): Authentication, configuration, and API session management\n- **Fetcher classes** (`JiraFetcher`, `ConfluenceFetcher`): Business operations by composing mixins; inherit from Client\n\n### Protocol-Based Dependencies\nMixins declare dependencies via Protocol interfaces instead of direct imports:\n```python\nclass IssuesMixin(AttachmentsOperationsProto, FieldsOperationsProto):\n    # Mixin knows it needs attachment and field operations\n    # Protocols define the contract without circular imports\n```\n\nThe final Fetcher class satisfies all protocols through multiple inheritance.\n\n### Data Models\n- All models extend `ApiModel` base class with `from_api_response()` for deserialization\n- Use `TimestampMixin` for timestamp handling across Jira/Confluence models\n- Models support `to_simplified_dict()` for MCP tool responses\n- Located in `src/mcp_atlassian/models/`\n\n### MCP Server Layer\nServers (`src/mcp_atlassian/servers/`) use FastMCP framework:\n- Instantiate Fetchers via dependency injection (`get_jira_fetcher()`, `get_confluence_fetcher()`)\n- Wrap fetcher methods as MCP tools using `@mcp.tool()` decorator\n- Handle error conversion and response serialization\n- Support read-only and write modes\n\n## Key Conventions\n\n### Package Management\n**Always use `uv`, never `pip`**. This is a hard requirement for dependency management.\n\n### Branching Strategy\n**Never work on `main`**. Always create feature branches:\n```bash\ngit checkout -b feature/your-feature-name   # For new features\ngit checkout -b fix/issue-description       # For bug fixes\n```\n\n### Tool Naming\nMCP tools follow the pattern: `{service}_{action}`\n- Examples: `jira_create_issue`, `confluence_get_page`, `jira_search`\n\n### Type Safety\n- All functions require type hints\n- Use modern union syntax: `str | None` (not `Optional[str]`)\n- Use `type[T]` for class types\n- Collections: `list[str]`, `dict[str, Any]`\n\n### Code Style\n- **Line length**: 88 characters maximum (enforced by ruff)\n- **Imports**: Absolute imports, sorted by ruff\n- **Naming**: `snake_case` for functions/variables, `PascalCase` for classes\n- **Docstrings**: Google-style format for all public APIs\n- **Error handling**: Use specific exceptions, avoid bare `except:`\n\n### Testing\n- New features require tests\n- Bug fixes require regression tests\n- Test files mirror source structure: `tests/unit/` and `tests/integration/`\n- Use fixtures from `tests/fixtures/` for test data\n\n### Commit Messages\nUse git trailers for attribution:\n```bash\ngit commit --trailer \"Reported-by:<name>\"          # For bug reports\ngit commit --trailer \"Github-Issue:#<number>\"      # For issue references\n```\n\n**Never mention tools or AI assistants in commit messages**.\n\n## Authentication Support\nThe codebase supports multiple authentication methods:\n- **API Tokens**: Cloud deployments (username + token)\n- **Personal Access Tokens (PAT)**: Server/Data Center deployments\n- **OAuth 2.0**: Interactive user authentication with consent flow\n\nAuth configuration lives in `src/mcp_atlassian/utils/auth.py`.\n\n## Pre-commit Hooks\nPre-commit runs:\n- **ruff-format**: Auto-format Python code\n- **ruff**: Lint with auto-fix (select rules in pyproject.toml)\n- **mypy**: Type checking (currently lenient, see TODO comments in .pre-commit-config.yaml)\n- **prettier**: Format YAML/JSON\n- **Standard checks**: trailing whitespace, file endings, YAML/TOML validity\n\nTests are **not** run by pre-commit hooks—run them manually with `uv run pytest`.\n","isInternal":false,"tokens":1148,"sizeBytes":4868},{"name":"smithery.yaml","path":"smithery.yaml","rawUrl":"https://raw.githubusercontent.com/sooperset/mcp-atlassian/HEAD/smithery.yaml","title":"Model Context Protocol (MCP) Configuration","category":"mcp-config","format":"yaml","content":"# Smithery.ai configuration for mcp-atlassian\nstartCommand:\n  type: stdio # Specifies the server communicates over standard input/output\n  configSchema:\n    # JSON Schema defining the configuration options users need to provide\n    type: object\n    required:\n      - jiraUrl\n      - confluenceUrl\n      # Add other strictly required credentials based on auth needs\n    properties:\n      # Confluence Config\n      confluenceUrl:\n        type: string\n        description: \"Base URL for your Confluence instance (e.g., https://your-domain.atlassian.net/wiki or https://confluence.yourcompany.com).\"\n      confluenceUsername:\n        type: string\n        description: \"(Optional for Cloud Basic Auth) Your Confluence username or email.\"\n      confluenceApiToken:\n        type: string\n        description: \"(Optional for Cloud Basic Auth) Your Confluence API token.\"\n        format: password # Hides the value in UI inputs\n      confluencePersonalToken:\n        type: string\n        description: \"(Optional for Server/DC Token Auth) Your Confluence Personal Access Token.\"\n        format: password\n      confluenceSslVerify:\n        type: boolean\n        description: \"(Optional, Server/DC only) Verify SSL certificate for Confluence. Defaults to true.\"\n        default: true\n      confluenceSpacesFilter:\n        type: string\n        description: \"(Optional) Comma-separated list of Confluence space keys to limit searches to (e.g., 'DEV,QA').\"\n\n      # Jira Config\n      jiraUrl:\n        type: string\n        description: \"Base URL for your Jira instance (e.g., https://your-domain.atlassian.net or https://jira.yourcompany.com).\"\n      jiraUsername:\n        type: string\n        description: \"(Optional for Cloud Basic Auth or Server/DC Basic Auth) Your Jira username or email.\"\n      jiraApiToken:\n        type: string\n        description: \"(Optional for Cloud Basic Auth or Server/DC Basic Auth) Your Jira API token.\"\n        format: password\n      jiraPersonalToken:\n        type: string\n        description: \"(Optional for Server/DC Token Auth) Your Jira Personal Access Token.\"\n        format: password\n      jiraSslVerify:\n        type: boolean\n        description: \"(Optional, Server/DC only) Verify SSL certificate for Jira. Defaults to true.\"\n        default: true\n      jiraProjectsFilter:\n        type: string\n        description: \"(Optional) Comma-separated list of Jira project keys to limit searches to (e.g., 'PROJ1,PROJ2').\"\n\n      # General Config\n      readOnlyMode:\n        type: boolean\n        description: \"(Optional) Run in read-only mode (prevents create/update/delete). Defaults to false.\"\n        default: false\n\n    additionalProperties: false # Disallow properties not defined above\n\n  commandFunction:\n    # A JavaScript function that produces the CLI command and environment variables\n    # needed to start the MCP server, based on the user's configuration.\n    |-\n    (config) => {\n      // The command matches the ENTRYPOINT in the Dockerfile\n      const command = 'mcp-atlassian';\n      const args = []; // No arguments needed as config is via ENV\n\n      // Map the config schema properties to the environment variables\n      const env = {\n        // Confluence ENV VARS\n        CONFLUENCE_URL: config.confluenceUrl,\n        CONFLUENCE_USERNAME: config.confluenceUsername,\n        CONFLUENCE_API_TOKEN: config.confluenceApiToken,\n        CONFLUENCE_PERSONAL_TOKEN: config.confluencePersonalToken,\n        CONFLUENCE_SSL_VERIFY: config.confluenceSslVerify !== undefined ? String(config.confluenceSslVerify) : 'true',\n        CONFLUENCE_SPACES_FILTER: config.confluenceSpacesFilter,\n\n        // Jira ENV VARS\n        JIRA_URL: config.jiraUrl,\n        JIRA_USERNAME: config.jiraUsername,\n        JIRA_API_TOKEN: config.jiraApiToken,\n        JIRA_PERSONAL_TOKEN: config.jiraPersonalToken,\n        JIRA_SSL_VERIFY: config.jiraSslVerify !== undefined ? String(config.jiraSslVerify) : 'true',\n        JIRA_PROJECTS_FILTER: config.jiraProjectsFilter,\n\n        // General ENV VARS\n        READ_ONLY_MODE: config.readOnlyMode !== undefined ? String(config.readOnlyMode) : 'false',\n      };\n\n      // Filter out undefined/null env variables\n      const filteredEnv = Object.entries(env)\n        .filter(([key, value]) => value !== undefined && value !== null)\n        .reduce((obj, [key, value]) => {\n          obj[key] = value;\n          return obj;\n        }, {});\n\n      return {\n        command: command,\n        args: args,\n        env: filteredEnv\n      };\n    }\n","isInternal":false,"tokens":1016,"sizeBytes":4489}],"systemPromptSnippet":"<yakaai_skills repo=\"sooperset/mcp-atlassian\">\n<!-- File: AGENTS.md (Tokens: ~1066 | Category: root-instruction) -->\n# MCP Atlassian\n\n> **Audience**: LLM-driven engineering agents\n\n---\n\n## Repository map\n\n| Path | Purpose |\n| --- | --- |\n| `src/mcp_atlassian/` | Library source (Python ≥ 3.10) |\n| `  ├─ jira/` | Jira client + mixins (issues, search, SLA, metrics, …) |\n| `  ├─ confluence/` | Confluence client + mixins (pages, search, analytics, …) |\n| `  ├─ models/` | Pydantic v2 data models (`ApiModel` base) |\n| `  ├─ servers/` | FastMCP server instances (`jira_mcp`, `confluence_mcp`) |\n| `  ├─ preprocessing/` | Content conversion (ADF/Storage → Markdown) |\n| `  └─ utils/` | Shared utilities (auth, logging, SSL, decorators) |\n| `tests/` | Pytest suite — unit, integration, real-API validation |\n| `scripts/` | OAuth setup and testing scripts |\n\n---\n\n## Architecture\n\n- **Mixin composition**: `JiraFetcher` and `ConfluenceFetcher` are composed from the mixins listed in their `__init__.py`; client inheritance is transitive through mixins.\n- **FastMCP servers**: `servers/main.py` → lifespan → dependency injection via `get_jira_fetcher(ctx)` / `get_confluence_fetcher(ctx)`.\n- **Tool naming**: `{service}_{action}_{target}` (e.g., `jira_create_issue`, `confluence_get_page`).\n- **Config**: Environment-based `from_env()` factory on `JiraConfig` / `ConfluenceConfig` dataclasses.\n- **Auth**: Basic (Cloud + Server/DC), PAT (Server/DC), OAuth 2.0 (Cloud + Server/DC) — with multi-tenant header support.\n- **Models**: All extend `ApiModel` → `from_api_response()` + `to_simplified_dict()`.\n\n---\n\n## Dev workflow\n\n```bash\nuv sync --frozen --all-extras --dev  # install dependencies\npre-commit install                    # setup hooks\npre-commit run --all-files           # Ruff + mypy\nuv run pytest -xvs                   # full test suite\nuv run pytest tests/unit/ -xvs       # unit tests only\nuv run pytest tests/integration/     # integration tests\nuv run pytest --cov=src/mcp_atlassian --cov-report=term-missing  # coverage\n```\n\n*Tests must pass* and *lint/typing must be clean* before committing.\n\n---\n\n## Rules\n\n1. **Package management**: ONLY use `uv`, NEVER `pip`\n2. **Branching**: NEVER work on `main`, always create feature branches\n3. **Type safety**: All functions require type hints\n4. **Testing**: New features need tests, bug fixes need regression tests\n5. **Commits**: Use trailers for attribution, never mention tools/AI\n6. **Commit types**: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`, `perf`, `ci` — scopes: `jira`, `confluence`, `server`, `auth`, `docker`, `docs`\n7. **File hygiene**: Prefer editing existing files over creating new ones\n8. **Tool docs**: After changing tool signatures or registrations, run `uv run python scripts/generate_tool_docs.py` and commit the diff; CI (`Docs / check`) enforces this\n\n---\n\n## Code conventions\n\n- **Language**: Python ≥ 3.10\n- **Line length**: 88 characters maximum\n- **Imports**: Absolute imports, sorted by Ruff\n- **Naming**: `snake_case` functions, `PascalCase` classes\n- **Docstrings**: Google-style for all public APIs\n- **Error handling**: Specific exceptions only\n\n---\n\n## Gotchas\n\n- **Cloud vs Server/DC**: API endpoints, field names, and auth methods differ. Always check `is_cloud` before assuming behavior.\n- **OAuth 2.0**: Supported on both Cloud and Server/Data Center. PAT is also available for Server/DC. Basic auth (user + API token) works on both Cloud and Server/DC.\n- **Read-only mode**: `READ_ONLY_MODE=true` blocks all write tools at server level.\n- **Type checking**: pre-commit runs **mypy** (strict mode).\n- **Environment**: See `.env.example` for all configuration options (auth, proxy, SLA, filtering).\n\n---\n\n## Quick reference\n\n```bash\n# Running the server\nuv run mcp-atlassian                 # Start server\nuv run mcp-atlassian --oauth-setup   # OAuth wizard\nuv run mcp-atlassian -v              # Verbose mode\n\n# Git workflow\ngit checkout -b feature/description   # New feature\ngit checkout -b fix/issue-description # Bug fix\ngit commit --trailer \"Reported-by:<name>\"      # Attribution\ngit commit --trailer \"Github-Issue:#<number>\"  # Issue reference\n```\n\n<!-- File: .github/copilot-instructions.md (Tokens: ~1148 | Category: copilot-instructions) -->\n# MCP Atlassian - Development Guide\n\nModel Context Protocol (MCP) server for Atlassian products (Jira & Confluence). Python ≥3.10.\n\n## Build, Test, and Lint\n\n**Dependencies**:\n```bash\nuv sync --frozen --all-extras --dev  # Install all dependencies\n```\n\n**Code Quality** (required before commit):\n```bash\npre-commit run --all-files           # Run all checks: ruff, prettier, mypy\n```\n\n**Testing**:\n```bash\n# Run all tests\nuv run pytest\n\n# Run with coverage\nuv run pytest --cov=mcp_atlassian\n\n# Run single test file\nuv run pytest tests/unit/test_preprocessing.py\n\n# Run single test function\nuv run pytest tests/unit/test_preprocessing.py::test_specific_function\n```\n\n**Running the Server**:\n```bash\nuv run mcp-atlassian                 # Start MCP server\nuv run mcp-atlassian --oauth-setup   # OAuth configuration wizard\nuv run mcp-atlassian -v              # Verbose logging mode\n```\n\n## Architecture\n\n### Mixin-Based Composition\nFunctionality is organized into **focused mixins** that compose together:\n- **Jira**: `JiraFetcher` inherits from 13 feature mixins (ProjectsMixin, IssuesMixin, WorklogMixin, etc.)\n- **Confluence**: `ConfluenceFetcher` inherits from 7 feature mixins (SearchMixin, PagesMixin, SpacesMixin, etc.)\n\nEach mixin lives in its own module under `src/mcp_atlassian/jira/` or `src/mcp_atlassian/confluence/`.\n\n### Client + Fetcher Pattern\n- **Client classes** (`JiraClient`, `ConfluenceClient`): Authentication, configuration, and API session management\n- **Fetcher classes** (`JiraFetcher`, `ConfluenceFetcher`): Business operations by composing mixins; inherit from Client\n\n### Protocol-Based Dependencies\nMixins declare dependencies via Protocol interfaces instead of direct imports:\n```python\nclass IssuesMixin(AttachmentsOperationsProto, FieldsOperationsProto):\n    # Mixin knows it needs attachment and field operations\n    # Protocols define the contract without circular imports\n```\n\nThe final Fetcher class satisfies all protocols through multiple inheritance.\n\n### Data Models\n- All models extend `ApiModel` base class with `from_api_response()` for deserialization\n- Use `TimestampMixin` for timestamp handling across Jira/Confluence models\n- Models support `to_simplified_dict()` for MCP tool responses\n- Located in `src/mcp_atlassian/models/`\n\n### MCP Server Layer\nServers (`src/mcp_atlassian/servers/`) use FastMCP framework:\n- Instantiate Fetchers via dependency injection (`get_jira_fetcher()`, `get_confluence_fetcher()`)\n- Wrap fetcher methods as MCP tools using `@mcp.tool()` decorator\n- Handle error conversion and response serialization\n- Support read-only and write modes\n\n## Key Conventions\n\n### Package Management\n**Always use `uv`, never `pip`**. This is a hard requirement for dependency management.\n\n### Branching Strategy\n**Never work on `main`**. Always create feature branches:\n```bash\ngit checkout -b feature/your-feature-name   # For new features\ngit checkout -b fix/issue-description       # For bug fixes\n```\n\n### Tool Naming\nMCP tools follow the pattern: `{service}_{action}`\n- Examples: `jira_create_issue`, `confluence_get_page`, `jira_search`\n\n### Type Safety\n- All functions require type hints\n- Use modern union syntax: `str | None` (not `Optional[str]`)\n- Use `type[T]` for class types\n- Collections: `list[str]`, `dict[str, Any]`\n\n### Code Style\n- **Line length**: 88 characters maximum (enforced by ruff)\n- **Imports**: Absolute imports, sorted by ruff\n- **Naming**: `snake_case` for functions/variables, `PascalCase` for classes\n- **Docstrings**: Google-style format for all public APIs\n- **Error handling**: Use specific exceptions, avoid bare `except:`\n\n### Testing\n- New features require tests\n- Bug fixes require regression tests\n- Test files mirror source structure: `tests/unit/` and `tests/integration/`\n- Use fixtures from `tests/fixtures/` for test data\n\n### Commit Messages\nUse git trailers for attribution:\n```bash\ngit commit --trailer \"Reported-by:<name>\"          # For bug reports\ngit commit --trailer \"Github-Issue:#<number>\"      # For issue references\n```\n\n**Never mention tools or AI assistants in commit messages**.\n\n## Authentication Support\nThe codebase supports multiple authentication methods:\n- **API Tokens**: Cloud deployments (username + token)\n- **Personal Access Tokens (PAT)**: Server/Data Center deployments\n- **OAuth 2.0**: Interactive user authentication with consent flow\n\nAuth configuration lives in `src/mcp_atlassian/utils/auth.py`.\n\n## Pre-commit Hooks\nPre-commit runs:\n- **ruff-format**: Auto-format Python code\n- **ruff**: Lint with auto-fix (select rules in pyproject.toml)\n- **mypy**: Type checking (currently lenient, see TODO comments in .pre-commit-config.yaml)\n- **prettier**: Format YAML/JSON\n- **Standard checks**: trailing whitespace, file endings, YAML/TOML validity\n\nTests are **not** run by pre-commit hooks—run them manually with `uv run pytest`.\n\n<!-- File: smithery.yaml (Tokens: ~1016 | Category: mcp-config) -->\n# Smithery.ai configuration for mcp-atlassian\nstartCommand:\n  type: stdio # Specifies the server communicates over standard input/output\n  configSchema:\n    # JSON Schema defining the configuration options users need to provide\n    type: object\n    required:\n      - jiraUrl\n      - confluenceUrl\n      # Add other strictly required credentials based on auth needs\n    properties:\n      # Confluence Config\n      confluenceUrl:\n        type: string\n        description: \"Base URL for your Confluence instance (e.g., https://your-domain.atlassian.net/wiki or https://confluence.yourcompany.com).\"\n      confluenceUsername:\n        type: string\n        description: \"(Optional for Cloud Basic Auth) Your Confluence username or email.\"\n      confluenceApiToken:\n        type: string\n        description: \"(Optional for Cloud Basic Auth) Your Confluence API token.\"\n        format: password # Hides the value in UI inputs\n      confluencePersonalToken:\n        type: string\n        description: \"(Optional for Server/DC Token Auth) Your Confluence Personal Access Token.\"\n        format: password\n      confluenceSslVerify:\n        type: boolean\n        description: \"(Optional, Server/DC only) Verify SSL certificate for Confluence. Defaults to true.\"\n        default: true\n      confluenceSpacesFilter:\n        type: string\n        description: \"(Optional) Comma-separated list of Confluence space keys to limit searches to (e.g., 'DEV,QA').\"\n\n      # Jira Config\n      jiraUrl:\n        type: string\n        description: \"Base URL for your Jira instance (e.g., https://your-domain.atlassian.net or https://jira.yourcompany.com).\"\n      jiraUsername:\n        type: string\n        description: \"(Optional for Cloud Basic Auth or Server/DC Basic Auth) Your Jira username or email.\"\n      jiraApiToken:\n        type: string\n        description: \"(Optional for Cloud Basic Auth or Server/DC Basic Auth) Your Jira API token.\"\n        format: password\n      jiraPersonalToken:\n        type: string\n        description: \"(Optional for Server/DC Token Auth) Your Jira Personal Access Token.\"\n        format: password\n      jiraSslVerify:\n        type: boolean\n        description: \"(Optional, Server/DC only) Verify SSL certificate for Jira. Defaults to true.\"\n        default: true\n      jiraProjectsFilter:\n        type: string\n        description: \"(Optional) Comma-separated list of Jira project keys to limit searches to (e.g., 'PROJ1,PROJ2').\"\n\n      # General Config\n      readOnlyMode:\n        type: boolean\n        description: \"(Optional) Run in read-only mode (prevents create/update/delete). Defaults to false.\"\n        default: false\n\n    additionalProperties: false # Disallow properties not defined above\n\n  commandFunction:\n    # A JavaScript function that produces the CLI command and environment variables\n    # needed to start the MCP server, based on the user's configuration.\n    |-\n    (config) => {\n      // The command matches the ENTRYPOINT in the Dockerfile\n      const command = 'mcp-atlassian';\n      const args = []; // No arguments needed as config is via ENV\n\n      // Map the config schema properties to the environment variables\n      const env = {\n        // Confluence ENV VARS\n        CONFLUENCE_URL: config.confluenceUrl,\n        CONFLUENCE_USERNAME: config.confluenceUsername,\n        CONFLUENCE_API_TOKEN: config.confluenceApiToken,\n        CONFLUENCE_PERSONAL_TOKEN: config.confluencePersonalToken,\n        CONFLUENCE_SSL_VERIFY: config.confluenceSslVerify !== undefined ? String(config.confluenceSslVerify) : 'true',\n        CONFLUENCE_SPACES_FILTER: config.confluenceSpacesFilter,\n\n        // Jira ENV VARS\n        JIRA_URL: config.jiraUrl,\n        JIRA_USERNAME: config.jiraUsername,\n        JIRA_API_TOKEN: config.jiraApiToken,\n        JIRA_PERSONAL_TOKEN: config.jiraPersonalToken,\n        JIRA_SSL_VERIFY: config.jiraSslVerify !== undefined ? String(config.jiraSslVerify) : 'true',\n        JIRA_PROJECTS_FILTER: config.jiraProjectsFilter,\n\n        // General ENV VARS\n        READ_ONLY_MODE: config.readOnlyMode !== undefined ? String(config.readOnlyMode) : 'false',\n      };\n\n      // Filter out undefined/null env variables\n      const filteredEnv = Object.entries(env)\n        .filter(([key, value]) => value !== undefined && value !== null)\n        .reduce((obj, [key, value]) => {\n          obj[key] = value;\n          return obj;\n        }, {});\n\n      return {\n        command: command,\n        args: args,\n        env: filteredEnv\n      };\n    }\n</yakaai_skills>"}