Content
# confluence-markdown-mcp
A lightweight **Confluence ⇄ local Markdown** synchronization tool, providing **MCP (Model Context Protocol)** server, which can be directly connected to clients that support MCP, such as Claude Desktop, Continue, Cursor, etc.
Main Features:
- 🧩 **Based on the latest MCP framework** (`mcp.server.fastmcp`) to implement stdio server
- 🔐 **All configurations go through environment variables**, no need to write token in code or command line
- ⬇️ **Pull**: pull Confluence pages to local as `.md` files (with front matter)
- ⬆️ **Push**: upload local `.md` files back to Wiki by `pageId`
- 🧱 **Correctly handle special style blocks**: code macros, `info/note/warning/tip` prompts, tables, lists, links, images, and attachments (bidirectional synchronization), as well as unknown macros (保留并原样回写)
- 🧭 **Hierarchical/modular**: `config` / `client` / `converter` / `files` / `service` / `server` / `cli` each have their own responsibilities, with high code readability and easy to extend
- 🧪 With basic unit tests to ensure format stability
## Directory Structure
```
confluence_markdown_mcp/
├── __init__.py # package entry, export main API
├── __main__.py # support `python -m confluence_markdown_mcp`
├── cli.py # command line: pull / push / serve
├── config.py # environment variable reading and verification
├── client.py # Confluence REST client (only depends on standard library)
├── converter/
│ ├── __init__.py
│ ├── macros.py # handle <ac:structured-macro>: code / info / ...
│ ├── storage_to_md.py # Confluence storage format → Markdown
│ └── md_to_storage.py # Markdown → Confluence storage format
├── files.py # read and write markdown files with front matter
├── server.py # MCP server (FastMCP)
└── service.py # business orchestration layer (for CLI and MCP reuse)
skill.md # default MCP skill description
tests/ # unit tests
```
## Installation
### Install from source via pip
```bash
git clone https://github.com/lan99mu/confluence-markdown-mcp.git
cd confluence-markdown-mcp
pip install .
```
After installation, the `confluence-markdown-mcp` command and Python package `confluence_markdown_mcp` will be provided.
### Development mode (with test dependencies)
```bash
pip install -e ".[dev]"
pytest
```
### Run directly as a module (without installation)
```bash
pip install -r requirements.txt
python -m confluence_markdown_mcp --help
```
## Package Artifacts (Windows / macOS)
The repository provides a GitHub Actions workflow: `.github/workflows/build-packages.yml`.
- Supported platforms: `windows-latest`, `macos-latest`
- Trigger methods:
- Manual trigger (`workflow_dispatch`)
- Automatic trigger when pushing version tags (`v*`)
- Artifact forms:
- Windows: `confluence-markdown-mcp-windows-x64.zip` (contains `confluence-markdown-mcp.exe`)
- macOS: `confluence-markdown-mcp-macos.tar.gz` (contains `confluence-markdown-mcp`)
- Upload location:
- All builds will be uploaded to the workflow run's Artifacts
- When pushing `v*` tags, a new GitHub Release will be created/updated with the above packaged files
## Configuration (Environment Variables)
| Variable | Required | Description |
| --- | --- | --- |
| `CONFLUENCE_BASE_URL` | ✅ | Wiki root URL, e.g., `https://<your-domain>.atlassian.net` |
| `CONFLUENCE_EMAIL` | Conditionally required | Account email for Basic Auth |
| `CONFLUENCE_API_TOKEN` | Conditionally required | API token for Basic Auth |
| `CONFLUENCE_PAT` | Conditionally required | Personal Access Token; if set, will use `Authorization: Bearer <PAT>` and take precedence over email + API token |
| `CONFLUENCE_TIMEOUT` | ❎ | HTTP timeout in seconds, default `30` |
| `CONFLUENCE_MARKDOWN_DIR` | ❎ | Default directory for `pull` relative path |
| `CONFLUENCE_IS_CLOUD` | ❎ | Whether it's Confluence Cloud; default `true`. Set to `false` for Server/Data Center's `/rest/api`; Cloud uses `/wiki/rest/api` |
Authentication methods:
- **Basic Auth**: set `CONFLUENCE_EMAIL` + `CONFLUENCE_API_TOKEN`
- **PAT**: set `CONFLUENCE_PAT`
### macOS / Linux (bash / zsh)
```bash
export CONFLUENCE_BASE_URL="https://example.atlassian.net"
export CONFLUENCE_EMAIL="you@example.com"
export CONFLUENCE_API_TOKEN="xxxxxxxxxxxx"
```
Or use PAT:
```bash
export CONFLUENCE_BASE_URL="https://wiki.example.com"
export CONFLUENCE_PAT="xxxxxxxxxxxx"
```
To make it permanent, add the corresponding authentication method to `~/.bashrc`, `~/.zshrc`, or `~/.profile`, then execute `source ~/.bashrc` (or the corresponding file) to take effect.
### Windows (Command Prompt CMD)
```cmd
set CONFLUENCE_BASE_URL=https://example.atlassian.net
set CONFLUENCE_EMAIL=you@example.com
set CONFLUENCE_API_TOKEN=xxxxxxxxxxxx
```
To make it permanent, use `setx` (note that `setx` settings require reopening the terminal to take effect):
```cmd
setx CONFLUENCE_BASE_URL "https://example.atlassian.net"
setx CONFLUENCE_EMAIL "you@example.com"
setx CONFLUENCE_API_TOKEN "xxxxxxxxxxxx"
```
Or add user variables in the Control Panel → System → Advanced system settings → Environment Variables.
### Windows (PowerShell)
```powershell
$env:CONFLUENCE_BASE_URL = "https://example.atlassian.net"
$env:CONFLUENCE_EMAIL = "you@example.com"
$env:CONFLUENCE_API_TOKEN = "xxxxxxxxxxxx"
```
To make it persistent across PowerShell sessions, add the above three lines to your PowerShell profile file (`$PROFILE`):
```powershell
Add-Content $PROFILE "`n`$env:CONFLUENCE_BASE_URL = `"https://example.atlassian.net`""
Add-Content $PROFILE "`$env:CONFLUENCE_EMAIL = `"you@example.com`""
Add-Content $PROFILE "`$env:CONFLUENCE_API_TOKEN = `"xxxxxxxxxxxx`""
```
## Command Line Usage
```bash
# Pull to stdout
confluence-markdown-mcp pull --page-id 123456
# Pull to file (with front matter)
confluence-markdown-mcp pull --page-id 123456 -o ./docs/my-page.md
# Pull to directory: filename automatically uses wiki page title (illegal characters will be replaced)
confluence-markdown-mcp pull --page-id 123456 -o ./docs/
# Write back to wiki (page ID from front matter or --page-id)
confluence-markdown-mcp push --file ./docs/my-page.md
confluence-markdown-mcp push --file ./docs/my-page.md --page-id 123456 --title "New Title"
# Start MCP stdio server
confluence-markdown-mcp serve
```
### Attachment Upload Rules for `push`
`push_page` / `confluence-markdown-mcp push` will not automatically upload all attachments in the `attachments/` directory.
Only the following two types of local references will be created/updated as Confluence attachments before updating the body:
1. Image reference (automatically uploaded):
``
2. File links with marker:
`[file](attachments/example.eml) <!--cm-attachment-->`
Note:
- `<!--cm-attachment-->` **must be written after the link**, writing before will not be recognized.
- Unmarked links will be treated as ordinary `<a href="...">` and will not be uploaded as attachments.
- When generating attachment references, `pull_page` / `read_page` will URL encode spaces, parentheses, non-ASCII characters, etc. to avoid Markdown parsers breaking links.
- URL-encoded paths will be decoded and then processed, so `attachments/%E9%99%84%E4%BB%B6%E7%A4%BA%E4%BE%8B.eml` will match the local file `attachments/附件示例.eml` and use the same attachment filename.
Correct example:
```md
[Attachment example.eml](attachments/附件示例.eml) <!--cm-attachment-->
```
Incorrect example (marker in front, not recognized as attachment upload):
```md
<!--cm-attachment-->[Attachment example.eml](attachments/附件示例.eml)
```
## Using as MCP Service
Start: `confluence-markdown-mcp serve` (stdio transport). The service provides the following tools:
| Tool | Parameters | Description |
| --- | --- | --- |
| `pull_page` | `page_id`, `output_dir?` | Pull as Markdown; `output_dir` only specifies the directory (filename is automatically generated by the server based on the page title), or directly returns content if not provided |
| `push_page` | `file_path`, `page_id?`, `title?` | Upload local `.md` to wiki |
| `read_page` | `page_id` | Returns Markdown only (no local file) |
Resource: `confluence://page/{page_id}` — Read-only Markdown view.
### Claude Desktop
Config file location:
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
```json
{
"mcpServers": {
"confluence-markdown": {
"command": "confluence-markdown-mcp",
"args": ["serve"],
"env": {
"CONFLUENCE_BASE_URL": "https://example.atlassian.net",
"CONFLUENCE_EMAIL": "you@example.com",
"CONFLUENCE_API_TOKEN": "xxxxxxxxxxxx"
}
}
}
}
```
### Cursor
Global config file: `~/.cursor/mcp.json`; can also create `.cursor/mcp.json` in the project root to take effect only for the current project.
```json
{
"mcpServers": {
"confluence-markdown": {
"command": "confluence-markdown-mcp",
"args": ["serve"],
"env": {
"CONFLUENCE_BASE_URL": "https://example.atlassian.net",
"CONFLUENCE_EMAIL": "you@example.com",
"CONFLUENCE_API_TOKEN": "xxxxxxxxxxxx"
}
}
}
}
```
### Windsurf
Config file location: `~/.codeium/windsurf/mcp_config.json`
```json
{
"mcpServers": {
"confluence-markdown": {
"command": "confluence-markdown-mcp",
"args": ["serve"],
"env": {
"CONFLUENCE_BASE_URL": "https://example.atlassian.net",
"CONFLUENCE_EMAIL": "you@example.com",
"CONFLUENCE_API_TOKEN": "xxxxxxxxxxxx"
}
}
}
}
```
### VS Code (GitHub Copilot Agent mode)
Create `.vscode/mcp.json` in the project root (only takes effect for the current workspace), or add `mcp.servers` to `settings.json` (globally effective).
`.vscode/mcp.json`:
```json
{
"servers": {
"confluence-markdown": {
"type": "stdio",
"command": "confluence-markdown-mcp",
"args": ["serve"],
"env": {
"CONFLUENCE_BASE_URL": "https://example.atlassian.net",
"CONFLUENCE_EMAIL": "you@example.com",
"CONFLUENCE_API_TOKEN": "xxxxxxxxxxxx"
}
}
}
}
```
### Continue (VS Code / JetBrains plugin)
Add to `.continue/config.yaml` (or `config.json`):
```yaml
mcpServers:
- name: confluence-markdown
command: confluence-markdown-mcp
args:
- serve
env:
CONFLUENCE_BASE_URL: https://example.atlassian.net
CONFLUENCE_EMAIL: you@example.com
CONFLUENCE_API_TOKEN: xxxxxxxxxxxx
```
### Generic Alternative (when not globally installed)
If the package is not installed globally, you can use `python -m` instead (replace `python` with the actual executable name, e.g., `python3`):
```json
{
"command": "python",
"args": ["-m", "confluence_markdown_mcp", "serve"],
"env": {
"CONFLUENCE_BASE_URL": "https://example.atlassian.net",
"CONFLUENCE_EMAIL": "you@example.com",
"CONFLUENCE_API_TOKEN": "xxxxxxxxxxxx"
}
}
```
PAT configuration example:
```json
{
"command": "confluence-markdown-mcp",
"args": ["serve"],
"env": {
"CONFLUENCE_BASE_URL": "https://wiki.example.com",
"CONFLUENCE_PAT": "xxxxxxxxxxxx"
}
}
```
Or use `uvx` to run directly (without manual installation):
```json
{
"command": "uvx",
"args": ["confluence-markdown-mcp", "serve"],
"env": {
"CONFLUENCE_BASE_URL": "https://example.atlassian.net",
"CONFLUENCE_EMAIL": "you@example.com",
"CONFLUENCE_API_TOKEN": "xxxxxxxxxxxx"
}
}
```
## Handling Special Style Blocks
| Confluence Structure | Markdown Representation |
| --- | --- |
| `<ac:structured-macro ac:name="code">` + `<ac:plain-text-body><![CDATA[...]]>` | Fenced code block with language identifier |
| `<ac:structured-macro ac:name="info/note/warning/tip">` | GFM admonition block with `> [!INFO]` style |
| `<table>` + `<th>/<td>` | Standard pipe-separated table with header row |
| `<ul>/<ol>/<li>` | `-` / `1.` list, supporting nesting with two-space indentation |
| `<ac:task-list>` / `<ac:task>` | GFM task list: `- [ ] body` / `- [x] body` |
| `<span style="color:…">` / `<font color="…">` | Preserve inline HTML `<span>` with color value |
| `<p style="text-align: left/right/center/justify">` | Preserve `<p>` with alignment style |
| Inline `<u>`, `<s>`/`<del>`, `<ins>`, `<sub>`, `<sup>`, `<br>` | Preserve same tags |
| `<a href=...>` / `<img>` | `[text](url)` / `` |
| `plantuml` / `puml` code block | Generate `<iframe>` pointing to PlantUML SVG service, wrapped in `html-bobswift` macro; restore to `plantuml` code block when pulling |
| `mermaid` code block | Wrap in Confluence `markdown` structure macro (preserve complete ````mermaid```` fenced code block in CDATA); render chart with wiki Markdown macro; restore to `mermaid` code block when pulling |
| `html` / `html-bobswift` macro containing `<iframe>` (drawio / diagrams.net, etc.) | Unpack to single-line `<iframe …></iframe>` when pulling; rewrap with `html-bobswift` macro when uploading, with `src` restricted to http/https and non-whitelisted attributes stripped |
| Other unknown `<ac:structured-macro>` | Preserve as HTML comment token, restore when uploading |
Code block content is saved using `CDATA` to preserve original content; the `]]>` sequence is split to avoid XML parsing errors.
### Known Unsupported Markdown Input Forms
To avoid misjudging ordinary paragraphs, the table recognition in `md → storage` follows the standard GFM specification, requiring the header row, separator row (`| --- | --- |`), and each data row to **occupy a separate line**, with no **line breaks or empty lines** within cells. The following "Confluence-style" input, which may be exported from or handwritten with other tools, is currently not recognized as a table and will be rendered as a paragraph + list + task list (content will not be lost, but the outer layer will not generate `<table>`):
```
| 是否有架构设计:
- [ ] 有,架构设计地址是:https://example.com/...
- [ ] 无,原因是:
本人已充分理解架构设计方案:
- [ ] 一致
- [ ] 不一致,原因是: | | --- |
```
Typical characteristics:
* Table header cells contain embedded multi-line content (even empty lines), with the closing `|` appearing on a separate line;
* The separator row `| --- |` is on the same line as the last data row (`… | | --- |`), rather than on a separate line.
If a table appearance is needed, rewrite it as a standard Markdown table with single-line cells (using `<br>` to represent line breaks within cells if necessary), or edit directly in Confluence using the native table editor.
## Development and Testing
```bash
pip install -e ".[dev]"
pytest
```
## License
MIT (see [LICENSE](LICENSE)).
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
everything-claude-code
Complete Claude Code configuration collection - agents, skills, hooks,...
markitdown
Python tool for converting files and office documents to Markdown.
awesome-claude-skills
A curated list of awesome Claude Skills, resources, and tools for...
antigravity-awesome-skills
The Ultimate Collection of 130+ Agentic Skills for Claude...
claude-context-mode
claude-context-mode plugin reduces MCP context bloat, saving up to 99% of tokens.
context-mode
MCP is the protocol for tool access. We're the virtualization layer for context.