Skip to content

v0.17.0#17

Closed
raphael-cohere wants to merge 142 commits intomainfrom
merge-v0.17.0
Closed

v0.17.0#17
raphael-cohere wants to merge 142 commits intomainfrom
merge-v0.17.0

Conversation

@raphael-cohere
Copy link
Copy Markdown

Description

Fixes: #

Changes

Testing

  • Unit tests added/updated
  • Integration tests passed
  • Manual checks performed: [briefly describe]

Checklist

  • Code follows project style guidelines (linting passes).
  • Tests added/updated for changes.
  • All tests pass locally.
  • Documentation updated (if needed).

guillegarciac and others added 30 commits November 15, 2025 14:42
- Add explicit timeouts (5s connect, 20s read) to OAuth HTTP requests
- Replace ADD with COPY in Dockerfile per best practices
- Add HEALTHCHECK for HTTP transport modes

Prevents indefinite hangs on slow Atlassian APIs (AIVSS 6.5).
No breaking changes - fully backward compatible.
The latest pydantic version (2.12.0) is not compatible with the project's current usage.
Updates dependency specification in `pyproject.toml` to "pydantic>=2.10.0,<2.12.0" to prevent runtime errors when using with uvx.

Related to sooperset#721.
Add required OAuth scopes that were missing from the example:
- read:jira-user: Required for Jira user operations
- read:confluence-content.summary: Required for Confluence content
- search:confluence: Required for Confluence search
- read:page:confluence: Granular scope required for Confluence v2 API

The read:page:confluence scope is particularly important as OAuth
authentication uses the v2 API which requires this granular scope
for page operations.
…ooperset#767)

Self-hosted Confluence (especially older versions like 6.7.1) may return
pages without body content, causing TypeError when accessing
page["body"]["storage"]["value"]. This adds try/except handling with
logging to gracefully handle None values in the body chain.

Fixes sooperset#760

Github-Issue:sooperset#760
…operset#768)

Add field_serializer to JiraChangelog model to ensure datetime fields
are properly serialized to ISO 8601 format for JSON. This fixes the
"Object of type datetime is not JSON serializable" error when using
expand='changelog' with Jira search.

- Add @field_serializer("created") to JiraChangelog
- Update to_simplified_dict() to use isoformat()
- Add regression tests for datetime serialization
- Update existing test expectations for ISO 8601 format

Fixes sooperset#749
Github-Issue:sooperset#749
The Jira Cloud v2 search API (/rest/api/*/search) has been deprecated and
is now returning errors. This commit migrates Cloud deployments to the new
v3 search endpoint (POST /rest/api/3/search/jql).

Changes:
- Cloud: Use POST /rest/api/3/search/jql with nextPageToken pagination
- Server/DC: Continue using the v2 /rest/api/2/search endpoint unchanged
- Updated tests to mock the new v3 API calls for Cloud scenarios

The v3 API has some differences:
- Uses JSON body instead of query parameters
- Uses nextPageToken for pagination instead of startAt
- Does not return total count (returns -1)
- Max 100 results per request (was 50 for Server/DC)

Fixes sooperset#720

Github-Issue:sooperset#720
Fixes sooperset#784, sooperset#785, sooperset#772 - ADF parsing for Jira Cloud descriptions and comments
…t#794)

Upgrade fastmcp from 2.3.x to 2.14.x to address high-severity OAuth
vulnerability (SNYK-PYTHON-FASTMCP-13776148).

Breaking API changes migrated:
- FastMCP() `description` parameter renamed to `instructions`
- `mount(prefix, server)` signature changed to `mount(server, prefix=)`
- `sse_app()` replaced with `http_app(transport="sse")`
- `streamable_http_app()` replaced with `http_app()`
- Client `call_tool()` returns `CallToolResult` object (not list)
- Tests restricted to asyncio backend (FastMCP client limitation)
Add comprehensive tests for the adf_to_text function that converts
Atlassian Document Format to plain text.

Test coverage includes:
- Basic input handling (None, string, empty dict/list)
- Text nodes (simple, empty, with marks)
- HardBreak nodes
- Paragraph and content processing
- Full ADF documents with nested structures
- Edge cases (unknown types, mixed content)
- XFail tests for future node types (mention, emoji, date, status, inlineCard)

26 passing tests, 5 xfail tests for planned improvements.
… codeBlock nodes (sooperset#793)

Expands the ADF parser to handle additional inline and block node types
that were previously being silently dropped during text conversion.

- mention: Extracts @username text or falls back to @{id}
- emoji: Returns unicode character or shortName
- date: Formats UNIX timestamp as YYYY-MM-DD
- status: Wraps status text in brackets
- inlineCard: Extracts URL from link cards
- codeBlock: Wraps code content in markdown backticks

Includes 38 unit tests covering all new node types and edge cases.
sooperset#795)

- Add **kwargs to http_app() override for FastMCP 2.14.x json_response param
- Rename _mcp_list_tools to _list_tools_mcp to match FastMCP expected method name
- Update test references to use correct method name

Fixes read-only mode which was not filtering write tools due to incorrect
method override name.
Python 3.14 is not yet supported due to upstream pydantic-core
limitations (PyO3 0.24.1 only supports up to Python 3.13).

- Add requires-python upper bound
- Document workaround in README

Github-Issue:sooperset#776
When search returns attachments, use the container's page ID
instead of the attachment ID for URL construction.

- Check content type before URL construction
- Use container.id for attachments
- Keep using id for pages/blogposts
- Add tests for attachment URL scenarios

Fixes sooperset#790

Github-Issue:sooperset#790
Change indent formula from `ident // 4` to `ident // 2` to correctly
handle 2-space indentation in markdown.

- Fix bulleted list level calculation with proper regex for *, -, +
- Fix numbered list level calculation with proper regex for any digit
- Add tests for 2-space indented nested lists

Fixes sooperset#717

Reported-by:@vkrasnoselskikh
Github-Issue:sooperset#717
…ment-url

fix(confluence): use parent page ID for attachment URLs
…nstraint

fix(deps): add Python <3.14 version constraint
…tation

fix(jira): fix multi-level bullet list indentation
Adds MCP tool annotations (readOnlyHint, destructiveHint, title) to all 42 tools.

- 31 Jira tools annotated
- 11 Confluence tools annotated
- Helps LLMs understand tool behavior and make safer decisions
Adds include_folders parameter to get_page_children to return child folders alongside pages.

- Default: include_folders=True for backward compatibility
- Graceful error handling if folder API fails
- 4 new tests added
- Fixes sooperset#165
…eouts-docker-hardening

Security: Add HTTP timeouts and Docker hardening
The HEALTHCHECK added in sooperset#755 assumes HTTP transport on port 8000,
but the default transport is stdio (no network listener). This causes:
- Docker to mark containers as unhealthy after 3 failed checks
- Container orchestrators (k8s, Swarm) to restart containers
- A restart loop for most users using the default configuration

Remove the HEALTHCHECK entirely. If needed in the future, it should
be conditional on transport mode via environment variable.

Github-Issue: sooperset#755
fix(docker): remove HEALTHCHECK that breaks stdio transport
- Slim down README to ~105 lines as landing page
- Make uvx the primary/default installation method
- Create docs/ folder with detailed documentation:
  - installation.md: uvx, Docker, pip, from source
  - authentication.md: API tokens, PAT, OAuth, BYOT
  - configuration.md: IDE configs, env vars, filters
  - http-transport.md: SSE, streamable-http, multi-user
  - tools-reference.md: all Jira/Confluence tools
  - troubleshooting.md: common issues, debugging

Github-Issue:sooperset#641
…set#806)

Convert documentation to Mintlify MDX format for hosted docs site
with automatic llms.txt and llms-full.txt generation.
Mintlify requires a favicon field in mint.json. Added simple SVG
favicon with Atlassian blue color scheme.
fix(docs): add required favicon for Mintlify deployment
Mintlify updated their configuration format:
- Rename mint.json to docs.json
- Update schema URL to https://mintlify.com/docs.json
- Update navigation structure to use tabs/groups format
sooperset and others added 29 commits February 21, 2026 02:36
…#858) (sooperset#954)

Add regression tests verifying the fix for the OAuth refresh token
failure that occurs when a server has ATLASSIAN_OAUTH_ENABLE=true
globally but receives per-request PAT/Bearer tokens. The actual fixes
were delivered in PR sooperset#952 (early return in configure_oauth_session) and
PR sooperset#953 (bearer disambiguation fallback to PAT).

Github-Issue:sooperset#858
…set#955)

Add HTTP Basic authentication (email:api_token) support for multi-user
scenarios, enabling each user to authenticate with their own Atlassian
Cloud credentials via the Authorization: Basic header.

Changes:
- Parse Authorization: Basic <base64(email:api_token)> in middleware
- Add 'basic' auth type to dependency injection layer
- Create user-specific fetchers with per-request basic auth credentials
- Validate email/token presence with clear error messages

Based on the approach from PR sooperset#739 by @kangis89.

Github-Issue:sooperset#380
Reported-by:kangis89
…operset#956)

Fix service detection to recognize ATLASSIAN_OAUTH_ENABLE=true as a
fallback when URL-based auth detection fails. Previously, the check was
inside an `elif` branch only reached when no service URL was set. Now it
acts as a fallback regardless of URL presence.

This enables BYOT (Bring Your Own Token) mode where users provide
OAuth tokens via per-request headers, with or without service URLs.

Based on the approach from PR sooperset#699 by @nealedj.

Github-Issue:sooperset#698
Reported-by:nealedj
… and BYOT (sooperset#957)

Update AGENTS.md, CLI help text, and .env.example to reflect the new
authentication capabilities added in Phase 3: OAuth 2.0 for Data Center,
Basic Auth multi-user support, BYOT OAuth mode, service-specific OAuth
env vars, and configurable HTTP timeouts.
…perset#958)

fix(jira): use new createmeta endpoint for Server/DC (Jira 9.x+)

The old `/rest/api/2/issue/createmeta?projectKeys=...&expand=...`
endpoint was deprecated in Jira 9.x and broken in Jira 10.x, causing
`jira_get_field_options`, `get_required_fields`, and
`get_project_issue_types` to silently return empty results on Server/DC.

Switch all three methods to the new paginated endpoints:
- `/rest/api/2/issue/createmeta/{project}/issuetypes` (values format)
- `/rest/api/2/issue/createmeta/{project}/issuetypes/{id}` (field meta)

Also fix FieldOption model to fall back to `name` when `value` is empty,
which is the case for system fields like priority on Server/DC.
…sooperset#948)

Fix catastrophic backtracking in citation regex that caused jira_get_issue to hang on unmatched `??` markers. Replace overlapping alternation pattern with non-overlapping structure that operates in linear time.

Thanks @johnny

Prepared head SHA: 5677e26
Github-Issue:sooperset#948
Add server-level anyOf flattening to fix JSON Schema incompatibilities
with Vertex AI / Google ADK (sooperset#640, sooperset#733), LiteLLM / OpenAI gateways
(PR sooperset#938), and other AI platforms.

Changes:
- Add _sanitize_schema_for_compatibility() in main.py that collapses
  simple nullable unions (T | None → {type: T}) in tool schemas
- Narrow 9 complex union params in jira.py to string-based types
  (visibility → JSON string, list → CSV, dict|str → str)
- Extract _parse_visibility() helper for DRY visibility JSON parsing
- Add name_filter param to get_link_types (fixes zero-arg tool issue)
- Convert upload_attachments file_paths to CSV string in confluence.py
- Add comprehensive schema compatibility test harness (314 tests)
  validating all 59 tools against platform constraints

Validated against Gemini 2.5 Flash and Gemini 2.5 Pro APIs — all 59
tool schemas accepted and function calling works correctly.

Github-Issue:sooperset#640
Github-Issue:sooperset#733
Add docs/compatibility.mdx with platform compatibility matrix,
schema compatibility details, and platform-specific setup notes
for GitHub Copilot, Vertex AI / Google ADK, and ChatGPT.

Github-Issue:sooperset#541
Github-Issue:sooperset#484
- Remove unreleased version references (v0.18.0) — latest tag is v0.16.0
- Remove hardcoded tool count (59) that will become stale
- Distinguish "Supported" (tested) from "Compatible" (untested) platforms
Remove legacy test_real_api_validation.py (1483 lines, always skipped in
CI) and replace with two E2E test suites:

- DC E2E (61 tests): Jira DC 10.3 + Confluence DC 9.2 in Docker, covering
  auth matrix (basic/PAT/BYO-OAuth), DC-specific operations, and MCP
  tool-level tests via FastMCPTransport
- Cloud E2E (48 tests): Jira Cloud + Confluence Cloud, covering auth
  matrix (basic/BYO-OAuth), Cloud-specific behavior (accountId, analytics,
  subtask naming), and MCP tool-level tests

Both suites auto-skip without their respective flags (--dc-e2e, --cloud-e2e).
Includes Docker Compose infrastructure, health checks, PAT creation, and
test data provisioning scripts.
…er URLs (sooperset#964)

base_url already includes /wiki for Cloud instances (added by
atlassian-python-api). Five URL constructions were prepending /wiki
again, producing 404s for analytics views, page attachments, and
attachment operations.

Fixes: v2_adapter.py (4 URLs) and analytics.py (1 URL).
Regression tests added for both files.

Github-Issue:sooperset#962
…rset#967)

When a project key matches a JQL reserved word (e.g., IF, AND, OR),
Jira API returns "'IF' is a reserved JQL word" error. Add automatic
quoting of reserved words in project = VALUE and project IN (...)
patterns, mirroring the existing Confluence CQL pattern.

- Add RESERVED_JQL_WORDS constant from official Atlassian docs
- Add quote_jql_identifier_if_needed() and sanitize_jql_reserved_words()
- Apply sanitization in search_issues() and get_board_issues()
- Refactor projects_filter to use smart quoting (only when needed)

Github-Issue:sooperset#966
…t#970)

Epic link aliases (epicKey, epic_link, epicLink, "Epic Link") passed
via additional_fields were silently dropped because
_process_additional_fields only recognizes Jira field map names, not
user-friendly aliases.

Add _prepare_epic_link_fields() that discovers the real custom field
ID via get_field_ids_to_epic() and falls back to the parent field on
Cloud when no epic link custom field exists (team-managed projects).

Also add explicit parent handling in update_issue, which previously
skipped the parent kwarg entirely causing silent data loss.

Github-Issue:sooperset#623
sooperset#978)

- Track CLAUDE.md (@AGENTS.md) so worktrees get it automatically
- Track .claude/settings.json for shared team permissions
- Selectively gitignore .claude/worktrees/ and settings.local.json
  instead of the entire .claude/ directory
- Add .worktreeinclude for .env and dev/ copying into worktrees
- Add dev/ to .gitignore (local task documents)
…erset#973)

The d57b7fd schema compatibility commit converted all dict-typed tool
parameters to str for better AI platform compatibility, but missed the
`fields` parameter in update_issue(). This caused a Pydantic validation
error when an LLM passed fields as a JSON string instead of a dict.

Fix by changing the type annotation to `dict[str, Any] | str` and
routing through the existing `_parse_additional_fields()` helper,
consistent with how additional_fields is handled in the same function.

Co-authored-by: Henrik Teichmann <teichmann@strato-rz.de>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(jira): add jira_get_project_components tool

* test(jira): add test for jira_get_project_components tool

- Add import and registration for get_project_components in test fixture
- Add test_get_project_components_tool test function

* docs: add jira_get_project_components to tools reference

---------

Co-authored-by: Ruslan Tabolin <ryutabolin@cloud.ru>
* fix: remove credential/token logging and harden security

- Remove OAuth token exchange payload logging containing client_secret
- Remove OAuth token response body logging containing access/refresh tokens
- Replace partial access/refresh token logging with safe confirmation messages
- Redact client_secret value in OAuth setup environment variable output
- Redact partial token values in multi-user HTTP mode log messages
- Remove SSL legacy renegotiation flags (OP_LEGACY_SERVER_CONNECT, OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)
- Add path traversal guard to Jira attachment download
- Sanitize JQL project filter interpolation to prevent injection via double-quote characters
- Remove unused pprint import from oauth.py

* fix: resolve CI failures — ruff-format line length and test mocks for path traversal guard

- Wrap long raise ValueError() line to satisfy ruff-format 88-char limit
- Add os.getcwd mock to test_download_attachment_success so /tmp path passes traversal check
- Fix test_download_attachment_relative_path: use side_effect for abspath mock and
  separate os.getcwd mock to handle the second abspath call from the traversal guard

* style: fix ruff-format lambda expression formatting

* fix: address PR review comments

- Fix JQL injection bypass: escape backslashes before double-quotes
- Replace str.startswith() with Path.is_relative_to() for path traversal check
- Add path traversal guard to download_issue_attachments()
- Redact client_secret in VS Code config JSON blob

* fix: address CI failures

- Fix ruff-format: multi-line list comprehension in search.py
- Replace Path.resolve() with direct Path.is_relative_to() to avoid
  breaking os.path mocks in tests (resolve() internally calls os.path.isabs
  on Python 3.12)
- Add os.getcwd mocks to download_issue_attachments tests that use
  /tmp/attachments paths

---------

Co-authored-by: JKAW <jkaw@demant.com>
…perset#979)

* feat(jira): add service desk queue read tools

Reported-by: Ilgar Dadashi

* test(jira): add queue read unit coverage

Reported-by: Ilgar Dadashi

* docs(docs): document jira queue read tools

Reported-by: Ilgar Dadashi

* chore(jira): apply queue mixin formatting

* fix(jira): enforce upper limit on service desk queue results

---------

Co-authored-by: Ilgar <97271325+ilgaur@users.noreply.github.com>
* Upgrade python and dependencies to fix trivy scan issues.

Upgraded python version in Dockerfile and dependencies (with `uv lock --upgrade`)
to address vulnerabilities found in trivy scan:
```
docker run -v /var/run/docker.sock:/var/run/docker.sock -v $HOME/Library/Caches:/root/.cache/ aquasec/trivy:0.69.1 image ghcr.io/sooperset/mcp-atlassian:0.16.1
```

Also modified ConfluencePreprocessor to add new ConfluenceSiteMetadata required by md2conf.

* Update python in build container too.
The md2conf.metadata module was introduced in 0.3.4. The previous
minimum >=0.3.0 could resolve to 0.3.0-0.3.3 which lack this module,
causing ModuleNotFoundError at runtime. Follow-up to PR sooperset#977.

Github-Issue: sooperset#977
…erset#981)

- Update update_issue fields parameter description from 'Dictionary' to
  'JSON string' to match the str type (follow-up to PR sooperset#973)
- Add PROJECT_KEY_PATTERN validation to get_project_components for
  consistency with get_project_versions (follow-up to PR sooperset#873)
)

- Add 'Server/Data Center only' to queue tool docstrings
- Expand Cloud-rejection tests to cover all 3 queue methods
- Add QueuesMixin to JiraFetcher docstring

Follow-up to PR sooperset#971.

Github-Issue: sooperset#971
…sanitization (sooperset#983)

Add tests for security hardening from PR sooperset#949:
- Path traversal rejection in attachment downloads (absolute and relative paths)
- Path traversal rejection in issue attachment downloads (ValueError propagation)
- JQL value escaping for backslash and double-quote characters (inline logic)
- Integration tests for projects filter with malicious special characters
- Combined backslash+quote escaping case for quote_jql_identifier_if_needed

Follow-up to PR sooperset#949.

Github-Issue: sooperset#949
…ooperset#987)

Add validate_safe_path() utility that resolves symlinks via
Path.resolve() and validates containment with is_relative_to().
Guard Confluence download_attachment() and
download_content_attachments() against path traversal.
Refactor Jira attachment guards to use the shared utility,
strengthening them with symlink resolution.

Addresses GHSA-xjgw-4wvw-rgm4.

Reported-by: yotampe-pluto
Github-Issue: sooperset#984
…perset#986)

Add validate_url_for_ssrf() utility that checks scheme, blocks
private/reserved IPs, resolves DNS to detect rebinding, and supports
domain allowlisting via MCP_ALLOWED_URL_DOMAINS.

Apply validation in ASGI middleware before URLs reach fetcher
creation. Add redirect-based SSRF hook on header-based fetcher
sessions to block 302 redirects to internal targets.

Addresses GHSA-7r34-79r5-rcc9.

Reported-by: yotampe-pluto
Github-Issue: sooperset#985
…patibility (sooperset#985)

* fix: sync OAuth tokens to base keyring username for load_tokens() compatibility

When saving tokens, _save_tokens() uses _get_keyring_username() which
includes cloud_id or base_url hash in the key. However, load_tokens()
uses a simpler pattern (oauth-{client_id}) without the context suffix.

This mismatch causes load_tokens() to return stale tokens from keyring
after re-authentication, because the new tokens are saved under a
different key.

Fix: Also save tokens to the base oauth-{client_id} keyring entry when
the context-specific username differs, ensuring load_tokens() always
finds the latest tokens.

Fixes sooperset#984

* test: update test_save_tokens_keyring_success to expect two keyring calls

The _save_tokens() method now saves to both:
1. Context-specific key (oauth-{client_id}-cloud-{cloud_id})
2. Base key (oauth-{client_id}) for load_tokens() compatibility

Update the test to verify both keyring entries are created.

* address review comments: add inline comment and DC test case

- Add inline comment noting that base key may be overwritten if same
  client_id is used for both Cloud and DC (rare edge case)
- Add test_save_tokens_keyring_success_dc to verify dual-write behavior
  for Data Center context with oauth-{client_id}-dc-{url_hash} pattern
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.