Skip to content

confluence_get_space_page_tree fails on Confluence DC: TypeError sorting heterogeneous position values (str vs int) #1319

@wplagges

Description

@wplagges

Summary

confluence_get_space_page_tree raises TypeError: '<' not supported between instances of 'str' and 'int' against a Confluence Data Center / Server space whenever the space contains pages whose extensions.position is returned as a string (commonly the literal "none", but also numeric strings) instead of int/null.

The MCP tool surfaces this as:

Error calling tool 'get_space_page_tree': Failed to fetch page tree: '<' not supported between instances of 'str' and 'int'

Every other Confluence tool (confluence_search, confluence_get_page, ...) works fine against the same space, so this is specific to the tree builder's sort.

Environment

  • mcp-atlassian 0.21.1 (also reproducible in main at the time of writing — same code)
  • Launched via uvx mcp-atlassian (uv 0.11.9) from Cursor on Windows 11
  • Python 3.13.2
  • Atlassian backend: Confluence Data Center (on-prem), PAT auth
  • Confluence REST v1 API responses include pages where extensions.position is the string "none" mixed with integer positions (0, 1, 2, ...) within the same space

Repro

  1. Point mcp-atlassian at a Confluence DC instance with PAT auth.
  2. Pick any space whose root page has no explicit ordering (so the v1 API returns "position": "none" for it) and whose other pages have integer positions.
  3. Call:
    {"name": "confluence_get_space_page_tree", "arguments": {"space_key": "<KEY>", "limit": 100}}
  4. Observe the error above.

Root cause

src/mcp_atlassian/confluence/pages.py, in ConfluencePages.get_space_page_tree, builds tuples for list.sort using position directly:

# current code (around lines 919-926 on main)
# Sort by depth first (breadth-first), then by position
# Note: position can be 0 (valid), so check for None explicitly
result_pages.sort(
    key=lambda p: (
        p["depth"],
        p["position"] if p["position"] is not None else 999999,
        p["title"],
    )
)

The check guards against None, but Confluence DC's v1 API returns extensions.position as the string "none" (and sometimes numeric strings) for pages without an explicit ordering. Those values are not None, so they pass through into the sort key. Mixing str and int at the same tuple position raises TypeError in Python 3.

I confirmed this against a real space: of 100 pages returned, ~half had "position": "none" (str) and the rest had integer positions like 0, 1, 2, ....

Suggested fix

Coerce position to a sortable int (with a sentinel for missing/non-numeric values) before using it as a sort key. A minimal patch:

def _pos_sort_key(p: dict) -> int:
    pos = p.get("position")
    if pos is None:
        return 999999
    if isinstance(pos, int):
        return pos
    try:
        return int(str(pos))
    except (TypeError, ValueError):
        return 999999  # e.g. "none"

result_pages.sort(
    key=lambda p: (
        p["depth"],
        _pos_sort_key(p),
        p["title"] or "",
    )
)

(The p["title"] or "" is a small extra safety guard — title is normally a string but defending against None keeps the tuple comparable.)

Optionally, normalize position once when building result_pages so the field is always int | None in the returned payload too — currently callers see "position": "none" strings in the response, which is also surprising.

Workaround

I patched the locally cached copy in ~\AppData\Local\uv\cache\archive-v0\<hash>\Lib\site-packages\mcp_atlassian\confluence\pages.py with the snippet above and the tool now returns the full tree correctly.

Happy to send a PR if helpful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions