内容
# Netra MCP 服务器 - Confluence 写入工具
该工具允许您的 AI 助手(Claude、GitHub Copilot 或任何兼容 MCP 的客户端)为您读取和编辑 Confluence 页面。您可以用自然语言描述要更改的内容,AI 将调用正确的工具。
**它可以执行的操作:**
- 显示 Confluence 页面上的每个 JQL 查询,干净地提取并显示其位置
- 一次替换整个页面中的版本令牌或 JQL 值
- 在写入任何内容之前预览所有更改(默认启用 dry-run)
- 克隆发布报告页面到新版本,并更新所有宏
---
## 开始前
您需要:
- **Python 3.12 或更新版本** - 使用 `python --version` 检查
- **uv**(Python 包管理器)- 从 [docs.astral.sh/uv](https://docs.astral.sh/uv/getting-started/installation/) 安装
- 一个 **Confluence Cloud** 账户
- 一个 **Confluence API 令牌** - 在以下位置创建:Atlassian 账户 -> 安全 -> API 令牌 -> 创建 API 令牌
---
## 设置(一次性)
**1. 克隆仓库**
```bash
git clone <repo-url>
cd netra-confluence-mcp
```
**2. 安装依赖项**
```bash
uv sync
```
**3. 创建配置文件**
```bash
cp .env.example .env
```
打开 `.env` 并填写您的详细信息:
```ini
CONFLUENCE_BASE_URL=https://your-org.atlassian.net
CONFLUENCE_API_TOKEN=your-api-token-here
CONFLUENCE_USER_EMAIL=your-email@example.com
CONFLUENCE_SITE_URL=https://your-org.atlassian.net
LOG_LEVEL=INFO
```
`CONFLUENCE_BASE_URL` 和 `CONFLUENCE_SITE_URL` 通常是相同的值。
**4. 测试启动**
```bash
uv run python server.py
```
您应该看到服务器启动而没有错误。按 Ctrl+C 停止它 - 您的 AI 客户端将在需要时自动启动它。
---
## 连接您的 AI 客户端
### Claude Desktop
1. 打开您的 Claude Desktop 配置文件:
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
2. 添加此块(调整 `cwd` 路径到您克隆仓库的位置):
```json
{
"mcpServers": {
"netra-confluence-writer": {
"command": "uv",
"args": ["run", "python", "server.py"],
"cwd": "/absolute/path/to/netra-confluence-mcp"
}
}
}
```
3. 重启 Claude Desktop。Confluence 工具将出现在工具列表中。
### Claude Desktop 通过 HTTP(mcp-remote 桥接)
当服务器在 HTTP 模式下运行(Docker 容器、远程主机或 `SERVER_TRANSPORT=http uv run python server.py`)而不是作为 stdio 子进程时,请使用 [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) 作为 stdio 到 HTTP 的桥接。Claude Desktop 的 JSON 配置仅生成 stdio 子进程,因此桥接在 Claude Desktop 和正在运行的 HTTP 端点之间进行转换。
全局安装 `mcp-remote`:
```bash
npm install -g mcp-remote
```
添加到 `claude_desktop_config.json`:
```json
{
"mcpServers": {
"netra-confluence-writer": {
"command": "mcp-remote",
"args": ["http://127.0.0.1:8765/mcp"]
}
}
}
```
或者使用 `npx` 代替:
```json
{
"mcpServers": {
"netra-confluence-writer": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://127.0.0.1:8765/mcp"]
}
}
}
```
一旦桥接连接到正在运行的服务器,Confluence 工具将出现在工具列表中。服务器必须已经在 `args` 中的 URL 监听(参见 [生产环境传输(HTTP)](#生产环境传输-http))。
### VS Code with GitHub Copilot
1. 打开您的 VS Code 用户设置(`Ctrl+Shift+P` -> "打开用户设置 JSON")
2. 添加:
```json
{
"mcp": {
"servers": {
"netra-confluence-writer": {
"command": "uv",
"args": ["run", "python", "server.py"],
"cwd": "/absolute/path/to/netra-confluence-mcp"
}
}
}
}
```
3. 重新加载 VS Code。当您点击工具图标时,工具将在 Copilot Chat 中可用。
### 其他 MCP 客户端
使用 `uv run python server.py` 作为服务器命令,项目目录作为工作目录。默认情况下,服务器使用 stdio 传输(为每个客户端生成一个子进程)- 本地 MCP 客户端的标准传输。
---
## 生产环境传输(HTTP)
对于云或共享部署,服务器作为 Web 服务独立运行,而不是作为子进程生成 - 一个服务器进程通过 HTTP 为多个客户端提供服务。这里的每个工具调用都是对 Confluence 的独立读取-转换-写入操作(没有澄清循环或多轮会话),因此服务器运行 **无状态**:没有会话存储,没有 Valkey,内存中没有需要保留的内容。
在 HTTP 模式下启动:
```bash
SERVER_TRANSPORT=http uv run python server.py
```
(或者在 `.env` 中设置 `SERVER_TRANSPORT=http`。)`main()` 在 `server.py` 中读取设置并将 `host`、`port` 和 `stateless_http=True` 直接传递给 FastMCP 的 `run()` 以实现此传输,默认情况下 uvicorn 绑定到 `127.0.0.1:8765`。`/mcp` 路径是 FastMCP 的流式 HTTP 协议的默认端点:
```
http://127.0.0.1:8765/mcp
```
要更改绑定地址或端口,请在启动前设置 `SERVER_HOST` / `SERVER_PORT`(例如,主机 `0.0.0.0` 以接受来自其他机器的连接)。还暴露了一个 `/health` 端点用于负载均衡器 / CF 运行状况检查:
```bash
curl http://127.0.0.1:8765/health # {"status":"ok"}
```
使用 MCP Inspector(`npx @modelcontextprotocol/inspector`,传输 "Streamable HTTP",URL `http://127.0.0.1:8765/mcp`)连接,注册到 Claude Code:
```bash
claude mcp add --transport http netra-confluence http://127.0.0.1:8765/mcp
```
或者使用 `mcp-remote` 作为从 Claude Desktop 到 HTTP 的 stdio 到 HTTP 桥接(参见 [Claude Desktop 通过 HTTP](#claude-desktop-通过-http-mcp-remote-桥接))。
**目前没有终点身份验证。** `/mcp` 端点本身没有 API 密钥门控(参见 `docs/netra-mcp-confluence-write-phased-design.md` 中的第 4 阶段)。保持默认的环回绑定(`127.0.0.1`),除非您在受信任的网络中或位于身份验证终止代理后面 - 有关即使在连接了每个用户凭证后为何需要此功能,请参见下面的“HTTP 上的团队访问(多用户凭证传递)”。
### HTTP 上的团队访问(多用户凭证传递)
在 HTTP 传输上,服务器不持有自己的 Confluence 身份 - `CONFLUENCE_API_TOKEN` / `CONFLUENCE_USER_EMAIL` 必须在服务器的环境中保持未设置。每个工具调用改为携带调用者的自己的身份作为请求头:
```
X-Confluence-User-Email: alice@example.com
X-Confluence-Api-Token: <alice's own API token>
```
服务器根据每个调用构建一个新的 Confluence 客户端。因此,两个队友访问同一个共享服务器将以他们自己的身份写入 - Confluence 页面历史记录显示“Alice”和“Bob”,而不是共享服务帐户 - 并且每个人都受自己的 Confluence 权限约束。如果请求没有头部或头部为空,则会收到 `{"status": "ERROR", "error": "missing per-user Confluence credentials"}` - 没有回退到共享身份。
每个团队成员的 Claude Desktop 配置通过 `mcp-remote --header` 携带他们自己的头部:
```json
{
"mcpServers": {
"netra-confluence-writer": {
"command": "npx",
"args": [
"-y", "mcp-remote", "https://netra-confluence.<your-domain>/mcp",
"--header", "X-Confluence-User-Email: alice@example.com",
"--header", "X-Confluence-Api-Token: ${CONFLUENCE_API_TOKEN}"
],
"env": { "CONFLUENCE_API_TOKEN": "<alice's own token>" }
}
}
}
```
(`env` 间接将原始令牌保持在 JSON 配置体之外。具有原生 HTTP 头部支持的客户端可以直接配置两个头部,而不是通过 `mcp-remote`。)
**生产环境运行此代码的要求,而不仅仅是本地运行:**
- **端到端 TLS。** 这些头部携带一个实时 API 令牌;路由必须仅为 HTTPS。纯 HTTP 绑定仅在 `127.0.0.1` 上可接受。
- **终点仍然需要自己的门控。** 头部传递验证 *Confluence* 调用,而不是 *MCP 端点* - 任何可以到达 `/mcp` 并提供有效 Atlassian 令牌的人都可以将服务器用作开放的 Confluence 代理。在路由器上将 API 密钥/mTLS 门控置于其前面,直到 OAuth 2.0(第 2 层,参见 `docs/netra-mcp-confluence-write-phased-design.md` 第 16.4 节)落地。
- **不要记录头部。** `X-Confluence-Api-Token` 绝不能出现在请求日志中。structlog 处理器将任何日志字段的键与 `token` / `password` / `api_key` / `authorization` 匹配(不区分大小写)并将其替换为 `[REDACTED]` 作为最后一道防线,但不应将凭证值传递给日志调用。
如果您根本不需要共享服务器,每个用户 **stdio**(每个队友使用自己的 `.env` 运行自己的本地进程 - 参见 [设置](#设置一次性))已经提供原生每个用户归属,且无需额外配置。
---
## 查找您的 Confluence 页面 ID
页面 ID 在您打开 Confluence 页面时位于 URL 中:
```
https://your-org.atlassian.net/wiki/spaces/MYSPACE/pages/1234567890/Page+Title
^^^^^^^^^^
这是您的页面 ID
```
---
## 配方:列出页面上的所有 JQL 查询
在您决定更改内容之前,可以要求 AI 只显示页面上的内容。这是只读的 - 不会写入任何内容。
> "显示 Confluence 页面 34334 上的所有 JQL 查询。"
AI 调用 `inspect_page_jql("34334")` 并返回:
```json
{
"status": "INSPECTION",
"page_id": "34334",
"title": "R1.0 Release Report ProjectX",
"jira_macro_count": 7,
"jql_queries": [
{
"macro_id": "abc-123-...",
"location_path": "table[0]/row[1]/cell[0]",
"jql": "project = MYPROJ AND \"release status app1\" in (V1.0, V2.0) AND fixVersion = R1.0",
"columns": "type,key,summary,status",
"server": "MyJira",
"max_issues": "20"
},
{
"macro_id": "def-456-...",
"location_path": "table[1]/row[0]/cell[0]",
"jql": "project = MYPROJ AND label = app1_R1.0_Baseline AND fixVersion = R1.0",
"columns": "type,key,summary",
"server": "MyJira",
"max_issues": "20"
}
],
"unique_strings": ["MYPROJ", "R1.0", "V1.0", "V2.0", "app1_R1.0", "app1_R1.0_Baseline"]
}
```
响应中的关键字段:
- `status: "INSPECTION"` - 始终存在;确认这是只读路径。未发生写入。
- `jira_macro_count` - 页面有多少个 Jira 宏。如果为 `0`,则页面没有 Jira 宏,因此无需替换。
- `jql_queries[].jql` - 每个宏中存储的精确 JQL 字符串。如果计划写入替换规则,请原样复制此字符串 - 空格和引号必须完全匹配。
- `jql_queries[].location_path` - 人体可读的 ADF 路径,用于标识您正在查看的宏(`table[0]/row[1]/cell[0]`)。
- `jql_queries[].macro_id` - 宏的 UUID。在更新时保留,在克隆时重新生成。
- `unique_strings` - 已拆分为 JQL 语法的重复字符串(空格、运算符、引号)。可用作起点来发现候选字符串,但 **不是** 直接替换规则 - 它是候选字符串列表,而不是您将替换的完整子字符串。
何时使用此配方:
- 在任何更新之前,查看页面上出现哪些发布令牌、项目名称或版本标签。
- 更新后,验证更改是否按预期发生。
- 当您接收到不熟悉的页面时,您需要在采取任何操作之前了解页面上有什么。
您也可以传递完整的 Confluence URL 而不是裸页面 ID - AI 将提取 ID:
> "显示 https://your-org.atlassian.net/wiki/spaces/ENG/pages/34334/R1.0-Report 上的 JQL 查询。"
### 控制输出格式
该工具始终返回完整的 JSON 形状(带有 `status`、`page_id`、`title`、`jira_macro_count`、`jql_queries` 和 `unique_strings`)。代理拥有完整的上下文响应,但可以选择仅显示 JQL 字符串。因此:
| 您的提示 | 代理显示给您 |
| --- | --- |
| "显示页面 34334 上的所有 JQL 查询。" | 完整的 JSON 转储(默认行为,如上所述的配方) |
| "仅列出页面 34334 上的 JQL 字符串。" | 仅 `jql` 字段值的纯列表 |
| "以项目符号列表显示页面 34334 上的 JQL 查询。" | 每个 JQL 一个项目符号,无元数据 |
| "仅显示页面 34334 上的 JQL 查询,不显示其他内容。" | 与上述相同,显式指令禁止显示其余部分 |
| "给我 Markdown 表格的页面 34334 上的 JQL 查询。" | 格式化的表格 - 代理可以决定包括哪些列 |
称职的 MCP 客户端(Claude、Rovo)将遵守所有这些。用户始终看到他们所请求的内容。
---
## 案例:更改版本 V10.0 为 V20.0
假设您有一个发布报告页面,ID 为 `2811939182`,其上的所有 JQL 查询都引用 `V10.0`。以下是三个步骤,将整个页面更新为 `V20.0`。
### 步骤 1 - 检查页面
询问您的 AI:
> "Confluence 页面 2811939182 上有哪些 JQL 查询?"
AI 调用 `inspect_page_jql` 并返回类似的内容:
```json
{
"status": "INSPECTION",
"page_id": "2811939182",
"title": "V10.0 Release Report",
"jira_macro_count": 12,
"jql_queries": [
{
"macro_id": "abc-001",
"location_path": "table[0]/row[1]/cell[2]",
"jql": "project = MYPROJ AND fixVersion = ver_V10.0 AND status != Done",
"columns": "key,summary,status"
}
],
"unique_strings": ["Done", "MYPROJ", "ver_V10.0", "ver_V10.0_Baseline", "V10.0"]
}
```
查看 `unique_strings` - 这些是您可以替换的值。您可以看到 `ver_V10.0_Baseline`、`ver_V10.0` 和 `V10.0` 都需要更改。
### 步骤 2 - 预览更改(干运行)
询问您的 AI:
> "在页面 2811939182 上预览将 V10.0 替换为 V20.0。包括标签变体。"
AI 在干运行模式下调用 `update_release_version`:
```json
{
"status": "DRY_RUN",
"current_title": "V10.0 Release Report",
"new_title": "V20.0 Release Report",
"current_version": 14,
"total_changes": 47,
"change_summary": "jql: 36 changes\ntext: 8 changes\ntitle: 3 changes",
"change_log": [...],
"message": "仅预览。调用时附上 dry_run=False 以应用。"
}
```
尚未写入任何内容。您可以确切地看到将要发生什么。
### 步骤 3 - 应用更改
如果预览正确,请询问您的 AI:
> "应用它。"
AI 调用相同的工具,设置 `dry_run=False`:
```json
{
"status": "UPDATED",
"page_id": "2811939182",
"title": "V20.0 Release Report",
"version": 15,
"url": "https://your-org.atlassian.net/wiki/spaces/MYSPACE/pages/2811939182",
"total_changes": 47
}
```
您的 Confluence 页面现已更新。打开 URL 以验证。
---
## 您可以做的其他事情
### 仅替换 JQL 值
如果您只想更改 JQL 查询中的值而不更改文本或标题:
> "仅在页面 99887766 上将 OLD_VALUE 替换为 NEW_VALUE 的 JQL 查询。"
这使用 `scope="jql"`,这是精确的 - 它不会触及列标题名称或宏参数,即使它们包含相同的字符串。
### 克隆页面到新版本
> "将页面 2811939182 从版本 V10.0 克隆到 V20.0,交付日期为 2026-09-15。创建为草稿。"
AI 调用 `clone_release_report`。克隆得到:
- 所有版本令牌更新
- 所有 Jira 宏 UUID 重新生成(因此克隆不会与原始 ID 冲突)
- 所有日期节点更新为新的交付日期
### 从头创建页面
> "使用 ADF 正文创建 Confluence 空间 MYSPACE 中的新页面:{...}"
---
## 工作原理
```mermaid
flowchart TD
subgraph Client["您的 AI(Claude / Copilot)"]
A[您的消息]
end
subgraph Server["Netra MCP 服务器"]
subgraph Tools["MCP 工具"]
T0[inspect_page_jql]
T1[update_page_macros]
T2[update_release_version]
T3[clone_release_report]
T4[create_page_from_adf]
end
subgraph Engine["ADF 引擎"]
R[查找并替换]
V[写入前验证]
end
end
subgraph Confluence["Confluence Cloud"]
API[REST API]
end
A --> T0 & T1 & T2 & T3 & T4
T1 & T2 & T3 --> R --> V
T0 & V --> API
```
服务器以 ADF(Atlassian 文档格式 - Confluence 内部使用的本机 JSON 格式)读取页面。它在精确的 JSON 路径找到 JQL 值,替换它们,验证结果,然后写回。任何时候都不使用正则表达式。
---
## 工具参考
| 工具 | 功能 | 是否写入? |
| --- | --- | --- |
| `inspect_page_jql` | 列出页面上的所有 Jira 宏 JQL 查询及其位置路径 | 绝不 |
| `update_page_macros` | 替换页面上的宏参数中的值 | 是,如果 `dry_run=False` |
| `update_release_version` | 与上述相同,还更新日期节点的 timestamps | 是,如果 `dry_run=False` |
| `clone_release_report` | 克隆页面,更新所有版本令牌和宏 ID | 是,如果 `dry_run=False` |
| `create_page_from_adf` | 从 ADF 正文创建新页面 | 是,如果 `dry_run=False` |
所有写入工具默认 `dry_run=True`。您必须显式说明“应用它”或传递 `dry_run=False` 以进行任何更改。
### 响应状态值
| 状态 | 含义 |
| --- | --- |
| `INSPECTION` | 只读结果;`jql_queries` 和 `unique_strings` 存在 |
| `DRY_RUN` | 仅预览;未写入;存在 `change_log` |
| `UPDATED` | 页面已更新;存在 `version` 和 `url` |
| `CREATED` | 已创建新页面;存在 `page_id` 和 `url` |
| `NO_CHANGES` | 未找到搜索词的任何出现 |
| `VALIDATION_FAILED` | ADF 结构检查失败;写入被阻止;存在 `errors` 列表 |
| `VERSION_CONFLICT` | 另一个人同时编辑了页面;请重试 |
| `ERROR` | API 或网络错误;`error` 字段有详细信息 |
---
故障**"Missing required fields" 或 401 错误**
检查您的 `. 文件。确保 `CONFLUENCE` 与您的 Atlassian中的电子邮件地址匹配,并且 `CONFLUENCE_API_TOKEN` 是一个有效的不是您的密码)。
Page not found" (404)检查 URL 中的页面 ID。该.../pages/123456/...` 中的数字。
** denied" (403)**
您的至少对该页面的查看权限才能检查它,并且需要编辑权限它。
**服务器未出现在我的 AI 客户端中**
确保您的客户端 `cwd` 路径是server.py` 的文件夹的绝对路径。在 Windows 上使用正斜杠或转义反斜杠。
**应用后出现 "Version conflict"**
检查和应用之间,其他人已保存了该页面。只需重复操作在写入之前会重新读取最新版本。
---
## Docker 和云部署
服务器作为一个独立的、无状态 镜像提供 - 无 Val外部数据存储。完整的运行手册 首次部署、蓝、环境变量参考):`docs_deployment.md`。
###-compose 进行本地开发
```# 从仓库根目录(从不从 docker/ 目录)
docker-composecurl http://localhost:876 # {"status":"ok"}
://localhost:8765/mcp # MCP 端点
```
### 在本地构建镜像(单架构)
需要带有 buildx Desktop 4.x+()。
```bash
bash scripts/docker-build
docker run -p5:8765 -- .env ghcr.io/sbharat/netra-confluence:dev
```
### 构建和推送多平台(amd64 + arm64)并部署到 CFbash
docker buildx create multiarch --driver docker-container # 一次性
docker inspect --bootstrap
export REGISTRY=ghcr.io/sunishat
./scripts/cf # 构建两个平台,推送到 GHCR,然后 cf push将 Confluence 凭证设置为 CF(它们在 `cf push`/`cf restage` 后仍然
```bash
cf set-env netra-confluence-mcp CONFLU_URL https://your-org.atlassian.net
cf set-env netra-confluence-mcp CONFLUENCE_SITE_URL https://your-org.atlassian.net
cf set-env netra-confluence-mcp CONFLUENCE_USER_EMAIL service-account@example.com
cf set-env netra-confluence-mcp CONFLUENCE_API_TOKEN <token>
cf restage netra-confluence-mcp
```
CI 在每次 `v*.*.*推送时自动构建并将镜像推送到 GHCR(`./docker.yml`)。
运行测试
单元测试(fluence 连接):
```bash python -m pytest
```
针对fluence 页面的集成
```bash
CONFLU_PAGE_ID=<page-id> -m pytest -m integration
```
---
## 开发命令
uv sync # 安装
uv run ruff check # lint
uv run r --check . #
uv run mypy . # 类型检查
-m pytest --covfluence --cov-report=term
```
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器