关于 pbirb-mcp
pbirb-mcp 让 MCP 客户端检查和编辑 `.rdl` 格式的 Power BI Report Builder 分页报表。其工具覆盖报表结构与布局,并通过验证和原子写入避免文件只保存一部分。
主要功能
- 01检查报表内容与结构
- 02编辑数据源、数据集和参数
- 03调整 tablix 分组、筛选和布局
- 04创建并设置图表与报表项样式
- 05配置页面设置和分页
- 06验证并原子保存报表文件
适用场景
- 01更新现有报表中的数据集和参数
- 02调整 tablix 分组、筛选或格式
- 03在 RDL 报表中添加图表、页眉或嵌入图片
MCP 相关
它通过 stdio 上的 JSON-RPC 2.0 向 MCP 客户端提供报表检查、编辑和验证工具。客户端可打开 `.rdl` 文件、修改内容并原子保存。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
143收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| path | string | 是 | 要读取的 .rdl 文件的绝对路径。 |
详细介绍
pbirb-mcp
用于通过 Claude(桌面版、CLI 或任何 MCP 客户端)编辑 Power BI Report Builder 分页报表(.rdl)的 MCP 服务。140 多种工具涵盖了原本需要手动编写 XML 的各种操作:创建报表、数据源和数据集、计算字段、数据集和 tablix 筛选器、分组(行、列、矩阵)、排序、图表、页眉和页脚、主体内容编排、布局容器、定位、样式、页面设置、分页、高级参数、嵌入图像、交互功能(操作、工具提示、文档地图)、事务和验证。
该服务通过 stdio 使用 JSON-RPC 2.0。它会从磁盘打开 .rdl,通过 lxml 就地修改、验证结构并以原子方式写入——保存失败不会留下写了一半的报表,也不会清除原始文件。
稳定性
尚未达到 1.0 版本。工具接口——工具名称、inputSchema、输出格式和错误语义——构成契约。在 0.x 阶段,MINOR 版本可能包含小幅破坏性变更,并在 CHANGELOG.md 中附上迁移说明;v1.0 之后,破坏性变更必须提升 MAJOR 版本。完整的版本升级规则请参阅 CONTRIBUTING.md,这些规则是针对 MCP 工具接口调整后的 SemVer 规则。
在 0.x 阶段,如果提示词依赖特定的工具名称或架构,请固定使用某个 MINOR 版本(例如 pbirb-mcp~=0.1)。
快速开始
1. 安装
最简单的方式是使用 uv + PyPI——无需克隆、无需 venv,也无需安装步骤:
uvx pbirb-mcp
uvx 会将软件包提取到临时环境中,运行 pbirb-mcp 控制台脚本,然后退出。MCP 服务通过 stdio 使用 JSON-RPC,因此任何 MCP 客户端(Claude Desktop、Claude Code 等)都可以直接启动它。
如果要在此代码库上进行本地开发:
git clone https://github.com/mafaq229/pbirb-mcp
cd pbirb-mcp
uv venv .venv
uv pip install --python .venv/bin/python -e ".[dev]"
验证二进制文件是否正常工作:
printf '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}\n' \
| .venv/bin/pbirb-mcp
你应该会看到一条 JSON-RPC 响应,其中包含 protocolVersion、capabilities.tools 和 serverInfo.name = "pbirb-mcp"。
2. 接入 Claude Desktop
编辑 ~/Library/Application Support/Claude/claude_desktop_config.json(macOS)或 %APPDATA%\Claude\claude_desktop_config.json(Windows):
{
"mcpServers": {
"pbirb": {
"command": "uvx",
"args": ["pbirb-mcp"]
}
}
}
重启 Claude Desktop。锤子图标应显示 pbirb,并列出下方的 140 多种工具。
如需启用文件日志,请添加 env 块,但路径必须符合对应平台的格式。PBIRB_MCP_LOG_FILE 接受操作系统原生路径:类似 /tmp/pbirb-mcp.log 的 Unix 路径仅适用于 macOS/Linux。在 Windows 上,请使用 Windows 路径(例如 %TEMP%\\pbirb-mcp.log)。请参阅日志记录。未设置时,日志会写入 stderr;所有平台上的 Claude Desktop 都会在其 MCP 调试面板中捕获这些日志。
如需基于本地检出版本进行开发,请将 args 替换为 ["--from", "/absolute/path/to/pbirb-mcp", "pbirb-mcp"],这样 uvx 就会运行你的工作树,而不是已发布的版本。
3. 接入 Claude Code
claude mcp add pbirb -- uvx pbirb-mcp
或者,将以下内容添加到工作区根目录下的 .mcp.json:
{
"mcpServers": {
"pbirb": {
"command": "uvx",
"args": ["pbirb-mcp"]
}
}
}
或者将其安装为 Claude Code 插件——只需运行一条命令,无需手动编辑配置(它会为你接入相同的 uvx pbirb-mcp 服务):
/plugin marketplace add mafaq229/pbirb-mcp
/plugin install pbirb-mcp@pbirb
4. 冒烟测试
在任意聊天中,向模型提问:
打开
~/path/to/some-report.rdl,告诉我其中有哪些数据集和参数。
模型应该会调用 describe_report、get_datasets 和 get_parameters,并总结结果。如果没有调用,你的客户端可能尚未加载该服务——请检查客户端的 MCP 调试日志。
使用报表
建议的流程是先读取,再按名称编辑。每个会修改内容的工具都通过 RDL 的 Name 属性定位元素(Tablix 名称、Textbox 名称、ReportParameter 名称、DataSet 名称),而不是通过索引。多步编辑时,索引可能会变化。
典型会话:
You: Bind the existing report at ~/Reports/sales.rdl to the Finance
workspace's "FY26 Sales" dataset, change the body DAX to a date-
ranged query, and add a header with a logo and a parameter line.
Claude: → describe_report(path=…)
→ set_datasource_connection(name="PBIDataset",
workspace_url="Finance", dataset_name="FY26 Sales")
→ update_dataset_query(dataset_name="MainDataset",
dax_body="EVALUATE FILTER('Sales',
'Sales'[OrderDate] >= @DateFrom &&
'Sales'[OrderDate] <= @DateTo)")
→ add_query_parameter(dataset_name="MainDataset",
name="DateFrom",
value_expression="=Parameters!DateFrom.Value")
→ add_query_parameter(dataset_name="MainDataset",
name="DateTo",
value_expression="=Parameters!DateTo.Value")
→ add_embedded_image(name="Logo",
mime_type="image/png", image_path="~/brand/logo.png")
→ set_page_header(height="0.75in",
print_on_first_page=True, print_on_last_page=True)
→ add_header_image(name="HeaderLogo",
image_source="Embedded", value="Logo",
top="0in", left="0in", width="1in", height="0.5in")
→ add_header_textbox(name="DateLine",
text='="From: " & Parameters!DateFrom.Value & " To: "
& Parameters!DateTo.Value',
top="0.1in", left="1.2in", width="4in", height="0.25in")
在 Report Builder 中打开生成的 .rdl;更改会显示在设计器中,并且会在预览中使用绑定的数据集进行呈现。
工具参考
共有 143 个工具,按 RDL 涉及的内容分组。下表列出各组的重点工具;权威且始终最新的完整列表及其架构,见服务器的 tools/list 输出,LLM 可在注册时查看。每个工具都接受一个 path 参数(.rdl 的绝对路径)。
大多数会修改内容的工具也接受可选的 transaction_id,以便将多步编辑批量处理为一次原子保存——参见 事务 和 docs/TRANSACTIONS.md。
只读清单
用于查看“此报表中有哪些内容?”的工具。规划多步编辑时,始终先调用这些工具。
| 工具 | 返回内容 |
|---|---|
describe_report | 顶层清单:数据源、数据集、参数、tablix、页面设置 |
get_datasets / get_dataset | 完整的 DAX 命令文本、字段、查询参数、数据集筛选器(全部或按名称指定一个) |
list_data_sources / get_data_source | 数据源清单;一个数据源的连接详细信息 |
get_parameters | 报表参数,包括数据类型、提示词和标志(多值、隐藏、可空、允许空白) |
get_tablixes | Tablix 布局:列、行/列组、排序表达式、筛选器、可见性 |
list_tablix_filters / list_dataset_filters | 按文档顺序排列并带有稳定索引的筛选器 |
list_body_items / list_header_items / list_footer_items | 各区域中已命名的报表项 |
get_textbox / get_image / get_rectangle / get_chart | 已命名报表项的完整属性 |
list_embedded_images / get_embedded_image_data | 嵌入式图像名称和 MIME 类型;其中一个图像的 base64 字节 |
get_expression_reference | 常见 RDL 表达式模式速查表(count_where、sum_where、iif_format 辅助工具会构建这些模式) |
数据源与数据集
| 工具 | 编辑内容 |
|---|---|
set_datasource_connection | 将 <DataSource> 重定向到 Power BI XMLA 终结点。DataProvider=SQL(AS 提供程序 ID)。 |
add_data_source / remove_data_source / rename_data_source | 管理 <DataSource> 元素 |
update_dataset_query | 将 <DataSet>/<Query>/<CommandText> 替换为 DAX 表达式 |
add_query_parameter | 添加 <QueryParameter>(例如 =Parameters!DateFrom.Value) |
update_query_parameter | 更改现有查询参数的值表达式 |
remove_query_parameter | 删除查询参数(并清理空的 <QueryParameters>) |
add_dataset_field / remove_dataset_field | 管理数据集上的 <Field> 条目 |
add_calculated_field / remove_calculated_field | 管理由 <Value> 提供值的计算字段 |
refresh_dataset_fields | 根据查询的列元数据重新生成 <Fields> 列表 |
add_dataset_filter / remove_dataset_filter | 应用于数据集级别(而非 tablix)的筛选器 |
Tablix
| 工具 | 编辑内容 |
|---|---|
add_tablix_filter | 追加一个 <Filter>。运算符:Equal、NotEqual、GreaterThan、In、Between、Like、TopN、... |
remove_tablix_filter | 根据 list_tablix_filters 返回的序号索引移除 |
add_row_group / remove_row_group | 用新的外层组和标题行包裹行层次结构(以及反向操作) |
add_column_group / remove_column_group | 对列轴执行相同操作 |
convert_to_matrix | 将表格转换为矩阵(行组 + 列组)——参见 docs/MATRIX-cookbook.md |
set_tablix_corner | 设置矩阵角单元格文本/表达式 |
set_group_sort / set_column_group_sort | 替换组上的 <SortExpressions> |
set_group_visibility / set_column_group_visibility | 设置组的 TablixMember 上的 <Visibility> |
set_detail_row_visibility | 设置 Details 组上的 <Visibility> |
add_tablix_column / remove_tablix_column | 在 tablix 网格中添加/删除列 |
add_static_row / add_static_column | 插入非分组行/列 |
add_subtotal_row / add_subtotal_column | 在组上插入汇总行/列 |
set_cell_span | 设置单元格的 RowSpan / ColSpan |
set_column_width / set_row_height | 设置第 N 列/行的 <Width> / <Height> |
set_tablix_size | 设置 tablix 的整体 <Width> / <Height> |
页面
| 工具 | 编辑内容 |
|---|---|
set_page_setup | 页面尺寸、边距、分栏。所有字段均为可选。 |
set_page_orientation | 调整 PageHeight/PageWidth,以匹配 Portrait 或 Landscape。可重复执行而不改变结果。 |
页眉和页脚
每个区域都支持同一组操作,并且每项操作都接受命名项, 以避免后续编辑时索引发生偏移。
| 工具 | 编辑内容 |
|---|---|
set_page_header / set_page_footer | 区域高度 + PrintOnFirstPage / PrintOnLastPage |
add_header_textbox / add_footer_textbox | 追加一个 Textbox(静态文本或 =expression) |
add_header_image / add_footer_image | 追加一个 Image(外部 URL、嵌入名称或 Database 表达式) |
remove_header_item / remove_footer_item | 按名称移除;清理空的 <ReportItems> |
主体内容编排
| 工具 | 编辑内容 |
|---|---|
add_body_textbox | 将一个 Textbox 追加到 <Body>/<ReportItems> |
add_body_image | 在主体中追加一个 Image |
remove_body_item | 从主体中移除命名的 Textbox / Image / Tablix |
片段模板
通过单次调用插入常用报表项,以编程方式构建并 追加到主体中。
| 工具 | 构建内容 |
|---|---|
insert_tablix_from_template | 基本 Tablix,形状与样例一致——标题行以列名作为静态标签,明细行绑定到 =Fields!<column>.Value。每个请求的字段对应一列。 |
insert_chart_from_template | 基本柱形图:单个类别轴按 category_field 分组,单个 Y 系列为 =Sum(Fields!<value_field>.Value)。插入后可更改 <Type>(Bar / Line / Pie / 等)。 |
图表
在 insert_chart_from_template 之后(或针对任何现有的 <Chart>)优化图表。
| 工具 | 编辑内容 |
|---|---|
add_chart_series / remove_chart_series | 管理 Y 轴 <ChartSeries> |
set_chart_series_type | 为每个系列设置 Column / Bar / Line / Area / Pie / ... |
set_chart_series_grouping | 类别/系列分组表达式 |
set_chart_axis | 类别/值轴标题、刻度、格式 |
set_chart_legend | 图例可见性和位置 |
set_chart_data_labels | 切换并设置数据标签格式 |
set_chart_title | 图表标题文本/表达式 |
set_chart_palette / set_series_color | 调色板名称;为每个系列指定颜色 |
样式
| 工具 | 编辑内容 |
|---|---|
set_textbox_style | 自动将属性路由到正确的嵌套 <Style> 节点:框级(BackgroundColor、Border、VerticalAlign)、段落级(TextAlign)、文本运行级(FontFamily、FontSize、FontWeight、Color、Format) |
set_textbox_style_bulk | 一次调用即可将一种样式应用到多个文本框 |
set_textbox_runs / set_textbox_value | 设置包含多个文本运行的富文本段落内容;或替换值 |
find_textboxes_by_style / find_textbox_by_value | 查找文本框,以便进行后续编辑 |
style_tablix_row | 一次性设置 tablix 行中每个单元格的样式(表头 / 明细 / 页脚) |
set_alternating_row_color | 使用 BackgroundColor=IIf(RowNumber(Nothing) Mod 2, "<a>", "<b>") 为 tablix 的明细行设置斑马纹 |
set_conditional_row_color | 根据表达式设置明细行的 BackgroundColor |
set_image_sizing / set_image_source | 设置图像 <Sizing>;切换 External / Embedded / Database 来源 |
可见性
| 工具 | 编辑内容 |
|---|---|
set_element_visibility | 为任意已命名的 ReportItem(Tablix、Textbox、Image、Rectangle、Subreport、Chart)设置 <Visibility>。组 / 明细行可见性有各自专用的工具。 |
布局容器
| 工具 | 构建内容 |
|---|---|
add_rectangle | 一个 <Rectangle> 容器(用于组合其他项、控制分页符) |
add_list | 一个列表区域(单列 tablix 模板) |
add_line | 一个 <Line> 报表项 |
定位与尺寸
在每个区域中移动和调整已命名项的大小。坐标采用 RDL 尺寸
("1in"、"2.5cm" 等)。
| 工具 | 编辑内容 |
|---|---|
set_body_item_position / set_header_item_position / set_footer_item_position | 设置已命名项的 Top / Left |
set_body_item_size / set_header_item_size / set_footer_item_size | 设置已命名项的 Width / Height |
set_body_size | 设置 <Body> 区域的整体高度 |
交互性
| 工具 | 编辑内容 |
|---|---|
set_textbox_action / set_image_action / set_chart_series_action | <Action>:超链接、钻取或书签 |
set_textbox_tooltip | 文本框 <ToolTip> |
set_document_map_label | 导航窗格的 <DocumentMapLabel> |
分页
| 工具 | 编辑内容 |
|---|---|
set_group_page_break | <Group><PageBreak>(Start / End / Between) |
set_repeat_on_new_page | 在每页重复组表头 / 页脚 |
set_keep_together / set_keep_with_group | 设置保持在一起的呈现提示 |
参数(高级)
| 工具 | 编辑内容 |
|---|---|
add_parameter / remove_parameter / rename_parameter | 管理 <ReportParameter> 元素 |
set_parameter_prompt / set_parameter_type | 提示词文本;数据类型(Boolean / DateTime / Integer / Float / Text) |
set_parameter_available_values | 静态 <ParameterValues> 列表(字符串或 {value, label} 字典)或指向查找数据集的 <DataSetReference> |
set_parameter_default_values | 静态 <Values> 列表或<DataSetReference>(默认值仅接受 ValueField——默认值是值,而非显示文本) |
update_parameter_advanced | 切换四个布尔标志:multi_value、hidden、allow_null(写入 <Nullable>)、allow_blank |
reorder_parameters | 重新排列 <ReportParameters>(控制提示词顺序) |
set_parameter_layout / sync_parameter_layout | 在 <ReportParametersLayout> 网格中定位参数 |
级联参数
RDL 没有 <DependsOn> 元素——级联关系是根据查找数据集 <QueryParameters> 中对
=Parameters!X.Value 的引用推断出来的。
要设置参数 B 依赖于参数 A:
set_parameter_available_values(name="B", source="query", query_dataset="LookupB", ...)add_query_parameter(dataset_name="LookupB", name="@A", value_expression="=Parameters!A.Value")
Report Builder 会解析这些表达式来确定依赖关系图。
嵌入式图像
| 工具 | 编辑内容 |
|---|---|
add_embedded_image | 从磁盘读取实际文件,将其编码为 base64,并存储在 <EmbeddedImages> 下 |
list_embedded_images | 名称 + MIME 类型 |
remove_embedded_image | 按名称移除;清理空的 <EmbeddedImages> |
使用
add_*_image(image_source="Embedded", value="<image-name>")
引用嵌入式图像。
报表生命周期
| 工具 | 功能 |
|---|---|
create_report | 创建一个最简有效的 .rdl 文件,供后续编辑 |
duplicate_report | 将报表复制到新路径 |
backup_report / restore_from_backup | 创建报表快照并回滚到该快照 |
表达式辅助工具
这些工具不会修改报表,而是构建正确的 RDL 表达式字符串,供其他工具使用(文本、筛选器、条件样式)。
| 工具 | 返回内容 |
|---|---|
count_where / sum_where | 带内联条件的 Count/Sum 聚合表达式 |
iif_format | 用于条件值/格式设置的 IIf(...) 表达式 |
get_expression_reference | 常见 RDL 表达式模式参考表 |
事务与验证
将多项编辑批量纳入一次原子保存,并在保存前后检查正确性。
| 工具 | 功能 |
|---|---|
start_editing_transaction / commit_editing_transaction / cancel_editing_transaction | 开启内存事务,执行检查并保存一次,或放弃更改。参见 docs/TRANSACTIONS.md。 |
apply_edits | 在一个事务中应用一组工具调用 |
dry_run_edit | 预览编辑效果,但不写入磁盘 |
validate_report / verify_report | 结构验证(以及选择性地使用捆绑的 reportdefinition.xsd 进行 XSD 验证) |
lint_report | 显示 Report Builder 会标记的警告/错误 |
原始 XML 备用方案
| 工具 | 功能 |
|---|---|
raw_xml_view | 读取 XPath 下的 XML |
raw_xml_replace | 替换 XPath 处的 XML——用于没有专用工具时的最后手段 |
Power BI 相关说明
XMLA 连接字符串
set_datasource_connection 会写入规范形式:
Data Source=powerbi://api.powerbi.com/v1.0/myorg/<workspace>;Initial Catalog=<dataset>
workspace_url 接受不带前缀的工作区名称(Finance)或完整的
powerbi:// URL——该工具会检测后者,避免重复添加前缀。
DataProvider 会设置为 SQL(RDL 用于 PBI XMLA 的 Analysis Services 提供程序 ID,尽管名称容易引起误解)。
DAX 查询
DAX 主体会原样接受——pbirb-mcp 不会解析 DAX,因此语法以用户(或预览时的 Report Builder)为准。
空主体会在一开始就被拒绝,因为 Report Builder 虽然会加载它们,但会在预览时出错;这不如在此处明确返回 ValueError。
PBI 分页报表不会为 DAX 携带 <CommandType>(不同于可设置 CommandType=StoredProcedure 的
SSRS);这些工具从不输出该元素。
提交前钩子(贡献者)
pre-commit 包含在 [dev] 额外依赖中。全新检出后:
uv pip install --python .venv/bin/python -e ".[dev]"
.venv/bin/pre-commit install # one-time — installs the git hook
.venv/bin/pre-commit run --all-files # one-time — clean any drift
安装钩子后,每次 git commit 都会运行 ruff format +
ruff check(带 --fix)+ 快速 pytest 测试套件。如果检查或测试
失败,提交会被中止;请修复问题并重新暂存,然后再试。
要按需单独运行钩子:
.venv/bin/pre-commit run ruff --all-files
.venv/bin/pre-commit run ruff-format --all-files
.venv/bin/pre-commit run pytest-fast --all-files
完整配置位于 .pre-commit-config.yaml 中。Ruff 设置
(行长度、规则选择、按文件忽略项)位于 pyproject.toml 中的
[tool.ruff*] 下。
报表生成器安装
Power BI Report Builder 是 Microsoft 免费提供的 Windows 应用:
https://www.microsoft.com/en-us/download/details.aspx?id=105942
使用 Report Builder 直接打开 pbirb-mcp 生成的任意 .rdl 文件。“打开时没有升级提示且文件正常载入”这一检查才是真正的集成测试——单元测试会验证架构正确性,但 lxml 可能会往返处理 XML,而 Report Builder 的反序列化器仍会拒绝它(我们在图表模板开发中遇到过两次;两项修复都记录在 git 历史中)。
架构
pbirb-mcp/
├── pbirb_mcp_server.py # Entry point (logging + main())
├── pbirb_mcp/
│ ├── server.py # JSON-RPC stdio dispatch
│ ├── tools.py # Tool registry — wires ops into the server
│ ├── core/
│ │ ├── document.py # RDLDocument: open/save (lxml), atomic write
│ │ ├── xpath.py # Namespace-aware XPath helpers
│ │ ├── ids.py # Stable element addressing
│ │ ├── encoding.py # XML declaration / self-closing-tag fidelity
│ │ ├── transactions.py # In-memory transaction registry
│ │ └── schema.py # Structural + opt-in XSD validation
│ ├── ops/ # One module per RDL concern; wired into tools.py
│ │ ├── reader.py # describe / get_datasets / get_params / get_tablixes
│ │ ├── datasource.py # PBI XMLA connection + data-source management
│ │ ├── dataset.py # DAX body, query params, fields, calc fields, filters
│ │ ├── tablix.py # Row/column groups, sort, visibility, matrix
│ │ ├── tablix_columns.py # Add/remove tablix columns
│ │ ├── tablix_cells.py # Cell span
│ │ ├── tablix_static.py # Static rows / columns
│ │ ├── tablix_subtotals.py # Subtotal rows / columns
│ │ ├── chart.py # Chart series, axes, legend, labels, palette
│ │ ├── page.py # Page setup + orientation
│ │ ├── layout.py # Pagination (page breaks, keep-together, repeat)
│ │ ├── header_footer.py # Page header / footer authoring
│ │ ├── body.py # Body textboxes / images / containers / removal
│ │ ├── positioning.py # Move / resize named items per region
│ │ ├── templates.py # Chart + tablix snippet builders
│ │ ├── styling.py # Textbox styles, runs, bulk, row styling, find
│ │ ├── images.py # Image sizing / source
│ │ ├── actions.py # Actions, tooltips, document-map labels
│ │ ├── visibility.py # Element-level visibility
│ │ ├── parameters.py # Lifecycle, values, advanced flags, layout
│ │ ├── embedded_images.py # Base64 image embedding
│ │ ├── expressions.py # Expression-builder helpers (count/sum/iif)
│ │ ├── filter_types.py # Filter operator definitions
│ │ ├── clone.py # duplicate_report
│ │ ├── scratch.py # create_report
│ │ ├── snapshot.py # backup / restore
│ │ ├── transactions.py # start/commit/cancel + apply_edits
│ │ ├── dry_run.py # dry_run_edit
│ │ ├── validate.py # validate / verify
│ │ ├── lint.py # lint_report
│ │ └── escape.py # raw_xml_view / raw_xml_replace
│ └── schemas/ # Bundled RDL 2016 XSD (reportdefinition.xsd) for opt-in validation
└── tests/
├── fixtures/
│ └── pbi_paginated_minimal.rdl # Hand-tuned to match Report Builder's emitted style
└── test_*.py # 1188 tests — every tool plus round-trip invariants
强制规则(由测试执行)
- 测试优先。 每次提交都先编写失败的测试,再让测试通过。
- 使用 lxml,而不是标准库
xml.etree。 保持往返保真度是一项功能,而非锦上添花。Report Builder 会读取磁盘上的内容;格式漂移会导致静默损坏。 - 使用稳定 ID,绝不使用索引。 工具接收
tablix_name+group_name,而不是column_index: 2。索引在多步编辑中会失效。 - 原子保存。
RDLDocument.save_as会先写入<path>.tmp,然后再重命名。写入过程中发生故障,也不会留下只写入一半的报表。 - 通过
tests/test_document.py中的test_round_trip_byte_identical_to_fixture强制检查往返字节一致性。 空操作的打开 → 保存 → 重新打开流程会生成字节完全一致的文件。
血泪总结的 RDL 注意事项
<?xml version="1.0" encoding="utf-8"?>使用双引号,而非 lxml 默认的单引号。已在RDLDocument.save_as中通过手动声明修复。- 自闭合标签使用
<Tag />,中间有空格,而不是<Tag/>。已通过后处理正则表达式修复。 rd:前缀 (http://schemas.microsoft.com/SQLServer/reporting/reportdesigner) 携带 Report Builder 依赖的设计器元数据。不要移除它; 请保留前缀。- 除非同时声明
xmlns:df=...,否则不要在<Report>上添加MustUnderstand="df"。 <ChartCategoryAxes>/<ChartValueAxes>直接包含<ChartAxis>子元素——不存在<ChartCategoryAxis>/<ChartValueAxis>包装元素。<ChartMember>必须包含<Label>子元素,即使它为空也一样。- DAX 查询位于
<DataSet><Query><CommandText>EVALUATE ...</CommandText></Query></DataSet>。 DAX 不使用<CommandType>元素(与 SSRS 不同)。
日志记录
以下两个环境变量用于控制日志记录器:
| 变量 | 默认值 | 用途 |
|---|---|---|
PBIRB_MCP_LOG_LEVEL | WARNING | DEBUG / INFO / WARNING / ERROR |
PBIRB_MCP_LOG_FILE | stderr | 日志文件路径;否则日志会写入 stderr(Claude Desktop 会在其 MCP 调试面板中捕获这些日志) |
PBIRB_MCP_LOG_LEVEL=DEBUG PBIRB_MCP_LOG_FILE=/tmp/pbirb-mcp.log pbirb-mcp
开发
运行测试
.venv/bin/python -m pytest tests/ -v
测试套件运行很快(1188 个测试约需 1.7 秒),因此每次更改后都要重新运行。
对实时二进制文件进行冒烟测试
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| .venv/bin/pbirb-mcp
如需端到端健全性检查,可针对随附样例文件的副本执行实际修改:
SCRATCH=$(mktemp -d)/r.rdl
cp tests/fixtures/pbi_paginated_minimal.rdl "$SCRATCH"
.venv/bin/python -c "
from pbirb_mcp.ops.dataset import update_dataset_query
update_dataset_query(path='$SCRATCH', dataset_name='MainDataset',
dax_body=\"EVALUATE TOPN(10, 'Sales')\")
print('Wrote', '$SCRATCH')
"
在 Power BI Report Builder 中打开生成的文件。手动验证 .rdl 能否正常打开才是真正的集成测试——单元测试能发现架构层面的错误,但只有 Report Builder 能发现反序列化器的细微要求。
添加新工具
- 先在
tests/test_*.py下编写测试。 - 在相应的
pbirb_mcp/ops/*.py模块中实现(或创建新模块)。 - 在
pbirb_mcp/tools.py中注册,并提供清晰的description和严格的inputSchema。 - 运行完整测试套件,并针对样例文件执行 JSON-RPC 冒烟测试。
- 在 Report Builder 中打开修改后的 RDL。
逐次提交的历史记录展示了实际操作模式。
发布
CHANGELOG.md 按照 Keep a Changelog 格式跟踪每个版本的变更。发布版本也会同步发布到 GitHub Releases 和 PyPI。
版本遵循针对 MCP 工具接口调整的 SemVer 规范,详见 CONTRIBUTING.md § Versioning。
贡献
欢迎提交 PR。CONTRIBUTING.md 介绍了开发环境设置、硬性规则(先写测试、仅使用 lxml、稳定 ID、原子保存、往返字节完全一致、在 Report Builder 中进行冒烟测试)、SemVer-for-MCP 版本递增表,以及 PR 审查清单。
报告 Bug 和提议工具:请使用 问题模板。 安全问题请参阅 SECURITY.md。所有参与者 都应遵守行为准则。
致谢
现有的 bethmaloney/rdl-mcp 服务开创了 MCP-over-RDL 模式,但其范围仅限于 SSRS:列 元数据、基本参数管理、存储过程替换。Power BI 分页报表使用与 SSRS 相同的 RDL 2016 架构,但:
- 数据源是 Power BI XMLA 终结点,而不是 SQL Server。
- 查询使用 DAX,且上游工具不支持编辑正文(只能 替换存储过程名称,在此处毫无用处)。
- Report Builder 对 XML 往返处理很挑剔——格式漂移、
命名空间前缀丢失或无法识别的
MustUnderstand属性都会导致 静默损坏,或提示“此报表需要升级”。
pbirb-mcp 基于 lxml 构建,因此无操作编辑会生成字节完全一致的
文件;通过稳定名称(而非索引)定位每个元素,并将
“可在 Report Builder 中正常打开”作为实际集成测试。
mcp-name: io.github.mafaq229/pbirb-mcp
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。