A tool to download, read, and update Confluence Data Center pages with markdown support
Project description
Confluence Data Center Markdown Tool
A Python CLI tool to download, read, edit, and manage Confluence Data Center pages. Supports both Markdown (convenient default) and Confluence storage format (lossless XHTML — no conversion, no table/macro loss).
Features
Core Features
- Download Confluence pages as Markdown files or as raw storage format (XHTML)
- Read page content directly in terminal with Rich rendering
- Edit pages in your preferred editor (vim, VS Code, nano, etc.)
- Add content to existing pages (Markdown or storage XHTML)
- Create new pages with templates (interactive space and parent selection)
- Create task pages with Page Properties macro
Navigation & Search
- Interactive page selection with fzf or InquirerPy
- Browse recently viewed pages
- Edit recently edited pages
- Search pages by text or CQL query
- List child pages (with recursive option)
Batch Operations
- Download entire page trees recursively
- Parallel API calls for faster batch operations
- Export multiple pages to a directory
Quality of Life
- Response caching for faster repeated access
- Per-space configuration (different editors/settings per space)
- Shell tab completion (bash/zsh)
- Rate limiting and automatic retry on errors
- Complex table preservation (colspan/rowspan) in Markdown mode
- YAML table format for easier editing of complex tables
- Storage format mode for lossless editing of complex tables and macros
Configuration
- Save credentials in config file
- Multiple configuration profiles
- Space-specific settings
Installation
Using uv tool (recommended)
# Clone the repository
git clone https://github.com/jvanvinkenroye/confluence_markdown.git
cd confluence_markdown
# Install globally
uv tool install --editable .
# Now use from anywhere
confluence-markdown --help
Using uv (development)
cd confluence_markdown
uv sync
uv run confluence-markdown --help
Enable Tab Completion
# For bash - add to ~/.bashrc
eval "$(register-python-argcomplete confluence-markdown)"
# For zsh - add to ~/.zshrc
autoload -U bashcompinit && bashcompinit
eval "$(register-python-argcomplete confluence-markdown)"
Quick Start
1. Save your credentials
confluence-markdown \
--base-url https://confluence.company.com \
--username YOUR_USERNAME \
--token YOUR_PAT \
--save-config \
--action test-auth
2. Browse recent pages
# Interactive selection with fzf
confluence-markdown --action read-recent
# Use arrow keys if fzf not installed
confluence-markdown --action read-recent --no-fzf
3. Edit a page
confluence-markdown --action edit "https://confluence.company.com/pages/viewpage.action?pageId=12345"
Page formats: Markdown vs. storage format
Confluence stores pages in storage format — Atlassian's official XHTML format with ac: (Atlassian Confluence — macros, layouts, tasks) and ri: (resource identifiers — attachments, users, pages) namespaced elements. This is the representation:"storage" field in the REST API.
This tool supports two modes:
| Mode | Flag | Description |
|---|---|---|
| Markdown | --format md (default) |
Converts storage XHTML → Markdown for editing, then back on upload. Convenient for simple pages. |
| Storage format | --format storage |
Pure passthrough — reads and writes raw XHTML. Lossless for all content. |
When to use each
| Situation | Recommended mode |
|---|---|
| Simple text pages, bullet lists | Markdown (default) |
| Pages with complex tables (colspan/rowspan, multi-paragraph cells) | Storage format |
Pages with Confluence macros (ac:structured-macro, task lists, …) |
Storage format |
| Agents editing via MCP | Storage format (*_storage tools) |
| Summarising a page for a human | Markdown (*_md tools) |
The Markdown round-trip is lossy for:
- Tables with
colspan/rowspanor multi-paragraph cells - Confluence macros
- Layouts and nested content
Storage format mode is a pure passthrough — no conversion. Read the raw XHTML, edit it, upload it verbatim.
Validation
Storage XHTML is validated locally before every upload. Malformed input — unclosed tags, bare &, non-self-closing void elements — is rejected with a clear error message before any API call is made.
Usage Examples
Reading Pages
# Browse recently viewed pages (default action)
confluence-markdown
# Read specific page
confluence-markdown --action read "PAGE_URL"
# Read with raw markdown output
confluence-markdown --action read-recent --raw
# Search and read
confluence-markdown --action search --query "deployment guide"
Editing Pages
# Edit specific page (opens in editor, default Markdown mode)
confluence-markdown --action edit "PAGE_URL"
# Edit with specific editor
confluence-markdown --action edit --editor "code --wait" "PAGE_URL"
# Edit with YAML tables (easier to edit complex tables in Markdown mode)
confluence-markdown --action edit --table-format yaml "PAGE_URL"
# Edit in storage format — pass XHTML directly, no Markdown conversion
confluence-markdown --action edit --format storage \
--content '<p>Updated content</p>' "PAGE_URL"
# Select from recently edited pages
confluence-markdown --action edit-recent --limit 20
Downloading Pages
# Download single page as Markdown (default)
confluence-markdown --action download -o page.md "PAGE_URL"
# Download in storage format (writes pretty-printed XHTML with a comment header)
confluence-markdown --action download --format storage -o page.html "PAGE_URL"
# Download page and all children recursively (parallel, Markdown)
confluence-markdown --action download --recursive --output-dir ./export "PAGE_URL"
# Limit number of pages in a recursive download
confluence-markdown --action download --recursive --limit 100 --output-dir ./export "PAGE_URL"
Listing Child Pages
# List direct children
confluence-markdown --action list-children "PAGE_URL"
# List all descendants recursively (uses parallel API calls)
confluence-markdown --action list-children --recursive "PAGE_URL"
Creating Pages
# Fully interactive: select space and parent page via fzf
confluence-markdown --action create-edit
# Non-interactive: all parameters provided
confluence-markdown --action create \
--space MYSPACE \
--title "My New Page" \
--content "# Welcome\n\nPage content here"
# Create child page (parent-id known)
confluence-markdown --action create \
--space MYSPACE \
--title "Child Page" \
--parent-id 12345 \
--content "Content for child page"
# Create task page with Page Properties
confluence-markdown --action create-task \
--parent-id 12345 \
--title "New Task" \
--category "Development" \
--priority "80" \
--status "offen" \
--content "Task description here"
Adding Content
# Append markdown content
confluence-markdown --action add \
--content "## New Section\n\nNew content here" \
"PAGE_URL"
# Prepend content
confluence-markdown --action add --prepend \
--content "## Important Notice\n\nThis goes at the top" \
"PAGE_URL"
# Add storage XHTML directly (lossless — macros and tables preserved)
confluence-markdown --action add \
--content "<ac:structured-macro ac:name='info'>...</ac:structured-macro>" \
--content-type html \
"PAGE_URL"
Search
# Text search
confluence-markdown --action search --query "kubernetes deployment" --limit 20
# CQL search
confluence-markdown --action search --cql "space = DEV AND label = important"
# Search in specific space
confluence-markdown --action search --cql "space = DOCS AND text ~ 'API'"
Caching
# Disable cache for fresh data
confluence-markdown --no-cache --action read-recent
# Clear all cached data
confluence-markdown --clear-cache
Scripting Mode
# Quiet mode for scripts (suppress info messages)
confluence-markdown --quiet --action download -o page.md "PAGE_URL"
# Check exit code
if confluence-markdown --quiet --action test-auth; then
echo "Auth OK"
fi
Configuration
Config File Location
~/.config/confluence-markdown/config.json
Multiple Profiles
# Save work profile
confluence-markdown \
--base-url https://work.confluence.com \
--username work_user \
--token WORK_TOKEN \
--save-config --profile work \
--action test-auth
# Use work profile
confluence-markdown --profile work --action read-recent
# List profiles
confluence-markdown --list-profiles
# Delete profile
confluence-markdown --delete-profile --profile old
Per-Space Configuration
Edit ~/.config/confluence-markdown/config.json:
{
"default": {
"base_url": "https://confluence.company.com",
"username": "user",
"token": "...",
"editor": "vim",
"table_format": "markdown",
"spaces": {
"DOCS": {
"editor": "code --wait",
"table_format": "yaml"
},
"WIKI": {
"editor": "nano"
}
}
}
}
Now pages in the DOCS space will open in VS Code with YAML tables.
Command Line Reference
Actions:
read-recent Browse recently viewed pages (default)
edit-recent Edit recently edited pages
read Read specific page
edit Edit specific page
download Download page as markdown or storage XHTML
add Add content to page
create Create new page
create-task Create task page with Page Properties
search Search pages
list-children List child pages
test-auth Test authentication
Options:
--base-url URL Confluence base URL
--username USER Username for auth
--token TOKEN Personal Access Token
--password PASS Password (alternative to token)
--profile NAME Config profile (default: "default")
--config Load from config file explicitly
--action ACTION Action to perform
--format FORMAT Page format: md (default) or storage
md: convert to/from Markdown (convenient, lossy for tables/macros)
storage: Confluence storage format (XHTML, Atlassian's official
format) — lossless passthrough, no conversion
--output, -o FILE Output file for download
--content TEXT Content for add/create/edit
--content-type TYPE markdown (default) or html
--space KEY Space key for create
--title TEXT Page title for create
--parent-id ID Parent page ID
--category TEXT Task category (create-task)
--priority TEXT Task priority (create-task)
--status TEXT Task status (create-task)
--query TEXT Search query text
--cql TEXT CQL query for search
--limit N Number of results (default: 10)
--recursive, -r Process children recursively
--output-dir DIR Output directory for batch downloads
--editor CMD Editor command (e.g., "vim", "code --wait")
--table-format FMT Table format in Markdown mode: markdown or yaml
--raw Output raw markdown
--width N Override terminal width
--no-fzf Use InquirerPy instead of fzf
--no-cache Disable response caching
--clear-cache Clear cache and exit
--quiet, -q Suppress info messages
--verbose Enable debug output
--completion SHELL Output completion script (bash/zsh)
Config Management:
--init-config Create example config file
--save-config Save credentials to config
--list-profiles List all profiles
--delete-profile Delete profile specified by --profile
MCP Server (Claude Desktop / AI agents)
The tool can run as an MCP stdio server, exposing Confluence operations as tools that Claude and other MCP clients can call directly.
Install the MCP extra
uv pip install -e ".[mcp]"
Configure Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"confluence": {
"command": "uv",
"args": [
"--directory",
"/absolute/path/to/confluence_markdown",
"run",
"confluence-markdown-mcp"
]
}
}
}
The server automatically uses your saved config profile (same credentials as the CLI). If credentials aren't saved, add them via environment variables:
{
"mcpServers": {
"confluence": {
"command": "uv",
"args": [
"--directory",
"/absolute/path/to/confluence_markdown",
"run",
"confluence-markdown-mcp"
],
"env": {
"CONFLUENCE_URL": "https://your-confluence.com",
"CONFLUENCE_USERNAME": "your_username",
"CONFLUENCE_TOKEN": "your_pat_token"
}
}
}
}
Then restart Claude Desktop (⌘Q and reopen).
Configure Claude Code
Edit ~/.claude/settings.json:
{
"mcpServers": {
"confluence": {
"command": "uv",
"args": [
"--directory",
"/absolute/path/to/confluence_markdown",
"run",
"confluence-markdown-mcp"
]
}
}
}
Then restart Claude Code (close and reopen, or in a new tab).
Available MCP tools
The server exposes two content tool families (see Page formats above for when to use each):
Navigation / search (no format dimension):
| Tool | Description |
|---|---|
search_pages |
Search via CQL or free-text query |
list_recent_pages |
Pages recently modified by you |
list_spaces |
All accessible spaces |
list_children |
Direct child pages of a page |
*_storage family — RECOMMENDED for agents (Confluence storage format, lossless):
| Tool | Description |
|---|---|
get_page_storage |
Get page in Confluence storage format (XHTML) — preserves tables, macros, layouts |
edit_page_storage |
Replace page body with storage XHTML — lossless, validates before upload |
create_page_storage |
Create a page with storage XHTML content |
add_content_storage |
Append/prepend storage XHTML to a page |
*_md family (Markdown, convenient but lossy for complex tables/macros):
| Tool | Description |
|---|---|
get_page_md |
Get page content converted to Markdown |
edit_page_md |
Replace page body with Markdown content |
create_page_md |
Create a page with Markdown content |
add_content_md |
Append/prepend Markdown content to a page |
Diagnostic:
| Tool | Description |
|---|---|
check_elicitation_support |
Returns {"elicitation_supported": true/false} — verify whether human-in-the-loop confirmation for write tools will be triggered |
Pages are also accessible as MCP resources:
confluence://page/{page_id}— Markdownconfluence://page/{page_id}/storage— Confluence storage format (XHTML)
MCP Usage Examples
In Claude Desktop or Claude Code, just describe what you want:
"List all Confluence spaces I have access to"
→ Claude calls list_spaces automatically
"Create a new page in the DOCS space about API authentication"
→ Claude calls create_page_md with your content
"Show me the last 5 pages I modified"
→ Claude calls list_recent_pages(limit=5)
"Search for pages mentioning 'deployment'"
→ Claude calls search_pages with your query
"Read the page confluence://page/12345 and explain the table"
→ Claude reads the page via resource and explains it
You don't need to invoke tools manually. Claude automatically:
- Selects the appropriate tool (
*_storagefor APIs,*_mdfor humans) - Handles errors and retries
- Confirms writes if the client supports it
Write protection (human-in-the-loop)
When the MCP client supports
elicitation,
all write tools (*_storage and *_md) prompt for explicit confirmation
before executing. Clients that do not support elicitation (automated agents,
older clients) proceed without the prompt.
The confirmation form has two fields:
| Field | Type | Description |
|---|---|---|
confirm |
bool | true to proceed, false to abort |
remember |
bool | true to skip confirmation for the rest of the session |
MCP Troubleshooting
MCP tools don't appear in Claude Code's tool list
This is normal behavior! Claude Code lazy-loads local MCPs and may not show them in the UI. They still work. Test by asking Claude:
"List my Confluence spaces"
If it succeeds, the MCP is active. Claude automatically selects the right tool based on your request.
Tools time out or "server not responding" in Claude Desktop/Code
The MCP server is a persistent stdio process. If it becomes unresponsive:
- Claude Desktop: Restart (⌘Q → reopen)
- Claude Code: Restart or open in a new tab
This resets the server connection.
Server fails to start or "command not found"
Verify the server works:
# Test the binary directly
timeout 5 uv run confluence-markdown-mcp 2>&1
# Should timeout waiting for stdin (this is normal)
# Verify credentials are saved
confluence-markdown --action test-auth
If test-auth fails with 403, regenerate your API token in Confluence and update:
confluence-markdown \
--base-url https://your-confluence.com \
--username your_username \
--token NEW_TOKEN \
--save-config \
--action test-auth
Authentication fails (403 Forbidden)
- Verify your Confluence URL, username, and token are correct
- If using Data Center, token must have API access enabled
- Check that your account isn't locked or suspended
- Regenerate a new API token in Confluence
XHTML validation errors when creating pages with *_storage tools
Special characters must be escaped in XHTML:
&→&<→<>→>"→"
The MCP server validates XHTML before upload and returns an error if malformed.
Page creation appears to succeed but no output returned
Operations like create_page_md and edit_page_md trigger write confirmation in Claude (if supported). The server prints progress to stderr to keep stdout clean for JSON-RPC. This is normal and expected.
Format Comparison: *_storage vs *_md
| Feature | Storage (*_storage) |
Markdown (*_md) |
|---|---|---|
| Tables with colspan/rowspan | ✅ Preserved | ❌ Flattened |
| Confluence macros | ✅ Preserved (ac:structured-macro) | ❌ Lost |
| HTML styling | ✅ Preserved | ❌ Lost |
| Human readability | ⚠️ XHTML (verbose) | ✅ Easy to read |
| Lossless round-trip | ✅ Yes (get → edit) | ❌ No (lossy) |
| Use when | Building automation, APIs, complex pages | Summarizing, quick edits, simple content |
Requirements
- Python 3.10+
- httpx
- requests
- markdownify
- beautifulsoup4
- InquirerPy
- rich
- tenacity
- argcomplete
- pyyaml
- markdown
- keyring (credential storage)
Optional:
- fzf (for fuzzy page selection)
- mcp (for MCP server support —
uv pip install -e ".[mcp]")
Troubleshooting
Authentication Errors
# Test credentials
confluence-markdown --verbose --action test-auth
# For Data Center, always use username + token
confluence-markdown --username USER --token PAT --action test-auth
Rate Limiting
The tool automatically handles rate limits with exponential backoff. If you hit limits frequently:
# Add delays between batch operations
confluence-markdown --action download --recursive --limit 50 "PAGE_URL"
Cache Issues
# Clear cache if data seems stale
confluence-markdown --clear-cache
# Disable cache for single command
confluence-markdown --no-cache --action read "PAGE_URL"
Complex Tables / Macros
If a page has merged cells (colspan/rowspan), Confluence macros, or complex layouts, the Markdown round-trip may lose or corrupt them. Use storage format mode instead:
# Download the page as lossless XHTML, edit it, re-upload
confluence-markdown --action download --format storage -o page.html "PAGE_URL"
# ... edit page.html ...
confluence-markdown --action edit --format storage --content "$(cat page.html)" "PAGE_URL"
For agents using the MCP server, use get_page_storage + edit_page_storage directly.
License
WTFPL - Do What The Fuck You Want To Public License
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file confluence_markdown-0.2.0.tar.gz.
File metadata
- Download URL: confluence_markdown-0.2.0.tar.gz
- Upload date:
- Size: 176.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5d5713339fddc188209c035831013f4d3ebcb7863a9d2596878decfe232ed988
|
|
| MD5 |
2713ddbec8255767dbd1c64579741c77
|
|
| BLAKE2b-256 |
b113cd72bbcd804358ece86108e682eaaf9de6547ed882c2b8247226920094bb
|
File details
Details for the file confluence_markdown-0.2.0-py3-none-any.whl.
File metadata
- Download URL: confluence_markdown-0.2.0-py3-none-any.whl
- Upload date:
- Size: 51.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b4de68af9fadf7ded1b2f0c0ca8141e536963b28b8dc41258af38486fea35f68
|
|
| MD5 |
316a536a11566c35c2756c72d71567de
|
|
| BLAKE2b-256 |
a83f8d4275a1ecf32f87ae7db07875d8aa3b4746e532091ea131120da0b85e2b
|