内容
<!-- mcp-name: io.github.tdries/tableau-graphql-mcp -->
<p align="center">
<img src="docs/images/banner.png" alt="tableau-graphql-mcp" width="880">
</p>
<h1 align="center">tableau-graphql-mcp</h1>
<p align="center"><em>通过 Tableau 元数据 API,在任何 MCP 客户端中提出 Tableau 血缘问题。</em></p>
<p align="center">
<a href="https://github.com/tdries/tableau-graphQL-mcp/actions/workflows/ci.yml"><img src="https://github.com/tdries/tableau-graphQL-mcp/actions/workflows/ci.yml/badge.svg" alt="持续集成"></a>
<a href="https://github.com/tdries/tableau-graphQL-mcp/actions/workflows/codeql.yml"><img src="https://github.com/tdries/tableau-graphQL-mcp/actions/workflows/codeql.yml/badge.svg" alt="CodeQL"></a>
<a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff"></a>
<a href="https://pypi.org/project/tableau-graphql-mcp/"><img src="https://img.shields.io/pypi/v/tableau-graphql-mcp.svg" alt="PyPI"></a>
<img src="https://img.shields.io/pypi/pyversions/tableau-graphql-mcp.svg" alt="Python 版本">
<img src="https://img.shields.io/badge/MCP-compatible-8A2BE2.svg" alt="MCP 兼容">
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-00696E.svg" alt="MIT 许可证"></a>
<img src="https://img.shields.io/badge/Tableau-Server%20%2B%20Cloud-006EFF.svg" alt="服务器 + 云">
<img src="https://img.shields.io/badge/deps-just%20mcp-64FA8C.svg" alt="最小依赖">
</p>
<p align="center">
<a href="cursor://anysphere.cursor-deeplink/mcp/install?name=tableau-graphql&config=eyJjb21tYW5kIjogInV2eCIsICJhcmdzIjogWyJ0YWJsZWF1LWdyYXBocWwtbWNwIl19"><img src="https://img.shields.io/badge/Add%20to-Cursor-0098FF.svg" alt="添加到 Cursor"></a>
</p>
<p align="center">
<img src="docs/images/demo.gif" alt="在 Claude 中提问血缘问题" width="760">
</p>
---
**tableau-graphql-mcp** 将您的 Tableau 站点的 [元数据 API](https://help.tableau.com/current/api/metadata_api/en-us/index.html) 转换为一组 MCP 工具,以便 AI 助手(Claude、Cursor、Cline 等)可以回答血缘问题:
- _"如果我删除列 `SALES`,哪些工作簿会受到影响?"_
- _"工作簿 **Sales Overview** 依赖哪些表?"_
- _"哪些计算字段引用 `Profit`,在哪些仪表板上?"_
- _"在更改 `DIM_CUSTOMER` 表之前,我应该通知谁?"_
它提供了 **七种精选工具**:通用 GraphQL 直通、实时模式 introspection、嵌入式正确查询模板库、强大的 `where_used` 解析器、多跳 `impact_analysis`、子字符串内容搜索和连接探测。它们一起让模型回答 *任何* 血缘问题,而不仅仅是一个固定的菜单。
### 为什么与众不同
- **任何问题,正确回答。** `graphql_query` 运行任何只读 GraphQL 查询;`introspect_schema` 和内置的速查表加上 28 个有效的示例保持模型的查询正确。
- **真正的 impact 分析(多跳)。** `impact_analysis` 跟随整个依赖链(计算字段建立在计算字段上,列上),并返回完整的辐射范围加上 **通知所有者**,而不仅仅是直接引用。
- **在任何地方工作。** Tableau **服务器** 和 **云**。REST API 版本和 GraphQL 端点(`/api/metadata/graphql`,带有 `/relationship-service-war/graphql` 回退)是 **自动检测** 的。
- **无需目录的强大血缘。** `where_used` 通过核心血缘解析工作簿(`referencedByFields -> sheets -> workbook`),因此即使数据管理插件的 `downstreamWorkbooks` 为空,它也有效。
- **无静默截断。** `graphql_query` 在查询达到节点限制时标记 `partial_results`,而 `search_content` 报告 `scanned`/`total` 覆盖范围,以便不会将截断的答案误认为是完整的答案。
- **小且安全。** 只读,stdio-only(无传入端口),环境变量中的机密,**除了 MCP SDK 之外没有依赖**(用于 HTTP 的标准库 `urllib`)。
## 快速入门
您需要 [`uv`](https://docs.astral.sh/uv/) (`curl -LsSf https://astral.sh/uv/install.sh | sh`) 和 Tableau [个人访问令牌](https://help.tableau.com/current/server/en-us/security_personal_access_tokens.htm)。
**Claude 代码,一行:
```bash
claude mcp add tableau-graphql \
-e TABLEAU_SERVER=https://10ax.online.tableau.com \
-e TABLEAU_SITE_CONTENT_URL=YourSite \
-e TABLEAU_PAT_NAME=my-token \
-e TABLEAU_PAT_SECRET=the-full-secret \
-- uvx tableau-graphql-mcp
```
就这样。`uvx` 从 PyPI 获取包并在隔离环境中运行;无需克隆或安装(无需 `git`)。然后向 Claude 询问一个血缘问题。
## 配置
所有配置都通过环境变量(在客户端的 `env` 块中设置,而不是在命令行上)。
| 环境变量 | 必需 | 默认值 | 描述 |
|---|:---:|---|---|
| `TABLEAU_SERVER` | 是 | n/a | `https://tableau.company.com`(服务器)或 `https://<pod>.online.tableau.com`(云)。 |
| `TABLEAU_SITE_CONTENT_URL` | 否 | `""` | 站点 slug(`/#/site/` 之后的部分)。空 = 默认站点(仅限服务器);云始终有一个。 |
| `TABLEAU_PAT_NAME` | 是¹ | n/a | 个人访问令牌 **名称**。 |
| `TABLEAU_PAT_SECRET` | 是¹ | n/a | PAT **机密**:整个字符串,**不要** 在 `:` 上拆分。 |
| `TABLEAU_TIMEOUT` | 否 | `60` | 每个请求的超时时间(秒)。 |
| `TABLEAU_API_VERSION` | 否 | 自动 | REST API 版本;否则从 `/api/serverinfo` 读取。 |
| `TABLEAU_METADATA_PATH` | 否 | 自动 | 重写 GraphQL 路径;否则自动检测。 |
| `TABLEAU_AUTH_TOKEN` | 否 | n/a | 高级:预先获得的 `X-Tableau-Auth` 令牌(禁用 PAT 的 SSO 租户)。 |
| `TABLEAU_COOKIE` | 否 | n/a | 高级:浏览器会话 cookie(SSO 回退)。 |
¹ 提供 PAT(`TABLEAU_PAT_NAME` + `TABLEAU_PAT_SECRET`)**或** 高级 `TABLEAU_AUTH_TOKEN` / `TABLEAU_COOKIE`。
<details>
<summary><b>Claude 桌面版</b></summary>
编辑 `claude_desktop_config.json`(macOS: `~/Library/Application Support/Claude/`,Windows: `%APPDATA%\Claude\`):
```json
{
"mcpServers": {
"tableau-graphql": {
"command": "uvx",
"args": ["tableau-graphql-mcp"],
"env": {
"TABLEAU_SERVER": "https://10ax.online.tableau.com",
"TABLEAU_SITE_CONTENT_URL": "YourSite",
"TABLEAU_PAT_NAME": "my-token",
"TABLEAU_PAT_SECRET": "the-full-secret"
}
}
}
}
```
完全 **退出并重新打开** Claude 桌面版,然后检查工具菜单。
</details>
<details>
<summary><b>Cursor</b> · <b>Cline</b> · <b>Windsurf</b></summary>
每个客户端都使用上面显示的相同的 `mcpServers` 架构。将相同的块添加到:
- **Cursor**:`~/.cursor/mcp.json`(全局)或 `.cursor/mcp.json`(项目)。
- **Cline**:MCP 服务器面板,然后 *配置*,进入 `cline_mcp_settings.json`。
- **Windsurf**:`~/.codeium/windsurf/mcp_config.json`。
在 Windows 上,如果 GUI 应用程序找不到 `uvx`,请使用其绝对路径(例如 `%USERPROFILE%\.local\bin\uvx.exe`)。
</details>
## 工具
| 工具 | 功能 | 关键参数 |
|---|---|---|
| `graphql_query` | 运行 **任何** 只读元数据 API GraphQL 查询。用于任何血缘问题的通用工具。 | `query`,`variables` |
| `introspect_schema` | 实时模式 introspection:列出入口点或类型的确切字段。 | `type_name` |
| `lineage_examples` | 模式速查表加上 28 个精选的查询到 GraphQL 模板(8 类)。 | `category` |
| `where_used` | 哪些工作簿/数据源使用给定的列 / 字段 / 表名(强大的单跳核心血缘解析)。 | `names` |
| `impact_analysis` | 列/字段/表的完整传递 **多跳** 辐射范围:每个依赖字段,加上受影响的工作表、仪表板、工作簿和 **通知所有者**。 | `name` |
| `search_content` | 查找内容名称中包含术语(不区分大小写的子字符串)的项,跨工作簿、数据源、表(和可选的字段/列),并带有覆盖率数字。 | `term`,`types` |
| `server_info` | 连接的服务器、站点、版本、端点、身份验证以及是否可用 Catalog 血缘。 | 无 |
所有工具都是 **只读** 的。元数据 API 没有突变。
## 示例提示
连接后,尝试:
- _"使用 `server_info` 确认您连接的是什么。"_
- _"搜索名称中包含 'revenue' 的任何内容。"_
- _"哪些工作簿使用列 SALES、PROFIT 和 DISCOUNT?按所有者分组。"_
- _"显示 'Sales Overview' 工作簿的字段到源列映射。"_
- _"列出该工作簿中每个计算字段及其公式。"_
- _"哪些已发布的数据源为 Analytics 项目中的工作簿提供数据,哪些是未认证的?"_
- _"对 'Profit Ratio' 字段运行 impact_analysis:每个依赖关系的工作表、仪表板、工作簿和通知所有者。"_
- _"删除 DIM_CUSTOMER 表的辐射范围是什么:工作簿、工作表和通知所有者?"_
## 架构
<p align="center"><img src="docs/images/architecture.svg" alt="架构" width="900"></p>
服务器通过 **stdio** 与客户端进行 MCP 通信,通过 HTTPS 与 Tableau 通信:它使用您的 PAT 登录以获取 `X-Tableau-Auth` 令牌(在过期时自动刷新),自动检测 REST API 版本和 GraphQL 端点,然后将查询转发到元数据 API。没有任何数据被存储;每个答案都是实时的。
## 安全
- **只读,强制执行。** 只有 GraphQL 查询:无写入,无 shell。`graphql_query` 拒绝 `mutation`/`subscription` 操作,元数据 API 无论如何都是只读的。
- **本地且仅限 stdio。** 没有打开的传入网络端口。
- **仅限环境变量中的机密。** 绝不作为工具参数传递,绝不记录,绝不返回在输出中。
- **最小权限。** PAT 继承您的 Tableau 权限;API 只返回您可以查看的内容。
- 在生产环境中固定版本:`uvx tableau-graphql-mcp==0.1.0`。
参见 [SECURITY.md](SECURITY.md)。
## 故障排除
| 症状 | 修复方法 |
|---|---|
| 服务器未出现 | 完全退出并重新启动客户端;检查配置路径和 JSON 有效性。 |
| `spawn uvx ENOENT` | 安装 `uv`,或使用 `uvx` 的绝对路径。 |
| 登录失败(401) | 检查 PAT 名称/机密和 `TABLEAU_SITE_CONTENT_URL`。在 SSO 租户上,PAT 可能被禁用;使用 `TABLEAU_AUTH_TOKEN`/`TABLEAU_COOKIE`。 |
| "无法访问元数据 API" | 在 Tableau **服务器** 上,管理员必须启用它:`tsm maintenance metadata-services enable`。在云上,它始终处于启用状态。 |
| 空的 `downstreamWorkbooks` | 在没有数据管理插件的情况下预期为空;使用 `where_used` 工具,它通过核心血缘解析。 |
使用 MCP 检视器直接检查服务器:
```bash
npx @modelcontextprotocol/inspector uvx tableau-graphql-mcp
```
## 开发
```bash
git clone https://github.com/tdries/tableau-graphQL-mcp && cd tableau-graphQL-mcp
uv sync --all-extras
uv run tableau-graphql-mcp # 从源代码运行
uv run pytest --cov=tableau_graphql_mcp # 测试 + 覆盖率(离线;无需 Tableau)
uv run ruff check . # 校验
uv run ruff format --check . # 格式化
```
相同的三个门控(校验、格式化、测试,覆盖率下限为 85%)在 CI 中运行,涵盖 Linux/macOS/Windows 和 Python 3.10 至 3.13。覆盖率报告给 Codecov,代码在每次推送时都由 CodeQL 扫描。
相同的门控在 CI 中运行(Linux/macOS/Windows,Python 3.10 至 3.13):`ruff check`、`ruff format --check`、`mypy --strict` 和 `pytest`,覆盖率下限。包附带一个 PEP 561 `py.typed` 标记,以便导入它为您的类型检查器提供完整的类型。
欢迎贡献:请参阅 [CONTRIBUTING.md](CONTRIBUTING.md) 和 [行为准则](CODE_OF_CONDUCT.md)。
## 路线图
已发布:发布在 [PyPI](https://pypi.org/project/tableau-graphql-mcp/) 上,并在官方 [MCP 注册表](https://registry.modelcontextprotocol.io/v0/servers?search=tableau-graphql) 中列出。
接下来:
- [ ] 可选的数据管理路径:当存在目录时,更丰富的 `downstreamWorkbooks`
- [ ] `lineage_examples` 中更多的精选查询模板
- [ ] 会话内重复 introspection 的可选响应缓存
在 [讨论](https://github.com/tdries/tableau-graphQL-mcp/discussions) 中欢迎想法和投票。
## 许可证
[MIT](LICENSE) © Tim Dries。在 [Biztory](https://www.biztory.com) 构建。